@bitkyc08/opencodex 2.55.0 → 2.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/bin/ocx.mjs +10 -0
  2. package/gui/dist/assets/{index-BBOZWGB6.css → index-C5-RdDmD.css} +1 -1
  3. package/gui/dist/assets/{index-VuoiWj9J.js → index-Cz7CLdif.js} +21 -21
  4. package/gui/dist/index.html +2 -2
  5. package/package.json +4 -3
  6. package/src/adapters/base.ts +21 -0
  7. package/src/adapters/codebuddy/adapter.ts +2 -1
  8. package/src/adapters/codebuddy/scaffold-guard.ts +248 -0
  9. package/src/adapters/command-code.ts +1 -1
  10. package/src/adapters/cursor/envelope-echo.ts +8 -2
  11. package/src/adapters/cursor/transport-retry.ts +46 -1
  12. package/src/adapters/cursor.ts +4 -0
  13. package/src/adapters/google.ts +7 -7
  14. package/src/adapters/kiro/adapter.ts +42 -1
  15. package/src/adapters/kiro/payload.ts +17 -3
  16. package/src/adapters/kiro/reasoning.ts +70 -7
  17. package/src/adapters/kiro/stream.ts +8 -2
  18. package/src/adapters/kiro/wire.ts +2 -1
  19. package/src/adapters/kiro-events.ts +21 -13
  20. package/src/adapters/kiro-retry.ts +23 -4
  21. package/src/adapters/openai-chat/errors.ts +116 -0
  22. package/src/adapters/openai-chat/messages.ts +346 -0
  23. package/src/adapters/openai-chat/passthrough.ts +146 -0
  24. package/src/adapters/openai-chat/response-events.ts +117 -0
  25. package/src/adapters/openai-chat/tool-call-validation.ts +200 -0
  26. package/src/adapters/openai-chat/tool-name-registry.ts +166 -0
  27. package/src/adapters/openai-chat/tool-schema.ts +495 -0
  28. package/src/adapters/openai-chat/wire.ts +50 -0
  29. package/src/adapters/openai-chat.ts +40 -1452
  30. package/src/adapters/openai-responses/canonical-forward.ts +202 -0
  31. package/src/adapters/openai-responses/image-gen.ts +406 -0
  32. package/src/adapters/openai-responses/internal.ts +3 -0
  33. package/src/adapters/openai-responses/passthrough.ts +642 -0
  34. package/src/adapters/openai-responses/prompt-cache.ts +83 -0
  35. package/src/adapters/openai-responses/reasoning.ts +220 -0
  36. package/src/adapters/openai-responses/request-strips.ts +185 -0
  37. package/src/adapters/openai-responses/tool-output-recovery.ts +509 -0
  38. package/src/adapters/openai-responses/tool-schema.ts +293 -0
  39. package/src/adapters/openai-responses/web-search.ts +156 -0
  40. package/src/adapters/openai-responses.ts +4 -2625
  41. package/src/bridge/errors.ts +58 -0
  42. package/src/bridge/internal.ts +174 -0
  43. package/src/bridge/response-json.ts +630 -0
  44. package/src/bridge/sse.ts +1462 -0
  45. package/src/bridge.ts +5 -2204
  46. package/src/chat/inbound.ts +12 -1
  47. package/src/claude/desktop-profile.ts +66 -9
  48. package/src/claude/outbound.ts +18 -0
  49. package/src/cli/account-main.ts +1 -1
  50. package/src/cli/capabilities.ts +2 -2
  51. package/src/cli/combo.ts +10 -1
  52. package/src/cli/index.ts +48 -5
  53. package/src/cli/registry.ts +2 -1
  54. package/src/cli/system-command.ts +4 -4
  55. package/src/clients/config-export.ts +7 -3
  56. package/src/codex/account-label.ts +14 -3
  57. package/src/codex/account-lifecycle.ts +3 -0
  58. package/src/codex/account-store.ts +184 -35
  59. package/src/codex/account-usability.ts +21 -0
  60. package/src/codex/auth-api/account-list.ts +507 -0
  61. package/src/codex/auth-api/http.ts +32 -0
  62. package/src/codex/auth-api/login-flow.ts +566 -0
  63. package/src/codex/auth-api/login-state.ts +64 -0
  64. package/src/codex/auth-api/main-account-probe.ts +331 -0
  65. package/src/codex/auth-api/pool-mode-gate.ts +274 -0
  66. package/src/codex/auth-api/pool-quota-probe.ts +512 -0
  67. package/src/codex/auth-api/reset-credit-service.ts +431 -0
  68. package/src/codex/auth-api/routes.ts +425 -0
  69. package/src/codex/auth-api/runtime-config.ts +48 -0
  70. package/src/codex/auth-api.ts +27 -3118
  71. package/src/codex/auth-context.ts +252 -35
  72. package/src/codex/catalog/aggregation.ts +80 -1
  73. package/src/codex/catalog/auto-review.ts +507 -0
  74. package/src/codex/catalog/build-entries.ts +981 -0
  75. package/src/codex/catalog/combo-member.ts +375 -0
  76. package/src/codex/catalog/derive-entry.ts +229 -0
  77. package/src/codex/catalog/effort.ts +0 -1
  78. package/src/codex/catalog/gated-native-warn.ts +63 -0
  79. package/src/codex/catalog/gather-capture.ts +533 -0
  80. package/src/codex/catalog/model-hints.ts +691 -0
  81. package/src/codex/catalog/model-visibility.ts +305 -0
  82. package/src/codex/catalog/provider-fetch.ts +52 -2942
  83. package/src/codex/catalog/provider-models.ts +685 -0
  84. package/src/codex/catalog/remote.ts +30 -0
  85. package/src/codex/catalog/restore.ts +132 -0
  86. package/src/codex/catalog/retained-sync.ts +714 -0
  87. package/src/codex/catalog/routed-gather.ts +895 -0
  88. package/src/codex/catalog/subagent-roster.ts +176 -0
  89. package/src/codex/catalog/sync.ts +52 -2698
  90. package/src/codex/cli-install-provenance.ts +7 -1
  91. package/src/codex/convergence.ts +7 -2
  92. package/src/codex/desktop-app/types.ts +11 -2
  93. package/src/codex/desktop-app/windows.ts +5 -5
  94. package/src/codex/inject/config-toml.ts +563 -0
  95. package/src/codex/inject/remove.ts +192 -0
  96. package/src/codex/inject/restore.ts +567 -0
  97. package/src/codex/inject/routing-classify.ts +109 -0
  98. package/src/codex/inject/routing-target.ts +125 -0
  99. package/src/codex/inject.ts +89 -1444
  100. package/src/codex/lineage.ts +458 -0
  101. package/src/codex/model-entitlements.ts +152 -15
  102. package/src/codex/pool-refresh-backoff.ts +161 -0
  103. package/src/codex/quota-rejection.ts +104 -15
  104. package/src/codex/routing/active-account.ts +194 -0
  105. package/src/codex/routing/cache-affinity.ts +70 -0
  106. package/src/codex/routing/cooldown-math.ts +285 -0
  107. package/src/codex/routing/health-store.ts +402 -0
  108. package/src/codex/routing/probe-lease.ts +358 -0
  109. package/src/codex/routing/selection.ts +780 -0
  110. package/src/codex/routing/thread-affinity.ts +586 -0
  111. package/src/codex/routing/transient-hold-dispatch.ts +141 -0
  112. package/src/codex/routing.ts +370 -2271
  113. package/src/codex/shim-fingerprint.ts +223 -0
  114. package/src/codex/shim-inspect.ts +175 -0
  115. package/src/codex/shim-probe.ts +367 -0
  116. package/src/codex/shim-restore-lock.ts +169 -0
  117. package/src/codex/shim-state-file.ts +151 -0
  118. package/src/codex/shim-templates.ts +265 -0
  119. package/src/codex/shim.ts +48 -1268
  120. package/src/codex/warmup.ts +1 -1
  121. package/src/combos/failover.ts +85 -0
  122. package/src/combos/request.ts +17 -10
  123. package/src/combos/types.ts +23 -2
  124. package/src/config/diagnostics.ts +705 -0
  125. package/src/config/feature-flags.ts +55 -0
  126. package/src/config/live-reconcile.ts +403 -0
  127. package/src/config/load-degrade.ts +880 -0
  128. package/src/config/mutation-lock.ts +244 -0
  129. package/src/config/openai-tier-backup.ts +268 -0
  130. package/src/config/pending-teardown.ts +31 -0
  131. package/src/config/persist-unlocked.ts +92 -0
  132. package/src/config/proxy-env.ts +188 -0
  133. package/src/config/salvage.ts +244 -0
  134. package/src/config/schema/config-schema.ts +640 -0
  135. package/src/config/schema/leaf-validators.ts +855 -0
  136. package/src/config/warn-memo.ts +28 -0
  137. package/src/config.ts +234 -4481
  138. package/src/generated/compatibility-version.json +649 -121
  139. package/src/images/loop.ts +1 -1
  140. package/src/lib/errors.ts +17 -0
  141. package/src/lib/request-execution-budget.ts +198 -23
  142. package/src/lib/spend-reservation-ledger.ts +958 -0
  143. package/src/lib/state-store-registrations.ts +6 -2
  144. package/src/lib/test-home-guard.ts +85 -1
  145. package/src/lib/upstream-retry.ts +132 -21
  146. package/src/lib/windows-elevation.ts +76 -14
  147. package/src/lib/workflow-budget.ts +553 -30
  148. package/src/oauth/index.ts +2 -2
  149. package/src/oauth/key-providers.ts +2 -2
  150. package/src/providers/kiro-models.ts +4 -3
  151. package/src/providers/label.ts +19 -1
  152. package/src/providers/model-discovery.ts +16 -0
  153. package/src/providers/quota/account-cache.ts +441 -0
  154. package/src/providers/quota/antigravity.ts +295 -0
  155. package/src/providers/quota/report-cache.ts +320 -0
  156. package/src/providers/quota/vendor-probes-key.ts +1243 -0
  157. package/src/providers/quota/vendor-probes-oauth.ts +590 -0
  158. package/src/providers/quota.ts +324 -3079
  159. package/src/providers/registry/entries-core.ts +1228 -0
  160. package/src/providers/registry/entries-extended.ts +1213 -0
  161. package/src/providers/registry/model-seeds.ts +912 -0
  162. package/src/providers/registry/types.ts +352 -0
  163. package/src/providers/registry.ts +24 -3536
  164. package/src/responses/continuation-ownership.ts +29 -0
  165. package/src/responses/reasoning-envelope.ts +6 -3
  166. package/src/responses/state/replay-fingerprint.ts +80 -0
  167. package/src/responses/state/snapshot-codec.ts +104 -0
  168. package/src/responses/state/spill-failure.ts +118 -0
  169. package/src/responses/state/spill-queue.ts +665 -0
  170. package/src/responses/state/temp-recovery.ts +257 -0
  171. package/src/responses/state.ts +82 -1143
  172. package/src/routing/identity-domains.ts +456 -0
  173. package/src/routing/probe-lease.ts +613 -0
  174. package/src/server/chat-completions.ts +3 -1
  175. package/src/server/chat-native.ts +37 -9
  176. package/src/server/index/bounded-request.ts +88 -0
  177. package/src/server/index/live-sideband.ts +601 -0
  178. package/src/server/index/serve-options.ts +1766 -0
  179. package/src/server/index/startup-warnings.ts +213 -0
  180. package/src/server/index/websocket-handler.ts +339 -0
  181. package/src/server/index.ts +45 -2552
  182. package/src/server/inspection-tee.ts +107 -0
  183. package/src/server/live.ts +46 -1
  184. package/src/server/management/combo-routes.ts +10 -1
  185. package/src/server/management/route-registry.ts +26 -23
  186. package/src/server/management/shared.ts +8 -5
  187. package/src/server/management/workflow-budget-routes.ts +133 -0
  188. package/src/server/management-api.ts +12 -0
  189. package/src/server/relay-eager.ts +2 -0
  190. package/src/server/relay.ts +14 -19
  191. package/src/server/request-log-conversation.ts +9 -7
  192. package/src/server/request-log.ts +372 -4
  193. package/src/server/response-log-body.ts +153 -0
  194. package/src/server/responses/account-change-state.ts +307 -0
  195. package/src/server/responses/adapter-continuation.ts +540 -0
  196. package/src/server/responses/adapter-delivery.ts +208 -0
  197. package/src/server/responses/adapter-dispatch.ts +1042 -0
  198. package/src/server/responses/codex-ws-wire.ts +5 -0
  199. package/src/server/responses/collaboration.ts +74 -4
  200. package/src/server/responses/combo-session-recall.ts +68 -8
  201. package/src/server/responses/compact.ts +113 -17
  202. package/src/server/responses/completion-policy.ts +33 -0
  203. package/src/server/responses/core-auth.ts +529 -0
  204. package/src/server/responses/core-codex-account.ts +907 -0
  205. package/src/server/responses/core-combo-failure.ts +210 -0
  206. package/src/server/responses/core-combo.ts +787 -0
  207. package/src/server/responses/core-errors.ts +170 -0
  208. package/src/server/responses/core-lifetime.ts +95 -0
  209. package/src/server/responses/core-normalize.ts +350 -0
  210. package/src/server/responses/core-opaque-recovery.ts +380 -0
  211. package/src/server/responses/core-options.ts +159 -0
  212. package/src/server/responses/core-replay.ts +298 -0
  213. package/src/server/responses/core.ts +192 -8893
  214. package/src/server/responses/encrypted-payload.ts +0 -1
  215. package/src/server/responses/input-admission.ts +126 -6
  216. package/src/server/responses/passthrough-delivery.ts +869 -0
  217. package/src/server/responses/passthrough-dispatch.ts +1494 -0
  218. package/src/server/responses/passthrough-error.ts +38 -2
  219. package/src/server/responses/passthrough-execution.ts +54 -0
  220. package/src/server/responses/request-prepare.ts +1080 -0
  221. package/src/server/responses/request-send-budget.ts +259 -0
  222. package/src/server/responses/request-sidecar-auth.ts +149 -0
  223. package/src/server/responses/request-spend.ts +147 -0
  224. package/src/server/responses/request-transport.ts +803 -0
  225. package/src/server/responses/response-effects.ts +157 -0
  226. package/src/server/responses/run-turn-execution.ts +476 -0
  227. package/src/server/responses/sidecar-execution.ts +463 -0
  228. package/src/server/responses/terminal-guard.ts +65 -4
  229. package/src/server/responses-image-gen-repair.ts +1 -1
  230. package/src/server/responses-undeclared-tool-guard.ts +9 -5
  231. package/src/server/workflow-refusal.ts +84 -0
  232. package/src/service/windows-ops.ts +210 -16
  233. package/src/service/windows-scheduler.ts +28 -21
  234. package/src/service.ts +1 -1
  235. package/src/types/config.ts +34 -1
  236. package/src/types/request.ts +8 -5
  237. package/src/types/tools.ts +24 -0
  238. package/src/types.ts +2 -0
  239. package/src/update/index.ts +10 -0
  240. package/src/update/stop-contract.d.mts +1 -0
  241. package/src/update/stop-contract.mjs +19 -0
  242. package/src/update/stop-decision.d.mts +1 -1
  243. package/src/update/stop-decision.mjs +12 -3
  244. package/src/usage/log.ts +147 -1
  245. package/src/usage/summary.ts +171 -21
  246. package/src/vision/anthropic-describe.ts +1 -1
  247. package/src/vision/describe.ts +5 -5
  248. package/src/web-search/anthropic-executor.ts +1 -1
  249. package/src/web-search/exa-executor.ts +1 -1
  250. package/src/web-search/executor.ts +1 -1
  251. package/src/web-search/gemini-executor.ts +1 -1
  252. package/src/web-search/loop.ts +1 -1
  253. package/src/web-search/ollama-executor.ts +1 -1
  254. package/src/web-search/parse.ts +67 -14
  255. package/src/web-search/passthrough-bridge.ts +64 -31
  256. package/src/web-search/xai-executor.ts +1 -1
@@ -78,7 +78,6 @@ import {
78
78
  catalogModelSupportsServiceTier,
79
79
  finishRequestAttempt,
80
80
  inspectResponseLogJson,
81
- noteAttemptSend,
82
81
  readConfiguredCodexServiceTier,
83
82
  requestLogSpeedLabel,
84
83
  sealRequestAttemptIdentity,
@@ -10,7 +10,13 @@
10
10
  * catches the pathological case and stays out of the way otherwise. Every uncertainty
11
11
  * resolves toward admitting.
12
12
  */
13
- import { nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, type NativeContextLimitsInput } from "../../codex/catalog/metadata";
13
+ import {
14
+ nativeOpenAiContextWindow,
15
+ nativeOpenAiMaxInputTokens,
16
+ nativeOpenAiMaxOutputTokens,
17
+ type NativeContextLimitsInput,
18
+ } from "../../codex/catalog/metadata";
19
+ import { getModelMetadata } from "../../generated/model-metadata";
14
20
  import { estimateTokens } from "../../lib/token-estimate";
15
21
  import { isCanonicalOpenAiForwardProvider, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
16
22
  import { modelRecordValue } from "../../reasoning-effort";
@@ -54,6 +60,8 @@ export interface InputAdmissionResult {
54
60
  estimatedTokens: number;
55
61
  /** Resolved ceiling, or null when nothing could be resolved (=> always admitted). */
56
62
  ceiling: number | null;
63
+ /** Output space reserved by the combo preflight; absent on the loose direct gate. */
64
+ requiredOutputHeadroom?: number;
57
65
  }
58
66
 
59
67
  function positive(value: unknown): number | null {
@@ -135,14 +143,19 @@ export function estimateInputTokens(parsed: OcxParsedRequest, modelId: string):
135
143
  * reject a user-defined provider that merely shares a built-in name using limits that
136
144
  * belong to a different service.
137
145
  */
138
- export function resolveInputCeiling(
146
+ interface ResolvedContextLimits {
147
+ /** The target's total context window: input and output share it. */
148
+ window: number | null;
149
+ /** Largest admissible input, which input-only caps may tighten below the window. */
150
+ ceiling: number | null;
151
+ }
152
+
153
+ function resolveContextLimits(
139
154
  provider: OcxProviderConfig,
140
155
  providerName: string,
141
156
  modelId: string,
142
- // Operator cap for the canonical native provider. Passed in rather than read from a
143
- // config here so this stays pure: no filesystem, no catalog, no registry scan.
144
157
  nativeContextCap?: NativeContextLimitsInput,
145
- ): number | null {
158
+ ): ResolvedContextLimits {
146
159
  // `modelRecordValue`, not a bare lookup: the catalog resolves these same two maps that
147
160
  // way, so a `gpt-oss` entry covers `gpt-oss:120b`. Reading raw here made the gate fall
148
161
  // back to the provider-wide window and refuse turns the model can plainly hold.
@@ -168,13 +181,120 @@ export function resolveInputCeiling(
168
181
  : null;
169
182
  const nativeMaxInput = canonicalNativeBare ? positive(nativeOpenAiMaxInputTokens(modelId, nativeLimits)) : null;
170
183
 
171
- const window = canonicalNativeBare ? native : configured;
184
+ const window = canonicalNativeBare ? (native ?? generatedNativeWindow(modelId, configured, nativeContextCap)) : configured;
172
185
  // modelMaxInputTokens is an input-only cap, so it can only tighten the window.
173
186
  const configuredMaxInput = positive(modelRecordValue(provider.modelMaxInputTokens, modelId));
174
187
  const limits = [window, configuredMaxInput, nativeMaxInput].filter((v): v is number => v !== null);
188
+ return { window, ceiling: limits.length === 0 ? null : Math.min(...limits) };
189
+ }
190
+
191
+ /**
192
+ * Generated-catalog keys, not routing provider names. `OPENAI_CODEX_PROVIDER_ID` is the string
193
+ * `"openai"` -- the canonical Codex forward route -- so using it to index the generated bundle
194
+ * would silently skip the native Codex rows and read the public API rows instead.
195
+ */
196
+ const NATIVE_METADATA_CATALOGS = ["openai-codex", "openai"] as const;
197
+
198
+ /**
199
+ * Static in-tree metadata for a canonical native slug the narrower override and pinned-native
200
+ * tables do not carry. Falling through to null made input admission completely blind for
201
+ * exactly those models, which is how a 128k target accepted a turn it could not finish.
202
+ *
203
+ * This deliberately covers slugs that are no longer offered in the picker: a retired slug is
204
+ * still dispatchable when an operator names it explicitly in a combo target, and that is the
205
+ * configuration where the gate was inert. This is a generated bundle compiled into the binary,
206
+ * not a live catalog read, so it adds no I/O. Explicit provider and operator caps may only
207
+ * narrow the result, never widen it.
208
+ */
209
+ function generatedNativeWindow(
210
+ modelId: string,
211
+ configured: number | null,
212
+ nativeContextCap: NativeContextLimitsInput | undefined,
213
+ ): number | null {
214
+ let generated: number | null = null;
215
+ for (const catalog of NATIVE_METADATA_CATALOGS) {
216
+ generated = positive(getModelMetadata(catalog, modelId)?.contextWindow);
217
+ if (generated !== null) break;
218
+ }
219
+ if (generated === null) return null;
220
+ const cap = typeof nativeContextCap === "number"
221
+ ? positive(nativeContextCap)
222
+ : positive(nativeContextCap?.cap);
223
+ return Math.min(generated, configured ?? generated, cap ?? generated);
224
+ }
225
+
226
+ export function resolveInputCeiling(
227
+ provider: OcxProviderConfig,
228
+ providerName: string,
229
+ modelId: string,
230
+ // Operator cap for the canonical native provider. Passed in rather than read from a
231
+ // config here so this stays pure: no filesystem, no catalog, no registry scan.
232
+ nativeContextCap?: NativeContextLimitsInput,
233
+ ): number | null {
234
+ return resolveContextLimits(provider, providerName, modelId, nativeContextCap).ceiling;
235
+ }
236
+
237
+ /**
238
+ * Largest output the concrete target can emit. Used only to avoid reserving MORE than the
239
+ * target could ever produce when a client asks for a bigger allowance than the model has.
240
+ * Unknown stays unknown rather than inventing a capability.
241
+ */
242
+ export function resolveOutputCeiling(
243
+ provider: OcxProviderConfig,
244
+ providerName: string,
245
+ modelId: string,
246
+ ): number | null {
247
+ const configured = positive(modelRecordValue(provider.modelMaxOutputTokens, modelId))
248
+ ?? positive(provider.defaultMaxOutputTokens);
249
+ const canonicalNativeBare = providerName === OPENAI_CODEX_PROVIDER_ID
250
+ && isCanonicalOpenAiForwardProvider(provider)
251
+ && !modelId.includes("/");
252
+ const native = canonicalNativeBare ? positive(nativeOpenAiMaxOutputTokens(modelId)) : null;
253
+ const limits = [configured, native].filter((v): v is number => v !== null);
175
254
  return limits.length === 0 ? null : Math.min(...limits);
176
255
  }
177
256
 
257
+ /**
258
+ * Combo-only admission. A fallback must be able to satisfy the caller's declared output
259
+ * allowance inside its OWN context window. Otherwise it returns 200, emits a few hundred
260
+ * tokens, and terminates on `finish_reason: length` — which the Anthropic surface renders as
261
+ * "response exceeded the output token maximum" even though the real cause was the total
262
+ * window. By then the next target cannot be tried, because output has already committed.
263
+ *
264
+ * Two budgets are checked separately so the reserve is counted exactly once. `ceiling` is an
265
+ * input-only budget once `modelMaxInputTokens` tightens it below the window, so the output
266
+ * reserve belongs against `window`, not against `ceiling`.
267
+ *
268
+ * Direct and single-target requests keep the deliberately loose 2.5x pathological-input gate.
269
+ * This stricter rule applies only to synthetic combo children, where skipping one known-small
270
+ * target is safe and the ladder continues before any upstream bytes are sent. Unknown context
271
+ * stays fail-open, and a caller that declared no output allowance is unaffected.
272
+ */
273
+ export function checkComboTargetInputAdmission(
274
+ parsed: OcxParsedRequest,
275
+ provider: OcxProviderConfig,
276
+ providerName: string,
277
+ modelId: string,
278
+ nativeContextCap?: NativeContextLimitsInput,
279
+ ): InputAdmissionResult {
280
+ const { window, ceiling } = resolveContextLimits(provider, providerName, modelId, nativeContextCap);
281
+ const requestedOutput = positive(parsed.options.maxOutputTokens);
282
+ if (window === null || ceiling === null || requestedOutput === null) {
283
+ return checkInputAdmission(parsed, provider, providerName, modelId, nativeContextCap);
284
+ }
285
+ const targetOutput = resolveOutputCeiling(provider, providerName, modelId);
286
+ const requiredOutputHeadroom = targetOutput === null
287
+ ? requestedOutput
288
+ : Math.min(requestedOutput, targetOutput);
289
+ const estimatedTokens = estimateInputTokens(parsed, modelId);
290
+ return {
291
+ admitted: estimatedTokens <= ceiling && estimatedTokens + requiredOutputHeadroom <= window,
292
+ estimatedTokens,
293
+ ceiling,
294
+ requiredOutputHeadroom,
295
+ };
296
+ }
297
+
178
298
  /**
179
299
  * Fail-open when no ceiling is known; refuse only past `ceiling * ADMISSION_TOLERANCE`.
180
300
  *