neoctl 0.2.17 → 0.2.23
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/html.js +22 -3
- package/dist/web/html.js.map +1 -1
- package/dist/web/index.d.ts +35 -1
- package/dist/web/index.js +160 -33
- package/dist/web/index.js.map +1 -1
- package/package.json +5 -3
- package/scripts/copy-model-metadata.mjs +4 -4
- package/scripts/install-ripgrep.cjs +210 -196
- package/scripts/release-local.mjs +190 -190
- package/scripts/verify-ripgrep.cjs +86 -0
- package/vendor/ripgrep/darwin-arm64/COPYING +3 -3
- package/vendor/ripgrep/darwin-arm64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/darwin-arm64/UNLICENSE +24 -24
- package/vendor/ripgrep/darwin-arm64/manifest.json +7 -7
- package/vendor/ripgrep/darwin-x64/COPYING +3 -3
- package/vendor/ripgrep/darwin-x64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/darwin-x64/UNLICENSE +24 -24
- package/vendor/ripgrep/darwin-x64/manifest.json +7 -7
- package/vendor/ripgrep/linux-arm64/COPYING +3 -3
- package/vendor/ripgrep/linux-arm64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/linux-arm64/UNLICENSE +24 -24
- package/vendor/ripgrep/linux-arm64/manifest.json +7 -7
- package/vendor/ripgrep/linux-x64/COPYING +3 -3
- package/vendor/ripgrep/linux-x64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/linux-x64/UNLICENSE +24 -24
- package/vendor/ripgrep/linux-x64/manifest.json +7 -7
- package/vendor/ripgrep/win32-arm64/COPYING +3 -3
- package/vendor/ripgrep/win32-arm64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/win32-arm64/UNLICENSE +24 -24
- package/vendor/ripgrep/win32-arm64/manifest.json +7 -7
- package/vendor/ripgrep/win32-x64/COPYING +3 -3
- package/vendor/ripgrep/win32-x64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/win32-x64/UNLICENSE +24 -24
- package/vendor/ripgrep/win32-x64/manifest.json +7 -7
|
@@ -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/html.js
CHANGED
|
@@ -231,7 +231,7 @@ es.addEventListener('error', () => {
|
|
|
231
231
|
connection.hidden = false;
|
|
232
232
|
connection.textContent = 'reconnecting…';
|
|
233
233
|
});
|
|
234
|
-
es.addEventListener('sync', (event) => {
|
|
234
|
+
es.addEventListener('sync', (event) => {
|
|
235
235
|
const payload = JSON.parse(event.data);
|
|
236
236
|
state.lines = payload.lines || [];
|
|
237
237
|
state.status = payload.status || state.status;
|
|
@@ -245,8 +245,27 @@ es.addEventListener('sync', (event) => {
|
|
|
245
245
|
if (payload.catalog) state.catalog = payload.catalog;
|
|
246
246
|
if (payload.interactive) state.interactive = payload.interactive;
|
|
247
247
|
updateInputPlaceholder();
|
|
248
|
-
scheduleRender();
|
|
249
|
-
});
|
|
248
|
+
scheduleRender();
|
|
249
|
+
});
|
|
250
|
+
es.addEventListener('delta', (event) => {
|
|
251
|
+
const payload = JSON.parse(event.data);
|
|
252
|
+
for (const operation of payload.operations || []) {
|
|
253
|
+
if (operation.type === 'line.append') {
|
|
254
|
+
if (!state.lines.some((line) => String(line.id) === String(operation.line && operation.line.id))) state.lines.push(operation.line);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const index = state.lines.findIndex((line) => String(line.id) === String(operation.id));
|
|
258
|
+
if (index < 0) {
|
|
259
|
+
location.reload();
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const line = state.lines[index];
|
|
263
|
+
if (operation.type === 'line.text.append') state.lines[index] = { ...line, text: String(line.text || '') + String(operation.text || '') };
|
|
264
|
+
else if (operation.type === 'line.patch') state.lines[index] = { ...line, ...(operation.patch || {}) };
|
|
265
|
+
}
|
|
266
|
+
if (payload.status) state.status = payload.status;
|
|
267
|
+
scheduleRender();
|
|
268
|
+
});
|
|
250
269
|
|
|
251
270
|
function scheduleRender() {
|
|
252
271
|
if (renderPending) return;
|
package/dist/web/html.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/web/html.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/web/html.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAw2B1B,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,9 +134,22 @@ 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
|
}
|
|
141
|
+
type WebLineOperation = {
|
|
142
|
+
type: "line.append";
|
|
143
|
+
line: UiLine;
|
|
144
|
+
} | {
|
|
145
|
+
type: "line.text.append";
|
|
146
|
+
id: number;
|
|
147
|
+
text: string;
|
|
148
|
+
} | {
|
|
149
|
+
type: "line.patch";
|
|
150
|
+
id: number;
|
|
151
|
+
patch: Partial<UiLine>;
|
|
152
|
+
};
|
|
132
153
|
export declare function runWebServer(argv?: string[], runtimeOptions?: RunWebServerOptions): Promise<void>;
|
|
133
154
|
export declare function createWebRuntime(options?: CreateWebRuntimeOptions): Promise<WebRuntime>;
|
|
134
155
|
export declare class WebRuntimeRouter {
|
|
@@ -144,10 +165,15 @@ export declare function createWebRuntimeRouter(options?: WebRuntimeRouterOptions
|
|
|
144
165
|
export declare class WebRepl {
|
|
145
166
|
private runtime;
|
|
146
167
|
private readonly subscribers;
|
|
168
|
+
private eventSequence;
|
|
169
|
+
private pendingDeltaOperations;
|
|
170
|
+
private pendingDeltaStatus;
|
|
171
|
+
private pendingDeltaTimer;
|
|
147
172
|
private lineId;
|
|
148
173
|
private assistantLineId;
|
|
149
174
|
private thinkingLineId;
|
|
150
175
|
private finalizedThinkingLineId;
|
|
176
|
+
private readonly liveToolLineIds;
|
|
151
177
|
private activeAbortController;
|
|
152
178
|
private interruptArmed;
|
|
153
179
|
private lines;
|
|
@@ -254,7 +280,7 @@ export declare class WebRepl {
|
|
|
254
280
|
cancelled: boolean;
|
|
255
281
|
};
|
|
256
282
|
private append;
|
|
257
|
-
private
|
|
283
|
+
private appendLineText;
|
|
258
284
|
private replaceLineText;
|
|
259
285
|
private replaceLine;
|
|
260
286
|
private setBusy;
|
|
@@ -267,11 +293,19 @@ export declare class WebRepl {
|
|
|
267
293
|
private reduce;
|
|
268
294
|
private finalizeLiveLine;
|
|
269
295
|
private finalizeThinkingLine;
|
|
296
|
+
private finalizeLiveToolLines;
|
|
270
297
|
private handleEvent;
|
|
271
298
|
private matchesPendingUserImageEcho;
|
|
272
299
|
private handleCommandOrPrompt;
|
|
273
300
|
private runCompaction;
|
|
274
301
|
private send;
|
|
302
|
+
private broadcastDelta;
|
|
303
|
+
private queueDeltaOperation;
|
|
304
|
+
private queueDeltaStatus;
|
|
305
|
+
private scheduleDeltaFlush;
|
|
306
|
+
private flushDeltaOperations;
|
|
307
|
+
private discardPendingDeltaOperations;
|
|
275
308
|
private broadcastSync;
|
|
276
309
|
}
|
|
310
|
+
export declare function compactLineOperations(operations: WebLineOperation[]): WebLineOperation[];
|
|
277
311
|
export {};
|
package/dist/web/index.js
CHANGED
|
@@ -249,10 +249,15 @@ function webRuntimeScopeKey(scope) {
|
|
|
249
249
|
export class WebRepl {
|
|
250
250
|
runtime;
|
|
251
251
|
subscribers = new Set();
|
|
252
|
+
eventSequence = 0;
|
|
253
|
+
pendingDeltaOperations = [];
|
|
254
|
+
pendingDeltaStatus = false;
|
|
255
|
+
pendingDeltaTimer;
|
|
252
256
|
lineId = 0;
|
|
253
257
|
assistantLineId;
|
|
254
258
|
thinkingLineId;
|
|
255
259
|
finalizedThinkingLineId;
|
|
260
|
+
liveToolLineIds = new Map();
|
|
256
261
|
activeAbortController;
|
|
257
262
|
interruptArmed = false;
|
|
258
263
|
lines;
|
|
@@ -278,16 +283,17 @@ export class WebRepl {
|
|
|
278
283
|
runtime.engine.onSessionTitleChange(() => this.broadcastSync());
|
|
279
284
|
}
|
|
280
285
|
subscribe(res) {
|
|
281
|
-
|
|
286
|
+
const subscriber = { response: res, blocked: false, needsSync: false };
|
|
287
|
+
this.subscribers.add(subscriber);
|
|
282
288
|
res.writeHead(200, {
|
|
283
289
|
"Content-Type": "text/event-stream; charset=utf-8",
|
|
284
290
|
"Cache-Control": "no-cache, no-transform",
|
|
285
291
|
Connection: "keep-alive",
|
|
286
292
|
"X-Accel-Buffering": "no",
|
|
287
293
|
});
|
|
288
|
-
this.send(
|
|
294
|
+
this.send(subscriber, "sync", this.snapshot(true));
|
|
289
295
|
reqKeepAlive(res);
|
|
290
|
-
res.on("close", () => this.subscribers.delete(
|
|
296
|
+
res.on("close", () => this.subscribers.delete(subscriber));
|
|
291
297
|
}
|
|
292
298
|
snapshot(includeCatalog = false) {
|
|
293
299
|
return {
|
|
@@ -394,6 +400,7 @@ export class WebRepl {
|
|
|
394
400
|
this.assistantLineId = undefined;
|
|
395
401
|
this.thinkingLineId = undefined;
|
|
396
402
|
this.finalizedThinkingLineId = undefined;
|
|
403
|
+
this.liveToolLineIds.clear();
|
|
397
404
|
if (line)
|
|
398
405
|
this.append(line);
|
|
399
406
|
this.broadcastSync();
|
|
@@ -426,8 +433,18 @@ export class WebRepl {
|
|
|
426
433
|
content: payload.content ?? "",
|
|
427
434
|
id: payload.id,
|
|
428
435
|
title: payload.title,
|
|
436
|
+
usage: payload.usage,
|
|
429
437
|
source: payload.source,
|
|
430
438
|
});
|
|
439
|
+
const usage = payload.usage?.trim();
|
|
440
|
+
if (!shouldClear && usage) {
|
|
441
|
+
this.append({
|
|
442
|
+
kind: "meta",
|
|
443
|
+
title: "提示词用法",
|
|
444
|
+
text: usage,
|
|
445
|
+
format: "markdown",
|
|
446
|
+
});
|
|
447
|
+
}
|
|
431
448
|
this.broadcastSync();
|
|
432
449
|
return { ok: true, appPrompt };
|
|
433
450
|
}
|
|
@@ -493,15 +510,19 @@ export class WebRepl {
|
|
|
493
510
|
this.broadcastSync();
|
|
494
511
|
return { ok: true, cancelled: had };
|
|
495
512
|
}
|
|
496
|
-
append(line) {
|
|
513
|
+
append(line, streaming = false) {
|
|
497
514
|
const id = ++this.lineId;
|
|
498
|
-
|
|
499
|
-
this.
|
|
515
|
+
const nextLine = { id, ...line };
|
|
516
|
+
this.lines.push(nextLine);
|
|
517
|
+
if (streaming)
|
|
518
|
+
this.broadcastDelta({ type: "line.append", line: nextLine });
|
|
519
|
+
else
|
|
520
|
+
this.broadcastSync();
|
|
500
521
|
return id;
|
|
501
522
|
}
|
|
502
|
-
|
|
503
|
-
this.lines = this.lines.map((line) => line.id === id ? { ...line, text:
|
|
504
|
-
this.
|
|
523
|
+
appendLineText(id, text) {
|
|
524
|
+
this.lines = this.lines.map((line) => line.id === id ? { ...line, text: line.text + text } : line);
|
|
525
|
+
this.broadcastDelta({ type: "line.text.append", id, text });
|
|
505
526
|
}
|
|
506
527
|
replaceLineText(id, text) {
|
|
507
528
|
this.lines = this.lines.map((line) => line.id === id ? { ...line, text } : line);
|
|
@@ -538,8 +559,9 @@ export class WebRepl {
|
|
|
538
559
|
this.queuedInput = undefined;
|
|
539
560
|
this.queuedAttachments = undefined;
|
|
540
561
|
this.finalizeForegroundView();
|
|
562
|
+
this.finalizeLiveToolLines();
|
|
541
563
|
this.busy = false;
|
|
542
|
-
this.status = { ...this.status, phase: "ready", detail: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined };
|
|
564
|
+
this.status = { ...this.status, phase: "ready", detail: undefined, currentTool: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined };
|
|
543
565
|
this.broadcastSync();
|
|
544
566
|
return runWasActive;
|
|
545
567
|
}
|
|
@@ -608,6 +630,7 @@ export class WebRepl {
|
|
|
608
630
|
if (id === undefined)
|
|
609
631
|
return;
|
|
610
632
|
this.lines = this.lines.map((line) => line.id === id ? { ...line, live: false } : line);
|
|
633
|
+
this.queueDeltaOperation({ type: "line.patch", id, patch: { live: false } });
|
|
611
634
|
}
|
|
612
635
|
finalizeThinkingLine() {
|
|
613
636
|
const id = this.thinkingLineId;
|
|
@@ -617,6 +640,11 @@ export class WebRepl {
|
|
|
617
640
|
this.finalizedThinkingLineId = id;
|
|
618
641
|
this.thinkingLineId = undefined;
|
|
619
642
|
}
|
|
643
|
+
finalizeLiveToolLines() {
|
|
644
|
+
for (const id of this.liveToolLineIds.values())
|
|
645
|
+
this.finalizeLiveLine(id);
|
|
646
|
+
this.liveToolLineIds.clear();
|
|
647
|
+
}
|
|
620
648
|
handleEvent(event) {
|
|
621
649
|
this.reduce(event);
|
|
622
650
|
if (event.type === "message" && this.matchesPendingUserImageEcho(event.message)) {
|
|
@@ -624,22 +652,26 @@ export class WebRepl {
|
|
|
624
652
|
this.broadcastSync();
|
|
625
653
|
return;
|
|
626
654
|
}
|
|
627
|
-
if (event.type === "
|
|
655
|
+
if (event.type === "tool_call.delta") {
|
|
656
|
+
this.queueDeltaStatus();
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
if (event.type === "state" || event.type === "context.metrics" || event.type === "usage" || event.type === "retrying") {
|
|
628
660
|
this.broadcastSync();
|
|
629
661
|
return;
|
|
630
662
|
}
|
|
631
663
|
if (event.type === "assistant.delta") {
|
|
632
664
|
this.finalizeThinkingLine();
|
|
633
|
-
const id = this.assistantLineId ?? this.append({ kind: "assistant", text: "", live: true });
|
|
665
|
+
const id = this.assistantLineId ?? this.append({ kind: "assistant", text: "", live: true }, true);
|
|
634
666
|
this.assistantLineId = id;
|
|
635
|
-
this.
|
|
667
|
+
this.appendLineText(id, event.text);
|
|
636
668
|
return;
|
|
637
669
|
}
|
|
638
670
|
if (event.type === "thinking.delta") {
|
|
639
|
-
const id = this.thinkingLineId ?? this.finalizedThinkingLineId ?? this.append(thinkingLine("", true));
|
|
671
|
+
const id = this.thinkingLineId ?? this.finalizedThinkingLineId ?? this.append(thinkingLine("", true), true);
|
|
640
672
|
this.thinkingLineId = id;
|
|
641
673
|
this.finalizedThinkingLineId = undefined;
|
|
642
|
-
this.
|
|
674
|
+
this.appendLineText(id, event.text);
|
|
643
675
|
return;
|
|
644
676
|
}
|
|
645
677
|
if (event.type === "message") {
|
|
@@ -670,7 +702,14 @@ export class WebRepl {
|
|
|
670
702
|
return;
|
|
671
703
|
}
|
|
672
704
|
if (event.message.role === "tool_result") {
|
|
673
|
-
renderToolResultMessage(event.message, (line) =>
|
|
705
|
+
renderToolResultMessage(event.message, (line, toolUseId) => {
|
|
706
|
+
const liveLineId = this.liveToolLineIds.get(toolUseId);
|
|
707
|
+
if (liveLineId === undefined)
|
|
708
|
+
return this.append(line);
|
|
709
|
+
this.replaceLine(liveLineId, line);
|
|
710
|
+
this.liveToolLineIds.delete(toolUseId);
|
|
711
|
+
return liveLineId;
|
|
712
|
+
});
|
|
674
713
|
renderMessageImages(event.message, (line) => this.append(line));
|
|
675
714
|
return;
|
|
676
715
|
}
|
|
@@ -691,13 +730,22 @@ export class WebRepl {
|
|
|
691
730
|
if (event.type === "tool.started") {
|
|
692
731
|
this.finalizeLiveLine(this.assistantLineId);
|
|
693
732
|
this.finalizeThinkingLine();
|
|
733
|
+
const id = this.append({ ...formatToolUse(event.toolUse), live: true });
|
|
734
|
+
this.liveToolLineIds.set(event.toolUse.id, id);
|
|
694
735
|
return;
|
|
695
736
|
}
|
|
696
|
-
if (event.type === "tool.finished")
|
|
737
|
+
if (event.type === "tool.finished") {
|
|
738
|
+
const id = this.liveToolLineIds.get(event.toolUse.id);
|
|
739
|
+
if (id !== undefined) {
|
|
740
|
+
this.finalizeLiveLine(id);
|
|
741
|
+
this.liveToolLineIds.delete(event.toolUse.id);
|
|
742
|
+
}
|
|
697
743
|
return;
|
|
744
|
+
}
|
|
698
745
|
if (event.type === "terminal") {
|
|
699
746
|
this.finalizeLiveLine(this.assistantLineId);
|
|
700
747
|
this.finalizeThinkingLine();
|
|
748
|
+
this.finalizeLiveToolLines();
|
|
701
749
|
this.assistantLineId = undefined;
|
|
702
750
|
this.broadcastSync();
|
|
703
751
|
return;
|
|
@@ -905,15 +953,86 @@ export class WebRepl {
|
|
|
905
953
|
this.setStatus({ ...this.status, phase: "ready", detail: undefined, activityTick: this.status.activityTick + 1 });
|
|
906
954
|
}
|
|
907
955
|
}
|
|
908
|
-
send(
|
|
909
|
-
|
|
910
|
-
|
|
956
|
+
send(subscriber, event, data) {
|
|
957
|
+
if (subscriber.blocked) {
|
|
958
|
+
subscriber.needsSync = true;
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
const eventId = ++this.eventSequence;
|
|
962
|
+
const frame = `id: ${eventId}\nevent: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
963
|
+
if (subscriber.response.write(frame))
|
|
964
|
+
return;
|
|
965
|
+
subscriber.blocked = true;
|
|
966
|
+
subscriber.response.once("drain", () => {
|
|
967
|
+
subscriber.blocked = false;
|
|
968
|
+
if (!subscriber.needsSync || subscriber.response.destroyed)
|
|
969
|
+
return;
|
|
970
|
+
subscriber.needsSync = false;
|
|
971
|
+
this.send(subscriber, "sync", this.snapshot(false));
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
broadcastDelta(operation) {
|
|
975
|
+
this.queueDeltaOperation(operation);
|
|
976
|
+
}
|
|
977
|
+
queueDeltaOperation(operation) {
|
|
978
|
+
this.pendingDeltaOperations.push(operation);
|
|
979
|
+
this.scheduleDeltaFlush();
|
|
980
|
+
}
|
|
981
|
+
queueDeltaStatus() {
|
|
982
|
+
this.pendingDeltaStatus = true;
|
|
983
|
+
this.scheduleDeltaFlush();
|
|
984
|
+
}
|
|
985
|
+
scheduleDeltaFlush() {
|
|
986
|
+
if (this.pendingDeltaTimer)
|
|
987
|
+
return;
|
|
988
|
+
this.pendingDeltaTimer = setTimeout(() => this.flushDeltaOperations(), 25);
|
|
989
|
+
this.pendingDeltaTimer.unref?.();
|
|
990
|
+
}
|
|
991
|
+
flushDeltaOperations() {
|
|
992
|
+
this.pendingDeltaTimer = undefined;
|
|
993
|
+
if (this.pendingDeltaOperations.length === 0 && !this.pendingDeltaStatus)
|
|
994
|
+
return;
|
|
995
|
+
const operations = compactLineOperations(this.pendingDeltaOperations);
|
|
996
|
+
this.pendingDeltaOperations = [];
|
|
997
|
+
this.pendingDeltaStatus = false;
|
|
998
|
+
const payload = {
|
|
999
|
+
protocolVersion: 2,
|
|
1000
|
+
sessionId: this.runtime.engine.snapshot().session?.sessionId,
|
|
1001
|
+
operations,
|
|
1002
|
+
status: this.status,
|
|
1003
|
+
};
|
|
1004
|
+
for (const subscriber of this.subscribers)
|
|
1005
|
+
this.send(subscriber, "delta", payload);
|
|
1006
|
+
}
|
|
1007
|
+
discardPendingDeltaOperations() {
|
|
1008
|
+
if (this.pendingDeltaTimer)
|
|
1009
|
+
clearTimeout(this.pendingDeltaTimer);
|
|
1010
|
+
this.pendingDeltaTimer = undefined;
|
|
1011
|
+
this.pendingDeltaOperations = [];
|
|
1012
|
+
this.pendingDeltaStatus = false;
|
|
911
1013
|
}
|
|
912
1014
|
broadcastSync() {
|
|
1015
|
+
this.discardPendingDeltaOperations();
|
|
913
1016
|
const payload = this.snapshot(false);
|
|
914
|
-
for (const
|
|
915
|
-
this.send(
|
|
1017
|
+
for (const subscriber of this.subscribers)
|
|
1018
|
+
this.send(subscriber, "sync", payload);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
export function compactLineOperations(operations) {
|
|
1022
|
+
const compacted = [];
|
|
1023
|
+
for (const operation of operations) {
|
|
1024
|
+
const previous = compacted.at(-1);
|
|
1025
|
+
if (operation.type === "line.text.append" && previous?.type === "line.text.append" && previous.id === operation.id) {
|
|
1026
|
+
previous.text += operation.text;
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
if (operation.type === "line.patch" && previous?.type === "line.patch" && previous.id === operation.id) {
|
|
1030
|
+
previous.patch = { ...previous.patch, ...operation.patch };
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
compacted.push(operation.type === "line.patch" ? { ...operation, patch: { ...operation.patch } } : { ...operation });
|
|
916
1034
|
}
|
|
1035
|
+
return compacted;
|
|
917
1036
|
}
|
|
918
1037
|
function reqKeepAlive(res) {
|
|
919
1038
|
const timer = setInterval(() => res.write(": keep-alive\n\n"), 25_000);
|
|
@@ -1100,7 +1219,7 @@ function pushTextBlock(blocks, text) {
|
|
|
1100
1219
|
}
|
|
1101
1220
|
function reduceStatus(status, event) {
|
|
1102
1221
|
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 };
|
|
1222
|
+
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
1223
|
if (event.type === "context.metrics")
|
|
1105
1224
|
return { ...status, metrics: event.metrics, inputTokenUpdatedAt: event.metrics.estimatedInputTokens !== status.metrics?.estimatedInputTokens ? Date.now() : status.inputTokenUpdatedAt, activityTick: status.activityTick + 1 };
|
|
1106
1225
|
if (event.type === "usage")
|
|
@@ -1113,9 +1232,13 @@ function reduceStatus(status, event) {
|
|
|
1113
1232
|
return { ...status, phase: "calling_model", streamedOutputTokens: status.streamedOutputTokens + estimateTokens(event.argumentsDelta), outputTokenUpdatedAt: Date.now(), activityTick: status.activityTick + 1 };
|
|
1114
1233
|
if (event.type === "retrying")
|
|
1115
1234
|
return { ...status, phase: "calling_model", detail: `retrying in ${(event.delayMs / 1000).toFixed(1)}s`, retryCooldownUntil: Date.now() + event.delayMs, activityTick: status.activityTick + 1 };
|
|
1235
|
+
if (event.type === "tool.started")
|
|
1236
|
+
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 };
|
|
1237
|
+
if (event.type === "tool.finished")
|
|
1238
|
+
return { ...status, currentTool: status.currentTool?.id === event.toolUse.id ? undefined : status.currentTool, activityTick: status.activityTick + 1 };
|
|
1116
1239
|
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 === "
|
|
1240
|
+
return { ...status, phase: "stopped", detail: event.reason, currentTool: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined, activityTick: status.activityTick + 1 };
|
|
1241
|
+
if (event.type === "message" || event.type === "error")
|
|
1119
1242
|
return { ...status, activityTick: status.activityTick + 1 };
|
|
1120
1243
|
return status;
|
|
1121
1244
|
}
|
|
@@ -1237,7 +1360,7 @@ const LOGIN_FIELD_DEFINITIONS = {
|
|
|
1237
1360
|
openai: [
|
|
1238
1361
|
{ key: "apiKey", label: "API key", envKey: "OPENAI_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-..." },
|
|
1239
1362
|
{ 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.
|
|
1363
|
+
{ key: "model", label: "Model", envKey: "OPENAI_MODEL", scope: "provider", required: true, placeholder: "gpt-5.6" },
|
|
1241
1364
|
{ key: "fallbackModel", label: "Fallback model", envKey: "OPENAI_FALLBACK_MODEL", scope: "provider" },
|
|
1242
1365
|
{ key: "endpoint", label: "Endpoint", envKey: "OPENAI_ENDPOINT", scope: "provider", placeholder: "auto", options: ["auto", "responses", "chat"] },
|
|
1243
1366
|
...SHARED_LOGIN_FIELDS,
|
|
@@ -1292,7 +1415,7 @@ function defaultBaseUrlForLoginProvider(provider) {
|
|
|
1292
1415
|
function defaultModelForLoginProvider(provider) {
|
|
1293
1416
|
if (provider === "anthropic")
|
|
1294
1417
|
return "claude-sonnet-4-6";
|
|
1295
|
-
return "gpt-5.
|
|
1418
|
+
return "gpt-5.6";
|
|
1296
1419
|
}
|
|
1297
1420
|
function validateLoginFormPayload(payload) {
|
|
1298
1421
|
for (const field of LOGIN_FIELD_DEFINITIONS[payload.provider]) {
|
|
@@ -1444,6 +1567,7 @@ function renderMessage(message, append, activeAssistantId, options = {}) {
|
|
|
1444
1567
|
return false;
|
|
1445
1568
|
if (message.role === "assistant" && activeAssistantId !== undefined && message.blocks.some((block) => block.type === "text"))
|
|
1446
1569
|
return true;
|
|
1570
|
+
const parentToolName = typeof message.metadata?.tool === "string" ? message.metadata.tool : undefined;
|
|
1447
1571
|
let rendered = false;
|
|
1448
1572
|
for (const block of message.blocks) {
|
|
1449
1573
|
if (block.type === "text") {
|
|
@@ -1460,7 +1584,7 @@ function renderMessage(message, append, activeAssistantId, options = {}) {
|
|
|
1460
1584
|
const line = imageLineForBlock(message.role, block);
|
|
1461
1585
|
if (!line)
|
|
1462
1586
|
continue;
|
|
1463
|
-
append(line);
|
|
1587
|
+
append({ ...line, parentToolName });
|
|
1464
1588
|
rendered = true;
|
|
1465
1589
|
}
|
|
1466
1590
|
else if (block.type === "thinking") {
|
|
@@ -1485,20 +1609,21 @@ function renderToolResultMessage(message, append) {
|
|
|
1485
1609
|
for (const block of message.blocks) {
|
|
1486
1610
|
if (block.type !== "tool_result")
|
|
1487
1611
|
continue;
|
|
1488
|
-
append(formatToolResultLine(block.name, block.output, block.ok));
|
|
1612
|
+
append(formatToolResultLine(block.name, block.output, block.ok), block.toolUseId);
|
|
1489
1613
|
rendered = true;
|
|
1490
1614
|
}
|
|
1491
1615
|
return rendered;
|
|
1492
1616
|
}
|
|
1493
1617
|
function renderMessageImages(message, append) {
|
|
1494
1618
|
let rendered = false;
|
|
1619
|
+
const parentToolName = typeof message.metadata?.tool === "string" ? message.metadata.tool : undefined;
|
|
1495
1620
|
for (const block of message.blocks) {
|
|
1496
1621
|
if (block.type !== "image")
|
|
1497
1622
|
continue;
|
|
1498
1623
|
const line = imageLineForBlock(message.role, block);
|
|
1499
1624
|
if (!line)
|
|
1500
1625
|
continue;
|
|
1501
|
-
append(line);
|
|
1626
|
+
append({ ...line, parentToolName });
|
|
1502
1627
|
rendered = true;
|
|
1503
1628
|
}
|
|
1504
1629
|
return rendered;
|
|
@@ -1586,13 +1711,15 @@ function thinkingLine(text, live = false) {
|
|
|
1586
1711
|
}
|
|
1587
1712
|
function formatToolUse(toolUse) {
|
|
1588
1713
|
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 };
|
|
1714
|
+
return { kind: "tool", toolName: toolUse.name, title: toolTitle(toolUse.name, "running"), bodyTitle: planToolBodyTitle(toolUse.input), text: formatPlanToolPayload(toolUse.input), collapsible: true };
|
|
1715
|
+
if (toolUse.name === "image2")
|
|
1716
|
+
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
1717
|
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 };
|
|
1718
|
+
return { kind: "tool", toolName: toolUse.name, title: toolTitle(toolUse.name, "running"), bodyTitle: summary.bodyTitle, text: summary.text, previewStyle: "summary", collapsible: true };
|
|
1592
1719
|
}
|
|
1593
1720
|
function formatToolResultLine(toolName, output, ok) {
|
|
1594
1721
|
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 };
|
|
1722
|
+
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
1723
|
}
|
|
1597
1724
|
function toolTitle(toolName, _phase) {
|
|
1598
1725
|
const labels = {
|