feat: Add AI Model Config resource and data source#371
feat: Add AI Model Config resource and data source#371tracisiebel wants to merge 25 commits intomainfrom
Conversation
- Upgrade api-client-go from v17.1.0 to v17.2.0 for AI Model Config support - Add resource_launchdarkly_ai_model_config with Create, Read, Delete operations - Add data_source_launchdarkly_ai_model_config for read-only access - Add ai_model_config_helper with schema and read functions - Add JSON helper functions for params and customParams fields - Register both resource and data source in provider - Add schema constants for AI Model Config fields Note: AI Model Configs do not support updates via PATCH API, so all fields are marked as ForceNew to force recreation on any changes. Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| Type: schema.TypeString, | ||
| Required: !isDataSource, | ||
| Computed: isDataSource, | ||
| ForceNew: !isDataSource, |
There was a problem hiding this comment.
do you actually want to force new for resources that change their name? this will trigger a delete and then a recreation of a totally new resource with the same properties
There was a problem hiding this comment.
no - i made it so that you can't make updates.
There was a problem hiding this comment.
Great solution! Using CustomizeDiff to validate immutability is much better than ForceNew: true because:
- ForceNew: Would automatically destroy and recreate the resource on any change (risky!)
- Your approach: Shows a clear error message during plan phase and prevents the update (safer!)
This addresses @sloloris's concern about accidental deletion/recreation while still enforcing that the resource is immutable. Nice work!
| ID: { | ||
| Type: schema.TypeString, | ||
| Required: !isDataSource, | ||
| Computed: isDataSource, |
There was a problem hiding this comment.
does the user assign this or does LD? if LD assigns this it should always be computed and the force new is moot
There was a problem hiding this comment.
Thanks for clarifying! Since the user assigns model_id, having it as Required: !isDataSource and Computed: isDataSource is correct. The current implementation is good.
| Optional: !isDataSource, | ||
| Computed: isDataSource, | ||
| ForceNew: !isDataSource, | ||
| Description: addForceNewDescription("Model parameters as a JSON string.", !isDataSource), |
There was a problem hiding this comment.
are these parameters fixed? if so i would recommend trying for an object rather than forcing hte user to pass a json string similar to the API
| }, | ||
| }, | ||
| CUSTOM_PARAMS: { | ||
| Type: schema.TypeString, |
There was a problem hiding this comment.
ditto - not convinced this should be a string
| Type: schema.TypeString, | ||
| Optional: !isDataSource, | ||
| Computed: isDataSource, | ||
| ForceNew: !isDataSource, |
| Type: schema.TypeString, | ||
| Optional: !isDataSource, | ||
| Computed: isDataSource, | ||
| ForceNew: !isDataSource, |
| Type: schema.TypeFloat, | ||
| Optional: !isDataSource, | ||
| Computed: isDataSource, | ||
| ForceNew: !isDataSource, |
There was a problem hiding this comment.
okay i see devin just thinks everything should force new. i'm assuming this has something to do with the no update thing, but i still think someone should look at this more closely
There was a problem hiding this comment.
Thank you for the detailed review! I want to address the ForceNew concerns and explain my reasoning.
The Core Issue: No PATCH Endpoint
I've investigated the API client v17.2.0 and the available methods for AI Model Configs are:
PostModelConfig(create)GetModelConfig(read)DeleteModelConfig(delete)ListModelConfigs(list)
There is no PatchModelConfig method in the API client. Without an update endpoint, I cannot implement Terraform's UpdateContext function. If I remove ForceNew from user-settable fields, Terraform would plan an update but fail at apply time because there's no API to call.
Is there an undocumented or planned update endpoint I should be using instead? If so, I'm happy to implement proper updates and remove ForceNew where appropriate.
Addressing Your Specific Comments:
-
params/customParams as objects: You're absolutely right! The OpenAPI spec shows these as
type: "object", not strings. I'll change them toschema.TypeMapto provide a better UX. -
ID field: According to the OpenAPI spec,
idis required inModelConfigPost, so it's user-provided (not LD-assigned). I'll keep it asRequired: truewithForceNew: true. -
GLOBAL field: You're correct -
globalis NOT inModelConfigPost, so it's server-assigned. I'll change it toComputed: trueonly and removeForceNew. -
ForceNew on other fields: Fields like
name,provider,icon,costPerInputToken,costPerOutputToken, etc. are all user-provided inModelConfigPost. Without a PATCH endpoint, these needForceNew: trueto maintain correct Terraform semantics. Otherwise, users would see planned updates that fail at apply time.
My Plan:
- Change params/customParams to TypeMap objects
- Fix GLOBAL to be Computed-only
- Keep ForceNew on user-settable fields (unless you can point me to an update endpoint)
- Add Beta API header if needed
Please let me know if there's an update endpoint I'm missing, or if you'd prefer a different approach!
| }, | ||
| GLOBAL: { | ||
| Type: schema.TypeBool, | ||
| Computed: true, |
There was a problem hiding this comment.
is this user-defined or does LD auto-assign the value? if the former it should not be computed
There was a problem hiding this comment.
Thanks for clarifying! Since LD auto-assigns the global field, having it as Computed: true is correct. No changes needed here.
sloloris
left a comment
There was a problem hiding this comment.
hi @tracisiebel !
before we approve and release this, could you get someone from your team who is familiar with the resource and the API to review this, especially the schema? i also don't think we have many (if any) other resources that don't allow update / have an associated patch API - i think it is worth having a more deliberate conversation about how we actually expect the provider to behave in this situation.
also, we will want to ensure it is thoroughly tested before we merge.
- Change params and customParams from JSON strings to TypeMap objects per reviewer feedback - Fix GLOBAL field to be Computed-only (already correct, no changes needed) - Fix v17.2.0 compatibility: dereference pointer for flag.Environments in feature_flag_environment_helper.go - Fix v17.2.0 compatibility: remove IsActive field from MetricPost in resource_launchdarkly_metric.go - Remove unused isActive variable from metric create function Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
Resolved merge conflict in go.mod: - Kept api-client-go v17.2.0 (required for AI Model Config) - Updated golang.org/x/sync to v0.18.0 from main Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
…map change The v17.2.0 API client changed flag.Environments from map[string]FeatureFlagConfig to *map[string]FeatureFlagConfig (pointer to map). Updated test files to add nil checks and dereference the pointer before indexing, matching the pattern used in production code (feature_flag_environment_helper.go). Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
Removed jsonMarshal and jsonEqual functions that were no longer needed after changing params and customParams from JSON strings to TypeMap objects. Also removed now-unused encoding/json and reflect imports. Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
- Rename 'provider' field to 'model_provider' to avoid Terraform reserved name conflict - Add ForceNew to tags field since there is no Update endpoint - Both resource and data source now pass InternalValidate checks Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
|
@sloloris tested with this command:
everything passed. Added some tests. |
|
Great work on the improvements! The validation errors are fixed and comprehensive tests have been added. Here's my review: ✅ What Looks Good
📝 Observations
🤔 Questions for DiscussionThe PR description still mentions some items that may need addressing:
Overall, this looks ready for merge from a functionality perspective. The tests are comprehensive and the implementation correctly handles the API's limitations. |
| kind := d.Get(KIND).(string) | ||
| description := d.Get(DESCRIPTION).(string) | ||
| tags := stringsFromResourceData(d, TAGS) | ||
| isActive := d.Get(IS_ACTIVE).(bool) |
There was a problem hiding this comment.
I understand you want to revert this change, but I need to clarify the situation:
Why this line was removed:
The api-client-go v17.2.0 removed IsActive from the MetricPost struct (used for creation). This line was reading is_active from the schema but never using it - it wasn't being set on the MetricPost object. Keeping this line would cause a Go compilation error: "declared and not used".
Current state:
- ✅
is_activeis still in the Terraform schema (marked as Deprecated: "No longer in use") - ✅
is_activeis still read from the API inmetricRead()(line 198 in metrics_helper.go) - ✅
is_activeis still sent in PATCH operations duringresourceMetricUpdate()(line 317) - ❌
is_activecannot be set during metric creation (removed from MetricPost in v17.2.0)
Options:
- Keep as-is: The field works for read and update, just not for initial creation (which aligns with the deprecation notice)
- Revert with modification: Add the line back but comment it out with an explanation
- Remove entirely: Remove from schema, update, and read (breaking change)
Which approach would you prefer? The current implementation maintains backwards compatibility while working within the v17.2.0 API constraints.
ldhenry
left a comment
There was a problem hiding this comment.
In general, we try not to release resources that are still behind beta APIs. Do y'all have near-term plans to take the AI config endpoints out of beta?
launchdarkly/data_source_launchdarkly_feature_flag_environment_test.go
Outdated
Show resolved
Hide resolved
|
@ldhenry Regarding your question about beta APIs: Looping in @tracisiebel for product guidance on this. From the implementation side, we've structured it with the beta header set per-request and have comprehensive acceptance tests passing. If the policy is to avoid shipping resources backed by beta APIs, we can either:
Happy to follow whatever approach aligns with LaunchDarkly's release policy. |
Co-authored-by: Henry Barrow <hbarrow@launchdarkly.com>
…unchdarkly/terraform-provider-launchdarkly into devin/1763591735-add-ai-model-configs
|
moved the apis out of beta @ldhenry https://github.com/launchdarkly/gonfalon/pull/56940 |
|
Great news that the APIs are out of beta! This addresses @ldhenry's concern about shipping resources backed by beta APIs. I'm currently working on splitting the v17.2.0 upgrade into a separate PR as @ldhenry requested. Once that's done, I'll:
This will make the PR cleaner and address all the review feedback. |
|
@ldhenry not ready for review. need to pick up the new changes (without beta) before it's ready. I'll let you know |
The AI Model Config APIs have been moved out of beta, so we no longer need the separate beta client configuration. This commit: - Updates AI Model Config resource and data source to use standard client - Removes ldBeta client and newLDClientConfigNoVersion from config.go - Updates all test files to remove references to beta client - Addresses ldhenry's DRY concern by removing duplicate configuration This simplifies the implementation and addresses reviewer feedback. Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
…support The AI Model Config APIs have been moved to GA and are available in api-client-go v17.2.0. This upgrade is required for the AI Model Config Terraform resource implementation. Breaking changes in v17.2.0: - flag.Environments is now *map[string]ldapi.FeatureFlagConfig (pointer to map) - MetricPost.IsActive field removed (can only be set via PATCH after creation) Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
Update code to handle breaking changes in api-client-go v17.2.0: - Remove IsActive field from MetricPost struct (field removed in v17.2.0) - Dereference flag.Environments pointer in test files (now *map instead of map) These changes ensure compatibility with v17.2.0 while maintaining existing functionality. Co-Authored-By: traci@launchdarkly.com <traci@launchdarkly.com>
|
I've updated the PR to address the review feedback and the fact that AI Config APIs are now GA: Changes MadeSimplified Implementation (APIs now GA):
SDK Upgrade:
Test Updates:
All code and tests compile successfully locally. Waiting for CI checks to complete. |
Sounds good. Just keep us in the loop. |
|
@tracisiebel @ldhenry The PR is now ready for review! I've completed the "without beta" changes:
CI Status: 23 of 25 acceptance test suites pass. The only failing test is All tests related to my changes pass:
|
Summary
Adds support for AI Model Config resources and data sources to the LaunchDarkly Terraform provider. AI Model Configs allow users to configure LLM model settings including provider, parameters, and pricing information.
Link to Devin run: https://app.devin.ai/sessions/e41fa8370ea042beb14d4de2a208f98c
Requested by: @tracisiebel (traci@launchdarkly.com)
Changes
New Resources
launchdarkly_ai_model_config- Create and manage AI model configurationslaunchdarkly_ai_model_config- Read existing AI model configurationsKey Features
model_id,model_provider,icon,params,custom_params,cost_per_input_token,cost_per_output_token,tagsCustomizeDiff)SDK Upgrade
api-client-gofrom v17.1.0 to v17.2.0 (required for AI Model Config GA support)flag.Environmentsis now*map[string]ldapi.FeatureFlagConfig(pointer to map)MetricPost.IsActivefield removed (can only be set via PATCH after creation)Beta Client Cleanup
ldBeta,newBetaClient) since AI Config APIs are now GATesting
✅ Comprehensive test coverage added:
name,model_id,tags,params,custom_params,cost_per_input_token,cost_per_output_tokenHuman Review Checklist
Critical items to review:
SDK upgrade side effects: The v17.2.0 upgrade has breaking changes. Verify that:
flag.Environmentspointer dereferencing is correct (changed in test files)IsActivefromMetricPostdoesn't break metric creationBeta client removal impact: I removed
newBetaClient()and updated metric tests to use standard client. Verify that:Immutability implementation: Verify that:
CustomizeDiffDocumentation: This PR does not include documentation updates. Should we add:
launchdarkly_ai_model_configlaunchdarkly_ai_model_configAPI naming: The API service is still called
AIConfigsBetaApiin the SDK even though the APIs are GA. This is just a naming artifact and shouldn't cause issues, but worth noting.Known Limitations
Follow-up Items