@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
package/src/adapters/devin.ts
CHANGED
|
@@ -7,14 +7,76 @@
|
|
|
7
7
|
* streams CloudChatEvent into AdapterEvent.
|
|
8
8
|
*/
|
|
9
9
|
import type { AdapterEvent, OcxAssistantMessage, OcxContentPart, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxTool, OcxToolCall, OcxToolResultMessage, OcxUsage } from "../types";
|
|
10
|
+
import { namespacedToolName } from "../types";
|
|
10
11
|
import type { IncomingMeta, ProviderAdapter } from "./base";
|
|
11
12
|
import { streamChatEvents, allocateCascadeId, CloudChatError, type ChatHistoryItem, type ToolDef } from "./devin/cloud-direct";
|
|
12
13
|
import { getCachedCatalog } from "./devin/cloud-direct/catalog";
|
|
14
|
+
import { collapseDevinModelUid } from "./devin/live-models";
|
|
15
|
+
import { buildNonOpenAIToolCatalogNudgeForTools } from "./tool-catalog-nudge";
|
|
13
16
|
import { DEVIN_DEFAULT_API_SERVER, resolveDevinApiServer } from "../oauth/devin";
|
|
14
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Combine two usage frames from one turn by keeping the larger count per field.
|
|
20
|
+
*
|
|
21
|
+
* Devin's counters are cumulative within a turn, so a frame that reports less
|
|
22
|
+
* than an earlier one is reporting a subset, not a correction.
|
|
23
|
+
*/
|
|
24
|
+
export function mergeDevinUsage(previous: OcxUsage, next: OcxUsage): OcxUsage {
|
|
25
|
+
const keys = [
|
|
26
|
+
"inputTokens", "outputTokens",
|
|
27
|
+
"cachedInputTokens", "cacheReadInputTokens", "cacheCreationInputTokens",
|
|
28
|
+
"reasoningOutputTokens",
|
|
29
|
+
] as const;
|
|
30
|
+
const merged: OcxUsage = { ...previous, ...next };
|
|
31
|
+
for (const key of keys) {
|
|
32
|
+
const a = previous[key];
|
|
33
|
+
const b = next[key];
|
|
34
|
+
if (typeof a === "number" && typeof b === "number") merged[key] = Math.max(a, b);
|
|
35
|
+
else if (typeof a === "number" && b === undefined) merged[key] = a;
|
|
36
|
+
}
|
|
37
|
+
// totalTokens is derived, not merged. Taking the max of two totals alongside
|
|
38
|
+
// per-field maxima can leave total !== input + output, and the cost and log
|
|
39
|
+
// paths read the total.
|
|
40
|
+
const total = (merged.inputTokens ?? 0) + (merged.outputTokens ?? 0);
|
|
41
|
+
if (total > 0) merged.totalTokens = total;
|
|
42
|
+
return merged;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The wording `isClientClosedMessage` recognises.
|
|
47
|
+
*
|
|
48
|
+
* "Devin turn was aborted." matched nothing, so a cancelled turn fell through to
|
|
49
|
+
* the default inference and was logged as a 502 upstream failure rather than as
|
|
50
|
+
* the client hanging up.
|
|
51
|
+
*/
|
|
52
|
+
const DEVIN_CLIENT_CLOSED_MESSAGE = "client closed request";
|
|
53
|
+
|
|
54
|
+
/** Map a cloud-direct failure onto the structured fields the error event carries. */
|
|
55
|
+
export function devinErrorClassification(error: unknown): { status?: number; errorType?: string; retryable?: boolean } {
|
|
56
|
+
const status = error instanceof CloudChatError ? error.status : undefined;
|
|
57
|
+
if (status === undefined) return {};
|
|
58
|
+
if (status === 401) return { status, errorType: "authentication_error", retryable: false };
|
|
59
|
+
if (status === 403) return { status, errorType: "permission_error", retryable: false };
|
|
60
|
+
if (status === 429) return { status, errorType: "rate_limit_error", retryable: true };
|
|
61
|
+
// 501 is the one 5xx that will never succeed on a second attempt: the service
|
|
62
|
+
// does not implement the call. Marking it retryable put `retryable: true` on
|
|
63
|
+
// the SSE failure a client reads, inviting a retry that cannot change.
|
|
64
|
+
if (status === 501) return { status, retryable: false };
|
|
65
|
+
if (status >= 500) return { status, retryable: true };
|
|
66
|
+
return { status, retryable: false };
|
|
67
|
+
}
|
|
68
|
+
|
|
15
69
|
export const DEVIN_API_SERVER = DEVIN_DEFAULT_API_SERVER;
|
|
16
70
|
|
|
17
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Reasoning-effort values a CALLER may name. Deliberately not the same set as
|
|
73
|
+
* the catalog suffix tokens: `priority` is a service tier that appears in a UID
|
|
74
|
+
* but is not something a caller asks for as effort, and `max-1m` / `none-1m`
|
|
75
|
+
* are compound values a caller can send that never appear as a trailing token.
|
|
76
|
+
* The two sets share most members and mean different things; merging them would
|
|
77
|
+
* both admit a tier as an effort and silently drop the compound values.
|
|
78
|
+
*/
|
|
79
|
+
const CALLER_EFFORT_VALUES = new Set(["low", "medium", "high", "xhigh", "max", "none", "1m", "max-1m", "none-1m", "fast"]);
|
|
18
80
|
|
|
19
81
|
/**
|
|
20
82
|
* Cognition's catalog spells model ids with hyphens (`swe-1-7`), but the same
|
|
@@ -27,9 +89,52 @@ export function normalizeDevinModelId(modelId: string): string {
|
|
|
27
89
|
return modelId.replace(/\./g, "-");
|
|
28
90
|
}
|
|
29
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Does this id already carry a catalog effort/variant suffix?
|
|
94
|
+
*
|
|
95
|
+
* Delegates to the collapser so there is one answer to "what is a suffix".
|
|
96
|
+
* The previous local set had drifted: it was missing `priority`, so
|
|
97
|
+
* `gpt-5-6-sol-medium-priority` read as unsuffixed and got a second suffix
|
|
98
|
+
* appended, producing a UID Cognition answers with an opaque permission_denied.
|
|
99
|
+
* Delegating also handles compound suffixes, which testing only the final
|
|
100
|
+
* hyphen-separated token never could.
|
|
101
|
+
*/
|
|
30
102
|
function hasEffortSuffix(modelId: string): boolean {
|
|
31
|
-
|
|
32
|
-
|
|
103
|
+
return collapseDevinModelUid(modelId) !== modelId;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* SWE-2 ships exactly three native lanes. Cognition spells them as the model id,
|
|
108
|
+
* not as a separate effort field, so an explicit caller effort has to be resolved
|
|
109
|
+
* to the UID before the suffix shortcut below accepts whatever the picker sent.
|
|
110
|
+
*
|
|
111
|
+
* Kept as a named table rather than an inline branch because the caller-effort
|
|
112
|
+
* set does not carry `ultra`, `off`, or `minimal`, so the two would drift apart
|
|
113
|
+
* silently.
|
|
114
|
+
* Values below Medium select Medium: SWE-2 has no lane under it, and rounding down
|
|
115
|
+
* to nothing would quietly disable its reasoning.
|
|
116
|
+
*/
|
|
117
|
+
const SWE2_EFFORT: Record<string, "medium" | "high" | "max"> = {
|
|
118
|
+
none: "medium",
|
|
119
|
+
off: "medium",
|
|
120
|
+
minimal: "medium",
|
|
121
|
+
low: "medium",
|
|
122
|
+
medium: "medium",
|
|
123
|
+
high: "high",
|
|
124
|
+
xhigh: "max",
|
|
125
|
+
ultra: "max",
|
|
126
|
+
max: "max",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Resolve an explicit effort onto a SWE-2 lane, or undefined when this is not a
|
|
131
|
+
* SWE-2 id or the caller named no usable effort. Undefined leaves every existing
|
|
132
|
+
* path untouched, which is what keeps other model families on suffix precedence.
|
|
133
|
+
*/
|
|
134
|
+
function resolveSwe2Variant(modelId: string, reasoningEffort?: string): string | undefined {
|
|
135
|
+
if (!/^swe-2(?:-(?:medium|high|max))?$/.test(modelId)) return undefined;
|
|
136
|
+
const mapped = reasoningEffort ? SWE2_EFFORT[reasoningEffort.toLowerCase()] : undefined;
|
|
137
|
+
return mapped ? `swe-2-${mapped}` : undefined;
|
|
33
138
|
}
|
|
34
139
|
|
|
35
140
|
/**
|
|
@@ -51,11 +156,16 @@ async function resolveWireModelUid(
|
|
|
51
156
|
reasoningEffort?: string,
|
|
52
157
|
): Promise<string> {
|
|
53
158
|
const modelId = normalizeDevinModelId(rawModelId);
|
|
159
|
+
// Explicit effort wins over a suffix the picker already baked into the id, so
|
|
160
|
+
// `swe-2-high` asked for at `medium` becomes `swe-2-medium` instead of ignoring
|
|
161
|
+
// the caller. Runs before the shortcut below, which would otherwise return early.
|
|
162
|
+
const swe2 = resolveSwe2Variant(modelId, reasoningEffort);
|
|
163
|
+
if (swe2) return swe2;
|
|
54
164
|
if (hasEffortSuffix(modelId)) return modelId;
|
|
55
165
|
const catalog = await getCachedCatalog(apiKey, host);
|
|
56
166
|
if (catalog) {
|
|
57
167
|
if (catalog.byUid.has(modelId)) return modelId;
|
|
58
|
-
const effort = reasoningEffort &&
|
|
168
|
+
const effort = reasoningEffort && CALLER_EFFORT_VALUES.has(reasoningEffort) ? reasoningEffort : "medium";
|
|
59
169
|
const suffixed = `${modelId}-${effort}`;
|
|
60
170
|
if (catalog.byUid.has(suffixed)) return suffixed;
|
|
61
171
|
// Fall back to any enabled variant of this base model.
|
|
@@ -64,10 +174,17 @@ async function resolveWireModelUid(
|
|
|
64
174
|
}
|
|
65
175
|
}
|
|
66
176
|
// Degraded mode: append the default effort suffix.
|
|
67
|
-
const effort = reasoningEffort &&
|
|
177
|
+
const effort = reasoningEffort && CALLER_EFFORT_VALUES.has(reasoningEffort) ? reasoningEffort : "medium";
|
|
68
178
|
return `${modelId}-${effort}`;
|
|
69
179
|
}
|
|
70
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Test seam. The resolver stays module-private because it reaches the catalog;
|
|
183
|
+
* exporting it under its bare name would make an async network-touching helper
|
|
184
|
+
* part of the adapter public API. Mirrors sanitizeToolDescriptionForCognitionForTests.
|
|
185
|
+
*/
|
|
186
|
+
export const resolveWireModelUidForTests = resolveWireModelUid;
|
|
187
|
+
|
|
71
188
|
export class DevinMissingCredentialError extends Error {
|
|
72
189
|
constructor() {
|
|
73
190
|
super("Devin live transport requires a Devin API key. Run ocx login devin to sign in with your Cognition/Devin account.");
|
|
@@ -108,18 +225,60 @@ function assistantToolCalls(message: OcxAssistantMessage): Array<{ id: string; n
|
|
|
108
225
|
|
|
109
226
|
function assistantText(message: OcxAssistantMessage): string {
|
|
110
227
|
return message.content
|
|
111
|
-
// Thinking stays out of the replayed
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
228
|
+
// Thinking stays out of the replayed TEXT: folding chain-of-thought into
|
|
229
|
+
// assistant text sends it back as visible prior output, which the model
|
|
230
|
+
// then treats as something it said to the user. It is replayed in its own
|
|
231
|
+
// field instead — see assistantThinking below.
|
|
115
232
|
.map((part) => (part.type === "text" ? part.text : ""))
|
|
116
233
|
.filter(Boolean)
|
|
117
234
|
.join("\n");
|
|
118
235
|
}
|
|
119
236
|
|
|
237
|
+
/**
|
|
238
|
+
* The assistant turn's own reasoning, for replay in ChatMessagePrompt #11.
|
|
239
|
+
*
|
|
240
|
+
* This adapter previously asserted that Cognition has no reasoning-replay
|
|
241
|
+
* field and dropped the thinking outright, so a reasoning model restarted its
|
|
242
|
+
* chain on every turn of a tool loop. The field exists: two independent
|
|
243
|
+
* clients of the same service write #11 thinking with #12 signature and #18
|
|
244
|
+
* signature_type on the assistant prompt.
|
|
245
|
+
*
|
|
246
|
+
* The signature attests the thinking it was produced with, so a block without
|
|
247
|
+
* one contributes its text and nothing else rather than borrowing a neighbour's.
|
|
248
|
+
*/
|
|
249
|
+
function assistantThinking(
|
|
250
|
+
message: OcxAssistantMessage,
|
|
251
|
+
): { thinking?: string; signature?: string } {
|
|
252
|
+
const blocks = message.content.filter(
|
|
253
|
+
(part): part is Extract<typeof part, { type: "thinking" }> => part.type === "thinking",
|
|
254
|
+
);
|
|
255
|
+
if (blocks.length === 0) return {};
|
|
256
|
+
const thinking = blocks.map(b => b.thinking).filter(Boolean).join("\n");
|
|
257
|
+
// Only one signature can ride the prompt, so take the last block that has
|
|
258
|
+
// one: that is the block the turn actually ended on.
|
|
259
|
+
const signature = blocks.filter(b => b.signature).at(-1)?.signature;
|
|
260
|
+
return {
|
|
261
|
+
...(thinking ? { thinking } : {}),
|
|
262
|
+
...(signature ? { signature } : {}),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
120
266
|
export function mapOcxMessagesToDevin(parsed: OcxParsedRequest): ChatHistoryItem[] {
|
|
121
267
|
const items: ChatHistoryItem[] = [];
|
|
122
|
-
|
|
268
|
+
// Cognition is not an OpenAI host, and this adapter does advertise a real
|
|
269
|
+
// client tool catalog (proto #10 via `mapOcxToolsToDevin`), so the same
|
|
270
|
+
// contract paragraph the other non-OpenAI adapters inject belongs here. The
|
|
271
|
+
// wire name is the bare `tool.name` that encoder writes, not the namespaced
|
|
272
|
+
// form, so the nudge names exactly what the model is offered.
|
|
273
|
+
const toolCatalogNudge = buildNonOpenAIToolCatalogNudgeForTools(
|
|
274
|
+
parsed.context.tools,
|
|
275
|
+
parsed.options.toolChoice,
|
|
276
|
+
(tool) => tool.name,
|
|
277
|
+
);
|
|
278
|
+
const systemPrompt = parsed.context.systemPrompt?.filter((line) => line.trim().length > 0).join("\n");
|
|
279
|
+
const system = [systemPrompt, toolCatalogNudge]
|
|
280
|
+
.filter((part): part is string => typeof part === "string" && part.length > 0)
|
|
281
|
+
.join("\n\n");
|
|
123
282
|
if (system) items.push({ role: "system", content: system });
|
|
124
283
|
|
|
125
284
|
for (const message of parsed.context.messages) {
|
|
@@ -138,11 +297,15 @@ function mapOneMessage(message: OcxMessage): ChatHistoryItem | undefined {
|
|
|
138
297
|
if (message.role === "assistant") {
|
|
139
298
|
const toolCalls = assistantToolCalls(message);
|
|
140
299
|
const text = assistantText(message);
|
|
141
|
-
|
|
300
|
+
const reasoning = assistantThinking(message);
|
|
301
|
+
// A turn that produced only reasoning is still worth replaying: dropping it
|
|
302
|
+
// is what makes the next turn re-derive the same chain.
|
|
303
|
+
if (!text && toolCalls.length === 0 && !reasoning.thinking) return undefined;
|
|
142
304
|
return {
|
|
143
305
|
role: "assistant",
|
|
144
306
|
content: text || "",
|
|
145
307
|
...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
|
|
308
|
+
...reasoning,
|
|
146
309
|
};
|
|
147
310
|
}
|
|
148
311
|
if (message.role === "toolResult") {
|
|
@@ -164,13 +327,87 @@ export function mapOcxToolsToDevin(tools: OcxTool[] | undefined): ToolDef[] | un
|
|
|
164
327
|
}));
|
|
165
328
|
}
|
|
166
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Devin's request mapper advertises the local tool name, so a namespaced Codex tool such as
|
|
332
|
+
* `mcp__cua_repl__js` is sent upstream as `js`. Restore a returned bare name to its canonical request
|
|
333
|
+
* identity only when exactly one advertised tool owns it. A null owner is an ambiguous catalog and
|
|
334
|
+
* must fail before dispatch; an absent owner remains unchanged for the shared undeclared-tool guard
|
|
335
|
+
* to reject.
|
|
336
|
+
*
|
|
337
|
+
* Canonical names are registered as aliases of themselves because the adapter accepts them on return
|
|
338
|
+
* too. Tracking only local names let one tool's canonical identity collide with another tool's local
|
|
339
|
+
* name and resolve to the wrong owner: with `{ namespace: "a", name: "x" }` and
|
|
340
|
+
* `{ namespace: "b", name: "a__x" }`, a returned `a__x` is both the first tool's canonical identity
|
|
341
|
+
* and the second tool's advertised name, and it used to map to `b__a__x` — so the bridge dispatched
|
|
342
|
+
* the call to the wrong client tool. That case is genuinely ambiguous and now fails closed.
|
|
343
|
+
*/
|
|
344
|
+
function buildDevinReturnedToolNameMap(
|
|
345
|
+
tools: OcxTool[] | undefined,
|
|
346
|
+
): ReadonlyMap<string, string | null> {
|
|
347
|
+
const names = new Map<string, string | null>();
|
|
348
|
+
const addOwner = (alias: string, canonical: string) => {
|
|
349
|
+
if (!names.has(alias)) {
|
|
350
|
+
names.set(alias, canonical);
|
|
351
|
+
} else if (names.get(alias) !== canonical) {
|
|
352
|
+
names.set(alias, null);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
for (const tool of tools ?? []) {
|
|
356
|
+
const canonical = namespacedToolName(tool.namespace, tool.name);
|
|
357
|
+
addOwner(tool.name, canonical);
|
|
358
|
+
addOwner(canonical, canonical);
|
|
359
|
+
}
|
|
360
|
+
return names;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function restoreDevinReturnedToolName(
|
|
364
|
+
name: string,
|
|
365
|
+
names: ReadonlyMap<string, string | null>,
|
|
366
|
+
): string | null {
|
|
367
|
+
return names.has(name) ? names.get(name)! : name;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
type DevinMappedToolCallStart =
|
|
371
|
+
| Extract<AdapterEvent, { type: "tool_call_start" }>
|
|
372
|
+
| Extract<AdapterEvent, { type: "error" }>;
|
|
373
|
+
|
|
374
|
+
function mapDevinToolCallStart(
|
|
375
|
+
id: string,
|
|
376
|
+
name: string,
|
|
377
|
+
names: ReadonlyMap<string, string | null>,
|
|
378
|
+
): DevinMappedToolCallStart {
|
|
379
|
+
const restoredName = restoreDevinReturnedToolName(name, names);
|
|
380
|
+
if (restoredName === null) {
|
|
381
|
+
return {
|
|
382
|
+
type: "error",
|
|
383
|
+
message: "Devin emitted a bare client tool name that maps to multiple request-declared tools.",
|
|
384
|
+
status: 502,
|
|
385
|
+
retryable: false,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return { type: "tool_call_start", id, name: restoredName };
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Test seam for the request-scoped tool-call event mapping used by runTurn. */
|
|
392
|
+
export function mapDevinToolCallStartForTests(
|
|
393
|
+
id: string,
|
|
394
|
+
name: string,
|
|
395
|
+
tools: OcxTool[] | undefined,
|
|
396
|
+
): DevinMappedToolCallStart {
|
|
397
|
+
return mapDevinToolCallStart(id, name, buildDevinReturnedToolNameMap(tools));
|
|
398
|
+
}
|
|
399
|
+
|
|
167
400
|
export function createDevinAdapter(
|
|
168
401
|
provider: OcxProviderConfig,
|
|
169
402
|
context: { providerId?: string } = {},
|
|
170
403
|
): ProviderAdapter {
|
|
171
|
-
// Which credential slot holds this row's tenant.
|
|
172
|
-
//
|
|
173
|
-
//
|
|
404
|
+
// Which credential slot holds this row's tenant. The key is the configured
|
|
405
|
+
// provider id verbatim: `devin-cli` is a deprecated alias for the one merged
|
|
406
|
+
// `devin` provider, and the startup migration rekeys the config row and the
|
|
407
|
+
// credential slot together, so normalizing here would only misread a row that
|
|
408
|
+
// has not been migrated yet. Defaults to `devin` so every existing caller —
|
|
409
|
+
// including the tests that construct this adapter directly — behaves exactly
|
|
410
|
+
// as before.
|
|
174
411
|
const credentialProviderId = context.providerId ?? "devin";
|
|
175
412
|
const cascadeIds = new Map<string, string>();
|
|
176
413
|
const CASCADE_ID_MAX = 256;
|
|
@@ -196,7 +433,7 @@ export function createDevinAdapter(
|
|
|
196
433
|
|
|
197
434
|
async runTurn(parsed: OcxParsedRequest, incoming: IncomingMeta, emit: (event: AdapterEvent) => void) {
|
|
198
435
|
if (incoming.abortSignal?.aborted) {
|
|
199
|
-
emit({ type: "error", message:
|
|
436
|
+
emit({ type: "error", message: DEVIN_CLIENT_CLOSED_MESSAGE, status: 499, retryable: false });
|
|
200
437
|
return;
|
|
201
438
|
}
|
|
202
439
|
let apiKey: string;
|
|
@@ -225,6 +462,7 @@ export function createDevinAdapter(
|
|
|
225
462
|
// every RPC to the US server it is not provisioned on.
|
|
226
463
|
const host = resolveDevinApiServer(provider.baseUrl, credentialProviderId);
|
|
227
464
|
const modelUid = await resolveWireModelUid(rawModelId, apiKey, host, parsed.options.reasoning);
|
|
465
|
+
const returnedToolNames = buildDevinReturnedToolNameMap(parsed.context.tools);
|
|
228
466
|
let openToolId: string | undefined;
|
|
229
467
|
let usage: OcxUsage | undefined;
|
|
230
468
|
let stopReason: string | undefined;
|
|
@@ -258,7 +496,7 @@ export function createDevinAdapter(
|
|
|
258
496
|
// Say what happened instead, the way the other runTurn-only adapter
|
|
259
497
|
// does, and carry any usage already seen.
|
|
260
498
|
closeOpenTool();
|
|
261
|
-
emit({ type: "error", message:
|
|
499
|
+
emit({ type: "error", message: DEVIN_CLIENT_CLOSED_MESSAGE, status: 499, retryable: false, ...(usage ? { usage } : {}) });
|
|
262
500
|
return;
|
|
263
501
|
}
|
|
264
502
|
if (event.kind === "text") {
|
|
@@ -270,10 +508,21 @@ export function createDevinAdapter(
|
|
|
270
508
|
if (event.text) emit({ type: "thinking_delta", thinking: event.text });
|
|
271
509
|
continue;
|
|
272
510
|
}
|
|
511
|
+
if (event.kind === "reasoning_signature") {
|
|
512
|
+
// Carried back out so the next turn can replay it in the prompt's
|
|
513
|
+
// signature field; an unsigned replay is what the service ignores.
|
|
514
|
+
emit({ type: "thinking_signature", signature: event.signature });
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
273
517
|
if (event.kind === "tool_call_start") {
|
|
274
518
|
closeOpenTool();
|
|
519
|
+
const mapped = mapDevinToolCallStart(event.id, event.name, returnedToolNames);
|
|
520
|
+
if (mapped.type === "error") {
|
|
521
|
+
emit({ ...mapped, ...(usage ? { usage } : {}) });
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
275
524
|
openToolId = event.id;
|
|
276
|
-
emit(
|
|
525
|
+
emit(mapped);
|
|
277
526
|
continue;
|
|
278
527
|
}
|
|
279
528
|
if (event.kind === "tool_call_args") {
|
|
@@ -291,7 +540,7 @@ export function createDevinAdapter(
|
|
|
291
540
|
}
|
|
292
541
|
if (event.kind === "usage") {
|
|
293
542
|
const total = event.totalTokens ?? ((event.promptTokens ?? 0) + (event.completionTokens ?? 0));
|
|
294
|
-
|
|
543
|
+
const next: OcxUsage = {
|
|
295
544
|
inputTokens: event.promptTokens ?? 0,
|
|
296
545
|
outputTokens: event.completionTokens ?? 0,
|
|
297
546
|
...(total > 0 ? { totalTokens: total } : {}),
|
|
@@ -299,19 +548,24 @@ export function createDevinAdapter(
|
|
|
299
548
|
...(event.cacheCreationInputTokens !== undefined ? { cacheCreationInputTokens: event.cacheCreationInputTokens } : {}),
|
|
300
549
|
...(event.reasoningTokens !== undefined ? { reasoningOutputTokens: event.reasoningTokens } : {}),
|
|
301
550
|
};
|
|
551
|
+
// Merge rather than replace. A turn can carry more than one usage
|
|
552
|
+
// frame, and the counters are cumulative, so a later partial frame
|
|
553
|
+
// that omits a field used to zero a count the earlier frame had
|
|
554
|
+
// already reported.
|
|
555
|
+
usage = usage ? mergeDevinUsage(usage, next) : next;
|
|
302
556
|
continue;
|
|
303
557
|
}
|
|
304
558
|
}
|
|
305
559
|
closeOpenTool();
|
|
306
560
|
if (incoming.abortSignal?.aborted) {
|
|
307
|
-
emit({ type: "error", message:
|
|
561
|
+
emit({ type: "error", message: DEVIN_CLIENT_CLOSED_MESSAGE, status: 499, retryable: false, ...(usage ? { usage } : {}) });
|
|
308
562
|
} else {
|
|
309
563
|
emit({ type: "done", ...(usage ? { usage } : {}), ...(stopReason ? { stopReason } : {}) });
|
|
310
564
|
}
|
|
311
565
|
} catch (error) {
|
|
312
566
|
closeOpenTool();
|
|
313
567
|
if (incoming.abortSignal?.aborted) {
|
|
314
|
-
emit({ type: "error", message:
|
|
568
|
+
emit({ type: "error", message: DEVIN_CLIENT_CLOSED_MESSAGE, status: 499, retryable: false, ...(usage ? { usage } : {}) });
|
|
315
569
|
return;
|
|
316
570
|
}
|
|
317
571
|
const message = error instanceof CloudChatError
|
|
@@ -319,7 +573,13 @@ export function createDevinAdapter(
|
|
|
319
573
|
: error instanceof Error ? error.message : String(error);
|
|
320
574
|
// Usage that already arrived is still real; dropping it loses the
|
|
321
575
|
// accounting for a turn that did most of its work before failing.
|
|
322
|
-
emit({
|
|
576
|
+
emit({
|
|
577
|
+
type: "error",
|
|
578
|
+
message,
|
|
579
|
+
...devinErrorClassification(error),
|
|
580
|
+
...(error instanceof CloudChatError && error.code ? { code: error.code } : {}),
|
|
581
|
+
...(usage ? { usage } : {}),
|
|
582
|
+
});
|
|
323
583
|
}
|
|
324
584
|
},
|
|
325
585
|
};
|
|
@@ -130,12 +130,20 @@ function compileGenerationConfig(value: unknown): JsonObject | undefined {
|
|
|
130
130
|
))].slice(0, 5);
|
|
131
131
|
if (stopSequences.length > 0) out.stopSequences = stopSequences;
|
|
132
132
|
}
|
|
133
|
-
if (isObject(value.thinkingConfig)
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
if (isObject(value.thinkingConfig)) {
|
|
134
|
+
const thinking: JsonObject = {};
|
|
135
|
+
if (typeof value.thinkingConfig.thinkingLevel === "string") {
|
|
136
|
+
const raw = value.thinkingConfig.thinkingLevel.toLowerCase();
|
|
137
|
+
const thinkingLevel = GOOGLE_THINKING_LEVELS.has(raw)
|
|
138
|
+
? raw
|
|
139
|
+
: (["xhigh", "max", "ultra"].includes(raw) ? "high" : undefined);
|
|
140
|
+
if (thinkingLevel) thinking.thinkingLevel = thinkingLevel;
|
|
141
|
+
}
|
|
142
|
+
// The one key that makes Google return `thought: true` text. Cloud Code Assist serves
|
|
143
|
+
// thinking either way (thoughtsTokenCount stays non-zero) but withholds the text unless the
|
|
144
|
+
// request opts in, so dropping it here silently reinstates the missing-thinking behavior.
|
|
145
|
+
if (value.thinkingConfig.includeThoughts === true) thinking.includeThoughts = true;
|
|
146
|
+
if (Object.keys(thinking).length > 0) out.thinkingConfig = thinking;
|
|
139
147
|
}
|
|
140
148
|
if (Array.isArray(value.responseModalities)) {
|
|
141
149
|
const valid = value.responseModalities.filter((m): m is string => typeof m === "string" && ["TEXT", "IMAGE", "AUDIO"].includes(m));
|
package/src/adapters/google.ts
CHANGED
|
@@ -568,13 +568,15 @@ function googleToolCallMetadataFromPart(
|
|
|
568
568
|
* Keep that provider visibility bit authoritative here so the streaming and buffered parsers
|
|
569
569
|
* cannot accidentally expose the same hidden reasoning through different event types.
|
|
570
570
|
*/
|
|
571
|
-
function googlePartTextEvent(part: GoogleResponsePart): AdapterEvent | undefined {
|
|
571
|
+
function googlePartTextEvent(part: GoogleResponsePart, thoughtSummary = false): AdapterEvent | undefined {
|
|
572
572
|
// A malformed scalar/object is not text and must not cross the AdapterEvent boundary. Dropping
|
|
573
573
|
// only this optional field preserves the rest of the part without inventing assistant output by
|
|
574
574
|
// coercion; an empty string keeps its existing no-event behavior.
|
|
575
575
|
if (typeof part.text !== "string" || part.text.length === 0) return undefined;
|
|
576
576
|
return part.thought === true
|
|
577
|
-
?
|
|
577
|
+
? thoughtSummary
|
|
578
|
+
? { type: "thinking_delta", thinking: part.text }
|
|
579
|
+
: { type: "reasoning_raw_delta", text: part.text }
|
|
578
580
|
: { type: "text_delta", text: part.text };
|
|
579
581
|
}
|
|
580
582
|
|
|
@@ -721,6 +723,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
721
723
|
// Per-request closure: resolveAdapter builds a fresh adapter per request (server.ts), so buildRequest
|
|
722
724
|
// can stash the CCA model/session for parseStream's reasoning-replay observation.
|
|
723
725
|
let antigravityModel: string | undefined;
|
|
726
|
+
let returnsThoughtSummaries = false;
|
|
724
727
|
let antigravitySession: string | undefined;
|
|
725
728
|
// Vertex returns the same opaque Gemini thought signatures as CCA, but its replay namespace
|
|
726
729
|
// must stay transport-scoped: a signature minted by one Google backend must never be sent to
|
|
@@ -795,6 +798,8 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
795
798
|
: provider.googleMode === "vertex"
|
|
796
799
|
? parsed.modelId
|
|
797
800
|
: resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false);
|
|
801
|
+
returnsThoughtSummaries = provider.googleMode === "cloud-code-assist"
|
|
802
|
+
&& /^gemini-/.test(routedModelId) && !isImageCapableModel(parsed.modelId);
|
|
798
803
|
// AI Studio's `-tiered` spelling is wire-only; CCA aliases may migrate to another generation.
|
|
799
804
|
const identityModelId = provider.googleMode === "cloud-code-assist" ? routedModelId : parsed.modelId;
|
|
800
805
|
const stripRejectedClaudeSdkParagraph = provider.googleMode === "cloud-code-assist"
|
|
@@ -866,11 +871,20 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
866
871
|
);
|
|
867
872
|
antigravityModel = wireModelId;
|
|
868
873
|
antigravitySession = sessionId;
|
|
874
|
+
// CCA Gemini exposes provider-authored thought summaries with includeThoughts.
|
|
875
|
+
// Other CCA model families do not share this request contract.
|
|
876
|
+
const includeThoughts = provider.showThinkingSummary === true
|
|
877
|
+
&& parsed.options.hideThinkingSummary !== true
|
|
878
|
+
&& /^gemini-/.test(wireModelId)
|
|
879
|
+
&& !isImageCapableModel(parsed.modelId);
|
|
869
880
|
// Effort → thinkingConfig for CCA (CLIProxyAPI proven: request.generationConfig.thinkingConfig).
|
|
870
881
|
// Suffix/compat IDs return thinkingLevel=undefined — the suffix IS the effort, no contradiction.
|
|
871
|
-
if (thinkingLevel) {
|
|
882
|
+
if (thinkingLevel || includeThoughts) {
|
|
872
883
|
const gc = (body.generationConfig ?? {}) as Record<string, unknown>;
|
|
873
|
-
gc.thinkingConfig = {
|
|
884
|
+
gc.thinkingConfig = {
|
|
885
|
+
...(thinkingLevel ? { thinkingLevel } : {}),
|
|
886
|
+
...(includeThoughts ? { includeThoughts: true } : {}),
|
|
887
|
+
};
|
|
874
888
|
body.generationConfig = gc;
|
|
875
889
|
}
|
|
876
890
|
// Reasoning continuity: Gemini models re-inject cached thoughtSignatures; Claude-on-Antigravity
|
|
@@ -1139,7 +1153,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
1139
1153
|
if (part.thought === true && sig && isLikelyRealThoughtSignature(sig)) {
|
|
1140
1154
|
pendingStreamThoughtSig = sig;
|
|
1141
1155
|
}
|
|
1142
|
-
const textEvent = googlePartTextEvent(part);
|
|
1156
|
+
const textEvent = googlePartTextEvent(part, returnsThoughtSummaries);
|
|
1143
1157
|
if (textEvent) {
|
|
1144
1158
|
emittedContentEvent = true;
|
|
1145
1159
|
yield textEvent;
|
|
@@ -1311,7 +1325,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
1311
1325
|
bytesReservation.commitRetained();
|
|
1312
1326
|
budget.releaseRetained(total, { kind: "retained_collectors" });
|
|
1313
1327
|
rawText = new TextDecoder().decode(bytes);
|
|
1314
|
-
rawTextBytes =
|
|
1328
|
+
rawTextBytes = Buffer.byteLength(rawText, "utf8");
|
|
1315
1329
|
const textReservation = budget.reserveTransient(rawTextBytes, { kind: "retained_collectors" });
|
|
1316
1330
|
textReservation.commitRetained();
|
|
1317
1331
|
budget.releaseRetained(total, { kind: "retained_collectors" });
|
|
@@ -1333,7 +1347,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
1333
1347
|
return [{ type: "error", message: `google response was not a JSON object (${valueType})` }];
|
|
1334
1348
|
}
|
|
1335
1349
|
raw = parsedRaw;
|
|
1336
|
-
rawBytes =
|
|
1350
|
+
rawBytes = Buffer.byteLength(JSON.stringify(raw), "utf8");
|
|
1337
1351
|
const rawReservation = budget.reserveTransient(rawBytes, { kind: "retained_collectors" });
|
|
1338
1352
|
rawReservation.commitRetained();
|
|
1339
1353
|
budget.releaseRetained(rawTextBytes, { kind: "retained_collectors" });
|
|
@@ -1415,7 +1429,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
1415
1429
|
if (part.thought === true && sig && isLikelyRealThoughtSignature(sig)) {
|
|
1416
1430
|
pendingThoughtSig = sig;
|
|
1417
1431
|
}
|
|
1418
|
-
const textEvent = googlePartTextEvent(part);
|
|
1432
|
+
const textEvent = googlePartTextEvent(part, returnsThoughtSummaries);
|
|
1419
1433
|
if (textEvent) events.push(textEvent);
|
|
1420
1434
|
const inline = (part as { inlineData?: { mimeType?: string; data?: string } }).inlineData;
|
|
1421
1435
|
if (inline && typeof inline.data === "string") {
|