DefangLabs / DefangLabs/defang
Consolidate default LLM model names into a single MIT source of truth
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 166
- Forks
- 24
- Avg merge
- 10h 8m
- Merged PRs (30d)
- 33
Description
Problem
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
chatPreferencelist inprovider/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
--modelcommand 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/embeddingPreferenceseed and keeps the deploy-time lifecycle filter from #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)
- pulumi-defang = AGPL-3.0 (viral), defang CLI = MIT.
- 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.goconfigureAccessGatewayreads AWS/GCP entries from it.- pulumi-defang adds
require github.com/DefangLabs/defang/srcand seeds the Azure selector from the table. - Keep the user-facing alias stable so
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
- Don't unify the resolution code paths.
- Don't couple defaults to per-model IAM allowlists (BYOC IAM stays model-agnostic; the Playground GCP
:predictallowlist indefang-mvpis 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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/pkg/cli/compose/fixup.go and its configureAccessGateway function, then compare the Azure chatPreference and embeddingPreference handling in pulumi-defang's provider/defangazure/azure/models.go and the lifecycle filter from pulumi-defang#376. Done means the MIT CLI module owns one declarative table, AWS/GCP resolution reads it, Azure seeds from it while retaining deploy-time filtering, and dependency direction remains pulumi-defang → defang.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, azure, gcp, go
- Domain
- cli, cloud, devops, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 38/100