neoctl 0.2.17 → 0.2.22
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 +11 -9
- package/dist/app/app-prompt.d.ts +2 -0
- package/dist/app/app-prompt.js +2 -0
- package/dist/app/app-prompt.js.map +1 -1
- package/dist/context/compaction.d.ts +12 -0
- package/dist/context/compaction.js +22 -0
- package/dist/context/compaction.js.map +1 -1
- package/dist/context/smoke-context.js +30 -3
- package/dist/context/smoke-context.js.map +1 -1
- package/dist/core/query.js +8 -4
- package/dist/core/query.js.map +1 -1
- package/dist/model/config.js +1 -1
- package/dist/model/env.js +1 -1
- package/dist/model/model-metadata.json +70 -6
- package/dist/repl/commands.js +1 -1
- package/dist/repl/index.js +2 -2
- package/dist/tools/builtins/ripgrep-binary.js +1 -1
- package/dist/tools/builtins/ripgrep-binary.js.map +1 -1
- package/dist/web/index.d.ts +11 -0
- package/dist/web/index.js +56 -14
- package/dist/web/index.js.map +1 -1
- package/package.json +5 -3
- package/scripts/install-ripgrep.cjs +15 -1
- package/scripts/verify-ripgrep.cjs +83 -0
- package/vendor/ripgrep/darwin-arm64/rg +0 -0
- package/vendor/ripgrep/darwin-x64/rg +0 -0
- package/vendor/ripgrep/linux-arm64/rg +0 -0
- package/vendor/ripgrep/linux-x64/rg +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"updatedAt": "2026-
|
|
2
|
+
"updatedAt": "2026-08-04",
|
|
3
3
|
"notes": [
|
|
4
4
|
"Static model metadata used for local REPL telemetry. Values are best-effort and should be refreshed when providers update model cards.",
|
|
5
5
|
"MODEL_CONTEXT_WINDOW_TOKENS or OPENAI_CONTEXT_WINDOW_TOKENS overrides contextWindowTokens at runtime.",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"reasoningEfforts lists the exact reasoning.effort values the /model command may set; omitted/empty means no supported effort enum is configured for that model."
|
|
9
9
|
],
|
|
10
10
|
"sources": {
|
|
11
|
-
"openai-models": "https://
|
|
11
|
+
"openai-models": "https://developers.openai.com/api/docs/models",
|
|
12
12
|
"anthropic-models": "https://docs.anthropic.com/en/docs/about-claude/models/overview",
|
|
13
13
|
"anthropic-context-windows": "https://docs.anthropic.com/en/docs/build-with-claude/context-windows",
|
|
14
14
|
"gemini-models": "https://ai.google.dev/gemini-api/docs/models",
|
|
@@ -16,10 +16,74 @@
|
|
|
16
16
|
"anthropic-vision": "https://docs.anthropic.com/en/docs/build-with-claude/vision",
|
|
17
17
|
"mistral-vision": "https://docs.mistral.ai/capabilities/vision",
|
|
18
18
|
"openai-reasoning": "https://developers.openai.com/api/docs/guides/reasoning"
|
|
19
|
-
},
|
|
20
|
-
"models": [
|
|
21
|
-
{
|
|
22
|
-
"id": "gpt-5.
|
|
19
|
+
},
|
|
20
|
+
"models": [
|
|
21
|
+
{
|
|
22
|
+
"id": "gpt-5.6-sol",
|
|
23
|
+
"provider": "openai",
|
|
24
|
+
"modelIds": [
|
|
25
|
+
"gpt-5.6",
|
|
26
|
+
"gpt-5.6-sol"
|
|
27
|
+
],
|
|
28
|
+
"contextWindowTokens": 1050000,
|
|
29
|
+
"maxOutputTokens": 128000,
|
|
30
|
+
"knowledgeCutoff": "2026-02-16",
|
|
31
|
+
"reasoning": true,
|
|
32
|
+
"imageInput": true,
|
|
33
|
+
"source": "openai-models",
|
|
34
|
+
"reasoningEfforts": [
|
|
35
|
+
"none",
|
|
36
|
+
"low",
|
|
37
|
+
"medium",
|
|
38
|
+
"high",
|
|
39
|
+
"xhigh",
|
|
40
|
+
"max"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "gpt-5.6-terra",
|
|
45
|
+
"provider": "openai",
|
|
46
|
+
"modelIds": [
|
|
47
|
+
"gpt-5.6-terra"
|
|
48
|
+
],
|
|
49
|
+
"contextWindowTokens": 1050000,
|
|
50
|
+
"maxOutputTokens": 128000,
|
|
51
|
+
"knowledgeCutoff": "2026-02-16",
|
|
52
|
+
"reasoning": true,
|
|
53
|
+
"imageInput": true,
|
|
54
|
+
"source": "openai-models",
|
|
55
|
+
"reasoningEfforts": [
|
|
56
|
+
"none",
|
|
57
|
+
"low",
|
|
58
|
+
"medium",
|
|
59
|
+
"high",
|
|
60
|
+
"xhigh",
|
|
61
|
+
"max"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "gpt-5.6-luna",
|
|
66
|
+
"provider": "openai",
|
|
67
|
+
"modelIds": [
|
|
68
|
+
"gpt-5.6-luna"
|
|
69
|
+
],
|
|
70
|
+
"contextWindowTokens": 1050000,
|
|
71
|
+
"maxOutputTokens": 128000,
|
|
72
|
+
"knowledgeCutoff": "2026-02-16",
|
|
73
|
+
"reasoning": true,
|
|
74
|
+
"imageInput": true,
|
|
75
|
+
"source": "openai-models",
|
|
76
|
+
"reasoningEfforts": [
|
|
77
|
+
"none",
|
|
78
|
+
"low",
|
|
79
|
+
"medium",
|
|
80
|
+
"high",
|
|
81
|
+
"xhigh",
|
|
82
|
+
"max"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "gpt-5.5",
|
|
23
87
|
"provider": "openai",
|
|
24
88
|
"modelIds": [
|
|
25
89
|
"gpt-5.5"
|
package/dist/repl/commands.js
CHANGED
|
@@ -195,7 +195,7 @@ export function cliHelpText(binaryName = "neo") {
|
|
|
195
195
|
` ${binaryName} -web`,
|
|
196
196
|
` ${binaryName} -web --port 3001`,
|
|
197
197
|
` ${binaryName} -model`,
|
|
198
|
-
` ${binaryName} -model gpt-5.
|
|
198
|
+
` ${binaryName} -model gpt-5.6 high`,
|
|
199
199
|
` ${binaryName} -new`,
|
|
200
200
|
"",
|
|
201
201
|
"Inside the REPL, use the original slash form such as /help or /model.",
|
package/dist/repl/index.js
CHANGED
|
@@ -3090,7 +3090,7 @@ const LOGIN_FIELD_DEFINITIONS = {
|
|
|
3090
3090
|
openai: [
|
|
3091
3091
|
{ key: "apiKey", label: "API key", envKey: "OPENAI_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-..." },
|
|
3092
3092
|
{ key: "baseUrl", label: "Base URL", envKey: "OPENAI_BASE_URL", scope: "provider", placeholder: "https://api.openai.com" },
|
|
3093
|
-
{ key: "model", label: "Model", envKey: "OPENAI_MODEL", scope: "provider", required: true, placeholder: "gpt-5.
|
|
3093
|
+
{ key: "model", label: "Model", envKey: "OPENAI_MODEL", scope: "provider", required: true, placeholder: "gpt-5.6" },
|
|
3094
3094
|
{ key: "fallbackModel", label: "Fallback model", envKey: "OPENAI_FALLBACK_MODEL", scope: "provider" },
|
|
3095
3095
|
{ key: "endpoint", label: "Endpoint", envKey: "OPENAI_ENDPOINT", scope: "provider", placeholder: "auto", options: ["auto", "responses", "chat"] },
|
|
3096
3096
|
...SHARED_LOGIN_FIELDS,
|
|
@@ -3430,7 +3430,7 @@ function defaultBaseUrlForLoginProvider(provider) {
|
|
|
3430
3430
|
function defaultModelForLoginProvider(provider) {
|
|
3431
3431
|
if (provider === "anthropic")
|
|
3432
3432
|
return "claude-sonnet-4-6";
|
|
3433
|
-
return "gpt-5.
|
|
3433
|
+
return "gpt-5.6";
|
|
3434
3434
|
}
|
|
3435
3435
|
function loginFormViewHeight(state) {
|
|
3436
3436
|
return state.step === "provider" ? state.providers.length + 3 : LOGIN_FIELD_DEFINITIONS[state.provider].length + 4;
|
|
@@ -16,7 +16,7 @@ export function resolveBundledRipgrepBinary(env = process.env) {
|
|
|
16
16
|
if (fs.existsSync(executablePath))
|
|
17
17
|
return { executablePath, platformKey };
|
|
18
18
|
}
|
|
19
|
-
throw new Error(`
|
|
19
|
+
throw new Error(`Required bundled ripgrep binary not found for ${platformKey}. Reinstall neoctl or restore the Git-managed vendor/ripgrep resources.`);
|
|
20
20
|
}
|
|
21
21
|
export function ripgrepPlatformKey() {
|
|
22
22
|
const key = `${process.platform}-${process.arch}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ripgrep-binary.js","sourceRoot":"","sources":["../../../src/tools/builtins/ripgrep-binary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAOzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,UAAU,2BAA2B,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC9E,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC;IAEnC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9C,sBAAsB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;QACxD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IACzC,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QACrF,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;YAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IAC5E,CAAC;IAED,MAAM,IAAI,KAAK,CACb,
|
|
1
|
+
{"version":3,"file":"ripgrep-binary.js","sourceRoot":"","sources":["../../../src/tools/builtins/ripgrep-binary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAOzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,UAAU,2BAA2B,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC9E,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC;IAEnC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9C,sBAAsB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;QACxD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IACzC,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QACrF,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC;YAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IAC5E,CAAC;IAED,MAAM,IAAI,KAAK,CACb,iDAAiD,WAAW,yEAAyE,CACtI,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAClD,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa,CAAC;QACnB,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa,CAAC;QACnB,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc;YACjB,OAAO,GAAG,CAAC;QACb;YACE,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,GAAsB;IAC5C,MAAM,eAAe,GAAG,OAAsD,CAAC;IAC/E,MAAM,KAAK,GAAG;QACZ,GAAG,CAAC,gBAAgB;QACpB,OAAO,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC;QACnC,eAAe,CAAC,aAAa;QAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;KAC/B,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAErD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,sBAAsB,CAAC,cAAsB,EAAE,MAAc;IACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,wCAAwC,cAAc,EAAE,CAAC,CAAC;IACrF,CAAC;AACH,CAAC"}
|
package/dist/web/index.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ interface UiLine {
|
|
|
49
49
|
id: number;
|
|
50
50
|
kind: "system" | "user" | "assistant" | "thinking" | "tool" | "error" | "meta";
|
|
51
51
|
text: string;
|
|
52
|
+
toolName?: string;
|
|
53
|
+
parentToolName?: string;
|
|
52
54
|
title?: string;
|
|
53
55
|
bodyTitle?: string;
|
|
54
56
|
titleStatus?: "success" | "failure";
|
|
@@ -62,6 +64,12 @@ interface UiLine {
|
|
|
62
64
|
interface UiStatus {
|
|
63
65
|
phase: string;
|
|
64
66
|
detail?: string;
|
|
67
|
+
currentTool?: {
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
input: unknown;
|
|
71
|
+
startedAt: number;
|
|
72
|
+
};
|
|
65
73
|
metrics?: ContextMetrics;
|
|
66
74
|
usage?: ModelUsage;
|
|
67
75
|
streamedOutputTokens: number;
|
|
@@ -126,6 +134,7 @@ interface WebSetAppPromptPayload {
|
|
|
126
134
|
content?: string;
|
|
127
135
|
id?: string;
|
|
128
136
|
title?: string;
|
|
137
|
+
usage?: string;
|
|
129
138
|
source?: string;
|
|
130
139
|
clear?: boolean;
|
|
131
140
|
}
|
|
@@ -148,6 +157,7 @@ export declare class WebRepl {
|
|
|
148
157
|
private assistantLineId;
|
|
149
158
|
private thinkingLineId;
|
|
150
159
|
private finalizedThinkingLineId;
|
|
160
|
+
private readonly liveToolLineIds;
|
|
151
161
|
private activeAbortController;
|
|
152
162
|
private interruptArmed;
|
|
153
163
|
private lines;
|
|
@@ -267,6 +277,7 @@ export declare class WebRepl {
|
|
|
267
277
|
private reduce;
|
|
268
278
|
private finalizeLiveLine;
|
|
269
279
|
private finalizeThinkingLine;
|
|
280
|
+
private finalizeLiveToolLines;
|
|
270
281
|
private handleEvent;
|
|
271
282
|
private matchesPendingUserImageEcho;
|
|
272
283
|
private handleCommandOrPrompt;
|
package/dist/web/index.js
CHANGED
|
@@ -253,6 +253,7 @@ export class WebRepl {
|
|
|
253
253
|
assistantLineId;
|
|
254
254
|
thinkingLineId;
|
|
255
255
|
finalizedThinkingLineId;
|
|
256
|
+
liveToolLineIds = new Map();
|
|
256
257
|
activeAbortController;
|
|
257
258
|
interruptArmed = false;
|
|
258
259
|
lines;
|
|
@@ -394,6 +395,7 @@ export class WebRepl {
|
|
|
394
395
|
this.assistantLineId = undefined;
|
|
395
396
|
this.thinkingLineId = undefined;
|
|
396
397
|
this.finalizedThinkingLineId = undefined;
|
|
398
|
+
this.liveToolLineIds.clear();
|
|
397
399
|
if (line)
|
|
398
400
|
this.append(line);
|
|
399
401
|
this.broadcastSync();
|
|
@@ -426,8 +428,18 @@ export class WebRepl {
|
|
|
426
428
|
content: payload.content ?? "",
|
|
427
429
|
id: payload.id,
|
|
428
430
|
title: payload.title,
|
|
431
|
+
usage: payload.usage,
|
|
429
432
|
source: payload.source,
|
|
430
433
|
});
|
|
434
|
+
const usage = payload.usage?.trim();
|
|
435
|
+
if (!shouldClear && usage) {
|
|
436
|
+
this.append({
|
|
437
|
+
kind: "meta",
|
|
438
|
+
title: "提示词用法",
|
|
439
|
+
text: usage,
|
|
440
|
+
format: "markdown",
|
|
441
|
+
});
|
|
442
|
+
}
|
|
431
443
|
this.broadcastSync();
|
|
432
444
|
return { ok: true, appPrompt };
|
|
433
445
|
}
|
|
@@ -538,8 +550,9 @@ export class WebRepl {
|
|
|
538
550
|
this.queuedInput = undefined;
|
|
539
551
|
this.queuedAttachments = undefined;
|
|
540
552
|
this.finalizeForegroundView();
|
|
553
|
+
this.finalizeLiveToolLines();
|
|
541
554
|
this.busy = false;
|
|
542
|
-
this.status = { ...this.status, phase: "ready", detail: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined };
|
|
555
|
+
this.status = { ...this.status, phase: "ready", detail: undefined, currentTool: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined };
|
|
543
556
|
this.broadcastSync();
|
|
544
557
|
return runWasActive;
|
|
545
558
|
}
|
|
@@ -617,6 +630,11 @@ export class WebRepl {
|
|
|
617
630
|
this.finalizedThinkingLineId = id;
|
|
618
631
|
this.thinkingLineId = undefined;
|
|
619
632
|
}
|
|
633
|
+
finalizeLiveToolLines() {
|
|
634
|
+
for (const id of this.liveToolLineIds.values())
|
|
635
|
+
this.finalizeLiveLine(id);
|
|
636
|
+
this.liveToolLineIds.clear();
|
|
637
|
+
}
|
|
620
638
|
handleEvent(event) {
|
|
621
639
|
this.reduce(event);
|
|
622
640
|
if (event.type === "message" && this.matchesPendingUserImageEcho(event.message)) {
|
|
@@ -670,7 +688,14 @@ export class WebRepl {
|
|
|
670
688
|
return;
|
|
671
689
|
}
|
|
672
690
|
if (event.message.role === "tool_result") {
|
|
673
|
-
renderToolResultMessage(event.message, (line) =>
|
|
691
|
+
renderToolResultMessage(event.message, (line, toolUseId) => {
|
|
692
|
+
const liveLineId = this.liveToolLineIds.get(toolUseId);
|
|
693
|
+
if (liveLineId === undefined)
|
|
694
|
+
return this.append(line);
|
|
695
|
+
this.replaceLine(liveLineId, line);
|
|
696
|
+
this.liveToolLineIds.delete(toolUseId);
|
|
697
|
+
return liveLineId;
|
|
698
|
+
});
|
|
674
699
|
renderMessageImages(event.message, (line) => this.append(line));
|
|
675
700
|
return;
|
|
676
701
|
}
|
|
@@ -691,13 +716,22 @@ export class WebRepl {
|
|
|
691
716
|
if (event.type === "tool.started") {
|
|
692
717
|
this.finalizeLiveLine(this.assistantLineId);
|
|
693
718
|
this.finalizeThinkingLine();
|
|
719
|
+
const id = this.append({ ...formatToolUse(event.toolUse), live: true });
|
|
720
|
+
this.liveToolLineIds.set(event.toolUse.id, id);
|
|
694
721
|
return;
|
|
695
722
|
}
|
|
696
|
-
if (event.type === "tool.finished")
|
|
723
|
+
if (event.type === "tool.finished") {
|
|
724
|
+
const id = this.liveToolLineIds.get(event.toolUse.id);
|
|
725
|
+
if (id !== undefined) {
|
|
726
|
+
this.finalizeLiveLine(id);
|
|
727
|
+
this.liveToolLineIds.delete(event.toolUse.id);
|
|
728
|
+
}
|
|
697
729
|
return;
|
|
730
|
+
}
|
|
698
731
|
if (event.type === "terminal") {
|
|
699
732
|
this.finalizeLiveLine(this.assistantLineId);
|
|
700
733
|
this.finalizeThinkingLine();
|
|
734
|
+
this.finalizeLiveToolLines();
|
|
701
735
|
this.assistantLineId = undefined;
|
|
702
736
|
this.broadcastSync();
|
|
703
737
|
return;
|
|
@@ -1100,7 +1134,7 @@ function pushTextBlock(blocks, text) {
|
|
|
1100
1134
|
}
|
|
1101
1135
|
function reduceStatus(status, event) {
|
|
1102
1136
|
if (event.type === "state")
|
|
1103
|
-
return { ...status, phase: event.phase, detail: event.detail, usage: event.phase === "preparing" ? undefined : status.usage, streamedOutputTokens: event.phase === "preparing" ? 0 : status.streamedOutputTokens, inputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.inputTokenUpdatedAt, outputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.outputTokenUpdatedAt, retryCooldownUntil: event.phase === "preparing" ? undefined : status.retryCooldownUntil, activityTick: status.activityTick + 1 };
|
|
1137
|
+
return { ...status, phase: event.phase, detail: event.detail, currentTool: event.phase === "running_tools" ? status.currentTool : undefined, usage: event.phase === "preparing" ? undefined : status.usage, streamedOutputTokens: event.phase === "preparing" ? 0 : status.streamedOutputTokens, inputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.inputTokenUpdatedAt, outputTokenUpdatedAt: event.phase === "preparing" ? undefined : status.outputTokenUpdatedAt, retryCooldownUntil: event.phase === "preparing" ? undefined : status.retryCooldownUntil, activityTick: status.activityTick + 1 };
|
|
1104
1138
|
if (event.type === "context.metrics")
|
|
1105
1139
|
return { ...status, metrics: event.metrics, inputTokenUpdatedAt: event.metrics.estimatedInputTokens !== status.metrics?.estimatedInputTokens ? Date.now() : status.inputTokenUpdatedAt, activityTick: status.activityTick + 1 };
|
|
1106
1140
|
if (event.type === "usage")
|
|
@@ -1113,9 +1147,13 @@ function reduceStatus(status, event) {
|
|
|
1113
1147
|
return { ...status, phase: "calling_model", streamedOutputTokens: status.streamedOutputTokens + estimateTokens(event.argumentsDelta), outputTokenUpdatedAt: Date.now(), activityTick: status.activityTick + 1 };
|
|
1114
1148
|
if (event.type === "retrying")
|
|
1115
1149
|
return { ...status, phase: "calling_model", detail: `retrying in ${(event.delayMs / 1000).toFixed(1)}s`, retryCooldownUntil: Date.now() + event.delayMs, activityTick: status.activityTick + 1 };
|
|
1150
|
+
if (event.type === "tool.started")
|
|
1151
|
+
return { ...status, phase: "running_tools", currentTool: { id: event.toolUse.id, name: event.toolUse.name, input: event.toolUse.input, startedAt: Date.now() }, activityTick: status.activityTick + 1 };
|
|
1152
|
+
if (event.type === "tool.finished")
|
|
1153
|
+
return { ...status, currentTool: status.currentTool?.id === event.toolUse.id ? undefined : status.currentTool, activityTick: status.activityTick + 1 };
|
|
1116
1154
|
if (event.type === "terminal")
|
|
1117
|
-
return { ...status, phase: "stopped", detail: event.reason, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined, activityTick: status.activityTick + 1 };
|
|
1118
|
-
if (event.type === "message" || event.type === "
|
|
1155
|
+
return { ...status, phase: "stopped", detail: event.reason, currentTool: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined, activityTick: status.activityTick + 1 };
|
|
1156
|
+
if (event.type === "message" || event.type === "error")
|
|
1119
1157
|
return { ...status, activityTick: status.activityTick + 1 };
|
|
1120
1158
|
return status;
|
|
1121
1159
|
}
|
|
@@ -1237,7 +1275,7 @@ const LOGIN_FIELD_DEFINITIONS = {
|
|
|
1237
1275
|
openai: [
|
|
1238
1276
|
{ key: "apiKey", label: "API key", envKey: "OPENAI_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-..." },
|
|
1239
1277
|
{ key: "baseUrl", label: "Base URL", envKey: "OPENAI_BASE_URL", scope: "provider", placeholder: "https://api.openai.com" },
|
|
1240
|
-
{ key: "model", label: "Model", envKey: "OPENAI_MODEL", scope: "provider", required: true, placeholder: "gpt-5.
|
|
1278
|
+
{ key: "model", label: "Model", envKey: "OPENAI_MODEL", scope: "provider", required: true, placeholder: "gpt-5.6" },
|
|
1241
1279
|
{ key: "fallbackModel", label: "Fallback model", envKey: "OPENAI_FALLBACK_MODEL", scope: "provider" },
|
|
1242
1280
|
{ key: "endpoint", label: "Endpoint", envKey: "OPENAI_ENDPOINT", scope: "provider", placeholder: "auto", options: ["auto", "responses", "chat"] },
|
|
1243
1281
|
...SHARED_LOGIN_FIELDS,
|
|
@@ -1292,7 +1330,7 @@ function defaultBaseUrlForLoginProvider(provider) {
|
|
|
1292
1330
|
function defaultModelForLoginProvider(provider) {
|
|
1293
1331
|
if (provider === "anthropic")
|
|
1294
1332
|
return "claude-sonnet-4-6";
|
|
1295
|
-
return "gpt-5.
|
|
1333
|
+
return "gpt-5.6";
|
|
1296
1334
|
}
|
|
1297
1335
|
function validateLoginFormPayload(payload) {
|
|
1298
1336
|
for (const field of LOGIN_FIELD_DEFINITIONS[payload.provider]) {
|
|
@@ -1444,6 +1482,7 @@ function renderMessage(message, append, activeAssistantId, options = {}) {
|
|
|
1444
1482
|
return false;
|
|
1445
1483
|
if (message.role === "assistant" && activeAssistantId !== undefined && message.blocks.some((block) => block.type === "text"))
|
|
1446
1484
|
return true;
|
|
1485
|
+
const parentToolName = typeof message.metadata?.tool === "string" ? message.metadata.tool : undefined;
|
|
1447
1486
|
let rendered = false;
|
|
1448
1487
|
for (const block of message.blocks) {
|
|
1449
1488
|
if (block.type === "text") {
|
|
@@ -1460,7 +1499,7 @@ function renderMessage(message, append, activeAssistantId, options = {}) {
|
|
|
1460
1499
|
const line = imageLineForBlock(message.role, block);
|
|
1461
1500
|
if (!line)
|
|
1462
1501
|
continue;
|
|
1463
|
-
append(line);
|
|
1502
|
+
append({ ...line, parentToolName });
|
|
1464
1503
|
rendered = true;
|
|
1465
1504
|
}
|
|
1466
1505
|
else if (block.type === "thinking") {
|
|
@@ -1485,20 +1524,21 @@ function renderToolResultMessage(message, append) {
|
|
|
1485
1524
|
for (const block of message.blocks) {
|
|
1486
1525
|
if (block.type !== "tool_result")
|
|
1487
1526
|
continue;
|
|
1488
|
-
append(formatToolResultLine(block.name, block.output, block.ok));
|
|
1527
|
+
append(formatToolResultLine(block.name, block.output, block.ok), block.toolUseId);
|
|
1489
1528
|
rendered = true;
|
|
1490
1529
|
}
|
|
1491
1530
|
return rendered;
|
|
1492
1531
|
}
|
|
1493
1532
|
function renderMessageImages(message, append) {
|
|
1494
1533
|
let rendered = false;
|
|
1534
|
+
const parentToolName = typeof message.metadata?.tool === "string" ? message.metadata.tool : undefined;
|
|
1495
1535
|
for (const block of message.blocks) {
|
|
1496
1536
|
if (block.type !== "image")
|
|
1497
1537
|
continue;
|
|
1498
1538
|
const line = imageLineForBlock(message.role, block);
|
|
1499
1539
|
if (!line)
|
|
1500
1540
|
continue;
|
|
1501
|
-
append(line);
|
|
1541
|
+
append({ ...line, parentToolName });
|
|
1502
1542
|
rendered = true;
|
|
1503
1543
|
}
|
|
1504
1544
|
return rendered;
|
|
@@ -1586,13 +1626,15 @@ function thinkingLine(text, live = false) {
|
|
|
1586
1626
|
}
|
|
1587
1627
|
function formatToolUse(toolUse) {
|
|
1588
1628
|
if (toolUse.name === "plan" && isPlanToolPayload(toolUse.input))
|
|
1589
|
-
return { kind: "tool", title: toolTitle(toolUse.name, "running"), bodyTitle: planToolBodyTitle(toolUse.input), text: formatPlanToolPayload(toolUse.input), collapsible: true };
|
|
1629
|
+
return { kind: "tool", toolName: toolUse.name, title: toolTitle(toolUse.name, "running"), bodyTitle: planToolBodyTitle(toolUse.input), text: formatPlanToolPayload(toolUse.input), collapsible: true };
|
|
1630
|
+
if (toolUse.name === "image2")
|
|
1631
|
+
return { kind: "tool", toolName: toolUse.name, title: toolTitle(toolUse.name, "running"), bodyTitle: "图片模型处理中", text: JSON.stringify(toolUse.input ?? {}, null, 2), format: "plain", previewStyle: "summary", collapsible: true };
|
|
1590
1632
|
const summary = summarizeToolUse(toolUse.name, toolUse.input);
|
|
1591
|
-
return { kind: "tool", title: toolTitle(toolUse.name, "running"), bodyTitle: summary.bodyTitle, text: summary.text, previewStyle: "summary", collapsible: true };
|
|
1633
|
+
return { kind: "tool", toolName: toolUse.name, title: toolTitle(toolUse.name, "running"), bodyTitle: summary.bodyTitle, text: summary.text, previewStyle: "summary", collapsible: true };
|
|
1592
1634
|
}
|
|
1593
1635
|
function formatToolResultLine(toolName, output, ok) {
|
|
1594
1636
|
const formatted = formatToolResult(toolName, output, ok);
|
|
1595
|
-
return { kind: ok ? "tool" : "error", title: toolTitle(toolName, "finished"), bodyTitle: formatted.bodyTitle, titleStatus: ok ? "success" : "failure", text: formatted.text, format: formatted.format, live: false, previewStyle: formatted.full ? undefined : "summary", summaryMaxLines: formatted.summaryMaxLines, collapsible: true };
|
|
1637
|
+
return { kind: ok ? "tool" : "error", toolName, title: toolTitle(toolName, "finished"), bodyTitle: formatted.bodyTitle, titleStatus: ok ? "success" : "failure", text: formatted.text, format: formatted.format, live: false, previewStyle: formatted.full ? undefined : "summary", summaryMaxLines: formatted.summaryMaxLines, collapsible: true };
|
|
1596
1638
|
}
|
|
1597
1639
|
function toolTitle(toolName, _phase) {
|
|
1598
1640
|
const labels = {
|