Repository navigation
Unify model resolution around canonical provider-qualified identities - #10681
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Provider-native identity handling and alias error paths still cause functional regressions in pricing, request acceptance, and management endpoints.
5 open issues
Preserve native provider IDs during pricing lookup · New Reject case-colliding aliases during configuration parsing · New Scope retirement checks to serving provider and resolved identity · New Block retired provider-pattern targets before fallback synthesis · New Resolve routing aliases before rejecting their labels · New
What changed in this PR
Connects AWF’s host and API-proxy model handling to shared, provider-qualified identities for #10670, while keeping bundled naming rules separate from remotely refreshed pricing.
Changes:
- Generate and package deterministic naming views and shared resolution contracts.
- Integrate canonical identity handling into requests, selectors, policy, retirement, fallback, and pricing.
- Add compatibility and packaged-execution coverage, and document publication v1 boundaries.
| File | Description |
|---|---|
tsconfig.json |
Includes bundled JavaScript contracts in host builds. |
src/model-information.naming.generated.json |
Supplies generated naming data for host consumers. |
src/model-information-resolution.test.ts |
Tests scoped matching, ambiguity, and family rules. |
src/model-information-contract/resolution.js |
Bundles shared identity resolution for host execution. |
src/model-information-contract/resolution.d.ts |
Defines host resolution types. |
src/model-information-contract/identity.js |
Bundles canonical identity matching for host execution. |
src/model-information-contract/identity.d.ts |
Defines host identity types. |
src/copilot-model.ts |
Uses shared resolution for CLI validation. |
src/copilot-model.test.ts |
Preserves CLI-specific model syntax restrictions. |
shared/model-information/resolution.js |
Implements the shared identity-resolution boundary. |
shared/model-information/resolution.d.ts |
Defines shared resolution inputs and results. |
shared/model-information/naming.generated.json |
Provides the deterministic reviewed naming projection. |
scripts/model-information/publication.test.ts |
Includes new assets in publication checks. |
scripts/model-information/compile.test.ts |
Tests generated ownership, consistency, and packaging. |
scripts/model-information/compile.cjs |
Generates naming views and copies shared contracts. |
eslint.config.mjs |
Supports bundled CommonJS contract files. |
docs/model-catalogue-publication.md |
Explains bundled naming versus refreshed pricing. |
containers/api-proxy/routing-candidates.test.js |
Tests retired-candidate filtering and native mappings. |
containers/api-proxy/routing-candidates.js |
Excludes retired Copilot routing candidates. |
containers/api-proxy/model-utils.js |
Re-exports shared provider-prefix normalization. |
containers/api-proxy/model-selector.js |
Adds canonical identity metadata to selections. |
containers/api-proxy/model-resolver.js |
Integrates identity lookup, lifecycle guards, and provenance. |
containers/api-proxy/model-information.naming.generated.json |
Supplies generated naming data for the proxy. |
containers/api-proxy/model-identity.js |
Connects scoped identities to discovered wire IDs. |
containers/api-proxy/model-identity-resolution.test.js |
Covers request integration, compatibility, and Docker staging. |
containers/api-proxy/model-fallback-chain.test.js |
Preserves legacy fallback provider aliases. |
containers/api-proxy/model-fallback-chain.js |
Resolves explicit fallback entries through canonical naming. |
containers/api-proxy/model-fallback-chain.identity.test.js |
Tests identity-aware policy, retirement, and fallback. |
containers/api-proxy/model-config.js |
Attaches resolved identity to requests. |
containers/api-proxy/model-body-rewriter.js |
Returns identity and provenance alongside rewritten bodies. |
containers/api-proxy/guards/retired-model-guard.test.js |
Tests qualified and parameterized retired names. |
containers/api-proxy/guards/retired-model-guard.js |
Resolves naming before retirement lookup. |
containers/api-proxy/guards/model-policy-guard.js |
Matches policy rules against canonical identities and aliases. |
containers/api-proxy/Dockerfile |
Packages proxy naming data and identity helpers. |
containers/api-proxy/catalogue-pricing.test.js |
Tests canonical pricing association and compatibility boundaries. |
containers/api-proxy/catalogue-pricing.js |
Associates feed tariffs with resolved identities. |
containers/api-proxy/catalogue-contract/resolution.js |
Bundles shared resolution for proxy execution. |
containers/api-proxy/catalogue-contract/resolution.d.ts |
Defines packaged proxy resolution types. |
containers/api-proxy/catalogue-contract/identity.d.ts |
Adds packaged identity declarations. |
containers/api-proxy/catalogue-contract/contracts.d.ts |
Adds packaged contract-validation declarations. |
Review effort: Max
| (entry.identity.rawId === model || entry.identity.lookupId === model || | ||
| entry.identity.key === model)); | ||
| const scope = { provider, channel, deployment: context.deployment }; | ||
| const requested = resolveModelIdentity(model, provider, { scope }); |
| if (entries.length > 1) { | ||
| const error = new Error(`Ambiguous routing alias "${key}"; use unique case-insensitive alias names`); | ||
| error.code = 'ambiguous_model_alias'; | ||
| error.statusCode = 400; | ||
| throw error; |
| const prefix = getProviderAliases('copilot') | ||
| .find(alias => model.toLowerCase().startsWith(`${alias}/`)); | ||
| const nativeModel = prefix ? stripRedundantProviderPrefix(model, prefix) : model; | ||
| const key = resolveModelIdentity(nativeModel, 'copilot', { | ||
| policy: { providerPrefix: false }, | ||
| }).wireId.toLowerCase(); |
| const effectiveCandidates = candidates.length > 0 ? candidates | ||
| : resolutionState.blocked ? [] : synthesizedCandidates; |
| if (currentProvider === 'copilot' && getRetiredModelBlockState(baseModel)) { | ||
| resolutionState.blocked = true; | ||
| return null; | ||
| } |
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
|
Addressed the review feedback in |
|
@copilot merge main and resolve conflicts |
…ame-resolution Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Merged |
|
✅ Copilot review passed with no inline comments. @copilot Add the |
Documentation PreviewDocumentation has been built for this PR. To view locally:
Built from commit 3a01e51 |
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 93.62% | 93.63% | ➡️ +0.01% |
| Statements | 92.11% | 92.12% | 📈 +0.01% |
| Functions | 91.22% | 91.21% | 📉 -0.01% |
| Branches | 86.18% | 86.20% | 📈 +0.02% |
📁 Per-file Coverage Changes (2 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/enclave/host-executor-server.ts |
91.2% → 91.2% (+0.00%) | 90.1% → 89.8% (-0.29%) |
src/nvx/one-shot-adapter.ts |
82.9% → 83.4% (+0.56%) | 80.2% → 80.7% (+0.52%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
|
✅ Smoke Copilot BYOK AOAI (api-key) completed. Copilot AOAI BYOK (api-key) mode operational. 🔓
|
|
🚀 Security Guard has started processing this pull request |
|
Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded.
|
|
Smoke Cloud Hypervisor completed. Cloud Hypervisor + Copilot passed.
|
|
🪪 Smoke Copilot BYOK AOAI (Entra) is testing Azure OpenAI BYOK (Entra / GitHub OIDC) mode on this pull request... |
|
📡 Smoke OTel Tracing is starting OTel tracing validation... |
|
✅ Smoke Claude passed
|
|
✅ Build Test Suite completed successfully!
|
|
🛡️ Smoke Copilot Network Isolation confirmed the egress allowlist is enforced. ✅
|
✅ Coverage Check PassedOverall Coverage
📁 Per-file Coverage Changes (1 files)
Coverage comparison generated by |
|
Smoke Copilot: PR "fix: skip stream_options injection for Claude on Vertex"
Overall: PASS —
|
Smoke Test
|
|
Cloud Hypervisor + Copilot smoke test
Overall: PASS
|
🏗️ Build Test Suite Results
Overall: 7/8 ecosystems passed — FAIL Java failure details: Maven could not resolve plugins ( Notes: .NET initially failed because
|
Smoke Claude Results
Overall result: PASS
|
|
EGRESS_RESULT allow=pass deny=pass
|
Chroot Version Comparison
Result: Not all tests passed (Node.js version mismatch), so the
|


Request resolution and downstream consumers interpreted model names independently. This change connects them to canonical identity contracts while keeping naming, pricing authority, and execution availability separate.
Broader eligibility/compiler migration and remote naming transport remain out of scope.