feat: add AIProvider types and client methods#24893
Conversation
b401da5 to
4a69dee
Compare
4a69dee to
8271800
Compare
0c4482a to
eacc052
Compare
8271800 to
b697680
Compare
eacc052 to
401fd51
Compare
b697680 to
5221fc9
Compare
401fd51 to
78ea362
Compare
5221fc9 to
fb7c328
Compare
73ce74c to
1a61871
Compare
fb7c328 to
9f6b23e
Compare
2573348 to
a650b5f
Compare
9f6b23e to
42dbe58
Compare
a650b5f to
fffa3e9
Compare
42dbe58 to
4f9930f
Compare
fffa3e9 to
1d16ab9
Compare
4f9930f to
02883ed
Compare
1d16ab9 to
da18210
Compare
02883ed to
b79d62d
Compare
86dbfac to
f78b55a
Compare
b79d62d to
6e813a9
Compare
f78b55a to
f16f248
Compare
984c734 to
5bfb65f
Compare
5bfb65f to
80d35d3
Compare
148bd38 to
5840ac5
Compare
|
/coder-agents-review |
There was a problem hiding this comment.
First-pass review (Netero only). The full review panel has not yet reviewed this PR; they will review after these findings are addressed.
Severity count: 1 P1, 1 P2, 1 P3, 1 Note.
The discriminated-union design for settings is well-structured, and the double-marshal pattern for injecting _type/_version keys is the right Go approach. The client methods follow established codersdk conventions cleanly.
The main gap is the custom JSON marshal/unmarshal logic: five distinct code paths (null input, missing discriminator, wrong version, unknown type, successful decode) with zero test coverage. The TS codegen limitation for the discriminated union is also worth addressing before consumers land.
"329 lines of new Go code across two files, 0 lines of test. Test:code ratio is 0:329." (Netero)
🤖 This review was automatically generated with Coder Agents.
80d35d3 to
69d019e
Compare
Adds the codersdk surface for runtime AI provider management. AI Bridge is the initial consumer but the data model and HTTP API are not aibridge-specific. - AIProvider, AIProviderSettings, AIProviderType - CreateAIProviderRequest, UpdateAIProviderRequest - Client.AIProviders, AIProvider, CreateAIProvider, UpdateAIProvider, DeleteAIProvider API key and Bedrock secret are write-only and never returned by the server; the type definitions reflect that. Refs RFC: https://www.notion.so/coderhq/RFC-Common-AI-Provider-Configs-34bd579be59280ed958feffb82024797
The keys table refactor (ai_provider_keys) moves api keys out of the
provider type and into a separate sub-resource. Update the codersdk
surface to match:
- AIProvider, CreateAIProviderRequest, UpdateAIProviderRequest no
longer carry an APIKey field. AIProvider still includes Settings
(Bedrock credentials live there).
- AIProviderSettings gains BedrockAccessKey alongside the existing
BedrockAccessKeySecret so a Bedrock provider can carry both halves
of its AWS credentials in one Settings blob.
- New AIProviderKey + CreateAIProviderKeyRequest types.
- New Client methods: AIProviderKeys, CreateAIProviderKey,
DeleteAIProviderKey under /api/v2/ai/providers/{idOrName}/keys.
- typesGenerated.ts refreshed via make gen.
Convert AIProviderSettings from a flat Bedrock-only struct into a
discriminated container. On the wire each provider that needs custom
settings has its own struct (just Bedrock for now), and the JSON
object carries _type and _version discriminator keys.
- AIProviderSettings is now a wrapper struct with a single
*AIProviderBedrockSettings field. Custom (Un)MarshalJSON routes
between concrete types using the _type discriminator.
- AIProviderBedrockSettings carries the Bedrock-specific fields
(Region, Model, SmallFastModel, AccessKey, AccessKeySecret) and
the bedrock_ prefix on the JSON keys goes away — the discriminator
carries that information.
- AIProviderSettings.IsZero() lets request bodies use json:",omitzero"
instead of the non-functional omitempty on a struct field.
This is the SDK-side of the unification described in AIGOV-201; the
on-disk and wire formats now both look like
{"_type":"bedrock","_version":1,...} so future provider types can
be added without grepping every consumer.
Replace bare require.Error / loose Contains checks with specific substring assertions so a regression in any of the discriminator error paths fails the test instead of silently passing on an unrelated error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use require.JSONEq to compare the entire marshal output instead of decoding into a map and checking individual fields. Any unexpected change to the response (added field, removed field, type change) now fails the test immediately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b63803f to
c76e3dc
Compare

Disclaimer: implemented by a Coder Agent using Claude Opus 4.7
Part of the implementation of RFC: Common AI Provider Configs (AIGOV-201).
Adds the
codersdktypes and client methods for runtime AI provider management. AI Bridge is the initial consumer but the data model is provider-generic — other Coder features (Agents, Chat, etc.) can read the same rows over time.What's in this PR
AIProvider,AIProviderType,AIProviderSettings,AIProviderBedrockSettingsCreateAIProviderRequest,UpdateAIProviderRequestAIProviderKey,CreateAIProviderKeyRequestClient.AIProviders,AIProvider,CreateAIProvider,UpdateAIProvider,DeleteAIProviderClient.CreateAIProviderKey,DeleteAIProviderKey(no list method — keys are write-managed)AIProviderSettingsis a discriminated, versioned container: the JSON wire form carries_typeand_versionkeys alongside the type-specific fields. Only providers that need custom configuration get a struct (justBedrockfor now); other types store SQLNULL.Bedrock
access_key/access_key_secretare write-only and never appear in responses. HTTP handlers are in a follow-up PR.TestAIProviderSettings_Marshal/_Unmarshal/_Roundtripcover the discriminator routing: null encode/decode, missing/unknown_type, unsupported version, bedrock encode and decode, malformed headers, and the reset-between-calls invariant.Notes
biome.jsoncadds anoEmptyInterfaceexemption fortypesGenerated.ts.AIProviderSettings.Bedrockisjson:"-"(custom marshal handles the discriminator), so the generator emits an empty interface and Biome flags it; suppress at the generated-file level rather than restructure the wrapper.