Skip to content

Commit 376c0c5

Browse files
lidge-junIngwannu
andcommitted
feat: preserve provider catalog metadata caps
Preserves context-window cap behavior from PR #12 and Umans catalog metadata propagation from PR #21 while keeping the verified Anthropic Messages runtime path. Co-authored-by: 0disoft <rodisoft1@gmail.com> Co-authored-by: Ingwannu <ingwannu@users.noreply.github.com>
1 parent c2c36d2 commit 376c0c5

15 files changed

Lines changed: 453 additions & 11 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ Config lives at `~/.opencodex/config.json`. Here's a typical multi-provider setu
217217
}
218218
```
219219

220+
Provider entries can also annotate routed catalog metadata. Use `contextWindow` for a provider-wide
221+
Codex-visible context cap, `modelContextWindows` for model-specific caps, and
222+
`modelInputModalities` for model-specific catalog input hints such as `["text"]` or
223+
`["text", "image"]`. Context values cap live `/models` metadata; they never raise a smaller live
224+
context window. See the configuration reference for the full field list.
225+
220226
Local models work too. Point opencodex at any OpenAI-compatible server running on your machine:
221227

222228
```json
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Provider Catalog Metadata Plan
2+
3+
## Goal
4+
5+
Update `dev` with the remaining safe provider-catalog metadata work from PR #12 and PR #21 without
6+
regressing the verified Umans Anthropic Messages provider.
7+
8+
## Source PRs
9+
10+
- PR #12 by 0disoft / ZeroDi: configurable provider and model context-window caps.
11+
- PR #21 by Ingwannu / 이완우: native Umans provider metadata and registry-to-catalog propagation.
12+
13+
## Decision
14+
15+
Do not cherry-pick PR #21 wholesale. Current `dev` already has a verified Umans provider that uses:
16+
17+
- `adapter: "anthropic"`
18+
- `baseUrl: "https://api.code.umans.ai"`
19+
- `POST /v1/messages`
20+
- `x-api-key`
21+
- `escapeBuiltinToolNames: true`
22+
23+
PR #21 changes Umans to OpenAI Chat Completions shape. That would reopen the stream/tool-call class
24+
of issues documented in `devlog/230_umans-wire-protocol/`.
25+
26+
Preserve these ideas instead:
27+
28+
- From PR #12:
29+
- `contextWindow?: number`
30+
- `modelContextWindows?: Record<string, number>`
31+
- configured context windows are caps, not blind overrides:
32+
- cap live `/models` metadata with `Math.min(live, configured)`
33+
- cap fresh/stale cached live metadata the same way
34+
- use configured values for static configured-model fallback
35+
- From PR #21:
36+
- `modelInputModalities?: Record<string, string[]>`
37+
- registry metadata should flow through provider config seed, key-login maps, saved login payloads,
38+
provider enrichment, and Codex catalog entries.
39+
40+
## Implementation Plan
41+
42+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/types.ts`
43+
44+
Add optional provider catalog metadata fields to `OcxProviderConfig`:
45+
46+
- `contextWindow?: number`
47+
- `modelContextWindows?: Record<string, number>`
48+
- `modelInputModalities?: Record<string, string[]>`
49+
50+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/providers/registry.ts`
51+
52+
Extend `ProviderRegistryEntry` and `ProviderConfigSeed` with the same metadata fields.
53+
54+
Add Umans metadata to the existing Anthropic Messages entry only:
55+
56+
- context windows:
57+
- `umans-coder`: `262_144`
58+
- `umans-kimi-k2.7`: `262_144`
59+
- `umans-kimi-k2.6`: `262_144`
60+
- `umans-flash`: `262_144`
61+
- `umans-glm-5.2`: `405_504`
62+
- `umans-glm-5.1`: `202_752`
63+
- `umans-qwen3.6-35b-a3b`: `262_144`
64+
- input modalities:
65+
- `umans-coder`: `["text", "image"]`
66+
- `umans-kimi-k2.7`: `["text", "image"]`
67+
- `umans-kimi-k2.6`: `["text", "image"]`
68+
- `umans-flash`: `["text", "image"]`
69+
- `umans-glm-5.2`: `["text"]`
70+
- `umans-glm-5.1`: `["text"]`
71+
- `umans-qwen3.6-35b-a3b`: `["text", "image"]`
72+
73+
The GLM rows stay text-only to match the current `noVisionModels` behavior and OMP's treatment of
74+
GLM vision as a handoff, not native image input.
75+
76+
Keep these fields unchanged:
77+
78+
- `adapter: "anthropic"`
79+
- `baseUrl: "https://api.code.umans.ai"`
80+
- `authKind: "key"`
81+
- `defaultModel: "umans-coder"`
82+
- `escapeBuiltinToolNames: true`
83+
84+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/providers/derive.ts`
85+
86+
Copy the new metadata fields through:
87+
88+
- `providerConfigSeed()`
89+
- `deriveKeyLoginMap()`
90+
- `DerivedKeyLoginProvider`
91+
92+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/oauth/key-providers.ts`
93+
94+
Copy the new metadata fields through:
95+
96+
- `KeyLoginProvider`
97+
- `enrichProviderFromCatalog()`
98+
99+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/oauth/login-cli.ts`
100+
101+
Copy the new metadata fields into the saved key-login provider config.
102+
103+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/oauth/index.ts`
104+
105+
Include the new metadata fields in OAuth provider reconciliation so future OAuth registry metadata
106+
stays synced.
107+
108+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/src/codex-catalog.ts`
109+
110+
Extend `catalogHintsFromProviderConfig()` so provider config metadata reaches `CatalogModel`:
111+
112+
- context cap selection must use existing per-model lookup semantics:
113+
- use `modelRecordValue(prov.modelContextWindows, id) ?? prov.contextWindow`
114+
- model-specific cap wins over provider-wide cap
115+
- if no live/cached context exists, return configured cap for configured/static models
116+
- input modalities:
117+
- use `modelRecordValue(prov.modelInputModalities, id)` when present
118+
119+
`catalogHintsFromProviderConfig()` alone cannot cap live/cached values because it does not know the
120+
live value. Add a merge helper for live/cached models:
121+
122+
```ts
123+
function applyProviderConfigHints(name: string, prov: OcxProviderConfig, model: CatalogModel): CatalogModel
124+
```
125+
126+
The helper should:
127+
128+
- compute the configured cap from `modelContextWindows` / `contextWindow`
129+
- set `contextWindow` to `Math.min(model.contextWindow, configuredCap)` when both values exist
130+
- set `contextWindow` to the configured cap when the model lacks live/cached context
131+
- copy `inputModalities` when `modelInputModalities` has a match
132+
- preserve current reasoning-effort behavior via `configuredReasoningEfforts()`
133+
134+
Use that helper in all three catalog paths:
135+
136+
- `applyConfigHintsToCachedModels()`
137+
- configured/static fallback models
138+
- live `/models` rows after `catalogHintsFromModelsApiItem()`
139+
140+
This preserves PR #12's cap semantics: config can lower oversized live metadata but must not raise a
141+
smaller live context window.
142+
143+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/tests/provider-registry-parity.test.ts`
144+
145+
Assert registry-derived key-login and provider presets preserve Umans context/input metadata.
146+
147+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/tests/umans-provider.test.ts`
148+
149+
Strengthen Umans tests so the saved/enriched provider retains catalog metadata while preserving
150+
Anthropic Messages runtime behavior.
151+
152+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/tests/codex-catalog.test.ts`
153+
154+
Add catalog tests for:
155+
156+
- static configured models receiving context/input metadata
157+
- live `/models` metadata being capped by provider-wide and model-specific config
158+
- configured caps not raising smaller live metadata
159+
- cached metadata being capped consistently
160+
161+
### MODIFY `/Users/jun/Developer/new/700_projects/opencodex/README.md`
162+
163+
Add a short configuration example or field summary for `contextWindow`, `modelContextWindows`, and
164+
`modelInputModalities`, then point detailed field definitions to the docs-site configuration
165+
reference.
166+
167+
### MODIFY docs-site config reference pages
168+
169+
Update English, Korean, and Chinese docs-site config/reference pages if the fields are documented
170+
there.
171+
172+
## Verification Plan
173+
174+
Run:
175+
176+
- `bun test tests/codex-catalog.test.ts tests/provider-registry-parity.test.ts tests/umans-provider.test.ts tests/reasoning-effort.test.ts`
177+
- `bun run typecheck`
178+
- `bun test tests`
179+
- `cd docs-site && bun run build`
180+
- `git diff --check`
181+
182+
## Contributor Credit
183+
184+
Commit with trailers:
185+
186+
```text
187+
Co-authored-by: 0disoft <rodisoft1@gmail.com>
188+
Co-authored-by: Ingwannu <ingwannu@users.noreply.github.com>
189+
```
190+
191+
## GitHub Closeout
192+
193+
After the dev commit is verified and pushed:
194+
195+
- Comment on PR #12 that context-window cap behavior has landed on `dev` with credit, then close it
196+
as superseded.
197+
- Comment on PR #21 that the metadata plumbing has landed on `dev` with credit, but the OpenAI Chat
198+
Umans runtime shape was intentionally not merged because `dev` keeps the verified Anthropic
199+
Messages provider, then close the draft PR as superseded.

docs-site/src/content/docs/ko/reference/configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ opencodex는 `~/.opencodex/config.json`으로 설정됩니다. 이 파일은 `oc
3434
| `apiKey?` | `string` | API 키, 또는 요청 시점에 해석되는 `${ENV_VAR}` / `$ENV_VAR` 참조. |
3535
| `defaultModel?` | `string` | 명시적인 모델 없이 이 프로바이더가 선택되었을 때 사용하는 모델. |
3636
| `models?` | `string[]` | 시드/폴백 모델 목록 (실시간 `/models`에 접근 가능하면 그쪽이 우선됨). |
37+
| `contextWindow?` | `number` | routed catalog entry에 표시할 프로바이더 전체 context-window cap. 실시간 metadata가 이보다 작으면 그대로 둡니다. |
38+
| `modelContextWindows?` | `Record<string,number>` | 모델별 context-window cap. 매칭되는 모델에서는 `contextWindow`보다 우선하며, 더 작은 실시간 metadata를 올리지 않습니다. |
39+
| `modelInputModalities?` | `Record<string,string[]>` | `["text"]` 또는 `["text", "image"]` 같은 모델별 catalog input hint. |
3740
| `headers?` | `Record<string,string>` | 업스트림으로 전송되는 추가 HTTP 헤더. |
3841
| `authMode?` | `"key" \| "forward" \| "oauth"` | 인증 방식 (기본 `key`). [프로바이더](/opencodex/ko/guides/providers/#auth-modes) 참조. |
3942
| `noReasoningModels?` | `string[]` | reasoning/thinking 파라미터를 거부하는 모델 — 어댑터가 이들에 대해 `reasoning_effort`를 제거함. |

docs-site/src/content/docs/reference/configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ also force the same native-provider recovery with `ocx recover-history --legacy-
3434
| `apiKey?` | `string` | API key, or an `${ENV_VAR}` / `$ENV_VAR` reference resolved at request time. |
3535
| `defaultModel?` | `string` | Model used when this provider is selected without an explicit model. |
3636
| `models?` | `string[]` | Seed/fallback model list (live `/models` is preferred when reachable). |
37+
| `contextWindow?` | `number` | Provider-wide Codex-visible context-window cap for routed catalog entries. Live metadata below this value is kept. |
38+
| `modelContextWindows?` | `Record<string,number>` | Model-specific context-window caps. These override `contextWindow` for matching model ids and never raise smaller live metadata. |
39+
| `modelInputModalities?` | `Record<string,string[]>` | Model-specific catalog input hints such as `["text"]` or `["text", "image"]`. |
3740
| `headers?` | `Record<string,string>` | Extra HTTP headers sent upstream. |
3841
| `authMode?` | `"key" \| "forward" \| "oauth"` | How to authenticate (default `key`). See [Providers](/opencodex/guides/providers/#auth-modes). |
3942
| `noReasoningModels?` | `string[]` | Models that reject a reasoning/thinking param — the adapter drops `reasoning_effort` for them. |

docs-site/src/content/docs/zh-cn/reference/configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ opencodex 通过 `~/.opencodex/config.json` 进行配置。它由 `ocx init` 和
3232
| `apiKey?` | `string` | API key,或在请求时解析的 `${ENV_VAR}` / `$ENV_VAR` 引用。 |
3333
| `defaultModel?` | `string` | 当选中该 provider 但未指定明确模型时使用的模型。 |
3434
| `models?` | `string[]` | 种子/回退模型列表(当实时 `/models` 可达时优先使用它)。 |
35+
| `contextWindow?` | `number` | 路由 catalog 条目的 provider 级上下文窗口上限。实时 metadata 小于该值时会保留实时值。 |
36+
| `modelContextWindows?` | `Record<string,number>` | 模型级上下文窗口上限。匹配模型时优先于 `contextWindow`,且不会抬高更小的实时 metadata。 |
37+
| `modelInputModalities?` | `Record<string,string[]>` | 模型级 catalog 输入提示,例如 `["text"]``["text", "image"]`|
3538
| `headers?` | `Record<string,string>` | 发送到上游的额外 HTTP 头。 |
3639
| `authMode?` | `"key" \| "forward" \| "oauth"` | 认证方式(默认 `key`)。见 [Providers](/opencodex/zh-cn/guides/providers/#auth-modes)|
3740
| `noReasoningModels?` | `string[]` | 会拒绝 reasoning/thinking 参数的模型 —— adapter 会为它们丢弃 `reasoning_effort`|

src/codex-catalog.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { CODEX_CONFIG_PATH, CODEX_MODELS_CACHE_PATH, DEFAULT_CATALOG_PATH, readR
66
import { DEFAULT_MODEL_CACHE_TTL_MS, getFreshCached, getStaleCached, setCached } from "./model-cache";
77
import { buildModelsRequest, resolveModelsAuthToken } from "./oauth/index";
88
import type { OcxConfig, OcxProviderConfig } from "./types";
9-
import { CODEX_REASONING_LEVELS, configuredReasoningEfforts, sanitizeCodexReasoningEfforts } from "./reasoning-effort";
9+
import { CODEX_REASONING_LEVELS, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "./reasoning-effort";
1010
import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "./generated/jawcode-model-metadata";
1111
import { shouldCaseFoldMetadataModelId } from "./providers/derive";
1212

@@ -341,19 +341,43 @@ type ProviderModelsApiItem = {
341341
};
342342
};
343343

344-
function catalogHintsFromProviderConfig(name: string, prov: OcxProviderConfig, id: string): Partial<CatalogModel> {
344+
function configuredContextWindow(prov: OcxProviderConfig, id: string): number | undefined {
345+
const configured = modelRecordValue(prov.modelContextWindows, id) ?? prov.contextWindow;
346+
return typeof configured === "number" && configured > 0 ? configured : undefined;
347+
}
348+
349+
function configuredInputModalities(prov: OcxProviderConfig, id: string): string[] | undefined {
350+
const modalities = modelRecordValue(prov.modelInputModalities, id);
351+
return Array.isArray(modalities) && modalities.length > 0 ? [...modalities] : undefined;
352+
}
353+
354+
function applyProviderConfigHints(name: string, prov: OcxProviderConfig, model: CatalogModel): CatalogModel {
345355
void name;
346-
const reasoningEfforts = configuredReasoningEfforts(prov, id);
356+
const contextCap = configuredContextWindow(prov, model.id);
357+
const inputModalities = configuredInputModalities(prov, model.id);
358+
const reasoningEfforts = configuredReasoningEfforts(prov, model.id);
347359
return {
360+
...model,
361+
...(contextCap !== undefined
362+
? {
363+
contextWindow: typeof model.contextWindow === "number" && model.contextWindow > 0
364+
? Math.min(model.contextWindow, contextCap)
365+
: contextCap,
366+
}
367+
: {}),
368+
...(inputModalities ? { inputModalities } : {}),
348369
...(reasoningEfforts !== undefined ? { reasoningEfforts } : {}),
349370
};
350371
}
351372

373+
function catalogHintsFromProviderConfig(name: string, prov: OcxProviderConfig, id: string): Partial<CatalogModel> {
374+
const hinted = applyProviderConfigHints(name, prov, { id, provider: name });
375+
const { provider: _provider, id: _id, ...hints } = hinted;
376+
return hints;
377+
}
378+
352379
function applyConfigHintsToCachedModels(name: string, prov: OcxProviderConfig, models: CatalogModel[]): CatalogModel[] {
353-
return models.map(model => ({
354-
...catalogHintsFromProviderConfig(name, prov, model.id),
355-
...model,
356-
}));
380+
return models.map(model => applyProviderConfigHints(name, prov, model));
357381
}
358382

359383
function isGlm52ModelId(id: string): boolean {
@@ -410,11 +434,10 @@ async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs:
410434
return stale ? applyConfigHintsToCachedModels(name, prov, stale) : configured;
411435
}
412436
const json = await res.json() as { data?: ProviderModelsApiItem[] };
413-
const live = (json.data ?? []).map(m => ({
437+
const live = (json.data ?? []).map(m => applyProviderConfigHints(name, prov, {
414438
id: m.id,
415439
provider: name,
416440
owned_by: m.owned_by,
417-
...catalogHintsFromProviderConfig(name, prov, m.id),
418441
...catalogHintsFromModelsApiItem(name, m),
419442
}));
420443
const liveIds = new Set(live.map(m => m.id));

src/oauth/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ function cloneProviderField(value: unknown): unknown {
129129

130130
const OAUTH_RECONCILE_FIELDS: (keyof OcxProviderConfig)[] = [
131131
"models",
132+
"contextWindow",
133+
"modelContextWindows",
134+
"modelInputModalities",
132135
"noReasoningModels",
133136
"noVisionModels",
134137
"reasoningEfforts",

src/oauth/key-providers.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export interface KeyLoginProvider {
1515
dashboardUrl: string;
1616
models?: string[];
1717
defaultModel?: string;
18+
contextWindow?: number;
19+
modelContextWindows?: Record<string, number>;
20+
modelInputModalities?: Record<string, string[]>;
1821
/**
1922
* Model ids that do NOT accept image input (the vision sidecar describes images for them) / do NOT
2023
* accept a reasoning param. Copied into the created provider config by `enrichProviderFromCatalog`,
@@ -47,6 +50,9 @@ export function enrichProviderFromCatalog(name: string, prov: OcxProviderConfig)
4750
if (!e) return;
4851
if (!prov.models && e.models) prov.models = [...e.models];
4952
if (!prov.defaultModel && e.defaultModel) prov.defaultModel = e.defaultModel;
53+
if (prov.contextWindow === undefined && e.contextWindow !== undefined) prov.contextWindow = e.contextWindow;
54+
if (!prov.modelContextWindows && e.modelContextWindows) prov.modelContextWindows = { ...e.modelContextWindows };
55+
if (!prov.modelInputModalities && e.modelInputModalities) prov.modelInputModalities = cloneRecordOfArrays(e.modelInputModalities);
5056
if (!prov.reasoningEfforts && e.reasoningEfforts) prov.reasoningEfforts = [...e.reasoningEfforts];
5157
if (!prov.modelReasoningEfforts && e.modelReasoningEfforts) prov.modelReasoningEfforts = cloneRecordOfArrays(e.modelReasoningEfforts);
5258
if (!prov.reasoningEffortMap && e.reasoningEffortMap) prov.reasoningEffortMap = { ...e.reasoningEffortMap };

src/oauth/login-cli.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ export function providerConfigFromKeyLoginProvider(def: KeyLoginProvider, key: s
5959
apiKey: key,
6060
...(def.defaultModel ? { defaultModel: def.defaultModel } : {}),
6161
...(def.models ? { models: [...def.models] } : {}),
62+
...(def.contextWindow !== undefined ? { contextWindow: def.contextWindow } : {}),
63+
...(def.modelContextWindows ? { modelContextWindows: { ...def.modelContextWindows } } : {}),
64+
...(def.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(def.modelInputModalities) } : {}),
6265
...(def.reasoningEfforts ? { reasoningEfforts: [...def.reasoningEfforts] } : {}),
6366
...(def.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(def.modelReasoningEfforts) } : {}),
6467
...(def.reasoningEffortMap ? { reasoningEffortMap: { ...def.reasoningEffortMap } } : {}),

src/providers/derive.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export interface DerivedKeyLoginProvider {
88
dashboardUrl: string;
99
models?: string[];
1010
defaultModel?: string;
11+
contextWindow?: number;
12+
modelContextWindows?: Record<string, number>;
13+
modelInputModalities?: Record<string, string[]>;
1114
reasoningEfforts?: string[];
1215
modelReasoningEfforts?: Record<string, string[]>;
1316
reasoningEffortMap?: Record<string, string>;
@@ -63,6 +66,9 @@ export function providerConfigSeed(entry: ProviderRegistryEntry): OcxProviderCon
6366
authMode: entry.authKind === "local" ? undefined : entry.authKind,
6467
...(entry.defaultModel ? { defaultModel: entry.defaultModel } : {}),
6568
...(entry.models ? { models: [...entry.models] } : {}),
69+
...(entry.contextWindow !== undefined ? { contextWindow: entry.contextWindow } : {}),
70+
...(entry.modelContextWindows ? { modelContextWindows: { ...entry.modelContextWindows } } : {}),
71+
...(entry.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(entry.modelInputModalities) } : {}),
6672
...(entry.reasoningEfforts ? { reasoningEfforts: [...entry.reasoningEfforts] } : {}),
6773
...(entry.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(entry.modelReasoningEfforts) } : {}),
6874
...(entry.reasoningEffortMap ? { reasoningEffortMap: { ...entry.reasoningEffortMap } } : {}),
@@ -90,6 +96,9 @@ export function deriveKeyLoginMap(): Record<string, DerivedKeyLoginProvider> {
9096
dashboardUrl: entry.dashboardUrl,
9197
...(entry.models ? { models: [...entry.models] } : {}),
9298
...(entry.defaultModel ? { defaultModel: entry.defaultModel } : {}),
99+
...(entry.contextWindow !== undefined ? { contextWindow: entry.contextWindow } : {}),
100+
...(entry.modelContextWindows ? { modelContextWindows: { ...entry.modelContextWindows } } : {}),
101+
...(entry.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(entry.modelInputModalities) } : {}),
93102
...(entry.reasoningEfforts ? { reasoningEfforts: [...entry.reasoningEfforts] } : {}),
94103
...(entry.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(entry.modelReasoningEfforts) } : {}),
95104
...(entry.reasoningEffortMap ? { reasoningEffortMap: { ...entry.reasoningEffortMap } } : {}),

0 commit comments

Comments
 (0)