@bitkyc08/opencodex 2.7.43-preview.20260728 → 2.8.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.
- package/README.md +8 -1
- package/bin/ocx.mjs +47 -22
- package/gui/dist/assets/index-BDjpkcRN.js +67 -0
- package/gui/dist/assets/index-BHsKRFh9.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic.ts +15 -6
- package/src/adapters/cursor/discovery.ts +4 -1
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/cursor/native-exec-shell.ts +18 -6
- package/src/adapters/cursor/protobuf-events.ts +24 -2
- package/src/adapters/cursor/protobuf-request.ts +1 -2
- package/src/adapters/cursor/tool-definitions.ts +68 -29
- package/src/adapters/google-wire-compiler.ts +4 -0
- package/src/adapters/google.ts +128 -2
- package/src/adapters/identity.ts +12 -2
- package/src/adapters/kiro.ts +64 -7
- package/src/adapters/mimo-free.ts +2 -0
- package/src/adapters/openai-responses.ts +246 -59
- package/src/claude/agents-inject.ts +5 -0
- package/src/claude/alias.ts +94 -14
- package/src/claude/inbound.ts +26 -9
- package/src/claude/outbound.ts +6 -3
- package/src/cli/account-auth.ts +1 -1
- package/src/cli/agent-driven.ts +37 -0
- package/src/cli/catalog-prewarm.ts +24 -0
- package/src/cli/claude.ts +35 -10
- package/src/cli/doctor.ts +71 -19
- package/src/cli/help.ts +42 -6
- package/src/cli/index.ts +93 -19
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/opencode.ts +701 -0
- package/src/cli/provider-runtime.ts +3 -0
- package/src/cli/provider.ts +31 -10
- package/src/cli/star-prompt.ts +79 -18
- package/src/cli/status.ts +47 -13
- package/src/cli/v2.ts +10 -1
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-lifecycle.ts +4 -1
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +149 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-store.ts +2 -0
- package/src/codex/account-usability.ts +6 -1
- package/src/codex/app-server-processes.ts +511 -0
- package/src/codex/auth-api.ts +293 -34
- package/src/codex/auth-collision.ts +2 -1
- package/src/codex/auth-context.ts +60 -17
- package/src/codex/catalog/bundled.ts +9 -2
- package/src/codex/catalog/parsing.ts +42 -2
- package/src/codex/catalog/provider-fetch.ts +264 -70
- package/src/codex/catalog/sync.ts +45 -8
- package/src/codex/catalog.ts +2 -2
- package/src/codex/features.ts +524 -5
- package/src/codex/history-provider.ts +145 -1
- package/src/codex/inject.ts +114 -14
- package/src/codex/main-account.ts +2 -8
- package/src/codex/pool-rotation.ts +186 -0
- package/src/codex/quota.ts +92 -2
- package/src/codex/routing.ts +695 -106
- package/src/codex/runtime.ts +10 -1
- package/src/codex/shim.ts +4 -1
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +2 -0
- package/src/codex/sync.ts +3 -0
- package/src/config.ts +574 -25
- package/src/generated/jawcode-model-metadata.ts +12 -12
- package/src/github/star-state.ts +191 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +111 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +789 -0
- package/src/images/plan.ts +133 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +6 -20
- package/src/lib/config-ownership.ts +327 -0
- package/src/lib/crash-guard.ts +2 -0
- package/src/lib/destination-policy.ts +132 -7
- package/src/lib/pinned-http.ts +151 -0
- package/src/lib/process-control.ts +2 -2
- package/src/lib/provider-outbound.ts +167 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/shadow-call.ts +30 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/win-exec.ts +12 -2
- package/src/lib/windows-elevation.ts +81 -3
- package/src/lib/windows-secret-acl.ts +189 -12
- package/src/lib/winsw.ts +2 -0
- package/src/oauth/anthropic-routing.ts +570 -0
- package/src/oauth/health.ts +6 -0
- package/src/oauth/index.ts +310 -75
- package/src/oauth/key-providers.ts +38 -8
- package/src/oauth/kimi.ts +2 -0
- package/src/oauth/kiro-credentials.ts +373 -12
- package/src/oauth/kiro.ts +424 -43
- package/src/oauth/login-cli.ts +33 -6
- package/src/oauth/store.ts +56 -4
- package/src/oauth/types.ts +11 -0
- package/src/providers/alibaba-region-migration.ts +16 -3
- package/src/providers/antigravity-models.ts +3 -0
- package/src/providers/api-keys.ts +13 -6
- package/src/providers/derive.ts +8 -2
- package/src/providers/key-failover.ts +24 -4
- package/src/providers/model-discovery.ts +356 -0
- package/src/providers/quota.ts +233 -29
- package/src/providers/registry.ts +125 -3
- package/src/responses/parser.ts +11 -0
- package/src/responses/state.ts +22 -8
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +19 -7
- package/src/server/auth-cors.ts +114 -24
- package/src/server/claude-messages.ts +8 -1
- package/src/server/gui-static.ts +30 -6
- package/src/server/images.ts +303 -9
- package/src/server/index.ts +77 -9
- package/src/server/lifecycle.ts +25 -1
- package/src/server/live.ts +75 -25
- package/src/server/management/agent-settings-routes.ts +106 -8
- package/src/server/management/combo-routes.ts +7 -0
- package/src/server/management/config-routes.ts +22 -7
- package/src/server/management/context.ts +11 -1
- package/src/server/management/logs-usage-routes.ts +167 -3
- package/src/server/management/model-routes.ts +46 -13
- package/src/server/management/oauth-account-routes.ts +163 -17
- package/src/server/management/provider-routes.ts +73 -10
- package/src/server/management/shared.ts +2 -2
- package/src/server/management/sidebar-routes.ts +39 -0
- package/src/server/management/system-restart.ts +172 -0
- package/src/server/management/system-routes.ts +33 -10
- package/src/server/management-api.ts +5 -3
- package/src/server/management-auth.ts +216 -0
- package/src/server/proxy-liveness.ts +14 -3
- package/src/server/responses/compact.ts +21 -13
- package/src/server/responses/core.ts +614 -172
- package/src/server/responses/upstream-error.ts +48 -0
- package/src/server/responses-image-gen-repair.ts +118 -0
- package/src/server/responses-item-id-repair.ts +10 -85
- package/src/server/sse-payload-rewrite.ts +116 -0
- package/src/server/startup-action-control.ts +30 -14
- package/src/server/system-env.ts +28 -10
- package/src/service.ts +284 -19
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +1504 -28
- package/src/storage/policy-job.ts +387 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +53 -0
- package/src/storage/policy.ts +522 -0
- package/src/storage/restore-job.ts +253 -0
- package/src/storage/restore-worker.ts +52 -0
- package/src/storage/storage-mutation-coordinator.ts +109 -0
- package/src/storage/worker-lifecycle.ts +81 -0
- package/src/tray/windows.ts +34 -4
- package/src/types.ts +107 -1
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +36 -18
- package/src/update/job.ts +111 -16
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/usage/debug.ts +2 -0
- package/src/usage/expected-prices.ts +6 -5
- package/src/usage/log.ts +12 -0
- package/src/web-search/loop.ts +57 -16
- package/gui/dist/assets/index-CjKFJHSC.js +0 -65
- package/gui/dist/assets/index-DfVGuN88.css +0 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { win32 } from "node:path";
|
|
3
|
+
|
|
4
|
+
const CMD_META = /([()%!^"`<>&|;, *?])/g;
|
|
5
|
+
|
|
6
|
+
function escapeCmdArg(arg) {
|
|
7
|
+
let out = String(arg).replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1");
|
|
8
|
+
return `"${out}"`.replace(CMD_META, "^$1");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function escapeCmdCommand(command) {
|
|
12
|
+
return command.replace(CMD_META, "^$1");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether a PATH entry *is* the current directory. The hijack this guards against is
|
|
17
|
+
* cmd.exe resolving a bare `npm` out of the directory opencodex was launched from, so
|
|
18
|
+
* only that exact directory has to be skipped — every candidate we hand to spawn is an
|
|
19
|
+
* absolute path, which is what actually defeats the implicit cwd-first search.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately not a subtree test: npm's default Windows global prefix is
|
|
22
|
+
* `%AppData%\npm` (`C:\Users\x\AppData\Roaming\npm`), so excluding everything under the
|
|
23
|
+
* cwd would fail closed for anyone whose shell sits in their home directory — a normal
|
|
24
|
+
* setup, not the untrusted-project case this hardening is for.
|
|
25
|
+
*/
|
|
26
|
+
function isCurrentDirectory(cwd, entry) {
|
|
27
|
+
const left = win32.resolve(entry);
|
|
28
|
+
const right = win32.resolve(cwd);
|
|
29
|
+
return left.toLowerCase() === right.toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function cleanPathEntry(entry) {
|
|
33
|
+
const trimmed = entry.trim();
|
|
34
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) return trimmed.slice(1, -1);
|
|
35
|
+
return trimmed;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function resolveNpmCommand(
|
|
39
|
+
platform = process.platform,
|
|
40
|
+
env = process.env,
|
|
41
|
+
deps = {},
|
|
42
|
+
) {
|
|
43
|
+
if (platform !== "win32") return "npm";
|
|
44
|
+
const exists = deps.exists ?? existsSync;
|
|
45
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
46
|
+
const extensions = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD")
|
|
47
|
+
.split(";")
|
|
48
|
+
.filter(Boolean);
|
|
49
|
+
const pathEntries = (env.PATH ?? env.Path ?? "")
|
|
50
|
+
.split(win32.delimiter)
|
|
51
|
+
.map(cleanPathEntry)
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
|
|
54
|
+
for (const entry of pathEntries) {
|
|
55
|
+
if (!win32.isAbsolute(entry)) continue;
|
|
56
|
+
if (isCurrentDirectory(cwd, entry)) continue;
|
|
57
|
+
for (const extension of extensions) {
|
|
58
|
+
const candidate = win32.join(entry, `npm${extension.toLowerCase()}`);
|
|
59
|
+
if (exists(candidate)) return win32.resolve(candidate);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function systemCommandProcessor(env) {
|
|
66
|
+
const systemRoot = env.SystemRoot ?? env.windir;
|
|
67
|
+
if (systemRoot && win32.isAbsolute(systemRoot)) {
|
|
68
|
+
return win32.join(systemRoot, "System32", "cmd.exe");
|
|
69
|
+
}
|
|
70
|
+
const comSpec = env.ComSpec;
|
|
71
|
+
return comSpec && win32.isAbsolute(comSpec) ? win32.resolve(comSpec) : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function npmInvocation(
|
|
75
|
+
args,
|
|
76
|
+
platform = process.platform,
|
|
77
|
+
env = process.env,
|
|
78
|
+
deps = {},
|
|
79
|
+
) {
|
|
80
|
+
const npm = resolveNpmCommand(platform, env, deps);
|
|
81
|
+
if (!npm) return null;
|
|
82
|
+
if (platform !== "win32" || !/\.(cmd|bat)$/i.test(npm)) {
|
|
83
|
+
return { file: npm, args: [...args], options: {} };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const commandProcessor = systemCommandProcessor(env);
|
|
87
|
+
if (!commandProcessor) return null;
|
|
88
|
+
const line = [escapeCmdCommand(npm), ...args.map(escapeCmdArg)].join(" ");
|
|
89
|
+
return {
|
|
90
|
+
file: commandProcessor,
|
|
91
|
+
args: ["/d", "/s", "/c", `"${line}"`],
|
|
92
|
+
options: { windowsVerbatimArguments: true },
|
|
93
|
+
};
|
|
94
|
+
}
|
package/src/usage/debug.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, writeFi
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { getConfigDir } from "../config";
|
|
6
6
|
import { DEBUG_ENV } from "../lib/debug-settings";
|
|
7
|
+
import { recordOwnedConfigPath } from "../lib/config-ownership";
|
|
7
8
|
import type { DebugLogEntry } from "../lib/debug-log-buffer";
|
|
8
9
|
import { redactSecretString, redactSecrets } from "../lib/redact";
|
|
9
10
|
import type { OcxUsage } from "../types";
|
|
@@ -42,6 +43,7 @@ export function truncateForDebug(text: string, max = USAGE_DEBUG_BODY_SAMPLE_BYT
|
|
|
42
43
|
|
|
43
44
|
function ensureUsageDebugDir(): void {
|
|
44
45
|
const dir = getConfigDir();
|
|
46
|
+
recordOwnedConfigPath(dir, usageDebugPath());
|
|
45
47
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
46
48
|
try { chmodSync(dir, 0o700); } catch { /* best-effort */ }
|
|
47
49
|
}
|
|
@@ -144,16 +144,17 @@ export function findExpectedPriceOverlay(
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
|
-
* OpenAI
|
|
148
|
-
* Source: https://
|
|
149
|
-
*
|
|
147
|
+
* OpenAI Fast mode (`service_tier=priority`) price multipliers by model slug.
|
|
148
|
+
* Source: https://openai.com/api-fast-mode/ (2026-07-31).
|
|
149
|
+
* Fast pricing applies uniformly to all token types (input, output, cache).
|
|
150
150
|
* Models not listed here fall back to 1× (no multiplier).
|
|
151
151
|
*/
|
|
152
152
|
export const PRIORITY_MULTIPLIERS: Readonly<Record<string, number>> = {
|
|
153
153
|
"gpt-5.6-sol": 2,
|
|
154
|
-
"gpt-5.6-terra":
|
|
155
|
-
"gpt-5.6-luna":
|
|
154
|
+
"gpt-5.6-terra": 1.6,
|
|
155
|
+
"gpt-5.6-luna": 0.4,
|
|
156
156
|
"gpt-5.5": 2.5,
|
|
157
|
+
"gpt-5.4-mini": 2,
|
|
157
158
|
"gpt-5.4": 2,
|
|
158
159
|
};
|
|
159
160
|
|
package/src/usage/log.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { chmodSync, closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, appendFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { getConfigDir } from "../config";
|
|
4
|
+
import { recordOwnedConfigPath } from "../lib/config-ownership";
|
|
4
5
|
import { usageDisplayTotalTokens } from "./totals";
|
|
5
6
|
import type { OcxUsage } from "../types";
|
|
6
7
|
|
|
@@ -11,6 +12,7 @@ export type AttemptRecoveryKind =
|
|
|
11
12
|
| "connection-reset"
|
|
12
13
|
| "oauth-401"
|
|
13
14
|
| "key-429"
|
|
15
|
+
| "anthropic-oauth-429"
|
|
14
16
|
| "image-413";
|
|
15
17
|
|
|
16
18
|
export interface PersistedUsageAttempt {
|
|
@@ -126,6 +128,13 @@ function normalizeUsageValue(usage: OcxUsage | undefined): OcxUsage | undefined
|
|
|
126
128
|
return {
|
|
127
129
|
inputTokens: usage.inputTokens,
|
|
128
130
|
outputTokens: usage.outputTokens,
|
|
131
|
+
// Absolute active-context checkpoint (types.ts). Stateful providers such as Kiro report
|
|
132
|
+
// per-attempt usage only, so this field is the ONLY carrier of the cumulative context
|
|
133
|
+
// figure once the log records raw adapter usage instead of re-parsing the bridged wire
|
|
134
|
+
// (usageFromBridge, request-log.ts). Omitting it here silently dropped Kiro's context
|
|
135
|
+
// growth from every persisted row. It is deliberately NOT folded into totalTokens:
|
|
136
|
+
// a checkpoint is not a per-request total and must never be summed across requests.
|
|
137
|
+
...(typeof usage.contextTotalTokens === "number" ? { contextTotalTokens: usage.contextTotalTokens } : {}),
|
|
129
138
|
...(typeof usage.totalTokens === "number" ? { totalTokens: usage.totalTokens } : {}),
|
|
130
139
|
...(typeof usage.cachedInputTokens === "number" ? { cachedInputTokens: usage.cachedInputTokens } : {}),
|
|
131
140
|
...(typeof usage.cacheReadInputTokens === "number" ? { cacheReadInputTokens: usage.cacheReadInputTokens } : {}),
|
|
@@ -140,6 +149,7 @@ const ATTEMPT_RECOVERY_KINDS = new Set<AttemptRecoveryKind>([
|
|
|
140
149
|
"connection-reset",
|
|
141
150
|
"oauth-401",
|
|
142
151
|
"key-429",
|
|
152
|
+
"anthropic-oauth-429",
|
|
143
153
|
"image-413",
|
|
144
154
|
]);
|
|
145
155
|
const USAGE_STATUSES = new Set<UsageStatus>([
|
|
@@ -159,6 +169,7 @@ function normalizeAttemptUsage(raw: unknown): OcxUsage | null {
|
|
|
159
169
|
if (!isNonNegativeFiniteNumber(usage.inputTokens)
|
|
160
170
|
|| !isNonNegativeFiniteNumber(usage.outputTokens)) return null;
|
|
161
171
|
for (const key of [
|
|
172
|
+
"contextTotalTokens",
|
|
162
173
|
"totalTokens",
|
|
163
174
|
"cachedInputTokens",
|
|
164
175
|
"cacheReadInputTokens",
|
|
@@ -315,6 +326,7 @@ function normalizeUsageEntry(entry: PersistedUsageEntry): PersistedUsageEntry {
|
|
|
315
326
|
|
|
316
327
|
function ensureUsageLogDir(): void {
|
|
317
328
|
const dir = getConfigDir();
|
|
329
|
+
recordOwnedConfigPath(dir, usageLogPath());
|
|
318
330
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
319
331
|
try { chmodSync(dir, 0o700); } catch { /* best-effort on platforms that ignore chmod */ }
|
|
320
332
|
}
|
package/src/web-search/loop.ts
CHANGED
|
@@ -103,23 +103,63 @@ async function* replay(events: AdapterEvent[]): AsyncGenerator<AdapterEvent> {
|
|
|
103
103
|
* replaying a bare toolCall 400s ("Expected `thinking` or `redacted_thinking`, but found
|
|
104
104
|
* `tool_use`"). The signature validity gate stays in the anthropic adapter; other adapters
|
|
105
105
|
* ignore or serialize the part harmlessly.
|
|
106
|
+
*
|
|
107
|
+
* Each signed block keeps its OWN signature and text, mirroring src/images/loop.ts: a signature
|
|
108
|
+
* authenticates the exact block it closed, so flattening two blocks under the last signature
|
|
109
|
+
* 400s on replay just as it does there.
|
|
110
|
+
*
|
|
111
|
+
* Raw reasoning (`reasoning_raw_delta`, what OpenAI-compatible providers emit instead of signed
|
|
112
|
+
* thinking) accumulates into a SEPARATE UNSIGNED part. It must never join a signed block: the
|
|
113
|
+
* anthropic serializer skips signature-less parts, while openai-chat serializes their text as
|
|
114
|
+
* `reasoning_content` — which DeepSeek V4 thinking mode requires back alongside the replayed
|
|
115
|
+
* tool_calls, and whose absence ended the turn as a provider 400 (issue #688).
|
|
116
|
+
*
|
|
117
|
+
* This assumes raw reasoning never interleaves INSIDE an unfinished signed block: Anthropic-family
|
|
118
|
+
* adapters emit thinking_delta/signature and OpenAI-compatible ones emit reasoning_raw_delta, and
|
|
119
|
+
* the two never share a stream. Honoring a genuinely mixed stream would need per-segment state,
|
|
120
|
+
* not another accumulator.
|
|
106
121
|
*/
|
|
107
|
-
function extractIterationThinking(events: AdapterEvent[]): OcxThinkingContent
|
|
122
|
+
function extractIterationThinking(events: AdapterEvent[]): OcxThinkingContent[] {
|
|
123
|
+
const parts: OcxThinkingContent[] = [];
|
|
108
124
|
let thinking = "";
|
|
109
125
|
let signature: string | undefined;
|
|
110
|
-
|
|
126
|
+
let rawReasoning = "";
|
|
127
|
+
|
|
128
|
+
const flushVisible = () => {
|
|
129
|
+
if (!thinking && !signature) return;
|
|
130
|
+
parts.push({
|
|
131
|
+
type: "thinking",
|
|
132
|
+
thinking,
|
|
133
|
+
...(signature ? { signature } : {}),
|
|
134
|
+
});
|
|
135
|
+
thinking = "";
|
|
136
|
+
signature = undefined;
|
|
137
|
+
};
|
|
138
|
+
const flushRaw = () => {
|
|
139
|
+
if (!rawReasoning) return;
|
|
140
|
+
parts.push({ type: "thinking", thinking: rawReasoning });
|
|
141
|
+
rawReasoning = "";
|
|
142
|
+
};
|
|
143
|
+
|
|
111
144
|
for (const e of events) {
|
|
112
|
-
if (e.type === "thinking_delta")
|
|
113
|
-
|
|
114
|
-
|
|
145
|
+
if (e.type === "thinking_delta") {
|
|
146
|
+
flushRaw();
|
|
147
|
+
thinking += e.thinking;
|
|
148
|
+
} else if (e.type === "reasoning_raw_delta") {
|
|
149
|
+
flushVisible();
|
|
150
|
+
rawReasoning += e.text;
|
|
151
|
+
} else if (e.type === "thinking_signature") {
|
|
152
|
+
signature = e.signature;
|
|
153
|
+
flushVisible();
|
|
154
|
+
} else if (e.type === "redacted_thinking") {
|
|
155
|
+
flushVisible();
|
|
156
|
+
flushRaw();
|
|
157
|
+
parts.push({ type: "thinking", thinking: "", redacted: [e.data] });
|
|
158
|
+
}
|
|
115
159
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
thinking,
|
|
120
|
-
...(signature ? { signature } : {}),
|
|
121
|
-
...(redacted.length > 0 ? { redacted } : {}),
|
|
122
|
-
};
|
|
160
|
+
flushVisible();
|
|
161
|
+
flushRaw();
|
|
162
|
+
return parts;
|
|
123
163
|
}
|
|
124
164
|
|
|
125
165
|
/** Normalize a query for failed-query de-duplication (case/whitespace-insensitive). */
|
|
@@ -406,7 +446,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
406
446
|
// valid, and surface as ONE search cell carrying every attempted query. A real search (one that
|
|
407
447
|
// hits the sidecar) shows the spinner WHILE the batch runs. Empty/limit/repeat placeholders never
|
|
408
448
|
// emit a cell (matching the prior single-query behavior).
|
|
409
|
-
async function* runSearchCall(call: WebSearchCall, precedingThinking
|
|
449
|
+
async function* runSearchCall(call: WebSearchCall, precedingThinking: OcxThinkingContent[] = []): AsyncGenerator<AdapterEvent> {
|
|
410
450
|
const results: { query: string; outcome: SidecarOutcome }[] = [];
|
|
411
451
|
let beganCell = false;
|
|
412
452
|
if (call.queries.length === 0) {
|
|
@@ -465,8 +505,9 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
465
505
|
messages.push({
|
|
466
506
|
role: "assistant",
|
|
467
507
|
content: [
|
|
468
|
-
// Signed thinking must precede tool_use on replay (Anthropic extended thinking)
|
|
469
|
-
|
|
508
|
+
// Signed thinking must precede tool_use on replay (Anthropic extended thinking), and
|
|
509
|
+
// unsigned raw reasoning has to ride along for providers that require it back (#688).
|
|
510
|
+
...precedingThinking,
|
|
470
511
|
{ type: "toolCall" as const, id: call.id, name: WEB_SEARCH_TOOL_NAME, arguments: callArgs },
|
|
471
512
|
],
|
|
472
513
|
timestamp: now,
|
|
@@ -559,7 +600,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
559
600
|
// The thinking that led to the search belongs to the FIRST call's assistant replay turn.
|
|
560
601
|
const iterationThinking = extractIterationThinking(split.passthrough);
|
|
561
602
|
for (const [callIndex, call] of split.calls.entries()) {
|
|
562
|
-
yield* runSearchCall(call, callIndex === 0 ? iterationThinking :
|
|
603
|
+
yield* runSearchCall(call, callIndex === 0 ? iterationThinking : []);
|
|
563
604
|
}
|
|
564
605
|
} catch (e) {
|
|
565
606
|
yield { type: "error", message: e instanceof LoopError ? e.message : (e instanceof Error ? e.message : String(e)) };
|