You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Default LLM model names live in two places that rot independently, and a retirement in either silently breaks deploys:
AWS/GCP — the CLI resolves the alias → concrete model ID statically in src/pkg/cli/compose/fixup.goconfigureAccessGateway (chat-default → us.amazon.nova-2-lite-v1:0 / gemini-2.5-flash).
Azure — pulumi-defang picks from a hardcoded chatPreference list in provider/defangazure/azure/models.go.
This just bit us: Azure's gpt-4o 2024-11-20 entered Deprecating, and defang up on Azure failed with 400 ServiceModelDeprecating. Fixed in pulumi-defang#376, but the fix only patched the Azure list — the two sources of truth remain separate.
Why the two resolution mechanisms must stay different (don't unify the code)
AWS / GCP
Azure
Model hosting
Serverless (Bedrock / Vertex) — a model ID is just a string; IAM is model-agnostic
Must be provisioned as an ARM cognitiveservices.Deployment
Resolution
Compile-time, in the CLI (no cloud creds needed)
Deploy-time, in the CD task (queries Accounts_ListModels per account+region)
"Do it in the CLI for all providers" regresses Azure: the CLI runs before the CD task with no Azure creds and can't know what's deployable in the user's account/region — exactly the blind spot that caused this incident.
"Do it in Pulumi for all providers" over-complicates serverless AWS/GCP (adds needless deploy-time catalog queries) and re-plumbs the LiteLLM --model command path.
Proposal: consolidate the data, not the code
Make a single declarative table the source of truth:
{provider, role} → ordered preferred model name(s) + format
CLI (AWS/GCP) reads the single top entry and resolves statically as it does today.
pulumi-defang (Azure) reads the ordered list as its chatPreference/embeddingPreference seed and keeps the deploy-time lifecycle filter from Implement use of DeleteSecrets cli call. #376 as defense-in-depth (availability is per-account/region; a static list can never be sufficient on Azure alone).
One edit updates every cloud; each provider keeps the resolution mechanism it actually needs.
AGPL may depend on MIT; MIT may not depend on AGPL (it would relicense the CLI).
∴ the shared table must be hosted in the CLI (MIT) module (github.com/DefangLabs/defang/src/...) and imported by pulumi-defang — never the reverse.
This is a natural home: the alias vocabulary (chat-default, embedding-default) already lives in the CLI, and the CLI already owns AWS/GCP defaults. The CLI becomes the canonical data owner for all providers even though it doesn't itself deploy Azure.
Sketch
Add a leaf package, e.g. src/pkg/cli/compose/models (minimal transitive deps, so pulumi-defang doesn't inherit the CLI's dependency graph), exporting the table.
fixup.goconfigureAccessGateway reads AWS/GCP entries from it.
pulumi-defang adds require github.com/DefangLabs/defang/src and seeds the Azure selector from the table.
Keep the user-facing alias stable so defang up output is unchanged while the concrete model updates underneath.
Optional follow-up (not required for v1)
Promote the table to Fabric so defaults update via control-plane config without a CLI or CD-image release — this incident required a CD-image rollout to fix. Adds a network hop and new Fabric surface; do it only if release-free updates become a priority.
Non-goals
Don't unify the resolution code paths.
Don't couple defaults to per-model IAM allowlists (BYOC IAM stays model-agnostic; the Playground GCP :predict allowlist in defang-mvp is a cautionary example, not a pattern to copy).
Acceptance criteria
Single declarative default-model table in the CLI (MIT) module.
CLI AWS/GCP resolution reads from it (behavior unchanged).
pulumi-defang Azure selector seeds from it and retains the lifecycle filter.
Updating a default model is a one-line change in one place.
Dependency direction is pulumi-defang → defang only.
Context captured from the model-consolidation investigation; see pulumi-defang#376 for the Azure lifecycle fix that motivated this.
Problem
Default LLM model names live in two places that rot independently, and a retirement in either silently breaks deploys:
src/pkg/cli/compose/fixup.goconfigureAccessGateway(chat-default→us.amazon.nova-2-lite-v1:0/gemini-2.5-flash).chatPreferencelist inprovider/defangazure/azure/models.go.This just bit us: Azure's
gpt-4o 2024-11-20enteredDeprecating, anddefang upon Azure failed with400 ServiceModelDeprecating. Fixed in pulumi-defang#376, but the fix only patched the Azure list — the two sources of truth remain separate.Why the two resolution mechanisms must stay different (don't unify the code)
cognitiveservices.DeploymentAccounts_ListModelsper account+region)--modelcommand path.Proposal: consolidate the data, not the code
Make a single declarative table the source of truth:
chatPreference/embeddingPreferenceseed and keeps the deploy-time lifecycle filter from Implement use of DeleteSecrets cli call. #376 as defense-in-depth (availability is per-account/region; a static list can never be sufficient on Azure alone).One edit updates every cloud; each provider keeps the resolution mechanism it actually needs.
Where it must live (licensing)
github.com/DefangLabs/defang/src/...) and imported by pulumi-defang — never the reverse.This is a natural home: the alias vocabulary (
chat-default,embedding-default) already lives in the CLI, and the CLI already owns AWS/GCP defaults. The CLI becomes the canonical data owner for all providers even though it doesn't itself deploy Azure.Sketch
src/pkg/cli/compose/models(minimal transitive deps, so pulumi-defang doesn't inherit the CLI's dependency graph), exporting the table.fixup.goconfigureAccessGatewayreads AWS/GCP entries from it.require github.com/DefangLabs/defang/srcand seeds the Azure selector from the table.defang upoutput is unchanged while the concrete model updates underneath.Optional follow-up (not required for v1)
Promote the table to Fabric so defaults update via control-plane config without a CLI or CD-image release — this incident required a CD-image rollout to fix. Adds a network hop and new Fabric surface; do it only if release-free updates become a priority.
Non-goals
:predictallowlist indefang-mvpis a cautionary example, not a pattern to copy).Acceptance criteria
Context captured from the model-consolidation investigation; see pulumi-defang#376 for the Azure lifecycle fix that motivated this.