Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: require bedrock model fields for the invoke-model protocol - #27846

Merged
evgeniy-scherbina merged 1 commit into
mainfrom
yevhenii/bedrock-validation
Aug 4, 2026
Merged

fix: require bedrock model fields for the invoke-model protocol#27846
evgeniy-scherbina merged 1 commit into
mainfrom
yevhenii/bedrock-validation

Conversation

@evgeniy-scherbina

@evgeniy-scherbina evgeniy-scherbina commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Implements: https://linear.app/codercom/issue/AIGOV-564/aibridge-bedrock-provider-skipped-404-on-all-routes-when-settings-omit

Improves validation when creating and updating AI providers: a Bedrock provider using the invoke-model protocol now requires model and small_fast_model.

This brings API validation in sync with the UI, which already required both fields.

@evgeniy-scherbina
evgeniy-scherbina force-pushed the yevhenii/bedrock-validation branch 6 times, most recently from dff49f5 to efcdd25 Compare August 4, 2026 17:37
@evgeniy-scherbina
evgeniy-scherbina force-pushed the yevhenii/bedrock-validation branch from efcdd25 to ff26bd1 Compare August 4, 2026 17:43
@evgeniy-scherbina
evgeniy-scherbina marked this pull request as ready for review August 4, 2026 17:44
@johnstcn

johnstcn commented Aug 4, 2026

Copy link
Copy Markdown
Member

AIGOV-564

@evgeniy-scherbina

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-08-04 17:56 UTC by @evgeniy-scherbina

Review history
  • R1 (2026-08-04), 2 Note, 1 P2, 3 P3, COMMENT. Review

deep-review v0.9.0 | Round 1 | 60161fd..ff26bd1

Last posted: Round 1, 6 findings (1 P2, 3 P3, 2 Note), COMMENT. Review

Finding inventory

Finding inventory, PR #27846

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P2 Open cli/server.go:3237 Env-seeded bedrock provider still accepted without model fields, same 404 failure remains reachable R1 Netero Yes
CRF-2 P3 Open codersdk/aiproviders.go:403 Models gate fires on any non-nil bedrock blob, including non-Bedrock providers; also reorders the type-mismatch error R1 Netero Yes
CRF-3 P3 Open coderd/ai_providers_test.go:658 Comment claims the rejected PATCH left the row untouched, no assertion proves it R1 Netero Yes
CRF-4 P3 Open codersdk/aiproviders_bedrock.go:79 Deleted IsConfigured rationale is still true, defaults still exist R1 Netero Yes
CRF-5 Note Open codersdk/aiproviders.go:396 Existing rows carrying the broken shape are unaffected; no detection or backfill R1 Netero Yes
CRF-6 Note Open codersdk/aiproviders_test.go:10 codersdk external test package now imports aibridge/config; deliberate, no cycle R1 Netero Yes

Contested and acknowledged

None.

Round log

Round 1

Netero-only (first pass, P2 gate). 1 P2, 3 P3, 2 Note. Panel not yet spawned.
Reviewed against 60161fd..ff26bd1.

Orchestrator verification notes:

  • CRF-1 confirmed by reading readAIProviders post-parse validation, the env key
    switch (no BEDROCK_PROTOCOL key exists, so env providers always resolve to
    invoke-model), and config.AWSBedrock.Validate.
  • CRF-2 confirmed: the new call site is gated on req.Settings.Bedrock != nil
    only. Netero's proposed fix (IsBedrockConfigured(baseURL, b)) is wrong:
    baseURL is always non-empty, so that gate would fire for every provider
    carrying a bedrock blob. The runtime's own "is this Bedrock" test is
    IsConfigured() on the settings blob alone (cli/aibridged.go:341-348, whose
    comment states base URL cannot serve as a detection signal), so mirroring
    IsConfigured() is the fix that matches runtime behavior. Checked the
    frontend: providerFormApiMap.ts only emits a bedrock blob when
    type === "bedrock", so the UI does not hit this.
  • CRF-4 confirmed: codersdk/deployment.go:1992 and :2002 still declare the
    model defaults the deleted comment described.
About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@linear-code

linear-code Bot commented Aug 4, 2026

Copy link
Copy Markdown

AIGOV-564

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First-pass review only. These are mechanical findings from a single first-pass reviewer; the full review panel has not reviewed this PR yet and will do so after these are addressed.

The fix itself is well targeted: the validator is scoped to invoke-model so mantle keeps forwarding the client's model, the doc comment on validateAIProviderBedrockModels explains the runtime consequence instead of restating the code, and TestAIProviderRequest_ValidationInSync is the right shape for a cross-layer duplicate, it asserts both validators independently so drift fails the build rather than silently returning. Test density is 84.6% and every branch of the new function is exercised.

1 P2, 3 P3, 2 Notes.

The P2 is the one that matters: AIGOV-564 is fixed for the API but not for CODER_AI_GATEWAY_PROVIDER_N_BEDROCK_*. Env-seeded providers reach the same 404-on-every-route state, and there is no BEDROCK_PROTOCOL env key, so every env-seeded Bedrock provider resolves to invoke-model and therefore always needs both models. The settings struct the check needs is already built in readAIProviders.

One process note: the existing Bedrock settings are only valid for type=anthropic subtest was edited to add model fields so it keeps reaching the type check. That edit is the visible symptom of an error-precedence change, described in the comment on validateAIProviderBedrockModels. Worth deciding deliberately rather than absorbing into a fixture.

Verbatim from the reviewer, on the deleted IsConfigured rationale: "the reason now lives everywhere except the definition it constrains."


cli/server.go:3237

P2 [CRF-1] The env-seeding path still accepts a bedrock provider with no model fields, so the exact 404-on-every-route failure this PR fixes for the API remains reachable through CODER_AI_GATEWAY_PROVIDER_N_BEDROCK_*. (Netero)

readAIProviders post-parse validation (cli/server.go:3200-3275) checks type/BEDROCK_* consistency, key exclusivity, and credential pairing, but never requires BEDROCK_MODEL / BEDROCK_SMALL_FAST_MODEL. [...] There is also no BEDROCK_PROTOCOL env key in the parser's switch (cli/server.go:3344-3388), so every env-seeded Bedrock provider resolves to invoke-model and therefore always needs both models.

Result of CODER_AI_GATEWAY_PROVIDER_0_TYPE=bedrock + CODER_AI_GATEWAY_PROVIDER_0_BEDROCK_REGION=us-east-2 and nothing else: startup seeds the row, buildProvider returns an error from runtimeCfg.Validate(), the provider never enters the route table, and the only signal is a WARN.

Verified independently: the post-parse loop builds settings via NewAIProviderBedrockSettings and only asks IsBedrockConfigured; the key switch has no BEDROCK_PROTOCOL case; config.AWSBedrock.Validate requires both models for invoke-model.

This is the same root cause as the API bug, in an unpatched sibling. Fixing one entry point and leaving the other means the linked issue can recur through env config with no API-visible error, only a startup WARN. Call the same check on the settings already constructed in readAIProviders so env and API reject the identical shape.

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread codersdk/aiproviders.go
// every request to it would 404. The mantle protocol forwards the client's
// model unchanged and needs neither field.
func validateAIProviderBedrockModels(b AIProviderBedrockSettings) []ValidationError {
if b.ResolvedProtocol() != AIProviderBedrockProtocolInvokeModel {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-2] The models gate fires on any non-nil bedrock blob, including one that is not a Bedrock provider at all, so a bearer-token Anthropic create carrying settings.bedrock: {} is now rejected with a Bedrock model error. (Netero)

Every other Bedrock gate in this area first asks whether the blob is a Bedrock provider: create's own type=bedrock requires bedrock settings uses IsConfigured(), bedrockConfig returns nil for an unconfigured blob [...] validateAIProviderBedrockModels skips that question.

create {type: anthropic, api_keys: [sk-test], settings.bedrock: {}}
  -> settings.model: model is required for the invoke-model protocol
     settings.small_fast_model: small_fast_model is required for the invoke-model protocol

The error names fields the caller has no reason to set. There is a second consequence on the PATCH path: req.Validate() runs before the handler's type check, so a PATCH placing bedrock settings on an openai provider without models now returns "model is required for the invoke-model protocol" instead of Bedrock settings are only valid for type=anthropic or type=bedrock. That is what forced the fixture edit at coderd/ai_providers_test.go:588-598; the existing subtest now only reaches the type check because it supplies models.

One correction to the reviewer's proposed fix. IsBedrockConfigured(baseURL, b) is baseURL != "" || b.IsConfigured(), and base URL is required on every provider, so that gate would fire for every request carrying a bedrock blob, which is the current behavior. The runtime's own "is this Bedrock" test is IsConfigured() on the settings blob alone (cli/aibridged.go:341-348, whose comment states base URL cannot serve as a detection signal), and a bedrock-typed provider with IsConfigured() == false is already rejected on create and refused at build time. Gating on IsConfigured() is what makes the API agree with the runtime.

Not reachable from the UI: providerFormApiMap.ts only emits a bedrock blob when type === "bedrock". API clients can hit it.

🤖

})
requireMissingModels(t, err)

// The same PATCH with both models is accepted, and the stored provider

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-3] The comment claims the rejected PATCH left the stored provider untouched, but no assertion can show that; the check passes either way. (Netero)

The rejected PATCH (line 649-656) sets Region: "us-west-2". The following accepted PATCH sets Region: "us-west-2" as well, and the assertions run only after it. If a future change let a validation failure partially apply, this test would still pass. Same for the model fields: they are only ever read after the successful PATCH.

A comment asserting coverage that does not exist is worse than no comment: the next reader trusts it and does not add the assertion. Either read the provider back between the rejected and the accepted PATCH and assert Region == "us-east-2" with both models at their created values, or drop the second clause of the comment.

🤖

// indicating that the operator wants the provider to authenticate via
// AWS Bedrock rather than as a bearer-token Anthropic provider.
//
// Model and SmallFastModel are intentionally excluded: they have

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-4] The PR deletes the rationale for why Model and SmallFastModel are excluded from IsConfigured(), and the rationale is still true. (Netero)

Those defaults still exist: codersdk/deployment.go:1992 (global.anthropic.claude-sonnet-4-5-20250929-v1:0) and :2002 (global.anthropic.claude-haiku-4-5-20251001-v1:0) [...] Three other sites still repeat the same reason as a secondhand claim: cli/server.go:3404-3407, coderd/ai_providers_migrate.go:219-220, and this file's own surviving "have no defaults" sentence.

the reason now lives everywhere except the definition it constrains, so the next reader who wants a stronger Bedrock detection signal sees only "region and credentials have no defaults" and no statement that adding Model would misfire on every deployment running the defaults.

Confirmed both default declarations are still present at those lines. This PR makes the models required at the API, which is exactly the change that invites a reader to also add them to IsConfigured(), so this is the worst moment to remove the sentence explaining why that breaks. Restore it.

🤖

Comment thread codersdk/aiproviders.go
return nil
}

// validateAIProviderBedrockModels requires the model identifiers that the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-5] Existing rows that already carry the broken shape are unaffected by this PR. (Netero)

Validation only guards new writes. Rows seeded from env, inserted by dbgen, or promoted by BackfillBedrockProviderType [...] keep 404ing with a WARN until an operator re-saves them through the UI, which now supplies both models. Nothing in the diff detects or reports them.

Recorded, not a request to change this PR. Whether AIGOV-564 is closed for deployments already in the broken state, and whether that needs a backfill or a surfaced provider-build status, is a human call. Say which one you intend, here or in the issue.

🤖


"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/aibridge/config"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-6] codersdk's external test package now imports aibridge/config. (Netero)

No cycle: aibridge/config imports no codersdk [...] and the test file is package codersdk_test. The dependency is deliberate, since the point of TestAIProviderRequest_ValidationInSync is to fail when the two validators drift.

Recorded so a future layering check does not read it as an accident.

🤖

@evgeniy-scherbina
evgeniy-scherbina merged commit 1142706 into main Aug 4, 2026
41 checks passed
@evgeniy-scherbina
evgeniy-scherbina deleted the yevhenii/bedrock-validation branch August 4, 2026 19:21
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants