@bitkyc08/opencodex 2.64.0 → 2.65.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 (208) hide show
  1. package/README.md +28 -25
  2. package/bin/ocx.mjs +16 -2
  3. package/gui/dist/assets/App-8NMiZxT0.css +1 -0
  4. package/gui/dist/assets/App-DGLte6IR.js +50 -0
  5. package/gui/dist/assets/Tray-D4bA1vff.js +1 -0
  6. package/gui/dist/assets/{index-DiBRuK-d.css → index--EWgGQvZ.css} +1 -1
  7. package/gui/dist/assets/{index-SggB6t3z.js → index-Bi1K37Wl.js} +12 -12
  8. package/gui/dist/assets/tray-data-BZXhB3qz.js +1 -0
  9. package/gui/dist/index.html +2 -2
  10. package/package.json +1 -4
  11. package/src/adapters/anthropic.ts +30 -1
  12. package/src/adapters/claude-cli/adapter.ts +218 -0
  13. package/src/adapters/claude-cli/profiles.ts +38 -0
  14. package/src/adapters/codebuddy/profiles.ts +2 -0
  15. package/src/adapters/coding-agent/profile.ts +12 -4
  16. package/src/adapters/coding-agent/turn.ts +16 -6
  17. package/src/adapters/command-code-tool-text.ts +133 -23
  18. package/src/adapters/cursor/catalog.ts +4 -8
  19. package/src/adapters/cursor/discovery.ts +10 -5
  20. package/src/adapters/cursor/effort-map.ts +2 -6
  21. package/src/adapters/cursor/envelope-echo.ts +10 -5
  22. package/src/adapters/cursor/request-builder.ts +9 -4
  23. package/src/adapters/cursor/thread-continuity.ts +53 -0
  24. package/src/adapters/cursor.ts +29 -13
  25. package/src/adapters/devin/cloud-direct/chat.ts +3 -1
  26. package/src/adapters/google-tool-schema.ts +26 -3
  27. package/src/adapters/identity.ts +214 -2
  28. package/src/adapters/openai-chat/passthrough.ts +1 -0
  29. package/src/adapters/openai-chat/serialized-tool-call-content.ts +569 -0
  30. package/src/adapters/openai-chat.ts +43 -15
  31. package/src/adapters/openai-responses/canonical-forward.ts +17 -10
  32. package/src/adapters/openai-responses/passthrough.ts +19 -4
  33. package/src/adapters/openai-responses/request-strips.ts +25 -0
  34. package/src/adapters/openai-responses/web-search.ts +22 -4
  35. package/src/adapters/qoder/profiles.ts +2 -0
  36. package/src/adapters/registry.ts +8 -0
  37. package/src/adapters/run-turn-queue.ts +7 -0
  38. package/src/bridge/response-json.ts +6 -4
  39. package/src/bridge/sse.ts +7 -5
  40. package/src/claude/alias.ts +73 -26
  41. package/src/claude/context-windows.ts +15 -6
  42. package/src/claude/desktop-3p-library.ts +3 -2
  43. package/src/claude/desktop-3p.ts +1 -1
  44. package/src/claude/desktop-first-party.ts +63 -22
  45. package/src/claude/desktop-picker-profile.ts +302 -0
  46. package/src/claude/desktop-picker.ts +365 -0
  47. package/src/claude/desktop-risk.ts +20 -0
  48. package/src/claude/gateway-cache.ts +13 -4
  49. package/src/claude/inbound.ts +5 -2
  50. package/src/claude/intercept/connect-proxy.ts +106 -29
  51. package/src/claude/intercept/local-ca.ts +76 -18
  52. package/src/claude/intercept/model-bindings.ts +145 -0
  53. package/src/claude/intercept/picker-bootstrap.ts +141 -0
  54. package/src/claude/intercept/picker-ca.ts +126 -0
  55. package/src/claude/intercept/picker-listener.ts +213 -0
  56. package/src/claude/intercept/picker-models.ts +101 -0
  57. package/src/claude/intercept/picker-runtime.ts +330 -0
  58. package/src/claude/intercept/picker-trust.ts +125 -0
  59. package/src/claude/intercept/runtime.ts +149 -2
  60. package/src/claude/model-info.ts +18 -4
  61. package/src/cli/agent.ts +16 -2
  62. package/src/cli/capabilities.ts +71 -2
  63. package/src/cli/claude-desktop.ts +319 -33
  64. package/src/cli/claude.ts +15 -7
  65. package/src/cli/codex-shim-autorestore.ts +1 -0
  66. package/src/cli/dispatch.ts +29 -23
  67. package/src/cli/effort.ts +16 -6
  68. package/src/cli/ensure-desired-integrations.ts +29 -4
  69. package/src/cli/ready.ts +1 -1
  70. package/src/cli/registry.ts +8 -0
  71. package/src/cli/restart-scope.ts +9 -1
  72. package/src/cli/runtime-api.ts +17 -0
  73. package/src/cli/system-command.ts +11 -12
  74. package/src/client/connect.ts +12 -2
  75. package/src/client/state.ts +39 -1
  76. package/src/clients/config-export.ts +57 -9
  77. package/src/codex/auth-context.ts +51 -11
  78. package/src/codex/catalog/derive-entry.ts +5 -5
  79. package/src/codex/catalog/gather-capture.ts +25 -6
  80. package/src/codex/catalog/metadata.ts +3 -3
  81. package/src/codex/catalog/parsing.ts +39 -1
  82. package/src/codex/catalog/provider-models.ts +8 -6
  83. package/src/codex/catalog/retained-sync.ts +17 -7
  84. package/src/codex/catalog/sync.ts +2 -2
  85. package/src/codex/desktop-app-restart.ts +8 -0
  86. package/src/codex/desktop-switches.ts +9 -1
  87. package/src/codex/home.ts +43 -4
  88. package/src/codex/inject/config-toml.ts +137 -0
  89. package/src/codex/inject/plan.ts +23 -0
  90. package/src/codex/inject/remove.ts +21 -1
  91. package/src/codex/inject.ts +63 -8
  92. package/src/codex/journal.ts +36 -0
  93. package/src/codex/main-account-hard-lock.ts +14 -1
  94. package/src/codex/main-account-policy-wait.ts +109 -0
  95. package/src/codex/native-profile-startup.ts +24 -6
  96. package/src/codex/native-residue.ts +28 -10
  97. package/src/codex/quota-types.ts +8 -1
  98. package/src/codex/quota.ts +49 -7
  99. package/src/codex/runtime.ts +31 -10
  100. package/src/combos/failover.ts +7 -6
  101. package/src/combos/resolve.ts +91 -14
  102. package/src/combos/types.ts +18 -1
  103. package/src/config/load-degrade.ts +2 -0
  104. package/src/config/schema/config-schema.ts +21 -2
  105. package/src/config/schema/leaf-validators.ts +6 -3
  106. package/src/config/subagent-models.ts +3 -1
  107. package/src/generated/compatibility-version.json +275 -163
  108. package/src/images/artifacts.ts +14 -0
  109. package/src/integrations/owned-refresh.ts +1 -1
  110. package/src/integrations/ownership-policy.ts +32 -1
  111. package/src/integrations/state.ts +3 -1
  112. package/src/integrations/writer.ts +9 -0
  113. package/src/lib/config-ownership.ts +3 -0
  114. package/src/lib/errors.ts +87 -0
  115. package/src/lib/package-tree-integrity.ts +1 -1
  116. package/src/lib/request-execution-budget.ts +42 -14
  117. package/src/lib/request-resend-gate.ts +4 -3
  118. package/src/lib/retry-delay.ts +7 -1
  119. package/src/lib/tool-envelope-echo-filter.ts +236 -0
  120. package/src/lib/upstream-retry.ts +20 -12
  121. package/src/oauth/index.ts +1 -0
  122. package/src/oauth/kiro-credentials.ts +14 -1
  123. package/src/oauth/login-cli.ts +1 -0
  124. package/src/providers/derive.ts +4 -0
  125. package/src/providers/fast-opt-in.ts +31 -0
  126. package/src/providers/model-rename-fields.ts +2 -0
  127. package/src/providers/provider-id-rewrite.ts +2 -0
  128. package/src/providers/quota/vendor-probes-key.ts +8 -2
  129. package/src/providers/registry/entries-core.ts +45 -2
  130. package/src/providers/registry/entries-extended.ts +99 -12
  131. package/src/providers/registry/model-ids.ts +2 -0
  132. package/src/providers/registry/types.ts +7 -1
  133. package/src/providers/resolved-model-policy.ts +11 -4
  134. package/src/providers/service-tier.ts +10 -3
  135. package/src/responses/code-mode-helper-compat.ts +3 -0
  136. package/src/responses/parser.ts +45 -3
  137. package/src/router.ts +6 -0
  138. package/src/server/auth-cors.ts +8 -0
  139. package/src/server/chat-completions.ts +3 -1
  140. package/src/server/claude-messages.ts +69 -14
  141. package/src/server/grok-upstream-envelope-echo.ts +120 -0
  142. package/src/server/index/claude-intercept-lifecycle.ts +24 -0
  143. package/src/server/index/serve-options.ts +2 -2
  144. package/src/server/index.ts +7 -0
  145. package/src/server/management/agent-settings-routes.ts +204 -112
  146. package/src/server/management/claude-desktop-picker-routes.ts +128 -0
  147. package/src/server/management/combo-routes.ts +59 -2
  148. package/src/server/management/config-routes.ts +81 -39
  149. package/src/server/management/context.ts +3 -0
  150. package/src/server/management/native-integration-routes.ts +169 -93
  151. package/src/server/management/provider-routes.ts +46 -4
  152. package/src/server/management/route-registry.ts +10 -0
  153. package/src/server/management/routing-profile-routes.ts +9 -0
  154. package/src/server/management/sidebar-routes.ts +52 -0
  155. package/src/server/management-api.ts +2 -0
  156. package/src/server/proxy-liveness.ts +38 -3
  157. package/src/server/request-log-account-rotation.ts +53 -0
  158. package/src/server/request-log.ts +3 -16
  159. package/src/server/responses/adapter-dispatch.ts +17 -1
  160. package/src/server/responses/agent-task-recovery.ts +49 -26
  161. package/src/server/responses/codex-ws-exchange.ts +18 -7
  162. package/src/server/responses/codex-ws-wire.ts +27 -4
  163. package/src/server/responses/core-combo.ts +21 -3
  164. package/src/server/responses/core-normalize.ts +7 -0
  165. package/src/server/responses/core-opaque-recovery.ts +3 -2
  166. package/src/server/responses/encrypted-payload.ts +15 -14
  167. package/src/server/responses/fetch-helpers.ts +1 -1
  168. package/src/server/responses/input-admission.ts +10 -6
  169. package/src/server/responses/native-response-control.ts +2 -2
  170. package/src/server/responses/passthrough-delivery.ts +182 -12
  171. package/src/server/responses/passthrough-dispatch.ts +102 -44
  172. package/src/server/responses/policy-fallback.ts +3 -0
  173. package/src/server/responses/policy-refusal.ts +67 -0
  174. package/src/server/responses/request-send-budget.ts +4 -0
  175. package/src/server/responses/run-turn-execution.ts +42 -11
  176. package/src/server/responses/ws-upstream.ts +2 -1
  177. package/src/server/system-env-shell.ts +0 -1
  178. package/src/server/system-env.ts +25 -4
  179. package/src/service/cli.ts +34 -3
  180. package/src/tray/assets/opencodex-tray-offline-update.ico +0 -0
  181. package/src/tray/assets/opencodex-tray-online-update.ico +0 -0
  182. package/src/tray/assets/opencodex-tray-warning-update.ico +0 -0
  183. package/src/tray/windows-tray.ps1 +188 -7
  184. package/src/tray/windows.ts +23 -2
  185. package/src/types/config.ts +52 -12
  186. package/src/types/provider.ts +22 -5
  187. package/src/types/tools.ts +11 -5
  188. package/src/types.ts +1 -0
  189. package/src/update/async-check.ts +109 -0
  190. package/src/update/badge.ts +11 -17
  191. package/src/update/check-types.ts +9 -0
  192. package/src/update/desktop-badge.ts +102 -0
  193. package/src/update/index.ts +48 -8
  194. package/src/update/install-detection.d.mts +29 -2
  195. package/src/update/install-detection.mjs +213 -7
  196. package/src/update/job.ts +17 -12
  197. package/src/update/notify.ts +16 -11
  198. package/src/update/pnpm-owner-worker.ts +12 -0
  199. package/src/update/refresh-scheduler.ts +141 -0
  200. package/src/usage/cost.ts +31 -4
  201. package/src/usage/expected-prices.ts +57 -0
  202. package/assets/download-linux.svg +0 -10
  203. package/assets/download-macos.svg +0 -10
  204. package/assets/download-windows.svg +0 -10
  205. package/gui/dist/assets/App-CpuDF3ci.js +0 -50
  206. package/gui/dist/assets/App-I5AnaSLh.css +0 -1
  207. package/gui/dist/assets/Tray-B4uEIa1O.js +0 -1
  208. package/gui/dist/assets/usage-companion-chart-DLbKOJml.js +0 -1
@@ -1,3 +1,5 @@
1
+ import type { OcxContext } from "../types";
2
+
1
3
  /**
2
4
  * Central routed-model identity repair.
3
5
  *
@@ -72,11 +74,221 @@ function safeRoutedModelIdentity(modelName: string): string | null {
72
74
  * native template.
73
75
  */
74
76
  export function identifyRoutedModel(systemText: string, modelName: string): string {
77
+ const replacement = routedIdentityLine(modelName);
78
+ return systemText
79
+ .replace(CODEX_GPT5_IDENTITY_RE, () => replacement)
80
+ .replace(NEUTRAL_IDENTITY_RE, () => replacement)
81
+ .replace(ROUTED_IDENTITY_RE, () => replacement);
82
+ }
83
+
84
+ function routedIdentityLine(modelName: string): string {
75
85
  const identity = safeRoutedModelIdentity(modelName);
76
- const replacement = identity
86
+ return identity
77
87
  ? `You are a coding agent powered by the ${identity}. If asked which model you are, identify as ${identity}. Do not claim to be a different model or to have a different creator.`
78
88
  : "You are a coding agent powered by the configured model. If asked which model you are, identify as configured model. Do not claim to be GPT-5 or made by OpenAI.";
79
- return systemText.replace(CODEX_GPT5_IDENTITY_RE, () => replacement);
89
+ }
90
+
91
+ /**
92
+ * This proxy's OWN generated identity sentence (both the named and the `configured model`
93
+ * fallback form). Codex stores a session's instructions once and replays them verbatim when it
94
+ * spawns a sub-agent on a DIFFERENT model (#5217), so a worker inherits the parent's sentence and
95
+ * then answers identity questions with the parent's model id.
96
+ *
97
+ * The pattern is deliberately anchored on the exact wording this module emits — the leading
98
+ * "You are a coding agent powered by the " and the matching "If asked which model you are,
99
+ * identify as " clause — so it can only ever rewrite text the proxy generated. The model id is
100
+ * matched with the same character class `safeRoutedModelIdentity` allows, never `.*`, so user
101
+ * prose, fenced code and provider-native identity blocks are out of reach.
102
+ */
103
+ const ROUTED_IDENTITY_RE =
104
+ /You are a coding agent powered by the (?:configured model|[A-Za-z0-9._/@:+\-[\]~]+)\. If asked which model you are, identify as (?:configured model|[A-Za-z0-9._/@:+\-[\]~]+)\. Do not claim to be (?:a different model or to have a different creator|GPT-5 or made by OpenAI)\./g;
105
+
106
+ /**
107
+ * The model-neutral catalog line. Since #5217 the catalog no longer bakes a model id into
108
+ * `base_instructions` — a stored instruction block is replayed to sub-agents on other models —
109
+ * so the id is written at request time instead, where the destination is known.
110
+ */
111
+ const NEUTRAL_IDENTITY_RE = new RegExp(
112
+ NEUTRAL_IDENTITY_LINE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
113
+ "g",
114
+ );
115
+
116
+ /**
117
+ * True when `text` carries an identity sentence this proxy generated — either a sentence that names
118
+ * a model already, or the model-neutral catalog line. Both need request-time attention: the named
119
+ * form is renamed for the destination, the neutral form is named for the first time.
120
+ */
121
+ export function hasRoutedIdentity(text: string): boolean {
122
+ ROUTED_IDENTITY_RE.lastIndex = 0;
123
+ NEUTRAL_IDENTITY_RE.lastIndex = 0;
124
+ return ROUTED_IDENTITY_RE.test(text) || NEUTRAL_IDENTITY_RE.test(text);
125
+ }
126
+
127
+ /**
128
+ * Request-time repair for a routed destination: rewrite an inherited identity sentence so it names
129
+ * the model this request is actually sent to. Text without one is returned unchanged.
130
+ */
131
+ export function repairRoutedIdentity(text: string, modelName: string): string {
132
+ const replacement = routedIdentityLine(modelName);
133
+ return text.replace(ROUTED_IDENTITY_RE, () => replacement);
134
+ }
135
+
136
+ /**
137
+ * Request-time naming for text that will be handed to a routed model from a stored instruction
138
+ * block: rewrite the model-neutral catalog line AND any sentence naming an earlier model so both
139
+ * name this request's destination.
140
+ *
141
+ * This is the parser's entry point. A routed adapter that never calls `identifyRoutedModel` (the
142
+ * native-wire adapters build their own system text) would otherwise ship the catalog's neutral line
143
+ * with no model name at all, which is what `base_instructions` used to carry before #5217 made the
144
+ * on-disk block model-neutral.
145
+ */
146
+ export function nameRoutedIdentity(text: string, modelName: string): string {
147
+ const replacement = routedIdentityLine(modelName);
148
+ // Name the neutral line first, then let the rename pass settle any earlier model id the block
149
+ // still carries — including the one just written, which the second pass rewrites to itself.
150
+ return repairRoutedIdentity(text.replace(NEUTRAL_IDENTITY_RE, () => replacement), modelName);
151
+ }
152
+
153
+ /**
154
+ * Settle this proxy's identity sentence on the model a routed request is actually dispatched to.
155
+ *
156
+ * The parser writes the CLIENT-selected id (an alias, a namespaced slug, a combo name) because
157
+ * routing has not run yet, and only some adapters rename the sentence afterwards: the ones that
158
+ * build their own system text and call `identifyRoutedModel`. Every other adapter — the native-wire
159
+ * ones and the `runTurn` ones — ships whatever the parser wrote, so a request routed anywhere else
160
+ * would hand the upstream an id it never sees, and an inherited sub-agent block the parent's id.
161
+ *
162
+ * The route owner knows the model id that will be sent, and this is the one place every dispatch
163
+ * path (passthrough, runTurn, request build) reads the context from. Text without a sentence of
164
+ * ours is returned unchanged, and the same by reference: the guard is a regex test, not a scan of
165
+ * every turn's text.
166
+ */
167
+ export function renameRoutedIdentityInContext(context: OcxContext, wireModelId: string): OcxContext {
168
+ let changed = false;
169
+ const mapText = (text: string): string => {
170
+ if (!hasRoutedIdentity(text)) return text;
171
+ const next = repairRoutedIdentity(text, wireModelId);
172
+ if (next !== text) changed = true;
173
+ return next;
174
+ };
175
+ const systemPrompt = context.systemPrompt?.map(mapText);
176
+ const messages = context.messages.map((message) => {
177
+ // Instruction text only. A user turn is the caller's own content, and every other role is
178
+ // either model output or tool output — none of it is ours to rewrite.
179
+ if (message.role !== "developer") return message;
180
+ const content = message.content;
181
+ if (typeof content === "string") {
182
+ const next = mapText(content);
183
+ return next === content ? message : { ...message, content: next };
184
+ }
185
+ let partChanged = false;
186
+ const parts = content.map((part) => {
187
+ if (part.type !== "text" || !hasRoutedIdentity(part.text)) return part;
188
+ const next = repairRoutedIdentity(part.text, wireModelId);
189
+ if (next === part.text) return part;
190
+ partChanged = true;
191
+ return { ...part, text: next };
192
+ });
193
+ if (!partChanged) return message;
194
+ changed = true;
195
+ return { ...message, content: parts };
196
+ });
197
+ if (!changed) return context;
198
+ return { ...context, ...(systemPrompt ? { systemPrompt } : {}), messages };
199
+ }
200
+
201
+ /** A content part carrying no text is not content; every other part shape stays. */
202
+ function isEmptyTextPart(part: unknown): boolean {
203
+ if (!part || typeof part !== "object" || Array.isArray(part)) return false;
204
+ const record = part as Record<string, unknown>;
205
+ return typeof record.text === "string" && record.text.length === 0;
206
+ }
207
+
208
+ /**
209
+ * Apply `repair` to the instruction text of a Responses request body: the top-level `instructions`
210
+ * string and every developer/system `input` message. Nothing else is in reach — user turns, tool
211
+ * output and assistant history are the caller's content.
212
+ *
213
+ * Stripping consumes text rather than replacing it, so a value can end up empty. An empty
214
+ * `instructions` string is a different payload from an absent key, and an empty developer message is
215
+ * a message the caller never wrote, so both are removed instead of sent blank.
216
+ */
217
+ export function repairIdentityInResponsesBody(body: unknown, repair: (text: string) => string): unknown {
218
+ if (!body || typeof body !== "object" || Array.isArray(body)) return body;
219
+ const record = body as Record<string, unknown>;
220
+ let changed = false;
221
+ const mapText = (text: string): string => {
222
+ if (!hasRoutedIdentity(text)) return text;
223
+ const next = repair(text);
224
+ if (next !== text) changed = true;
225
+ return next;
226
+ };
227
+ let instructions = record.instructions;
228
+ if (typeof instructions === "string") {
229
+ const next = mapText(instructions);
230
+ if (next !== instructions) {
231
+ changed = true;
232
+ instructions = next.length > 0 ? next : undefined;
233
+ }
234
+ }
235
+ const mapInputItem = (item: unknown): unknown => {
236
+ if (!item || typeof item !== "object" || Array.isArray(item)) return item;
237
+ const message = item as Record<string, unknown>;
238
+ if (message.type !== undefined && message.type !== "message") return item;
239
+ if (message.role !== "developer" && message.role !== "system") return item;
240
+ if (typeof message.content === "string") {
241
+ const next = mapText(message.content);
242
+ if (next === message.content) return item;
243
+ return next.length > 0 ? { ...message, content: next } : undefined;
244
+ }
245
+ if (!Array.isArray(message.content)) return item;
246
+ let partChanged = false;
247
+ const content = message.content.map((part: unknown) => {
248
+ if (!part || typeof part !== "object" || Array.isArray(part)) return part;
249
+ const partRecord = part as Record<string, unknown>;
250
+ if (typeof partRecord.text !== "string") return part;
251
+ const next = mapText(partRecord.text);
252
+ if (next === partRecord.text) return part;
253
+ partChanged = true;
254
+ return { ...partRecord, text: next };
255
+ });
256
+ if (!partChanged) return item;
257
+ return content.every(isEmptyTextPart) ? undefined : { ...message, content };
258
+ };
259
+ const input = Array.isArray(record.input)
260
+ ? record.input.flatMap((item: unknown) => {
261
+ const next = mapInputItem(item);
262
+ return next === undefined ? [] : [next];
263
+ })
264
+ : record.input;
265
+ if (!changed) return body;
266
+ const next: Record<string, unknown> = { ...record, input };
267
+ // `...record` carries the original key, so a removed instruction has to be deleted rather than
268
+ // merely left out of the spread.
269
+ if (instructions === undefined) delete next.instructions;
270
+ else next.instructions = instructions;
271
+ return next;
272
+ }
273
+
274
+ /**
275
+ * Request-time repair for a native (Codex/OpenAI) destination: drop an inherited routed identity
276
+ * sentence instead of rewriting it. A native worker keeps Codex's own identity wording, which the
277
+ * client already sends in its `model_switch` block; re-stating a routed sentence there would tell
278
+ * a first-party model it is some third-party model.
279
+ *
280
+ * The model-neutral catalog line goes too. It is proxy-authored text as well, and unlike the named
281
+ * form it does not even have to be inherited from a routed parent: the on-disk catalog block
282
+ * carries it since #5217, so it rides along on every instruction block Codex replays to a worker.
283
+ * Left in place it reaches a first-party model as an instruction that contradicts the model_switch
284
+ * identity Codex sends for the same request.
285
+ */
286
+ export function stripRoutedIdentity(text: string): string {
287
+ return text
288
+ .replace(ROUTED_IDENTITY_RE, () => "")
289
+ .replace(NEUTRAL_IDENTITY_RE, () => "")
290
+ .replace(/\n{3,}/g, "\n\n")
291
+ .trim();
80
292
  }
81
293
 
82
294
  /** The catalog (static, on-disk) replacement for `base_instructions`. Same neutral wording. */
@@ -96,6 +96,7 @@ export function buildOpenAIChatPassthroughRequest(
96
96
 
97
97
  if (modelInList(provider.noTemperatureModels, modelId)) delete body.temperature;
98
98
  if (modelInList(provider.noTopPModels, modelId)) delete body.top_p;
99
+ if (modelInList(provider.noStopModels, modelId)) delete body.stop;
99
100
  if (modelInList(provider.noPenaltyModels, modelId)) {
100
101
  delete body.presence_penalty;
101
102
  delete body.frequency_penalty;