@bitkyc08/opencodex 2.52.0 → 2.53.0-preview.20260913
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.
- package/gui/dist/assets/index-BBOZWGB6.css +1 -0
- package/gui/dist/assets/index-D7ynYo2K.js +128 -0
- package/gui/dist/index.html +2 -2
- package/native/remote-workspace-helper/Cargo.lock +130 -0
- package/native/remote-workspace-helper/Cargo.toml +24 -0
- package/native/remote-workspace-helper/src/main.rs +49 -0
- package/native/remote-workspace-helper/src/protocol.rs +246 -0
- package/native/remote-workspace-helper/src/sandbox/macos.rs +19 -0
- package/native/remote-workspace-helper/src/sandbox/mod.rs +77 -0
- package/native/remote-workspace-helper/src/sandbox/windows.rs +15 -0
- package/package.json +6 -1
- package/src/adapters/anthropic-image-normalize.ts +30 -2
- package/src/adapters/anthropic.ts +1 -1
- package/src/adapters/base.ts +8 -2
- package/src/adapters/cursor/cursor-errors.ts +12 -0
- package/src/adapters/cursor/thread-continuity.ts +93 -0
- package/src/adapters/cursor.ts +104 -73
- package/src/adapters/devin/cloud-direct/chat.ts +312 -23
- package/src/adapters/devin/cloud-direct/metadata.ts +31 -2
- package/src/adapters/devin/live-models.ts +70 -3
- package/src/adapters/devin.ts +281 -21
- package/src/adapters/google-wire-compiler.ts +14 -6
- package/src/adapters/google.ts +22 -8
- package/src/adapters/kiro/adapter.ts +316 -0
- package/src/adapters/kiro/conversation.ts +136 -0
- package/src/adapters/kiro/payload.ts +432 -0
- package/src/adapters/kiro/reasoning.ts +56 -0
- package/src/adapters/kiro/stream.ts +1153 -0
- package/src/adapters/kiro/usage.ts +223 -0
- package/src/adapters/kiro/wire.ts +76 -0
- package/src/adapters/kiro.ts +8 -2319
- package/src/adapters/mimo-free.ts +1 -1
- package/src/adapters/openai-chat-images.ts +101 -0
- package/src/adapters/openai-chat.ts +201 -181
- package/src/adapters/openai-responses.ts +92 -224
- package/src/adapters/registry.ts +0 -7
- package/src/adapters/run-turn-queue.ts +13 -6
- package/src/bridge.ts +14 -15
- package/src/chat/inbound.ts +29 -4
- package/src/chat/outbound.ts +145 -107
- package/src/claude/desktop-profile.ts +4 -6
- package/src/cli/account-api.ts +14 -0
- package/src/cli/account-extended.ts +1 -1
- package/src/cli/account-history.ts +60 -0
- package/src/cli/account-main.ts +80 -0
- package/src/cli/account.ts +11 -3
- package/src/cli/capabilities.ts +113 -0
- package/src/cli/catalog.ts +109 -0
- package/src/cli/dispatch.ts +9 -0
- package/src/cli/help.ts +2 -0
- package/src/cli/index.ts +2 -2
- package/src/cli/observe.ts +28 -1
- package/src/cli/opencode.ts +42 -8
- package/src/cli/provider-runtime.ts +11 -1
- package/src/cli/provider.ts +22 -2
- package/src/cli/registry.ts +21 -0
- package/src/cli/remote-workspace.ts +154 -0
- package/src/cli/status.ts +39 -7
- package/src/cli/usage-report.ts +14 -2
- package/src/client/hub-client.ts +34 -0
- package/src/client/hub-state.ts +9 -1
- package/src/codex/account-store.ts +78 -0
- package/src/codex/auth-api.ts +81 -54
- package/src/codex/auth-context.ts +45 -16
- package/src/codex/catalog/effort.ts +1 -1
- package/src/codex/catalog/metadata.ts +3 -6
- package/src/codex/catalog/native-models.ts +4 -4
- package/src/codex/catalog/parsing.ts +2 -20
- package/src/codex/catalog/provider-fetch.ts +10 -1
- package/src/codex/catalog/remote.ts +233 -0
- package/src/codex/catalog/sync.ts +403 -35
- package/src/codex/convergence.ts +1 -1
- package/src/codex/history-manifest.ts +36 -0
- package/src/codex/history-provider.ts +32 -5
- package/src/codex/inject.ts +9 -0
- package/src/codex/main-account.ts +113 -0
- package/src/codex/main-device-reauth-api.ts +89 -0
- package/src/codex/main-device-reauth.ts +217 -0
- package/src/codex/native-residue.ts +9 -2
- package/src/codex/quota-auto-refresh.ts +3 -2
- package/src/codex/quota-capacity.ts +98 -0
- package/src/codex/quota-history.ts +160 -0
- package/src/codex/quota-types.ts +8 -0
- package/src/codex/quota.ts +118 -91
- package/src/codex/refresh.ts +2 -1
- package/src/codex/routing.ts +90 -17
- package/src/codex/sync.ts +33 -4
- package/src/combos/request.ts +19 -1
- package/src/config/multi-agent-surface.ts +61 -0
- package/src/config/provider-validation.ts +176 -0
- package/src/config.ts +213 -11
- package/src/generated/compatibility-version.json +436 -168
- package/src/images/loop.ts +119 -36
- package/src/lib/admission.ts +12 -6
- package/src/lib/redact.ts +7 -0
- package/src/lib/translator-budget.ts +4 -3
- package/src/lib/windows-atomic-replace.ts +1 -0
- package/src/lib/windows-elevation.ts +1 -1
- package/src/oauth/chatgpt-device.ts +62 -5
- package/src/oauth/devin/cli-import.ts +130 -0
- package/src/oauth/devin.ts +63 -8
- package/src/oauth/index.ts +29 -14
- package/src/oauth/kiro.ts +18 -6
- package/src/oauth/login-cli.ts +9 -1
- package/src/oauth/meta-muse-device.ts +464 -0
- package/src/oauth/meta-muse.ts +123 -32
- package/src/oauth/pool-kernel.ts +9 -0
- package/src/oauth/pool-settings-capability.ts +2 -2
- package/src/oauth/store.ts +57 -0
- package/src/oauth/types.ts +31 -0
- package/src/providers/derive.ts +13 -3
- package/src/providers/devin-cli-authmode-migration.ts +57 -35
- package/src/providers/devin-provider-merge-migration.ts +240 -0
- package/src/providers/muse-key-quota.ts +117 -0
- package/src/providers/muse-subscription-usage.ts +14 -2
- package/src/providers/openai-sidecar.ts +25 -3
- package/src/providers/opencode-zen-rate-limit.ts +58 -0
- package/src/providers/provider-id-rewrite.ts +20 -5
- package/src/providers/quota-types.ts +12 -0
- package/src/providers/quota.ts +143 -102
- package/src/providers/reasoning-metadata.ts +543 -0
- package/src/providers/registry.ts +80 -49
- package/src/reasoning-effort.ts +26 -2
- package/src/remote/hub-usage.ts +32 -0
- package/src/remote-control/index.ts +192 -41
- package/src/remote-control/workspace-activation.ts +9 -0
- package/src/remote-control/workspace-agent-connection.ts +366 -0
- package/src/remote-control/workspace-claude-runtime.ts +243 -0
- package/src/remote-control/workspace-codex-runtime.ts +531 -0
- package/src/remote-control/workspace-codex-sandbox.ts +115 -0
- package/src/remote-control/workspace-command-runner.ts +748 -0
- package/src/remote-control/workspace-coordinator.ts +231 -0
- package/src/remote-control/workspace-device.ts +585 -0
- package/src/remote-control/workspace-executable.ts +43 -0
- package/src/remote-control/workspace-executor.ts +397 -0
- package/src/remote-control/workspace-hub.ts +519 -0
- package/src/remote-control/workspace-pi-runtime.ts +382 -0
- package/src/remote-control/workspace-process.ts +129 -0
- package/src/remote-control/workspace-rpc.ts +304 -0
- package/src/remote-control/workspace-runtime.ts +60 -0
- package/src/remote-control/workspace-secret-store.ts +39 -0
- package/src/remote-control/workspace-sessions.ts +799 -0
- package/src/remote-control/workspace-tool-bridge.ts +192 -0
- package/src/responses/code-mode-helper-compat.ts +22 -3
- package/src/responses/hosted-tool-policy.ts +0 -1
- package/src/responses/muse-tool-name-alias.ts +379 -0
- package/src/responses/plaintext-v2-agent-messages.ts +902 -0
- package/src/router.ts +7 -0
- package/src/routing/compatibility/behavior.ts +0 -1
- package/src/server/audio-client.ts +64 -0
- package/src/server/audio-dictation.ts +91 -0
- package/src/server/audio-live.ts +185 -0
- package/src/server/audio-transcriptions.ts +183 -0
- package/src/server/audio-upstream.ts +153 -0
- package/src/server/auth-cors.ts +61 -2
- package/src/server/chat-completions.ts +1 -1
- package/src/server/chat-native-sse.ts +92 -48
- package/src/server/chat-native.ts +37 -15
- package/src/server/hub-usage.ts +57 -0
- package/src/server/images.ts +4 -0
- package/src/server/index.ts +722 -57
- package/src/server/lifecycle.ts +5 -6
- package/src/server/live-call-bindings.ts +60 -0
- package/src/server/live.ts +12 -1
- package/src/server/management/agent-settings-routes.ts +25 -4
- package/src/server/management/api-access.ts +37 -0
- package/src/server/management/api-key-usage.ts +7 -2
- package/src/server/management/config-routes.ts +1 -18
- package/src/server/management/context.ts +15 -0
- package/src/server/management/logs-usage-routes.ts +2 -0
- package/src/server/management/oauth-account-routes.ts +39 -12
- package/src/server/management/provider-routes.ts +125 -2
- package/src/server/management/remote-workspace-routes.ts +140 -0
- package/src/server/management/route-registry.ts +15 -0
- package/src/server/management/usage-aggregate-cache.ts +14 -15
- package/src/server/management/usage-summary-cache.ts +2 -0
- package/src/server/management-api.ts +23 -0
- package/src/server/ports.ts +17 -0
- package/src/server/relay-eager.ts +4 -1
- package/src/server/relay.ts +70 -10
- package/src/server/request-decompress.ts +6 -3
- package/src/server/responses/agent-task-recovery.ts +25 -32
- package/src/server/responses/codex-auth-error.ts +11 -0
- package/src/server/responses/codex-ws-exchange.ts +52 -3
- package/src/server/responses/codex-ws-wire.ts +55 -0
- package/src/server/responses/compact.ts +9 -1
- package/src/server/responses/core.ts +337 -73
- package/src/server/responses/encrypted-payload.ts +45 -2
- package/src/server/responses/ws-upstream.ts +4 -1
- package/src/server/responses-self-named-namespace-scrub.ts +1 -3
- package/src/server/responses-undeclared-tool-guard.ts +1 -1
- package/src/server/search.ts +3 -0
- package/src/server/sse-payload-rewrite.ts +136 -51
- package/src/server/ws-bridge.ts +35 -1
- package/src/service/cli.ts +372 -0
- package/src/service/diagnostics.ts +340 -0
- package/src/service/guards.ts +303 -0
- package/src/service/health.ts +222 -0
- package/src/service/launchd.ts +853 -0
- package/src/service/orchestration.ts +617 -0
- package/src/service/repair.ts +334 -0
- package/src/service/state.ts +363 -0
- package/src/service/systemd.ts +229 -0
- package/src/service/windows-ops.ts +690 -0
- package/src/service/windows-scheduler.ts +769 -0
- package/src/service/windows-taskxml.ts +613 -0
- package/src/service.ts +22 -5550
- package/src/storage/cleanup/db.ts +258 -0
- package/src/storage/cleanup/execute.ts +358 -0
- package/src/storage/cleanup/paths.ts +189 -0
- package/src/storage/cleanup/pending.ts +140 -0
- package/src/storage/cleanup/preview.ts +292 -0
- package/src/storage/cleanup/reconcile.ts +347 -0
- package/src/storage/cleanup/restore.ts +932 -0
- package/src/storage/cleanup/satellite.ts +474 -0
- package/src/storage/cleanup/staging.ts +129 -0
- package/src/storage/cleanup/types.ts +98 -0
- package/src/storage/cleanup.ts +49 -3127
- package/src/types/accounts.ts +2 -0
- package/src/types/config.ts +13 -12
- package/src/types/provider.ts +37 -0
- package/src/types/request.ts +2 -0
- package/src/types/tools.ts +17 -5
- package/src/types.ts +1 -0
- package/src/usage/expected-prices.ts +127 -0
- package/src/usage/log.ts +58 -1
- package/src/vision/eligibility.ts +13 -2
- package/src/web-search/loop.ts +56 -3
- package/gui/dist/assets/index-CWXut3rG.js +0 -115
- package/gui/dist/assets/index-EdoPnm9_.css +0 -1
- package/src/adapters/devin-cli/acp.ts +0 -204
- package/src/adapters/devin-cli/adapter.ts +0 -345
- package/src/adapters/devin-cli/binary.ts +0 -69
- package/src/adapters/devin-cli/models.ts +0 -57
- package/src/oauth/devin-cli.ts +0 -149
- package/src/server/responses-reasoning-summary-rewrite.ts +0 -178
|
@@ -3,6 +3,7 @@ import { stripBracketedModelSuffix } from "./openai-chat";
|
|
|
3
3
|
import { normalizeOpenCodeGoAdditionalTools } from "./opencode-go-additional-tools";
|
|
4
4
|
import { isXaiResponsesDestination } from "../providers/xai-transport";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
|
+
import { Buffer } from "node:buffer";
|
|
6
7
|
import type { IncomingMeta, ProviderAdapter } from "./base";
|
|
7
8
|
import { namespacedToolName, type AdapterEvent, type OcxParsedRequest, type OcxProviderConfig, type OcxUsage, type TierDecision } from "../types";
|
|
8
9
|
import { catalogModelSupportsReasoningSummaries } from "../codex/catalog";
|
|
@@ -24,6 +25,8 @@ import type { TranslatorBudget } from "../lib/translator-budget";
|
|
|
24
25
|
import { rewriteRoutedCustomToolsForUpstream } from "../responses/custom-tool-compat";
|
|
25
26
|
import { rewriteRoutedToolSearchForUpstream } from "../responses/tool-search-compat";
|
|
26
27
|
import { rewriteRoutedNamespaceToolsForUpstream } from "../responses/namespace-tool-compat";
|
|
28
|
+
import { preparePlaintextV2AgentMessages } from "../responses/plaintext-v2-agent-messages";
|
|
29
|
+
import { isMetaAiResponsesDestination, rewriteMuseToolNamesForUpstream } from "../responses/muse-tool-name-alias";
|
|
27
30
|
import { openaiResponsesUrl } from "./openai-responses-url";
|
|
28
31
|
import { normalizeResponsesCodeMode } from "./responses-code-mode";
|
|
29
32
|
import { stripUnicodePropertyPatterns } from "./responses-tool-schema";
|
|
@@ -332,24 +335,6 @@ function scrubOcxCompactionItems(
|
|
|
332
335
|
return changed ? { ...body, input } : body;
|
|
333
336
|
}
|
|
334
337
|
|
|
335
|
-
/**
|
|
336
|
-
* Strip unsupported `reasoning` sub-parameters for native slugs that reject them (e.g. Spark).
|
|
337
|
-
* codex-rs injects `reasoning.context` and `reasoning.summary` based on catalog flags; Spark's
|
|
338
|
-
* backend rejects both. The catalog fix prevents `use_responses_lite` from being set, but this
|
|
339
|
-
* is a defense-in-depth guard so stale on-disk catalogs don't break until the user runs `ocx sync`.
|
|
340
|
-
*/
|
|
341
|
-
function stripUnsupportedReasoningParams(body: unknown): unknown {
|
|
342
|
-
if (!isPlainObject(body)) return body;
|
|
343
|
-
const model = typeof body.model === "string" ? body.model : "";
|
|
344
|
-
if (!model.includes("codex-spark")) return body;
|
|
345
|
-
if (!isPlainObject(body.reasoning)) return body;
|
|
346
|
-
const reasoning = body.reasoning as Record<string, unknown>;
|
|
347
|
-
// Spark supports reasoning.effort but rejects context, summary, and generate_summary.
|
|
348
|
-
const { context: _ctx, summary: _sum, generate_summary: _gs, ...rest } = reasoning;
|
|
349
|
-
if (_ctx === undefined && _sum === undefined && _gs === undefined) return body;
|
|
350
|
-
return { ...body, reasoning: Object.keys(rest).length > 0 ? rest : undefined };
|
|
351
|
-
}
|
|
352
|
-
|
|
353
338
|
/**
|
|
354
339
|
* GPT-5.6 retired the legacy 24-hour retention field, and the ChatGPT backend 400s the whole
|
|
355
340
|
* request when that field is present (issue #2092).
|
|
@@ -470,157 +455,10 @@ function normalizeConfiguredReasoningSummaryDelivery(
|
|
|
470
455
|
};
|
|
471
456
|
}
|
|
472
457
|
|
|
473
|
-
/**
|
|
474
|
-
* Comprehensive Spark compatibility layer. codex-rs emits five tool types (function,
|
|
475
|
-
* namespace, tool_search, web_search, custom) plus extensions (defer_loading,
|
|
476
|
-
* parallel_tool_calls, tool_search_call/output items). Spark's serving path only
|
|
477
|
-
* supports flat function tools and hosted web_search. This function:
|
|
478
|
-
* - Flattens MCP-style namespace tools → promotes inner functions to top level. The reserved
|
|
479
|
-
* `functions` group is kept as a group (#3217): Codex 0.147+ sends every ordinary client tool
|
|
480
|
-
* inside it on Responses Lite, the backend accepts the group as-is, and flattening it changes
|
|
481
|
-
* what the backend answers with — a `custom_tool_call` carrying `namespace: "exec"`, which
|
|
482
|
-
* codex-rs concatenates into the unroutable `execexec`. Traced on a live proxy: with the
|
|
483
|
-
* group intact the same backend returns the bare `exec` call and the turn completes.
|
|
484
|
-
* - Drops unsupported tool types (tool_search, custom)
|
|
485
|
-
* - Strips defer_loading from function tools
|
|
486
|
-
* - Strips namespace from input items
|
|
487
|
-
* - Drops tool_search_call/tool_search_output input items
|
|
488
|
-
* - Sets parallel_tool_calls to false
|
|
489
|
-
*/
|
|
490
|
-
function stripSparkCompatibility(body: unknown): unknown {
|
|
491
|
-
if (!isPlainObject(body)) return body;
|
|
492
|
-
const model = typeof body.model === "string" ? body.model : "";
|
|
493
|
-
if (!model.includes("codex-spark")) return body;
|
|
494
|
-
|
|
495
|
-
let changed = false;
|
|
496
|
-
|
|
497
|
-
const SPARK_SAFE_TOOL_TYPES = new Set(["function", "web_search", "web_search_preview"]);
|
|
498
|
-
// Inside the reserved group Codex sends freeform `custom` tools (code-mode `exec`) and the
|
|
499
|
-
// backend accepts them there; the top-level "drop custom" rule stays for flattened groups.
|
|
500
|
-
const SPARK_SAFE_FUNCTIONS_GROUP_CHILD_TYPES = new Set(["function", "custom"]);
|
|
501
|
-
const filterSparkFunctionsGroup = (group: Record<string, unknown>): Record<string, unknown> | undefined => {
|
|
502
|
-
if (!Array.isArray(group.tools)) return undefined;
|
|
503
|
-
let groupChanged = false;
|
|
504
|
-
const children: unknown[] = [];
|
|
505
|
-
for (const child of group.tools) {
|
|
506
|
-
if (!isPlainObject(child) || typeof child.type !== "string" || !SPARK_SAFE_FUNCTIONS_GROUP_CHILD_TYPES.has(child.type)) {
|
|
507
|
-
groupChanged = true;
|
|
508
|
-
continue;
|
|
509
|
-
}
|
|
510
|
-
if (child.type === "function" && "defer_loading" in child) {
|
|
511
|
-
const { defer_loading: _, ...rest } = child;
|
|
512
|
-
groupChanged = true;
|
|
513
|
-
children.push(rest);
|
|
514
|
-
continue;
|
|
515
|
-
}
|
|
516
|
-
children.push(child);
|
|
517
|
-
}
|
|
518
|
-
if (children.length === 0) return undefined;
|
|
519
|
-
return groupChanged ? { ...group, tools: children } : group;
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
let tools = body.tools;
|
|
523
|
-
if (Array.isArray(tools)) {
|
|
524
|
-
const flattened: unknown[] = [];
|
|
525
|
-
for (const t of tools) {
|
|
526
|
-
if (isPlainObject(t) && t.type === "namespace" && t.name === SPARK_RESERVED_FUNCTIONS_NAMESPACE) {
|
|
527
|
-
const kept = filterSparkFunctionsGroup(t);
|
|
528
|
-
if (kept !== t) changed = true;
|
|
529
|
-
if (kept) flattened.push(kept);
|
|
530
|
-
} else if (isPlainObject(t) && t.type === "namespace") {
|
|
531
|
-
changed = true;
|
|
532
|
-
if (Array.isArray(t.tools)) {
|
|
533
|
-
for (const inner of t.tools) flattened.push(inner);
|
|
534
|
-
}
|
|
535
|
-
} else if (isPlainObject(t) && typeof t.type === "string" && !SPARK_SAFE_TOOL_TYPES.has(t.type)) {
|
|
536
|
-
changed = true;
|
|
537
|
-
} else {
|
|
538
|
-
flattened.push(t);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
// Strip defer_loading from promoted/remaining function tools.
|
|
542
|
-
tools = flattened.map(t => {
|
|
543
|
-
if (isPlainObject(t) && t.type === "function" && "defer_loading" in t) {
|
|
544
|
-
const { defer_loading: _, ...rest } = t;
|
|
545
|
-
changed = true;
|
|
546
|
-
return rest;
|
|
547
|
-
}
|
|
548
|
-
return t;
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Clean input items: strip namespace, drop tool_search_call/tool_search_output.
|
|
553
|
-
const SPARK_UNSUPPORTED_INPUT_TYPES = new Set([
|
|
554
|
-
"tool_search_call", "tool_search_output",
|
|
555
|
-
"custom_tool_call", "custom_tool_call_output",
|
|
556
|
-
]);
|
|
557
|
-
let input = body.input;
|
|
558
|
-
if (Array.isArray(input)) {
|
|
559
|
-
const cleaned: unknown[] = [];
|
|
560
|
-
for (const item of input) {
|
|
561
|
-
if (isPlainObject(item) && typeof item.type === "string" && SPARK_UNSUPPORTED_INPUT_TYPES.has(item.type)) {
|
|
562
|
-
changed = true;
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
// Process additional_tools items: filter their inner tools array the same way.
|
|
566
|
-
if (isPlainObject(item) && item.type === "additional_tools" && Array.isArray(item.tools)) {
|
|
567
|
-
const innerTools = item.tools as unknown[];
|
|
568
|
-
const filteredInner: unknown[] = [];
|
|
569
|
-
for (const t of innerTools) {
|
|
570
|
-
if (isPlainObject(t) && t.type === "namespace" && t.name === SPARK_RESERVED_FUNCTIONS_NAMESPACE) {
|
|
571
|
-
const kept = filterSparkFunctionsGroup(t);
|
|
572
|
-
if (kept !== t) changed = true;
|
|
573
|
-
if (kept) filteredInner.push(kept);
|
|
574
|
-
} else if (isPlainObject(t) && t.type === "namespace") {
|
|
575
|
-
changed = true;
|
|
576
|
-
if (Array.isArray(t.tools)) {
|
|
577
|
-
for (const fn of t.tools) filteredInner.push(fn);
|
|
578
|
-
}
|
|
579
|
-
} else if (isPlainObject(t) && typeof t.type === "string" && !SPARK_SAFE_TOOL_TYPES.has(t.type)) {
|
|
580
|
-
changed = true; // drop custom, tool_search, etc.
|
|
581
|
-
} else {
|
|
582
|
-
filteredInner.push(t);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
// Strip defer_loading from remaining function tools.
|
|
586
|
-
const cleanedInner = filteredInner.map(t => {
|
|
587
|
-
if (isPlainObject(t) && t.type === "function" && "defer_loading" in t) {
|
|
588
|
-
const { defer_loading: _, ...rest } = t;
|
|
589
|
-
changed = true;
|
|
590
|
-
return rest;
|
|
591
|
-
}
|
|
592
|
-
return t;
|
|
593
|
-
});
|
|
594
|
-
cleaned.push({ ...item, tools: cleanedInner });
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
if (isPlainObject(item) && "namespace" in item) {
|
|
598
|
-
const { namespace: _, ...rest } = item;
|
|
599
|
-
changed = true;
|
|
600
|
-
cleaned.push(rest);
|
|
601
|
-
} else {
|
|
602
|
-
cleaned.push(item);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
if (changed) input = cleaned;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// Force parallel_tool_calls off for Spark.
|
|
609
|
-
const extraOverrides: Record<string, unknown> = {};
|
|
610
|
-
if (body.parallel_tool_calls === true) { extraOverrides.parallel_tool_calls = false; changed = true; }
|
|
611
|
-
|
|
612
|
-
return changed
|
|
613
|
-
? { ...body, ...(tools !== body.tools ? { tools } : {}), ...(input !== body.input ? { input } : {}), ...extraOverrides }
|
|
614
|
-
: body;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
458
|
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
618
459
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
619
460
|
}
|
|
620
461
|
|
|
621
|
-
/** Codex's reserved client-tool group on Responses Lite; carries no wire prefix. */
|
|
622
|
-
const SPARK_RESERVED_FUNCTIONS_NAMESPACE = "functions";
|
|
623
|
-
|
|
624
462
|
/**
|
|
625
463
|
* Apply the routed provider's real effort ladder to an existing Responses reasoning field.
|
|
626
464
|
* Native forward requests keep the server-owned native clamp; unknown third-party ladders stay
|
|
@@ -865,6 +703,7 @@ function promoteClientLoadedTools(body: unknown): unknown {
|
|
|
865
703
|
}
|
|
866
704
|
|
|
867
705
|
const MAX_RESPONSES_CALL_ID_LENGTH = 64;
|
|
706
|
+
|
|
868
707
|
const REPAIRED_CALL_ID_PREFIX = "call_ocx_";
|
|
869
708
|
const REPAIRED_CALL_ID_DIGEST_LENGTH = MAX_RESPONSES_CALL_ID_LENGTH - REPAIRED_CALL_ID_PREFIX.length;
|
|
870
709
|
|
|
@@ -2307,6 +2146,15 @@ function responsesErrorMessage(payload: unknown): string {
|
|
|
2307
2146
|
return "upstream compaction failed";
|
|
2308
2147
|
}
|
|
2309
2148
|
|
|
2149
|
+
/** Count an append without rescanning accumulated text, including split surrogate pairs. */
|
|
2150
|
+
function appendedUtf8Bytes(previousBytes: number, lastCodeUnit: number, fragment: string): number {
|
|
2151
|
+
const first = fragment.charCodeAt(0);
|
|
2152
|
+
// Separate lone surrogates each count as a three-byte replacement character; together
|
|
2153
|
+
// they encode as one four-byte scalar. Empty fragments produce NaN and never pair.
|
|
2154
|
+
const joinsSurrogatePair = lastCodeUnit >= 0xd800 && lastCodeUnit <= 0xdbff && first >= 0xdc00 && first <= 0xdfff;
|
|
2155
|
+
return previousBytes + Buffer.byteLength(fragment, "utf8") - (joinsSurrogatePair ? 2 : 0);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2310
2158
|
export function createResponsesPassthroughAdapter(provider: OcxProviderConfig): ProviderAdapter & { passthrough: true } {
|
|
2311
2159
|
return {
|
|
2312
2160
|
name: "openai-responses",
|
|
@@ -2370,6 +2218,9 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2370
2218
|
let routedCustomToolRepairNames: Set<string> | undefined;
|
|
2371
2219
|
let convertedRoutedToolSearchNames: Set<string> | undefined;
|
|
2372
2220
|
let convertedRoutedNamespaceToolAliases: Map<string, { namespace: string; name: string; kind: "function" | "custom" }> | undefined;
|
|
2221
|
+
let plaintextV2AgentMessageToolNames: ReadonlySet<string> | undefined;
|
|
2222
|
+
let plaintextV2AgentMessageAliasedToolNames: ReadonlySet<string> | undefined;
|
|
2223
|
+
let convertedMuseToolNameAliases: Map<string, string> | undefined;
|
|
2373
2224
|
const unexpandedMiss = !!parsed.previousResponseId && parsed._previousResponseInputExpanded !== true;
|
|
2374
2225
|
let outBody = stripPreviousResponseId(
|
|
2375
2226
|
parsed._rawBody,
|
|
@@ -2463,6 +2314,14 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2463
2314
|
outBody = stripOpenAiOnlyWebSearchFields(outBody);
|
|
2464
2315
|
}
|
|
2465
2316
|
outBody = stripMuseSparkUnsupportedWebSearchFields(outBody, parsed.modelId, url);
|
|
2317
|
+
// Host-only: api.meta.ai rejects function names over 64 chars on every Muse model,
|
|
2318
|
+
// including default muse-spark-1.3. Do not reuse the contributor/Zen web_search
|
|
2319
|
+
// predicates. Namespace flattening has already produced the public wire names.
|
|
2320
|
+
if (isMetaAiResponsesDestination(url)) {
|
|
2321
|
+
const rewritten = rewriteMuseToolNamesForUpstream(outBody);
|
|
2322
|
+
outBody = rewritten.body;
|
|
2323
|
+
convertedMuseToolNameAliases = rewritten.aliases;
|
|
2324
|
+
}
|
|
2466
2325
|
// Last, so promoted namespace children are also cleared of Codex-private fields.
|
|
2467
2326
|
outBody = stripCanonicalOnlyToolFields(outBody, provider.supportsOpenAiWebSearchToolFields === false);
|
|
2468
2327
|
}
|
|
@@ -2479,34 +2338,38 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2479
2338
|
// Run after routed compaction so nested input_image parts are replaced before a malformed
|
|
2480
2339
|
// tool output is flattened to text and can no longer be inspected structurally.
|
|
2481
2340
|
outBody = repairUnidentifiedToolOutputItems(outBody);
|
|
2341
|
+
if (parsed._plaintextV2AgentMessages === true && isCanonicalOpenAiForwardProvider(provider)) {
|
|
2342
|
+
const prepared = preparePlaintextV2AgentMessages(outBody);
|
|
2343
|
+
outBody = prepared.body;
|
|
2344
|
+
if (prepared.namespaceAliased) {
|
|
2345
|
+
plaintextV2AgentMessageToolNames = prepared.toolNames;
|
|
2346
|
+
plaintextV2AgentMessageAliasedToolNames = prepared.aliasedAgentMessageToolNames;
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2482
2349
|
const threadServingIdentityChanged = parsed._stripReasoningEncryptedContent === true;
|
|
2483
2350
|
const sanitizedBody = normalizeToolSchemas(
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
destinationDecodesNativeCompactionBlob(provider),
|
|
2493
|
-
threadServingIdentityChanged,
|
|
2494
|
-
),
|
|
2495
|
-
{
|
|
2496
|
-
preserveRawReasoningContent: provider.preserveResponsesReasoningContent === true,
|
|
2497
|
-
dropNullContentChannel: !isOpenAiOperatedResponsesDestination(provider),
|
|
2498
|
-
stripEncryptedContent: threadServingIdentityChanged,
|
|
2499
|
-
},
|
|
2500
|
-
),
|
|
2501
|
-
provider,
|
|
2351
|
+
stripItemIdsWhenUnstored(
|
|
2352
|
+
stripInvalidItemIds(
|
|
2353
|
+
stripUnsupportedHostedTools(
|
|
2354
|
+
sanitizeReasoningInputContent(
|
|
2355
|
+
scrubOcxCompactionItems(
|
|
2356
|
+
outBody,
|
|
2357
|
+
destinationDecodesNativeCompactionBlob(provider),
|
|
2358
|
+
threadServingIdentityChanged,
|
|
2502
2359
|
),
|
|
2360
|
+
{
|
|
2361
|
+
preserveRawReasoningContent: provider.preserveResponsesReasoningContent === true,
|
|
2362
|
+
dropNullContentChannel: !isOpenAiOperatedResponsesDestination(provider),
|
|
2363
|
+
stripEncryptedContent: threadServingIdentityChanged,
|
|
2364
|
+
},
|
|
2503
2365
|
),
|
|
2366
|
+
provider,
|
|
2504
2367
|
),
|
|
2505
2368
|
),
|
|
2506
2369
|
),
|
|
2507
2370
|
isXaiSchemaTarget(provider),
|
|
2508
2371
|
);
|
|
2509
|
-
const
|
|
2372
|
+
const unnormalizedBody = stripDisabledVerbosity(
|
|
2510
2373
|
stripDisabledReasoningSummaries(
|
|
2511
2374
|
normalizeConfiguredReasoningSummaryDelivery(sanitizedBody, provider, parsed.modelId),
|
|
2512
2375
|
provider,
|
|
@@ -2515,14 +2378,16 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2515
2378
|
provider,
|
|
2516
2379
|
parsed.modelId,
|
|
2517
2380
|
);
|
|
2381
|
+
// Normalize the wire model before deriving model-dependent transport metadata.
|
|
2382
|
+
const finalBody =
|
|
2383
|
+
provider.modelSuffixBracketStrip
|
|
2384
|
+
&& unnormalizedBody !== null
|
|
2385
|
+
&& typeof unnormalizedBody === "object"
|
|
2386
|
+
&& !Array.isArray(unnormalizedBody)
|
|
2387
|
+
&& typeof (unnormalizedBody as { model?: unknown }).model === "string"
|
|
2388
|
+
? { ...(unnormalizedBody as Record<string, unknown>), model: stripBracketedModelSuffix((unnormalizedBody as { model: string }).model) }
|
|
2389
|
+
: unnormalizedBody;
|
|
2518
2390
|
if (isCanonicalOpenAiForwardProvider(provider)) {
|
|
2519
|
-
// Spark closes Responses Lite streams before a terminal completion. Select compatibility
|
|
2520
|
-
// from the final wire model so aliases cannot leave the caller or a static header enabled.
|
|
2521
|
-
if (isPlainObject(finalBody) && finalBody.model === "gpt-5.3-codex-spark") {
|
|
2522
|
-
for (const name of Object.keys(headers)) {
|
|
2523
|
-
if (name.toLowerCase() === CODEX_RESPONSES_LITE_HEADER) delete headers[name];
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
2391
|
const routingHeaders = new Headers(headers);
|
|
2527
2392
|
applyCodexRoutingHint(routingHeaders, finalBody);
|
|
2528
2393
|
// Static headers may use mixed casing. Remove every stale spelling
|
|
@@ -2548,18 +2413,10 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2548
2413
|
// here, on the serialized body, not on the parsed selector. One place covers both the
|
|
2549
2414
|
// HTTP and the WebSocket outbound, because the WS path transports this same request
|
|
2550
2415
|
// instead of rebuilding it.
|
|
2551
|
-
const body = JSON.stringify(
|
|
2552
|
-
provider.modelSuffixBracketStrip
|
|
2553
|
-
&& finalBody !== null
|
|
2554
|
-
&& typeof finalBody === "object"
|
|
2555
|
-
&& !Array.isArray(finalBody)
|
|
2556
|
-
&& typeof (finalBody as { model?: unknown }).model === "string"
|
|
2557
|
-
? { ...(finalBody as Record<string, unknown>), model: stripBracketedModelSuffix((finalBody as { model: string }).model) }
|
|
2558
|
-
: finalBody,
|
|
2559
|
-
);
|
|
2416
|
+
const body = JSON.stringify(finalBody);
|
|
2560
2417
|
const releaseBodyObservation = translatorBudget.observeExternallyCapped(
|
|
2561
2418
|
"passthrough_serialization",
|
|
2562
|
-
|
|
2419
|
+
Buffer.byteLength(body, "utf8"),
|
|
2563
2420
|
);
|
|
2564
2421
|
return {
|
|
2565
2422
|
url,
|
|
@@ -2571,6 +2428,9 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2571
2428
|
...(routedCustomToolRepairNames ? { routedCustomToolRepairNames } : {}),
|
|
2572
2429
|
...(convertedRoutedToolSearchNames ? { convertedRoutedToolSearchNames } : {}),
|
|
2573
2430
|
...(convertedRoutedNamespaceToolAliases ? { convertedRoutedNamespaceToolAliases } : {}),
|
|
2431
|
+
...(plaintextV2AgentMessageToolNames ? { plaintextV2AgentMessageToolNames } : {}),
|
|
2432
|
+
...(plaintextV2AgentMessageAliasedToolNames ? { plaintextV2AgentMessageAliasedToolNames } : {}),
|
|
2433
|
+
...(convertedMuseToolNameAliases ? { convertedMuseToolNameAliases } : {}),
|
|
2574
2434
|
...(tierLog ? { tierLog } : {}),
|
|
2575
2435
|
};
|
|
2576
2436
|
},
|
|
@@ -2583,12 +2443,18 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2583
2443
|
yield { type: "error", message: "passthrough adapter received no response body" };
|
|
2584
2444
|
return;
|
|
2585
2445
|
}
|
|
2586
|
-
const budgetEncoder = new TextEncoder();
|
|
2587
2446
|
let deltas = "";
|
|
2447
|
+
let deltasBytes = 0;
|
|
2448
|
+
let deltasLastCodeUnit = 0;
|
|
2588
2449
|
let doneText = "";
|
|
2450
|
+
let doneTextBytes = 0;
|
|
2451
|
+
let doneTextLastCodeUnit = 0;
|
|
2589
2452
|
let snapshot = "";
|
|
2453
|
+
let snapshotBytes = 0;
|
|
2590
2454
|
let usage: OcxUsage | undefined;
|
|
2455
|
+
let usageRawBytes = 0;
|
|
2591
2456
|
let compactionEncryptedContent: string | undefined;
|
|
2457
|
+
let compactionEncryptedContentBytes = 0;
|
|
2592
2458
|
let completedSeen = false;
|
|
2593
2459
|
for await (const event of decodeServerSentEvents(response.body, { translatorBudget: budget })) {
|
|
2594
2460
|
let payload: unknown;
|
|
@@ -2598,21 +2464,25 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2598
2464
|
case "response.output_text.delta":
|
|
2599
2465
|
if (typeof payload.delta === "string") {
|
|
2600
2466
|
const next = deltas + payload.delta;
|
|
2601
|
-
const
|
|
2602
|
-
const reservation = budget.reserveTransient(
|
|
2467
|
+
const nextBytes = appendedUtf8Bytes(deltasBytes, deltasLastCodeUnit, payload.delta);
|
|
2468
|
+
const reservation = budget.reserveTransient(nextBytes, { kind: "retained_collectors" });
|
|
2603
2469
|
deltas = next;
|
|
2604
2470
|
reservation.commitRetained();
|
|
2605
|
-
budget.releaseRetained(
|
|
2471
|
+
budget.releaseRetained(deltasBytes, { kind: "retained_collectors" });
|
|
2472
|
+
deltasBytes = nextBytes;
|
|
2473
|
+
if (payload.delta.length > 0) deltasLastCodeUnit = payload.delta.charCodeAt(payload.delta.length - 1);
|
|
2606
2474
|
}
|
|
2607
2475
|
break;
|
|
2608
2476
|
case "response.output_text.done":
|
|
2609
2477
|
if (typeof payload.text === "string") {
|
|
2610
2478
|
const next = doneText + payload.text;
|
|
2611
|
-
const
|
|
2612
|
-
const reservation = budget.reserveTransient(
|
|
2479
|
+
const nextBytes = appendedUtf8Bytes(doneTextBytes, doneTextLastCodeUnit, payload.text);
|
|
2480
|
+
const reservation = budget.reserveTransient(nextBytes, { kind: "retained_collectors" });
|
|
2613
2481
|
doneText = next;
|
|
2614
2482
|
reservation.commitRetained();
|
|
2615
|
-
budget.releaseRetained(
|
|
2483
|
+
budget.releaseRetained(doneTextBytes, { kind: "retained_collectors" });
|
|
2484
|
+
doneTextBytes = nextBytes;
|
|
2485
|
+
if (payload.text.length > 0) doneTextLastCodeUnit = payload.text.charCodeAt(payload.text.length - 1);
|
|
2616
2486
|
}
|
|
2617
2487
|
break;
|
|
2618
2488
|
case "response.failed":
|
|
@@ -2630,28 +2500,28 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2630
2500
|
const compaction = output.find(item => isPlainObject(item) && item.type === "compaction");
|
|
2631
2501
|
if (isPlainObject(compaction) && typeof compaction.encrypted_content === "string") {
|
|
2632
2502
|
const nextEncryptedContent = compaction.encrypted_content;
|
|
2633
|
-
const
|
|
2634
|
-
const reservation = budget.reserveTransient(
|
|
2503
|
+
const nextEncryptedContentBytes = Buffer.byteLength(nextEncryptedContent, "utf8");
|
|
2504
|
+
const reservation = budget.reserveTransient(nextEncryptedContentBytes, { kind: "retained_collectors" });
|
|
2635
2505
|
compactionEncryptedContent = nextEncryptedContent;
|
|
2636
2506
|
reservation.commitRetained();
|
|
2637
|
-
budget.releaseRetained(
|
|
2507
|
+
budget.releaseRetained(compactionEncryptedContentBytes, { kind: "retained_collectors" });
|
|
2508
|
+
compactionEncryptedContentBytes = nextEncryptedContentBytes;
|
|
2638
2509
|
}
|
|
2639
2510
|
const next = responsesPayloadText(payload.response);
|
|
2640
|
-
const
|
|
2641
|
-
const reservation = budget.reserveTransient(
|
|
2511
|
+
const nextBytes = Buffer.byteLength(next, "utf8");
|
|
2512
|
+
const reservation = budget.reserveTransient(nextBytes, { kind: "retained_collectors" });
|
|
2642
2513
|
snapshot = next;
|
|
2643
2514
|
reservation.commitRetained();
|
|
2644
|
-
budget.releaseRetained(
|
|
2515
|
+
budget.releaseRetained(snapshotBytes, { kind: "retained_collectors" });
|
|
2516
|
+
snapshotBytes = nextBytes;
|
|
2645
2517
|
}
|
|
2646
2518
|
{
|
|
2647
2519
|
const nextUsage = usageFromResponsesPayload(payload.response);
|
|
2648
2520
|
// The attached raw usage object can be event-sized (unknown keys carry arbitrary
|
|
2649
2521
|
// values); it stays reachable until the terminal yields, so charge it like the
|
|
2650
2522
|
// adjacent retained collectors or it would defeat the per-request memory cap.
|
|
2651
|
-
const previousRawBytes = usage?.rawUsage === undefined ? 0
|
|
2652
|
-
: budgetEncoder.encode(JSON.stringify(usage.rawUsage)).byteLength;
|
|
2653
2523
|
const nextRawBytes = nextUsage?.rawUsage === undefined ? 0
|
|
2654
|
-
:
|
|
2524
|
+
: Buffer.byteLength(JSON.stringify(nextUsage.rawUsage), "utf8");
|
|
2655
2525
|
if (nextRawBytes > 0) {
|
|
2656
2526
|
const reservation = budget.reserveTransient(nextRawBytes, { kind: "retained_collectors" });
|
|
2657
2527
|
usage = nextUsage;
|
|
@@ -2659,9 +2529,10 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2659
2529
|
} else {
|
|
2660
2530
|
usage = nextUsage;
|
|
2661
2531
|
}
|
|
2662
|
-
if (
|
|
2663
|
-
budget.releaseRetained(
|
|
2532
|
+
if (usageRawBytes > 0) {
|
|
2533
|
+
budget.releaseRetained(usageRawBytes, { kind: "retained_collectors" });
|
|
2664
2534
|
}
|
|
2535
|
+
usageRawBytes = nextRawBytes;
|
|
2665
2536
|
}
|
|
2666
2537
|
break;
|
|
2667
2538
|
}
|
|
@@ -2683,10 +2554,7 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2683
2554
|
const text = snapshot || doneText || deltas;
|
|
2684
2555
|
if (text) yield { type: "text_delta", text };
|
|
2685
2556
|
budget.releaseRetained(
|
|
2686
|
-
|
|
2687
|
-
+ budgetEncoder.encode(doneText).byteLength
|
|
2688
|
-
+ budgetEncoder.encode(snapshot).byteLength
|
|
2689
|
-
+ (usage?.rawUsage === undefined ? 0 : budgetEncoder.encode(JSON.stringify(usage.rawUsage)).byteLength),
|
|
2557
|
+
deltasBytes + doneTextBytes + snapshotBytes + usageRawBytes,
|
|
2690
2558
|
{ kind: "retained_collectors" },
|
|
2691
2559
|
);
|
|
2692
2560
|
yield {
|
|
@@ -2701,7 +2569,7 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
2701
2569
|
try { payload = await response.json(); } catch {
|
|
2702
2570
|
return [{ type: "error", message: "malformed upstream compaction response" }];
|
|
2703
2571
|
}
|
|
2704
|
-
budget.chargeRetained(
|
|
2572
|
+
budget.chargeRetained(Buffer.byteLength(JSON.stringify(payload), "utf8"), { kind: "retained_collectors" });
|
|
2705
2573
|
if (!isPlainObject(payload)) {
|
|
2706
2574
|
return [{ type: "error", message: "malformed upstream compaction response" }];
|
|
2707
2575
|
}
|
package/src/adapters/registry.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { createCodeBuddyAdapter } from "./codebuddy/adapter";
|
|
|
6
6
|
import { createQoderAdapter } from "./qoder/adapter";
|
|
7
7
|
import { createCommandCodeAdapter } from "./command-code";
|
|
8
8
|
import { createCursorAdapter } from "./cursor";
|
|
9
|
-
import { createDevinCliAdapter } from "./devin-cli/adapter";
|
|
10
9
|
import { createDevinAdapter } from "./devin";
|
|
11
10
|
import { createGoogleAdapter } from "./google";
|
|
12
11
|
import { createKiroAdapter } from "./kiro";
|
|
@@ -43,7 +42,6 @@ export type AdapterWire =
|
|
|
43
42
|
| "google"
|
|
44
43
|
| "kiro"
|
|
45
44
|
| "cursor"
|
|
46
|
-
| "devin-cli"
|
|
47
45
|
| "devin";
|
|
48
46
|
|
|
49
47
|
export type AdapterMutationContract =
|
|
@@ -126,11 +124,6 @@ export const ADAPTER_REGISTRY = {
|
|
|
126
124
|
mutation: "codex-owned-with-gated-native-fallback",
|
|
127
125
|
create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createCursorAdapter(provider),
|
|
128
126
|
},
|
|
129
|
-
"devin-cli": {
|
|
130
|
-
wire: "devin-cli",
|
|
131
|
-
mutation: "codex-owned",
|
|
132
|
-
create: (provider: OcxProviderConfig, _context: AdapterFactoryContext) => createDevinCliAdapter(provider),
|
|
133
|
-
},
|
|
134
127
|
devin: {
|
|
135
128
|
wire: "devin",
|
|
136
129
|
mutation: "codex-owned",
|
|
@@ -12,7 +12,13 @@ export const PREFLIGHT_HEARTBEAT_RETAIN_LIMIT = 16;
|
|
|
12
12
|
export const COALESCE_MAX_CHUNK_LENGTH = 64 * 1024;
|
|
13
13
|
|
|
14
14
|
export interface AdapterEventQueue {
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Returns true when the event was merged into the buffered tail instead of
|
|
17
|
+
* becoming its own retained item. A caller that charges a memory budget for
|
|
18
|
+
* what the queue holds needs that distinction: a merged delta costs only its
|
|
19
|
+
* appended payload, while a new item costs a whole serialized event.
|
|
20
|
+
*/
|
|
21
|
+
push(event: AdapterEvent): boolean;
|
|
16
22
|
close(): void;
|
|
17
23
|
stream(): AsyncIterable<AdapterEvent>;
|
|
18
24
|
collect(): Promise<AdapterEvent[]>;
|
|
@@ -98,21 +104,22 @@ export function createAdapterEventQueue(opts?: {
|
|
|
98
104
|
return false;
|
|
99
105
|
};
|
|
100
106
|
|
|
101
|
-
const push = (event: AdapterEvent):
|
|
102
|
-
if (closed) return;
|
|
107
|
+
const push = (event: AdapterEvent): boolean => {
|
|
108
|
+
if (closed) return false;
|
|
103
109
|
const reader = readers.shift();
|
|
104
110
|
if (reader) {
|
|
105
111
|
reader({ done: false, value: event });
|
|
106
|
-
return;
|
|
112
|
+
return false;
|
|
107
113
|
}
|
|
108
|
-
if (coalesceIntoTail(event)) return;
|
|
114
|
+
if (coalesceIntoTail(event)) return true;
|
|
109
115
|
if (queued.length >= maxBacklog) {
|
|
110
116
|
opts?.onBacklogExceeded?.();
|
|
111
117
|
queued.push({ type: "error", message: "consumer stalled: adapter event backlog exceeded — turn aborted" });
|
|
112
118
|
close();
|
|
113
|
-
return;
|
|
119
|
+
return false;
|
|
114
120
|
}
|
|
115
121
|
queued.push(event);
|
|
122
|
+
return false;
|
|
116
123
|
};
|
|
117
124
|
|
|
118
125
|
const close = (): void => {
|
package/src/bridge.ts
CHANGED
|
@@ -663,16 +663,13 @@ export function bridgeToResponsesSSE(
|
|
|
663
663
|
const closeCurrentRawReasoning = () => {
|
|
664
664
|
if (!currentRawReasoning) return;
|
|
665
665
|
rawReasoningForNextToolCall = currentRawReasoning.text;
|
|
666
|
-
emit("response.
|
|
667
|
-
item_id: currentRawReasoning.itemId, output_index: currentRawReasoning.outputIndex,
|
|
668
|
-
});
|
|
669
|
-
emit("response.reasoning_summary_part.done", {
|
|
670
|
-
item_id: currentRawReasoning.itemId, output_index: currentRawReasoning.outputIndex, summary_index: 0,
|
|
671
|
-
part: { type: "summary_text", text: currentRawReasoning.text },
|
|
666
|
+
emit("response.reasoning_text.done", {
|
|
667
|
+
item_id: currentRawReasoning.itemId, output_index: currentRawReasoning.outputIndex, content_index: 0, text: currentRawReasoning.text,
|
|
672
668
|
});
|
|
673
669
|
const item = {
|
|
674
670
|
type: "reasoning", id: currentRawReasoning.itemId,
|
|
675
|
-
summary: [
|
|
671
|
+
summary: [] as never[],
|
|
672
|
+
content: [{ type: "reasoning_text", text: currentRawReasoning.text }],
|
|
676
673
|
};
|
|
677
674
|
emit("response.output_item.done", { output_index: currentRawReasoning.outputIndex, item });
|
|
678
675
|
retainFinishedItem(item as OutputItem, currentRawReasoning.textBytes, "reasoning");
|
|
@@ -1111,10 +1108,6 @@ export function bridgeToResponsesSSE(
|
|
|
1111
1108
|
const itemId = `rs_${uuid()}`;
|
|
1112
1109
|
const item = { type: "reasoning", id: itemId, summary: [] as { type: string; text: string }[] };
|
|
1113
1110
|
emit("response.output_item.added", { output_index: outputIndex, item });
|
|
1114
|
-
emit("response.reasoning_summary_part.added", {
|
|
1115
|
-
item_id: itemId, output_index: outputIndex, summary_index: 0,
|
|
1116
|
-
part: { type: "summary_text", text: "" },
|
|
1117
|
-
});
|
|
1118
1111
|
currentRawReasoning = { itemId, outputIndex, text: "", textBytes: 0 };
|
|
1119
1112
|
}
|
|
1120
1113
|
({ value: currentRawReasoning.text, bytes: currentRawReasoning.textBytes } = appendString(
|
|
@@ -1123,9 +1116,12 @@ export function bridgeToResponsesSSE(
|
|
|
1123
1116
|
event.text,
|
|
1124
1117
|
"reasoning",
|
|
1125
1118
|
));
|
|
1126
|
-
|
|
1119
|
+
// Raw reasoning (openai-chat reasoning_content, kiro tags) rides the CONTENT
|
|
1120
|
+
// channel. Clients control raw-reasoning display; this text is not a
|
|
1121
|
+
// provider-authored summary.
|
|
1122
|
+
emit("response.reasoning_text.delta", {
|
|
1127
1123
|
item_id: currentRawReasoning.itemId, output_index: currentRawReasoning.outputIndex,
|
|
1128
|
-
|
|
1124
|
+
content_index: 0, delta: event.text,
|
|
1129
1125
|
});
|
|
1130
1126
|
break;
|
|
1131
1127
|
}
|
|
@@ -1297,7 +1293,9 @@ export function bridgeToResponsesSSE(
|
|
|
1297
1293
|
if (isTruncatedStopReason(event.stopReason)) failCurrentToolCall();
|
|
1298
1294
|
else closeCurrentToolCall();
|
|
1299
1295
|
}
|
|
1300
|
-
|
|
1296
|
+
// A search still in flight when upstream truncates never returned results, so it
|
|
1297
|
+
// takes the same "failed" status as the error/incomplete terminals below.
|
|
1298
|
+
if (currentWebSearch) closeCurrentWebSearch(isTruncatedStopReason(event.stopReason) ? "failed" : "completed", []);
|
|
1301
1299
|
releasePendingWebSources();
|
|
1302
1300
|
// Redacted-only turns (or hidden thinking without a trailing signature event) still
|
|
1303
1301
|
// need their envelope-only reasoning item so the blocks replay next turn.
|
|
@@ -1783,7 +1781,8 @@ function buildResponseJSONWithBudget(
|
|
|
1783
1781
|
}
|
|
1784
1782
|
pushOutput({
|
|
1785
1783
|
type: "reasoning", id: `rs_${uuid()}`,
|
|
1786
|
-
summary: [
|
|
1784
|
+
summary: [],
|
|
1785
|
+
content: [{ type: "reasoning_text", text: currentRawReasoning }],
|
|
1787
1786
|
}, currentRawReasoningBytes, "reasoning");
|
|
1788
1787
|
currentRawReasoning = "";
|
|
1789
1788
|
currentRawReasoningBytes = 0;
|
package/src/chat/inbound.ts
CHANGED
|
@@ -46,10 +46,35 @@ function contentToText(content: unknown): string {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
function imageUrlFromPart(part: Rec): string | null {
|
|
49
|
-
if (part.type
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
if (part.type === "image_url") {
|
|
50
|
+
const imageUrl = part.image_url;
|
|
51
|
+
if (typeof imageUrl === "string" && imageUrl.length > 0) return imageUrl;
|
|
52
|
+
if (isRec(imageUrl) && typeof imageUrl.url === "string" && imageUrl.url.length > 0) return imageUrl.url;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
// Agent clients whose native wire shape is not OpenAI's still send images over
|
|
56
|
+
// Chat Completions: Pi/MCP-style parts carry {type:"image", data, mimeType}
|
|
57
|
+
// (Aside read_file tool results), Anthropic-shaped clients carry a source
|
|
58
|
+
// object. Dropping either silently blinds a vision model, so normalize both
|
|
59
|
+
// to the URL/data-URI form the Responses pipeline already understands.
|
|
60
|
+
if (part.type === "image") {
|
|
61
|
+
const data = part.data;
|
|
62
|
+
if (typeof data === "string" && data.length > 0) {
|
|
63
|
+
if (data.startsWith("data:")) return data;
|
|
64
|
+
const media = typeof part.mimeType === "string" && part.mimeType.length > 0 ? part.mimeType
|
|
65
|
+
: typeof part.mediaType === "string" && part.mediaType.length > 0 ? part.mediaType
|
|
66
|
+
: "image/png";
|
|
67
|
+
return "data:" + media + ";base64," + data;
|
|
68
|
+
}
|
|
69
|
+
const source = part.source;
|
|
70
|
+
if (isRec(source)) {
|
|
71
|
+
if (source.type === "base64" && typeof source.data === "string" && source.data.length > 0) {
|
|
72
|
+
const media = typeof source.media_type === "string" && source.media_type.length > 0 ? source.media_type : "image/png";
|
|
73
|
+
return "data:" + media + ";base64," + source.data;
|
|
74
|
+
}
|
|
75
|
+
if (source.type === "url" && typeof source.url === "string" && source.url.length > 0) return source.url;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
53
78
|
return null;
|
|
54
79
|
}
|
|
55
80
|
|