-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: resolve bedrock inference profiles when a provider is written #29112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0caebf5
7d51f6d
2fde4d3
493b668
0774d48
96adb4e
0ba3ad9
5f4d2a3
5a04d32
42f9cf3
051d2b5
a56f048
4e555de
b6c5568
03bfa2c
b1fdf6c
886dd2e
e68042a
7a5d01b
11ba473
1e1a54d
a417d6a
b5d4195
a291c80
9d5979b
7662f0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,6 +69,12 @@ type AWSBedrock struct { | |
| // Protocol selects the Bedrock wire protocol. The zero value behaves as | ||
| // BedrockProtocolInvokeModel. | ||
| Protocol BedrockProtocol | ||
| // ResolvedModel is the model ID behind Model, which differs from it only | ||
| // when Model is an application inference profile ARN. coderd resolves it | ||
| // when the provider is written, so the gateway never calls AWS for it. | ||
| ResolvedModel string | ||
| // ResolvedSmallFastModel is ResolvedModel for SmallFastModel. | ||
| ResolvedSmallFastModel string | ||
| } | ||
|
|
||
| // ResolvedProtocol returns the configured protocol, mapping the empty value to | ||
|
|
@@ -81,6 +87,20 @@ func (c AWSBedrock) ResolvedProtocol() BedrockProtocol { | |
| return c.Protocol | ||
| } | ||
|
|
||
| func (c AWSBedrock) ResolvedModelWithFallback() string { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit [CRF-11]
AGENTS.md requires doc comments on exported symbols, and the sibling methods on this type ( // ResolvedModelWithFallback returns the resolved model ID, or the configured
// Model when no resolution is stored. Model is already a model identity for
// plain model IDs and for providers saved before resolution existed.
func (c AWSBedrock) ResolvedModelWithFallback() string {
return cmp.Or(c.ResolvedModel, c.Model)
}
|
||
| if c.ResolvedModel != "" { | ||
| return c.ResolvedModel | ||
| } | ||
| return c.Model | ||
| } | ||
|
|
||
| func (c AWSBedrock) ResolvedSmallFastModelWithFallback() string { | ||
| if c.ResolvedSmallFastModel != "" { | ||
| return c.ResolvedSmallFastModel | ||
| } | ||
| return c.SmallFastModel | ||
| } | ||
|
|
||
| // Validate verifies protocol-specific Bedrock configuration. | ||
| func (c AWSBedrock) Validate() error { | ||
| switch c.ResolvedProtocol() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,25 +88,42 @@ func modelIDFromARN(modelARN string) (string, error) { | |
| return model, nil | ||
| } | ||
|
|
||
| // resolveBedrockModels resolves the configured model identifiers to the model | ||
| // IDs used for capability detection, usage recording, and pricing. Identifiers | ||
| // that are not application inference profile ARNs are returned unchanged and | ||
| // cost no AWS call. | ||
| func resolveBedrockModels(ctx context.Context, cfg config.AWSBedrock, awsCfg aws.Config) (model, smallFastModel string, err error) { | ||
| resolveOne := func(configured string) (string, error) { | ||
| if !isApplicationInferenceProfileARN(configured) { | ||
| return configured, nil | ||
| // ResolveBedrockModels resolves the application inference profile ARNs among | ||
| // the configured model identifiers, returning what each ARN refers to. The | ||
| // result is empty when neither identifier is an ARN, which costs no AWS call. | ||
| // | ||
| // The identity comes from cfg, including any role assumed via config.AWSBedrock.RoleARN, | ||
| // so the required bedrock:GetInferenceProfile permission belongs to that identity. | ||
| func ResolveBedrockModels(ctx context.Context, cfg config.AWSBedrock) (map[string]string, error) { | ||
| resolved := make(map[string]string, 2) | ||
|
|
||
| var profiles []string | ||
| for _, configured := range []string{cfg.Model, cfg.SmallFastModel} { | ||
| if isApplicationInferenceProfileARN(configured) { | ||
| profiles = append(profiles, configured) | ||
| } | ||
| return resolveInferenceProfile(ctx, awsCfg, configured) | ||
| } | ||
| if len(profiles) == 0 { | ||
| return resolved, nil | ||
| } | ||
|
|
||
| model, err = resolveOne(cfg.Model) | ||
| awsCfg, err := buildBedrockCredentials(ctx, cfg) | ||
| if err != nil { | ||
| return "", "", xerrors.Errorf("resolve model: %w", err) | ||
| return nil, xerrors.Errorf("build bedrock credentials: %w", err) | ||
| } | ||
| smallFastModel, err = resolveOne(cfg.SmallFastModel) | ||
| if err != nil { | ||
| return "", "", xerrors.Errorf("resolve small fast model: %w", err) | ||
|
|
||
| resolveCtx, cancel := context.WithTimeout(ctx, inferenceProfileResolutionTimeout) | ||
| defer cancel() | ||
|
|
||
| for _, profileARN := range profiles { | ||
| if _, ok := resolved[profileARN]; ok { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note [CRF-2] The dedup branch (
Low value: a one-line guard with obvious behavior. Noted for completeness.
|
||
| continue | ||
| } | ||
| model, err := resolveInferenceProfile(resolveCtx, awsCfg, profileARN) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| resolved[profileARN] = model | ||
| } | ||
| return model, smallFastModel, nil | ||
| return resolved, nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3 [CRF-7] Removing gateway-side resolution while leaving every stored row's
ResolvedModelempty means existing AIP providers silently degrade on upgrade, with no backfill and no operator signal. (Hisoka P3, Mafuuu P3, Chopper P3, Meruem P3, Pariston Note)Strong convergence from five reviewers. The fallback collapses two distinct states — "plain model ID, no resolution needed" and "AIP ARN never resolved" — into "serve the configured string." For the second, capability/pricing/usage/metrics key off the raw ARN and adaptive-only models revert to Bedrock 400s indefinitely until an operator re-saves each provider. Severity held at P3 (not higher) because #28877 is in no release tag (
git tag --containsempty), so the exposed population ismain/dogfood rows created between the two merges, and the state self-heals on any re-save. Blast radius narrow, teeth real. This needs a human decision, not a silent default: a first-write backfill, a release note telling operators to re-save AIP providers, or at minimum a warning log at gateway construction when a served Bedrock provider's identifier is an AIP ARN with empty resolution.ResolvedModelWithFallbackalready has the type in hand to tell the two cases apart viaisApplicationInferenceProfileARN(c.Model).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous functionality hadn't been released yet, so it should be okay.