Skip to content

fix(proxy): make proxy connectors work on non-EPAM tenant model catalogs - #566

Closed
vadimvlasenko wants to merge 12 commits into
mainfrom
feature/philips-tenant-model-catalog
Closed

vadimvlasenko wants to merge 12 commits into
mainfrom
feature/philips-tenant-model-catalog

Conversation

@vadimvlasenko

Copy link
Copy Markdown
Collaborator

Summary

codemie proxy connect broke on any tenant whose model catalog doesn't follow EPAM's naming convention (surfaced live on a customer call). Three connectors — VS Code Copilot BYOK, Claude Desktop, and VS Code Claude Code — each hardcoded assumptions about model-id shape or format that only held for EPAM's own tenant. Ref: EPMCDME-15073.

Changes

  • VS Code Copilot BYOK (vscode.ts, vscode-models.ts, new tenant-catalog.ts): replaced the static 25-model hardcoded list with a capability table intersected against the tenant's live GET /v1/llm_models catalog at connect time; writes the tenant's own model identifier verbatim.
  • Claude Desktop (desktop.ts, new model-name-resolver.ts): preferred-model resolution now handles both EPAM's claude-<family>-<version> and version-first (claude-<version>-<family>) naming, plus undated ids and vendor-prefixed ids (e.g. openai.gpt-...), instead of only appending suffixes.
  • VS Code Claude Code (vscode-claude-code.ts): switched from strict JSON.parse/JSON.stringify to jsonc-parser, so a settings.json with comments or trailing commas parses correctly and the write preserves the file's existing formatting instead of being silently skipped.
  • github-copilot-* deployments are explicitly excluded from both the VS Code Copilot BYOK picker and Claude Desktop (product decision, documented in spec.md).
  • Shared resolver is scoped to the two evidenced naming conventions (not a fully generic solver); codex-model-resolver.ts is untouched.

Full design rationale, acceptance criteria, and non-goals are in docs/superpowers/tasks/2026-09-17-philips-tenant-model-catalog/spec.md and plan.md (committed on this branch), produced by an sdlc-autonomous run with a full code-review cycle (initial round: 7 findings incl. 1 critical, all fixed and independently re-verified in a check round).

Testing

  • Tests added/updated — unit tests for the new resolver and tenant-catalog modules, updated connector tests, repaired the two VS Code integration test files broken by the API renames.
  • npx vitest run — full suite green.
  • npm run typecheck / npm run lint — clean.
  • Manual testing against a real non-EPAM tenant — not possible in this environment; covered by synthetic fixtures shaped like the reported tenant's catalog instead (see spec.md's open risks).

Checklist

  • Code follows project standards
  • CI is green (npm run ci) locally via qa-gates
  • No merge conflicts with main
  • CRITICAL check: diff does not touch any X-CodeMie-* attribution header, the Responses API user field, or JWT claim overrides — confirmed, out of scope for this change.

vadimvlasenko and others added 12 commits September 17, 2026 19:00
Generalizes codex-model-resolver.ts's date-stripping identity-parse
shape to strip vendor prefixes (GPT) and match both token orders
(Claude) so VS Code Copilot BYOK and Claude Desktop can resolve
tenant-shaped model ids (philips-tenant-model-catalog task 1).

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
Add fetchTenantModelCatalog and thread a live gateway catalog through
buildManagedModels via resolveTenantModelId, so the capability table
(previous commit) resolves each family to whatever id the tenant
actually registers instead of a fixed EPAM-shaped id. Unmatched
families are dropped; a fully unmatched catalog now rejects with no
file written. gatewayKey is threaded through
writeVsCodeLanguageModelsConfig[AtPath] and connect-orchestrator.ts,
which also reports the real resolved model count instead of the
static table length (philips-tenant-model-catalog tasks 3-4).

Squashed with task 2's vscode-models.ts capability-table rename
(VS_CODE_SUPPORTED_MODELS -> VS_CODE_CAPABILITY_TABLE): the rename's
sole consumers are vscode.ts and connect-orchestrator.ts, so the two
land together to keep every commit typecheck-clean and pre-commit
green, matching this repo's hook that runs `tsc --noEmit` on every
commit.

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
Replace selectPreferredClaudeModels's suffix-only exact/dated
matching with the shared resolveTenantModelId, so a tenant that
names models version-first (e.g. claude-5-opus) resolves correctly
instead of never matching PREFERRED_CLAUDE_MODELS's family-first
entries (philips-tenant-model-catalog task 5).

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
…Code settings

Read settings.json with jsonc-parser (allowTrailingComma) instead of
strict JSON.parse, and write the two managed keys via targeted
modify()/applyEdits() passes against the original text instead of
re-serializing the whole object, so a hand-edited settings.json with
// comments survives the write (philips-tenant-model-catalog task 6).
A genuinely unparseable file still rejects with ConfigurationError
and is left untouched.

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
…es by recency

RELEASE_DATE_PATTERN only matched separator-delimited dates, so a
single-number preferred family (claude-opus-5, claude-sonnet-5) never
resolved against a realistically-shaped concatenated-date tenant id
(claude-opus-5-20260101) — two-number families only worked by positional
coincidence. pickMostRecent's lexicographic tie-break was also unsound
across mixed id shapes (vendor-prefixed vs. dated vs. -vertex-suffixed).
Extend the date pattern to cover both shapes and rank same-identity
candidates by an explicit non-vertex-before-vertex, then parsed-date
precedence instead of raw string comparison.

philips-tenant-model-catalog CR-001, CR-002

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
…ch fallback

fetchTenantModelCatalog was a ~73-line function mixing fetch, HTTP-status
handling, content-type validation, response-shape parsing, and logging —
over the code-quality function-length/single-responsibility limit. It also
had no timeout on its fetch() call, so a hung gateway blocked `codemie proxy
connect` indefinitely, and its `{ data: [...] }` response branch only read
`m.id`, dropping the same base_name/deployment_name fallback the array
branch already applied.

Extract the parsing and logging into small named helpers, wrap the fetch in
an AbortController-backed timeout (converted into the same ConfigurationError
contract on abort), and apply one shared id/base_name/deployment_name
fallback chain to both response shapes.

philips-tenant-model-catalog CR-003, CR-004, CR-005

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
…tings

writeVsCodeClaudeCodeConfigAtPath's two jsonc-parser modify() calls passed
an empty ModificationOptions object, leaving `formattingOptions` undefined.
Per jsonc-parser's own contract that inserts the edit completely
unformatted — no newline, no indent — rather than falling back to any
default, so the managed keys could land jammed onto the same line as the
preceding property. Detect the file's actual indentation and EOL from its
raw text and pass real formattingOptions to both modify() calls.

philips-tenant-model-catalog CR-006

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
Both integration test files still imported the removed
VS_CODE_SUPPORTED_MODELS/VsCodeModelDefinition (renamed to
VS_CODE_CAPABILITY_TABLE/VsCodeCapabilityEntry, whose entries carry a
`family` name instead of a literal tenant id). vscode-byok.test.ts's
writeVsCodeLanguageModelsConfigAtPath call was also missing the new
required gatewayKey argument, and its mock upstream server never served a
/v1/llm_models catalog body, so the connector's catalog fetch found zero
models and the test never exercised its own scenario.

Update both files to the renamed exports and the family-based shape, pass
gatewayKey through, and have the BYOK test's mock server serve a catalog
whose ids exactly match every VS_CODE_CAPABILITY_TABLE family so each entry
resolves verbatim.

philips-tenant-model-catalog CR-007

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
Test fixtures and descriptions named a real customer. Rename them to
describe the tenant-naming shape under test instead: PHILIPS_CLAUDE_FIXTURE
-> VERSION_FIRST_CLAUDE_FIXTURE (desktop.test.ts) and PHILIPS_FIXTURE ->
NON_EPAM_TENANT_FIXTURE (vscode.test.ts), with matching test/describe
titles. No behavior change.

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
…t-model-catalog

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
state.local.json/gate-plan.local.json replaced .state.json/gate-plan.json
in the sdlc-factory scripts; the ignore patterns here still named the old
filenames, so every finished sdlc run left the task dir looking dirty.

Generated with AI

Co-Authored-By: codemie-ai <[email protected]>
@vadimvlasenko
vadimvlasenko deleted the feature/philips-tenant-model-catalog branch September 18, 2026 07:36
@vadimvlasenko

Copy link
Copy Markdown
Collaborator Author

Closed accidentally by a branch rename (removing a client name from the branch/directory names per internal policy) — GitHub deleted the old ref and auto-closed this PR instead of migrating it, and it can't be reopened without its head ref. Continued as #567 with identical content.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant