|
| 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. |
0 commit comments