neoctl 0.2.0 → 0.2.2
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 +20 -9
- package/dist/context/compaction.d.ts +3 -0
- package/dist/context/compaction.js +231 -40
- package/dist/context/compaction.js.map +1 -1
- package/dist/context/prompts.js +4 -4
- package/dist/context/prompts.js.map +1 -1
- package/dist/core/commands.d.ts +66 -0
- package/dist/core/commands.js +151 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/context-metrics.d.ts +5 -2
- package/dist/core/context-metrics.js +85 -9
- package/dist/core/context-metrics.js.map +1 -1
- package/dist/core/image-registry.d.ts +42 -0
- package/dist/core/image-registry.js +128 -0
- package/dist/core/image-registry.js.map +1 -0
- package/dist/core/message-pipeline.d.ts +6 -0
- package/dist/core/message-pipeline.js +12 -0
- package/dist/core/message-pipeline.js.map +1 -1
- package/dist/core/query-engine.d.ts +0 -4
- package/dist/core/query-engine.js +0 -22
- package/dist/core/query-engine.js.map +1 -1
- package/dist/core/query.d.ts +0 -4
- package/dist/core/query.js +21 -8
- package/dist/core/query.js.map +1 -1
- package/dist/core/runtime.d.ts +59 -0
- package/dist/core/runtime.js +161 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/state.d.ts +6 -7
- package/dist/core/state.js +2 -0
- package/dist/core/state.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/model/anthropic-adapter.d.ts +30 -0
- package/dist/model/anthropic-adapter.js +106 -0
- package/dist/model/anthropic-adapter.js.map +1 -0
- package/dist/model/anthropic-mapper.d.ts +13 -0
- package/dist/model/anthropic-mapper.js +482 -0
- package/dist/model/anthropic-mapper.js.map +1 -0
- package/dist/model/config.d.ts +8 -2
- package/dist/model/config.js +24 -1
- package/dist/model/config.js.map +1 -1
- package/dist/model/openai-mappers.js +1 -1
- package/dist/model/openai-mappers.js.map +1 -1
- package/dist/model/provider-factory.js +17 -0
- package/dist/model/provider-factory.js.map +1 -1
- package/dist/model/smoke-anthropic-mapper.d.ts +1 -0
- package/dist/model/smoke-anthropic-mapper.js +85 -0
- package/dist/model/smoke-anthropic-mapper.js.map +1 -0
- package/dist/repl/index.js +56 -27
- package/dist/repl/index.js.map +1 -1
- package/dist/repl/transcript-flush.d.ts +6 -0
- package/dist/repl/transcript-flush.js +54 -0
- package/dist/repl/transcript-flush.js.map +1 -0
- package/dist/repl/transcript-format.d.ts +16 -0
- package/dist/repl/transcript-format.js +199 -0
- package/dist/repl/transcript-format.js.map +1 -0
- package/dist/server/agent-manager.d.ts +56 -0
- package/dist/server/agent-manager.js +171 -0
- package/dist/server/agent-manager.js.map +1 -0
- package/dist/server/connection-manager.d.ts +18 -0
- package/dist/server/connection-manager.js +52 -0
- package/dist/server/connection-manager.js.map +1 -0
- package/dist/server/event-mapper.d.ts +4 -0
- package/dist/server/event-mapper.js +31 -0
- package/dist/server/event-mapper.js.map +1 -0
- package/dist/server/query-runtime.d.ts +29 -0
- package/dist/server/query-runtime.js +61 -0
- package/dist/server/query-runtime.js.map +1 -0
- package/dist/server/rpc-router.d.ts +24 -0
- package/dist/server/rpc-router.js +165 -0
- package/dist/server/rpc-router.js.map +1 -0
- package/dist/server/rpc-types.d.ts +92 -0
- package/dist/server/rpc-types.js +2 -0
- package/dist/server/rpc-types.js.map +1 -0
- package/dist/server/ws-server.d.ts +22 -0
- package/dist/server/ws-server.js +84 -0
- package/dist/server/ws-server.js.map +1 -0
- package/dist/tasks/task-record.d.ts +50 -0
- package/dist/tasks/task-record.js +50 -0
- package/dist/tasks/task-record.js.map +1 -0
- package/dist/tips.js +1 -1
- package/dist/tips.js.map +1 -1
- package/dist/tools/builtins/image-loader-tool.d.ts +22 -0
- package/dist/tools/builtins/image-loader-tool.js +235 -0
- package/dist/tools/builtins/image-loader-tool.js.map +1 -0
- package/dist/web/html.js +3 -4
- package/dist/web/html.js.map +1 -1
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +60 -20
- package/dist/web/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Tool } from "../tool.js";
|
|
2
|
+
export interface LoadImageToolInput {
|
|
3
|
+
/** Image references: ids like "img_1", labels, numeric refs like "image 1", storage paths, or external file paths. */
|
|
4
|
+
imageRefs: string[];
|
|
5
|
+
/** Optional question/context about what to look for in the image(s). Included as text alongside images. */
|
|
6
|
+
prompt?: string;
|
|
7
|
+
}
|
|
8
|
+
interface LoadedImageInfo {
|
|
9
|
+
id: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
origin: string;
|
|
13
|
+
storagePath?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface LoadImageToolOutput {
|
|
16
|
+
loadedImages: LoadedImageInfo[];
|
|
17
|
+
failedRefs: string[];
|
|
18
|
+
prompt?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function createLoadImageTool(): Tool<LoadImageToolInput>;
|
|
21
|
+
export declare const loadImageTool: Tool<LoadImageToolInput>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { supportsImageInput } from "../../model/context-window.js";
|
|
4
|
+
import { getImageRegistryFromMessages } from "../../core/message-pipeline.js";
|
|
5
|
+
import { resolveImageRef, formatImageRegistryForContext, loadImageData } from "../../core/image-registry.js";
|
|
6
|
+
const SUPPORTED_EXTENSIONS = {
|
|
7
|
+
".png": "image/png",
|
|
8
|
+
".jpg": "image/jpeg",
|
|
9
|
+
".jpeg": "image/jpeg",
|
|
10
|
+
".gif": "image/gif",
|
|
11
|
+
".webp": "image/webp",
|
|
12
|
+
".bmp": "image/bmp",
|
|
13
|
+
".svg": "image/svg+xml",
|
|
14
|
+
};
|
|
15
|
+
const MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
16
|
+
function isExternalFilePath(ref) {
|
|
17
|
+
const trimmed = ref.trim();
|
|
18
|
+
if (/^[a-zA-Z]:[\\/]/.test(trimmed))
|
|
19
|
+
return true;
|
|
20
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("~"))
|
|
21
|
+
return true;
|
|
22
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("..") || trimmed.startsWith(".\\"))
|
|
23
|
+
return true;
|
|
24
|
+
const ext = path.extname(trimmed).toLowerCase();
|
|
25
|
+
return ext in SUPPORTED_EXTENSIONS;
|
|
26
|
+
}
|
|
27
|
+
function loadExternalImage(filePath) {
|
|
28
|
+
const resolved = path.resolve(filePath);
|
|
29
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
30
|
+
const mimeType = SUPPORTED_EXTENSIONS[ext];
|
|
31
|
+
if (!mimeType) {
|
|
32
|
+
return { error: `Unsupported image format: ${ext}. Supported: ${Object.keys(SUPPORTED_EXTENSIONS).join(", ")}` };
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const stat = statSync(resolved);
|
|
36
|
+
if (!stat.isFile())
|
|
37
|
+
return { error: `Not a file: ${resolved}` };
|
|
38
|
+
if (stat.size > MAX_FILE_SIZE)
|
|
39
|
+
return { error: `File too large: ${(stat.size / 1024 / 1024).toFixed(1)}MB (max ${MAX_FILE_SIZE / 1024 / 1024}MB)` };
|
|
40
|
+
const buffer = readFileSync(resolved);
|
|
41
|
+
return {
|
|
42
|
+
base64: buffer.toString("base64"),
|
|
43
|
+
mimeType,
|
|
44
|
+
label: path.basename(resolved),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return { error: `Cannot read file: ${err instanceof Error ? err.message : String(err)}` };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function createLoadImageTool() {
|
|
52
|
+
return {
|
|
53
|
+
name: "load_image",
|
|
54
|
+
aliases: ["view_image", "inspect_image"],
|
|
55
|
+
description: "Load one or more images into the current context for direct visual inspection by the model. " +
|
|
56
|
+
"Supports two sources: (1) conversation history images via ids (img_1), labels, or numeric refs; " +
|
|
57
|
+
"(2) external files via absolute or relative file paths (e.g. ./screenshot.png, C:\\images\\photo.jpg). " +
|
|
58
|
+
"Supported formats: PNG, JPEG, GIF, WebP, BMP, SVG. Max file size: 20MB. " +
|
|
59
|
+
"The loaded images become visible to you in the next message. " +
|
|
60
|
+
"This tool is available only when the current model supports image input.",
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
imageRefs: {
|
|
65
|
+
type: "array",
|
|
66
|
+
items: { type: "string" },
|
|
67
|
+
description: "Image references: registry ids (img_1), labels, numeric refs (image 1, [img#2]), or file paths (./photo.png, /abs/path/img.jpg, C:\\images\\pic.png).",
|
|
68
|
+
},
|
|
69
|
+
prompt: {
|
|
70
|
+
type: "string",
|
|
71
|
+
description: "Optional analysis context or question about the image(s). Will be shown alongside the images.",
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
required: ["imageRefs"],
|
|
75
|
+
additionalProperties: false,
|
|
76
|
+
},
|
|
77
|
+
metadata: {
|
|
78
|
+
readOnly: true,
|
|
79
|
+
concurrent: true,
|
|
80
|
+
visible: true,
|
|
81
|
+
maxResultSizeChars: 2000,
|
|
82
|
+
},
|
|
83
|
+
isEnabled(context) {
|
|
84
|
+
if (!context)
|
|
85
|
+
return false;
|
|
86
|
+
const model = context.options?.mainLoopModel;
|
|
87
|
+
return Boolean(model) && supportsImageInput(model) === true;
|
|
88
|
+
},
|
|
89
|
+
validate(input) {
|
|
90
|
+
const record = input;
|
|
91
|
+
return {
|
|
92
|
+
imageRefs: record.imageRefs ?? [],
|
|
93
|
+
prompt: record.prompt,
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
validateInput(input, context) {
|
|
97
|
+
if (!input.imageRefs || input.imageRefs.length === 0) {
|
|
98
|
+
return { ok: false, message: "imageRefs must contain at least one image reference" };
|
|
99
|
+
}
|
|
100
|
+
if (input.imageRefs.some((ref) => !ref.trim())) {
|
|
101
|
+
return { ok: false, message: "imageRefs must contain non-empty strings" };
|
|
102
|
+
}
|
|
103
|
+
if (input.imageRefs.length > 10) {
|
|
104
|
+
return { ok: false, message: "Cannot load more than 10 images at once to avoid context overflow" };
|
|
105
|
+
}
|
|
106
|
+
const model = context.options?.mainLoopModel;
|
|
107
|
+
if (!model || supportsImageInput(model) !== true) {
|
|
108
|
+
return { ok: false, message: "load_image requires a model that supports image input" };
|
|
109
|
+
}
|
|
110
|
+
return { ok: true, value: input };
|
|
111
|
+
},
|
|
112
|
+
isConcurrencySafe() {
|
|
113
|
+
return true;
|
|
114
|
+
},
|
|
115
|
+
async call(input, context) {
|
|
116
|
+
const registry = getImageRegistryFromMessages(context.messages ?? []);
|
|
117
|
+
const loadedImages = [];
|
|
118
|
+
const failedRefs = [];
|
|
119
|
+
const imageBlocks = [];
|
|
120
|
+
let externalCount = 0;
|
|
121
|
+
for (const ref of input.imageRefs) {
|
|
122
|
+
const entry = resolveImageRef(registry, ref);
|
|
123
|
+
if (entry) {
|
|
124
|
+
const base64 = loadImageData(entry);
|
|
125
|
+
if (!base64) {
|
|
126
|
+
failedRefs.push(`${ref} (storage unreadable: ${entry.storagePath ?? "no path"})`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const rawBase64 = base64.replace(/^data:[^;,]+;base64,/su, "").replace(/\s+/gu, "");
|
|
130
|
+
imageBlocks.push({
|
|
131
|
+
type: "image",
|
|
132
|
+
mimeType: entry.mimeType,
|
|
133
|
+
data: rawBase64,
|
|
134
|
+
label: entry.label ?? entry.id,
|
|
135
|
+
storage: entry.storagePath && entry.storageFormat
|
|
136
|
+
? { path: entry.storagePath, format: entry.storageFormat }
|
|
137
|
+
: undefined,
|
|
138
|
+
});
|
|
139
|
+
loadedImages.push({
|
|
140
|
+
id: entry.id,
|
|
141
|
+
label: entry.label,
|
|
142
|
+
mimeType: entry.mimeType,
|
|
143
|
+
origin: entry.origin,
|
|
144
|
+
storagePath: entry.storagePath,
|
|
145
|
+
});
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (isExternalFilePath(ref)) {
|
|
149
|
+
const result = loadExternalImage(ref);
|
|
150
|
+
if ("error" in result) {
|
|
151
|
+
failedRefs.push(`${ref} (${result.error})`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
externalCount += 1;
|
|
155
|
+
const resolvedPath = path.resolve(ref);
|
|
156
|
+
imageBlocks.push({
|
|
157
|
+
type: "image",
|
|
158
|
+
mimeType: result.mimeType,
|
|
159
|
+
data: result.base64,
|
|
160
|
+
label: result.label,
|
|
161
|
+
});
|
|
162
|
+
loadedImages.push({
|
|
163
|
+
id: `ext_${externalCount}`,
|
|
164
|
+
label: result.label,
|
|
165
|
+
mimeType: result.mimeType,
|
|
166
|
+
origin: "external",
|
|
167
|
+
storagePath: resolvedPath,
|
|
168
|
+
});
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
failedRefs.push(ref);
|
|
172
|
+
}
|
|
173
|
+
if (loadedImages.length === 0) {
|
|
174
|
+
const available = formatImageRegistryForContext(registry);
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
output: {
|
|
178
|
+
error: `Could not load any images. Failed refs: ${failedRefs.join(", ")}`,
|
|
179
|
+
availableImages: available || "No images found in conversation history.",
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const textParts = [];
|
|
184
|
+
if (input.prompt)
|
|
185
|
+
textParts.push(input.prompt);
|
|
186
|
+
textParts.push(`Loaded ${loadedImages.length} image(s): ${loadedImages.map((i) => i.label ?? i.id).join(", ")}`);
|
|
187
|
+
if (failedRefs.length > 0)
|
|
188
|
+
textParts.push(`Failed to load: ${failedRefs.join(", ")}`);
|
|
189
|
+
const newMessage = {
|
|
190
|
+
id: `load-image-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
|
191
|
+
role: "user",
|
|
192
|
+
createdAt: new Date().toISOString(),
|
|
193
|
+
blocks: [
|
|
194
|
+
{ type: "text", text: textParts.join("\n") },
|
|
195
|
+
...imageBlocks,
|
|
196
|
+
],
|
|
197
|
+
isMeta: true,
|
|
198
|
+
metadata: { loadedImages: true, imageRefs: input.imageRefs },
|
|
199
|
+
};
|
|
200
|
+
const output = {
|
|
201
|
+
loadedImages,
|
|
202
|
+
failedRefs,
|
|
203
|
+
prompt: input.prompt,
|
|
204
|
+
};
|
|
205
|
+
return {
|
|
206
|
+
ok: true,
|
|
207
|
+
output,
|
|
208
|
+
summary: `Loaded ${loadedImages.length} image(s) into context for direct inspection`,
|
|
209
|
+
newMessages: [newMessage],
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
renderToolResultMessage(result, request) {
|
|
213
|
+
if (!request)
|
|
214
|
+
return undefined;
|
|
215
|
+
const output = result.output;
|
|
216
|
+
const text = result.ok
|
|
217
|
+
? `Images loaded into context: ${output.loadedImages.map((i) => i.label ?? i.id).join(", ")}. You can now see them directly.${output.failedRefs.length > 0 ? ` Failed: ${output.failedRefs.join(", ")}` : ""}`
|
|
218
|
+
: `Failed to load images: ${JSON.stringify(result.output)}`;
|
|
219
|
+
return {
|
|
220
|
+
id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,
|
|
221
|
+
role: "tool_result",
|
|
222
|
+
createdAt: new Date().toISOString(),
|
|
223
|
+
blocks: [{
|
|
224
|
+
type: "tool_result",
|
|
225
|
+
toolUseId: request.id,
|
|
226
|
+
name: "load_image",
|
|
227
|
+
ok: result.ok,
|
|
228
|
+
output: text,
|
|
229
|
+
}],
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
export const loadImageTool = createLoadImageTool();
|
|
235
|
+
//# sourceMappingURL=image-loader-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-loader-tool.js","sourceRoot":"","sources":["../../../src/tools/builtins/image-loader-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,6BAA6B,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAyB7G,MAAM,oBAAoB,GAA2B;IACnD,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;CACxB,CAAC;AAEF,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEvC,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACpE,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnG,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAChD,OAAO,GAAG,IAAI,oBAAoB,CAAC;AACrC,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,KAAK,EAAE,6BAA6B,GAAG,gBAAgB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IACnH,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,KAAK,EAAE,eAAe,QAAQ,EAAE,EAAE,CAAC;QAChE,IAAI,IAAI,CAAC,IAAI,GAAG,aAAa;YAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,aAAa,GAAG,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;QACpJ,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACtC,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACjC,QAAQ;YACR,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;SAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,CAAC,YAAY,EAAE,eAAe,CAAC;QACxC,WAAW,EACT,8FAA8F;YAC9F,kGAAkG;YAClG,yGAAyG;YACzG,0EAA0E;YAC1E,+DAA+D;YAC/D,0EAA0E;QAC5E,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,SAAS,EAAE;oBACT,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACzB,WAAW,EAAE,uJAAuJ;iBACrK;gBACD,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,+FAA+F;iBAC7G;aACF;YACD,QAAQ,EAAE,CAAC,WAAW,CAAC;YACvB,oBAAoB,EAAE,KAAK;SAC5B;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE,IAAI;YACb,kBAAkB,EAAE,IAAI;SACzB;QACD,SAAS,CAAC,OAAO;YACf,IAAI,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAC;YAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC;YAC7C,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;QAC9D,CAAC;QACD,QAAQ,CAAC,KAAK;YACZ,MAAM,MAAM,GAAG,KAAoC,CAAC;YACpD,OAAO;gBACL,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;gBACjC,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;QACJ,CAAC;QACD,aAAa,CAAC,KAAK,EAAE,OAAO;YAC1B,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC;YACvF,CAAC;YACD,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC/C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC;YAC5E,CAAC;YACD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;gBAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,mEAAmE,EAAE,CAAC;YACrG,CAAC;YACD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC;YAC7C,IAAI,CAAC,KAAK,IAAI,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;gBACjD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,uDAAuD,EAAE,CAAC;YACzF,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACpC,CAAC;QACD,iBAAiB;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO;YACvB,MAAM,QAAQ,GAAG,4BAA4B,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;YACtE,MAAM,YAAY,GAAsB,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,MAAM,WAAW,GAAmB,EAAE,CAAC;YACvC,IAAI,aAAa,GAAG,CAAC,CAAC;YAEtB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBAClC,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;oBACpC,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,yBAAyB,KAAK,CAAC,WAAW,IAAI,SAAS,GAAG,CAAC,CAAC;wBAClF,SAAS;oBACX,CAAC;oBACD,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBACpF,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,OAAO;wBACb,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,IAAI,EAAE,SAAS;wBACf,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,EAAE;wBAC9B,OAAO,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,aAAa;4BAC/C,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,aAAa,EAAE;4BAC1D,CAAC,CAAC,SAAS;qBACd,CAAC,CAAC;oBACH,YAAY,CAAC,IAAI,CAAC;wBAChB,EAAE,EAAE,KAAK,CAAC,EAAE;wBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,WAAW,EAAE,KAAK,CAAC,WAAW;qBAC/B,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBAED,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5B,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;oBACtC,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;wBACtB,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;wBAC5C,SAAS;oBACX,CAAC;oBACD,aAAa,IAAI,CAAC,CAAC;oBACnB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;oBACvC,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,OAAO;wBACb,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,IAAI,EAAE,MAAM,CAAC,MAAM;wBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;qBACpB,CAAC,CAAC;oBACH,YAAY,CAAC,IAAI,CAAC;wBAChB,EAAE,EAAE,OAAO,aAAa,EAAE;wBAC1B,KAAK,EAAE,MAAM,CAAC,KAAK;wBACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,MAAM,EAAE,UAAU;wBAClB,WAAW,EAAE,YAAY;qBAC1B,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBAED,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;YAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,SAAS,GAAG,6BAA6B,CAAC,QAAQ,CAAC,CAAC;gBAC1D,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE;wBACN,KAAK,EAAE,2CAA2C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;wBACzE,eAAe,EAAE,SAAS,IAAI,0CAA0C;qBACzE;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,SAAS,GAAa,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM;gBAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC/C,SAAS,CAAC,IAAI,CAAC,UAAU,YAAY,CAAC,MAAM,cAAc,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjH,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,CAAC,IAAI,CAAC,mBAAmB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEtF,MAAM,UAAU,GAAY;gBAC1B,EAAE,EAAE,cAAc,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;gBACrF,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,MAAM,EAAE;oBACN,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBAC5C,GAAG,WAAW;iBACf;gBACD,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE;aAC7D,CAAC;YAEF,MAAM,MAAM,GAAwB;gBAClC,YAAY;gBACZ,UAAU;gBACV,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CAAC;YAEF,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,MAAM;gBACN,OAAO,EAAE,UAAU,YAAY,CAAC,MAAM,8CAA8C;gBACpF,WAAW,EAAE,CAAC,UAAU,CAAC;aAC1B,CAAC;QACJ,CAAC;QACD,uBAAuB,CAAC,MAAM,EAAE,OAAO;YACrC,IAAI,CAAC,OAAO;gBAAE,OAAO,SAAS,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,MAA6B,CAAC;YACpD,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE;gBACpB,CAAC,CAAC,+BAA+B,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC9M,CAAC,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9D,OAAO;gBACL,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;gBAC3E,IAAI,EAAE,aAAsB;gBAC5B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,MAAM,EAAE,CAAC;wBACP,IAAI,EAAE,aAAsB;wBAC5B,SAAS,EAAE,OAAO,CAAC,EAAE;wBACrB,IAAI,EAAE,YAAY;wBAClB,EAAE,EAAE,MAAM,CAAC,EAAE;wBACb,MAAM,EAAE,IAAI;qBACb,CAAC;aACH,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,EAAE,CAAC"}
|
package/dist/web/html.js
CHANGED
|
@@ -686,8 +686,7 @@ async function submit() {
|
|
|
686
686
|
input.value = '';
|
|
687
687
|
state.attachments = [];
|
|
688
688
|
if (state.busy) {
|
|
689
|
-
state.
|
|
690
|
-
state.queuedInput = undefined;
|
|
689
|
+
state.queuedInput = text;
|
|
691
690
|
}
|
|
692
691
|
autosize();
|
|
693
692
|
renderCompletions();
|
|
@@ -752,8 +751,8 @@ input.addEventListener('keydown', (e) => {
|
|
|
752
751
|
if (e.key === 'ArrowUp' && !input.value) { e.preventDefault(); advanceTip(-1); return; }
|
|
753
752
|
if (e.key === 'ArrowDown' && state.historyIndex !== undefined) { e.preventDefault(); state.historyIndex -= 1; if (state.historyIndex < 0) { state.historyIndex = undefined; input.value = ''; } else input.value = state.history[state.historyIndex] || ''; autosize(); return; }
|
|
754
753
|
if (e.key === 'ArrowDown' && !input.value) { e.preventDefault(); advanceTip(); return; }
|
|
755
|
-
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') { if (input.value) { input.value = ''; autosize(); renderCompletions(); } else fetch('/api/interrupt', { method: 'POST' }); }
|
|
756
|
-
if (e.key === 'Escape') { state.completionIndex = 0; if (state.queuedInput) fetch('/api/
|
|
754
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') { if (input.value) { input.value = ''; autosize(); renderCompletions(); } else if (state.queuedInput) { state.queuedInput = undefined; scheduleRender(); fetch('/api/queue/cancel', { method: 'POST' }); } else fetch('/api/interrupt', { method: 'POST' }); }
|
|
755
|
+
if (e.key === 'Escape') { state.completionIndex = 0; if (state.queuedInput) { state.queuedInput = undefined; scheduleRender(); fetch('/api/queue/cancel', { method: 'POST' }); } else renderCompletions(); }
|
|
757
756
|
});
|
|
758
757
|
document.addEventListener('keydown', (e) => {
|
|
759
758
|
if (e.target === input || e.target.closest('input, textarea, select')) 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA21B1B,CAAC"}
|
package/dist/web/index.d.ts
CHANGED
|
@@ -140,6 +140,7 @@ export declare class WebRepl {
|
|
|
140
140
|
private status;
|
|
141
141
|
private busy;
|
|
142
142
|
private queuedInput;
|
|
143
|
+
private queuedAttachments;
|
|
143
144
|
private foregroundRun;
|
|
144
145
|
private foregroundRunToken;
|
|
145
146
|
private readonly backgroundSessionRuns;
|
|
@@ -183,6 +184,7 @@ export declare class WebRepl {
|
|
|
183
184
|
ok: false;
|
|
184
185
|
error: string;
|
|
185
186
|
}>;
|
|
187
|
+
private startRun;
|
|
186
188
|
listSessions(): Promise<{
|
|
187
189
|
sessions: import("../index.js").SessionSummary[];
|
|
188
190
|
runningSessionIds: string[];
|
|
@@ -217,6 +219,10 @@ export declare class WebRepl {
|
|
|
217
219
|
ok: true;
|
|
218
220
|
interrupted: boolean;
|
|
219
221
|
};
|
|
222
|
+
cancelQueue(): {
|
|
223
|
+
ok: true;
|
|
224
|
+
cancelled: boolean;
|
|
225
|
+
};
|
|
220
226
|
private append;
|
|
221
227
|
private updateLine;
|
|
222
228
|
private replaceLineText;
|
package/dist/web/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import { grepTool } from "../tools/builtins/grep-tool.js";
|
|
|
20
20
|
import { searchTool } from "../tools/builtins/search-tool.js";
|
|
21
21
|
import { planTool } from "../tools/builtins/plan-tool.js";
|
|
22
22
|
import { createOpenAIImageGenerationTool } from "../tools/builtins/image-generation-tool.js";
|
|
23
|
-
import {
|
|
23
|
+
import { createLoadImageTool } from "../tools/builtins/image-loader-tool.js";
|
|
24
24
|
import { createAgentTool, resumeAgentTask } from "../agents/agent-tool.js";
|
|
25
25
|
import { createTaskTools } from "../tasks/task-tools.js";
|
|
26
26
|
import { TaskStore } from "../tasks/task-store.js";
|
|
@@ -121,7 +121,7 @@ export async function createWebRuntime(options = {}) {
|
|
|
121
121
|
tools.register(readFileTool);
|
|
122
122
|
tools.register(grepTool);
|
|
123
123
|
tools.register(searchTool);
|
|
124
|
-
tools.register(
|
|
124
|
+
tools.register(createLoadImageTool());
|
|
125
125
|
if (modelConfig?.provider === "openai")
|
|
126
126
|
tools.register(createOpenAIImageGenerationTool());
|
|
127
127
|
tools.register(planTool);
|
|
@@ -193,12 +193,8 @@ function syncImageGenerationTool(runtime, provider) {
|
|
|
193
193
|
if (provider === "openai")
|
|
194
194
|
runtime.tools.register(createOpenAIImageGenerationTool());
|
|
195
195
|
}
|
|
196
|
-
function syncVisionTool(runtime, model) {
|
|
197
|
-
runtime.tools.unregister("vision");
|
|
198
|
-
runtime.tools.register(createVisionTool({ modelGateway: runtime.modelGateway, model }));
|
|
199
|
-
}
|
|
200
196
|
function formatCreatedEnvNotice(dotEnvPath) {
|
|
201
|
-
return `Created default config file: ${dotEnvPath}\nSet MODEL_PROVIDER and the matching provider section (for example OPENAI_API_KEY or KIMI_API_KEY), then restart neo.`;
|
|
197
|
+
return `Created default config file: ${dotEnvPath}\nSet MODEL_PROVIDER and the matching provider section (for example OPENAI_API_KEY, ANTHROPIC_API_KEY, or KIMI_API_KEY), then restart neo.`;
|
|
202
198
|
}
|
|
203
199
|
function parseResumeFlag(value) {
|
|
204
200
|
if (!value)
|
|
@@ -258,6 +254,7 @@ export class WebRepl {
|
|
|
258
254
|
status;
|
|
259
255
|
busy = false;
|
|
260
256
|
queuedInput;
|
|
257
|
+
queuedAttachments;
|
|
261
258
|
foregroundRun;
|
|
262
259
|
foregroundRunToken = 0;
|
|
263
260
|
backgroundSessionRuns = new Map();
|
|
@@ -315,8 +312,15 @@ export class WebRepl {
|
|
|
315
312
|
await this.detachRunningForeground("session browser");
|
|
316
313
|
}
|
|
317
314
|
else if (this.busy) {
|
|
318
|
-
this.
|
|
315
|
+
this.queuedInput = text;
|
|
316
|
+
this.queuedAttachments = attachments;
|
|
317
|
+
this.broadcastSync();
|
|
318
|
+
return { ok: true };
|
|
319
319
|
}
|
|
320
|
+
this.startRun(text, attachments);
|
|
321
|
+
return { ok: true };
|
|
322
|
+
}
|
|
323
|
+
startRun(text, attachments = []) {
|
|
320
324
|
const run = this.handleCommandOrPrompt(text, attachments).catch((error) => {
|
|
321
325
|
this.append({ kind: "error", text: error instanceof Error ? error.message : String(error) });
|
|
322
326
|
this.setBusy(false);
|
|
@@ -327,7 +331,6 @@ export class WebRepl {
|
|
|
327
331
|
if (this.foregroundRun === run)
|
|
328
332
|
this.foregroundRun = undefined;
|
|
329
333
|
}).catch(() => undefined);
|
|
330
|
-
return { ok: true };
|
|
331
334
|
}
|
|
332
335
|
async listSessions() {
|
|
333
336
|
const sessions = await this.runtime.engine.listSessions(Number.POSITIVE_INFINITY);
|
|
@@ -413,7 +416,7 @@ export class WebRepl {
|
|
|
413
416
|
async saveLogin(providerValue, values) {
|
|
414
417
|
const provider = parseLoginProvider(providerValue);
|
|
415
418
|
if (!provider)
|
|
416
|
-
return { ok: false, error: "provider must be openai, deepseek, or kimi" };
|
|
419
|
+
return { ok: false, error: "provider must be openai, anthropic, deepseek, or kimi" };
|
|
417
420
|
const payload = { ...createLoginFormPayload(this.runtime.envPath, provider), provider, values };
|
|
418
421
|
const validationError = validateLoginFormPayload(payload);
|
|
419
422
|
if (validationError)
|
|
@@ -429,7 +432,6 @@ export class WebRepl {
|
|
|
429
432
|
this.runtime.agentRuntime.modelGateway = this.runtime.modelGateway;
|
|
430
433
|
this.runtime.engine.setModelProvider({ modelGateway: this.runtime.modelGateway, model: config.model, fallbackModel: config.fallbackModel, reasoning: config.defaultReasoning });
|
|
431
434
|
syncImageGenerationTool(this.runtime, config.provider);
|
|
432
|
-
syncVisionTool(this.runtime, config.model);
|
|
433
435
|
this.runtime.defaultReasoning = config.defaultReasoning;
|
|
434
436
|
const metrics = await this.runtime.engine.contextMetrics();
|
|
435
437
|
this.setStatus({ ...this.status, metrics, activityTick: this.status.activityTick + 1 });
|
|
@@ -446,6 +448,14 @@ export class WebRepl {
|
|
|
446
448
|
const interrupted = this.stopForegroundRun("Interrupted from neo web");
|
|
447
449
|
return { ok: true, interrupted };
|
|
448
450
|
}
|
|
451
|
+
cancelQueue() {
|
|
452
|
+
const had = this.queuedInput !== undefined;
|
|
453
|
+
this.queuedInput = undefined;
|
|
454
|
+
this.queuedAttachments = undefined;
|
|
455
|
+
if (had)
|
|
456
|
+
this.broadcastSync();
|
|
457
|
+
return { ok: true, cancelled: had };
|
|
458
|
+
}
|
|
449
459
|
append(line) {
|
|
450
460
|
const id = ++this.lineId;
|
|
451
461
|
this.lines.push({ id, ...line });
|
|
@@ -490,6 +500,7 @@ export class WebRepl {
|
|
|
490
500
|
this.activeAbortController = undefined;
|
|
491
501
|
this.interruptArmed = false;
|
|
492
502
|
this.queuedInput = undefined;
|
|
503
|
+
this.queuedAttachments = undefined;
|
|
493
504
|
this.finalizeForegroundView();
|
|
494
505
|
this.busy = false;
|
|
495
506
|
this.status = { ...this.status, phase: "ready", detail: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined };
|
|
@@ -534,6 +545,7 @@ export class WebRepl {
|
|
|
534
545
|
this.activeAbortController = undefined;
|
|
535
546
|
this.interruptArmed = false;
|
|
536
547
|
this.queuedInput = undefined;
|
|
548
|
+
this.queuedAttachments = undefined;
|
|
537
549
|
this.busy = false;
|
|
538
550
|
this.status = { ...this.status, phase: "ready", detail: undefined };
|
|
539
551
|
this.append(systemLine(`Detached running ${sessionId} to background for ${reason}.`));
|
|
@@ -794,9 +806,19 @@ export class WebRepl {
|
|
|
794
806
|
this.activeAbortController = undefined;
|
|
795
807
|
this.interruptArmed = false;
|
|
796
808
|
this.finalizeForegroundView();
|
|
797
|
-
this.
|
|
798
|
-
|
|
799
|
-
this.
|
|
809
|
+
const queuedText = this.queuedInput;
|
|
810
|
+
const queuedAttach = this.queuedAttachments;
|
|
811
|
+
this.queuedInput = undefined;
|
|
812
|
+
this.queuedAttachments = undefined;
|
|
813
|
+
if (queuedText !== undefined) {
|
|
814
|
+
this.startRun(queuedText, queuedAttach ?? []);
|
|
815
|
+
this.broadcastSync();
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
this.setBusy(false);
|
|
819
|
+
this.setStatus({ ...this.status, phase: "ready", detail: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined });
|
|
820
|
+
this.broadcastSync();
|
|
821
|
+
}
|
|
800
822
|
}
|
|
801
823
|
}
|
|
802
824
|
async runCompaction(type) {
|
|
@@ -870,6 +892,8 @@ async function route(req, res, router) {
|
|
|
870
892
|
}
|
|
871
893
|
if (req.method === "POST" && url.pathname === "/api/interrupt")
|
|
872
894
|
return sendJson(res, repl.interrupt());
|
|
895
|
+
if (req.method === "POST" && url.pathname === "/api/queue/cancel")
|
|
896
|
+
return sendJson(res, repl.cancelQueue());
|
|
873
897
|
if (req.method === "GET" && url.pathname === "/api/sessions")
|
|
874
898
|
return sendJson(res, await repl.listSessions());
|
|
875
899
|
if (req.method === "POST" && url.pathname === "/api/sessions/resume") {
|
|
@@ -1086,7 +1110,6 @@ async function handleModelCommand(command, runtime) {
|
|
|
1086
1110
|
runtime.agentRuntime.modelGateway = runtime.modelGateway;
|
|
1087
1111
|
runtime.engine.setModelProvider({ modelGateway: runtime.modelGateway, model: config.model, fallbackModel: config.fallbackModel, reasoning: config.defaultReasoning });
|
|
1088
1112
|
syncImageGenerationTool(runtime, config.provider);
|
|
1089
|
-
syncVisionTool(runtime, config.model);
|
|
1090
1113
|
runtime.defaultReasoning = config.defaultReasoning;
|
|
1091
1114
|
}
|
|
1092
1115
|
}
|
|
@@ -1137,14 +1160,14 @@ async function persistModelCommandSettings(runtime, command, reasoningUpdate) {
|
|
|
1137
1160
|
return { providerChanged: targetProvider !== currentProvider };
|
|
1138
1161
|
}
|
|
1139
1162
|
function currentModelProvider() {
|
|
1140
|
-
return parseLoginProvider(process.env.MODEL_PROVIDER) ?? "openai";
|
|
1163
|
+
return parseLoginProvider(process.env.MODEL_PROVIDER) ?? (process.env.ANTHROPIC_API_KEY ? "anthropic" : "openai");
|
|
1141
1164
|
}
|
|
1142
1165
|
function parseLoginProvider(value) {
|
|
1143
|
-
if (value === "openai" || value === "deepseek" || value === "kimi")
|
|
1166
|
+
if (value === "openai" || value === "anthropic" || value === "deepseek" || value === "kimi")
|
|
1144
1167
|
return value;
|
|
1145
1168
|
return undefined;
|
|
1146
1169
|
}
|
|
1147
|
-
const LOGIN_PROVIDERS = ["openai", "deepseek", "kimi"];
|
|
1170
|
+
const LOGIN_PROVIDERS = ["openai", "anthropic", "deepseek", "kimi"];
|
|
1148
1171
|
const SHARED_LOGIN_FIELDS = [
|
|
1149
1172
|
{ key: "reasoningEffort", label: "Reasoning effort", envKey: "MODEL_REASONING_EFFORT", scope: "shared", options: ["", "off", "none", "minimal", "low", "medium", "high", "xhigh", "max"] },
|
|
1150
1173
|
{ key: "reasoningSummary", label: "Reasoning summary", envKey: "MODEL_REASONING_SUMMARY", scope: "shared", options: ["", "auto", "concise", "detailed"] },
|
|
@@ -1162,6 +1185,14 @@ const LOGIN_FIELD_DEFINITIONS = {
|
|
|
1162
1185
|
{ key: "endpoint", label: "Endpoint", envKey: "OPENAI_ENDPOINT", scope: "provider", placeholder: "auto", options: ["auto", "responses", "chat"] },
|
|
1163
1186
|
...SHARED_LOGIN_FIELDS,
|
|
1164
1187
|
],
|
|
1188
|
+
anthropic: [
|
|
1189
|
+
{ key: "apiKey", label: "API key", envKey: "ANTHROPIC_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-ant-..." },
|
|
1190
|
+
{ key: "baseUrl", label: "Base URL", envKey: "ANTHROPIC_BASE_URL", scope: "provider", placeholder: "https://api.anthropic.com" },
|
|
1191
|
+
{ key: "model", label: "Model", envKey: "ANTHROPIC_MODEL", scope: "provider", required: true, placeholder: "claude-sonnet-4-6" },
|
|
1192
|
+
{ key: "fallbackModel", label: "Fallback model", envKey: "ANTHROPIC_FALLBACK_MODEL", scope: "provider" },
|
|
1193
|
+
{ key: "version", label: "Anthropic version", envKey: "ANTHROPIC_VERSION", scope: "provider", placeholder: "2023-06-01" },
|
|
1194
|
+
...SHARED_LOGIN_FIELDS,
|
|
1195
|
+
],
|
|
1165
1196
|
deepseek: [
|
|
1166
1197
|
{ key: "apiKey", label: "API key", envKey: "DEEPSEEK_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-..." },
|
|
1167
1198
|
{ key: "baseUrl", label: "Base URL", envKey: "DEEPSEEK_BASE_URL", scope: "provider", placeholder: "https://api.deepseek.com" },
|
|
@@ -1180,6 +1211,7 @@ const LOGIN_FIELD_DEFINITIONS = {
|
|
|
1180
1211
|
const DEPRECATED_MODEL_ENV_KEYS = [
|
|
1181
1212
|
"MODEL_API_KEY", "MODEL_BASE_URL", "MODEL_ID", "MODEL_FALLBACK_ID", "MODEL_ENDPOINT", "OPENAI_PROVIDER",
|
|
1182
1213
|
"OPENAI_REASONING_EFFORT", "OPENAI_REASONING_SUMMARY", "OPENAI_MAX_OUTPUT_TOKENS", "OPENAI_TIMEOUT_MS", "OPENAI_STREAM_IDLE_TIMEOUT_MS", "OPENAI_MAX_RETRIES",
|
|
1214
|
+
"ANTHROPIC_REASONING_EFFORT", "ANTHROPIC_REASONING_SUMMARY", "ANTHROPIC_MAX_OUTPUT_TOKENS", "ANTHROPIC_TIMEOUT_MS", "ANTHROPIC_STREAM_IDLE_TIMEOUT_MS", "ANTHROPIC_MAX_RETRIES",
|
|
1183
1215
|
"DEEPSEEK_REASONING_EFFORT", "DEEPSEEK_REASONING_SUMMARY", "DEEPSEEK_MAX_OUTPUT_TOKENS", "DEEPSEEK_TIMEOUT_MS", "DEEPSEEK_STREAM_IDLE_TIMEOUT_MS", "DEEPSEEK_MAX_RETRIES",
|
|
1184
1216
|
"KIMI_REASONING_EFFORT", "KIMI_REASONING_SUMMARY", "KIMI_MAX_OUTPUT_TOKENS", "KIMI_TIMEOUT_MS", "KIMI_STREAM_IDLE_TIMEOUT_MS", "KIMI_MAX_RETRIES",
|
|
1185
1217
|
"MOONSHOT_REASONING_EFFORT", "MOONSHOT_REASONING_SUMMARY", "MOONSHOT_MAX_OUTPUT_TOKENS", "MOONSHOT_TIMEOUT_MS", "MOONSHOT_STREAM_IDLE_TIMEOUT_MS", "MOONSHOT_MAX_RETRIES",
|
|
@@ -1218,9 +1250,13 @@ function guessLoginProvider(env) {
|
|
|
1218
1250
|
return "kimi";
|
|
1219
1251
|
if (env.DEEPSEEK_API_KEY ?? process.env.DEEPSEEK_API_KEY)
|
|
1220
1252
|
return "deepseek";
|
|
1253
|
+
if (env.ANTHROPIC_API_KEY ?? process.env.ANTHROPIC_API_KEY)
|
|
1254
|
+
return "anthropic";
|
|
1221
1255
|
return currentModelProvider();
|
|
1222
1256
|
}
|
|
1223
1257
|
function defaultBaseUrlForLoginProvider(provider) {
|
|
1258
|
+
if (provider === "anthropic")
|
|
1259
|
+
return "https://api.anthropic.com";
|
|
1224
1260
|
if (provider === "deepseek")
|
|
1225
1261
|
return "https://api.deepseek.com";
|
|
1226
1262
|
if (provider === "kimi")
|
|
@@ -1228,6 +1264,8 @@ function defaultBaseUrlForLoginProvider(provider) {
|
|
|
1228
1264
|
return "https://api.openai.com";
|
|
1229
1265
|
}
|
|
1230
1266
|
function defaultModelForLoginProvider(provider) {
|
|
1267
|
+
if (provider === "anthropic")
|
|
1268
|
+
return "claude-sonnet-4-6";
|
|
1231
1269
|
if (provider === "deepseek")
|
|
1232
1270
|
return "deepseek-chat";
|
|
1233
1271
|
if (provider === "kimi")
|
|
@@ -1288,6 +1326,8 @@ function stripEnvQuotes(value) {
|
|
|
1288
1326
|
return value;
|
|
1289
1327
|
}
|
|
1290
1328
|
function modelEnvKeyForProvider(provider) {
|
|
1329
|
+
if (provider === "anthropic")
|
|
1330
|
+
return "ANTHROPIC_MODEL";
|
|
1291
1331
|
if (provider === "deepseek")
|
|
1292
1332
|
return "DEEPSEEK_MODEL";
|
|
1293
1333
|
if (provider === "kimi")
|
|
@@ -1859,12 +1899,12 @@ function formatUsageTotals(totals) {
|
|
|
1859
1899
|
function formatManualCompaction(result) {
|
|
1860
1900
|
if (!result.changed)
|
|
1861
1901
|
return "No context compaction was needed.";
|
|
1862
|
-
return `context compacted: ${result.messages.length} message(s) retained, ${formatNumber(result.tokensFreed ?? 0)} chars removed`;
|
|
1902
|
+
return `context compacted: ${result.messages.length} message(s) retained, ${formatNumber(result.charsFreed ?? result.tokensFreed ?? 0)} chars removed`;
|
|
1863
1903
|
}
|
|
1864
1904
|
function formatPureCompaction(result) {
|
|
1865
1905
|
if (!result.changed)
|
|
1866
1906
|
return "No context available to purify.";
|
|
1867
|
-
return `pure context compacted: ${result.messages.length} sanitized message(s) retained, ${formatNumber(result.tokensFreed ?? 0)} chars removed; raw command/log/code details omitted`;
|
|
1907
|
+
return `pure context compacted: ${result.messages.length} sanitized message(s) retained, ${formatNumber(result.charsFreed ?? result.tokensFreed ?? 0)} chars removed; raw command/log/code details omitted`;
|
|
1868
1908
|
}
|
|
1869
1909
|
function formatNumber(value) {
|
|
1870
1910
|
return value === undefined ? "?" : new Intl.NumberFormat("en-US").format(Math.round(value));
|