From d7fbb503d8e3c11a6b3bdfa311ca31db3055c159 Mon Sep 17 00:00:00 2001 From: can1357 Date: Thu, 20 Aug 2026 04:38:56 +0200 Subject: [PATCH] feat(ai): exposed catalog metadata in auth gateway model list - Added context length, max tokens, input modalities, and tool support flags to GET /v1/models response in auth gateway server. - Updated auth gateway model list tests to verify catalog metadata fields in output rows. --- packages/ai/CHANGELOG.md | 1 + packages/ai/src/auth-gateway/server.ts | 32 +++++++++++++++++-- .../ai/test/auth-gateway-model-list.test.ts | 22 +++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index dfe196b0c..7919ed5ac 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added +- Added model metadata fields (`context_length`, `max_output_tokens`, `input_modalities`, etc.) to auth gateway model listing responses - Added `Tool.coerceArguments` (default `true`): setting it `false` opts a tool out of every LLM-quirk argument repair pass (JSON-string parsing, object→string stringification, unrecognized-key dropping, singleton array wrapping) so validation runs verbatim. Tools whose arguments are the deliverable payload — like the subagent `yield` tool — use it to keep lossy repairs from silently corrupting data their own validate-and-retry loop is designed to correct. ### Fixed diff --git a/packages/ai/src/auth-gateway/server.ts b/packages/ai/src/auth-gateway/server.ts index 29202395c..5a41885ae 100644 --- a/packages/ai/src/auth-gateway/server.ts +++ b/packages/ai/src/auth-gateway/server.ts @@ -730,19 +730,45 @@ async function handleCredentialsCheck(storage: AuthStorage, signal: AbortSignal) return json(200, { generatedAt: Date.now(), credentials }); } +/** + * Row shape for `GET /v1/models`. Beyond the OpenAI-standard `id`/`object`/ + * `owned_by`, rows advertise the catalog metadata OpenAI-compatible clients + * (omp's own proxy discovery, Zed's openai_compatible provider, ...) read to + * size and capability-gate discovered models: `context_length`, + * `max_output_tokens`, `input_modalities`, and `supports_tools` (only emitted + * when the catalog explicitly reports `false`; absent means usable). + */ +interface ModelListRow { + id: string; + object: "model"; + owned_by: string; + api: Api; + display_name: string; + context_length?: number; + max_output_tokens?: number; + input_modalities: ("text" | "image")[]; + supports_tools?: boolean; +} + function handleModelsList(opts: AuthGatewayBootOptions): Response { const seen = new Set(); - const data: Array<{ id: string; object: "model"; owned_by: string; api: Api }> = []; + const data: ModelListRow[] = []; for (const model of opts.listModels?.() ?? []) { const id = `${model.provider}/${model.id}`; if (seen.has(id)) continue; seen.add(id); - data.push({ + const row: ModelListRow = { id, object: "model", owned_by: model.provider, api: model.api, - }); + display_name: model.name, + input_modalities: model.input, + }; + if (model.contextWindow != null) row.context_length = model.contextWindow; + if (model.maxTokens != null) row.max_output_tokens = model.maxTokens; + if (model.supportsTools === false) row.supports_tools = false; + data.push(row); } return json(200, { object: "list", data }); } diff --git a/packages/ai/test/auth-gateway-model-list.test.ts b/packages/ai/test/auth-gateway-model-list.test.ts index 59d0da81e..197da3d38 100644 --- a/packages/ai/test/auth-gateway-model-list.test.ts +++ b/packages/ai/test/auth-gateway-model-list.test.ts @@ -26,8 +26,26 @@ test("model listing exposes one provider-qualified route per upstream model", as expect(await response.json()).toEqual({ object: "list", data: [ - { id: "anthropic/shared-model", object: "model", owned_by: "anthropic", api: "mock" }, - { id: "devin/shared-model", object: "model", owned_by: "devin", api: "mock" }, + { + id: "anthropic/shared-model", + object: "model", + owned_by: "anthropic", + api: "mock", + display_name: "shared-model", + context_length: 200_000, + max_output_tokens: 32_768, + input_modalities: ["text"], + }, + { + id: "devin/shared-model", + object: "model", + owned_by: "devin", + api: "mock", + display_name: "shared-model", + context_length: 200_000, + max_output_tokens: 32_768, + input_modalities: ["text"], + }, ], }); } finally {