neoctl 0.1.20 → 0.1.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/dist/context/prompts.js +2 -2
- package/dist/context/prompts.js.map +1 -1
- package/dist/core/query-engine.d.ts +1 -0
- package/dist/core/query-engine.js +16 -5
- package/dist/core/query-engine.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/builtins/image-generation-tool.d.ts +2 -0
- package/dist/tools/builtins/image-generation-tool.js +94 -31
- package/dist/tools/builtins/image-generation-tool.js.map +1 -1
- package/dist/web/index.d.ts +239 -0
- package/dist/web/index.js +61 -10
- package/dist/web/index.js.map +1 -1
- package/package.json +1 -1
package/dist/web/index.d.ts
CHANGED
|
@@ -1,2 +1,241 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { type ServerResponse } from "node:http";
|
|
3
|
+
import { QueryEngine } from "../core/query-engine.js";
|
|
4
|
+
import { type ModelProviderName } from "../model/config.js";
|
|
5
|
+
import { CommunicationLogger, LoggingModelGateway } from "../model/communication-logger.js";
|
|
6
|
+
import type { ModelUsage, ReasoningConfig } from "../model/model-gateway.js";
|
|
7
|
+
import { ToolRegistry } from "../tools/registry.js";
|
|
8
|
+
import { type AgentToolRuntime } from "../agents/agent-tool.js";
|
|
9
|
+
import { TaskStore } from "../tasks/task-store.js";
|
|
10
|
+
import type { ContextMetrics } from "../types/events.js";
|
|
11
|
+
export interface WebRuntime {
|
|
12
|
+
engine: QueryEngine;
|
|
13
|
+
communicationLogger: CommunicationLogger;
|
|
14
|
+
modelGateway: LoggingModelGateway;
|
|
15
|
+
agentRuntime: AgentToolRuntime;
|
|
16
|
+
usage: SessionUsageTracker;
|
|
17
|
+
taskStore: TaskStore;
|
|
18
|
+
tools: ToolRegistry;
|
|
19
|
+
initialMetrics: ContextMetrics;
|
|
20
|
+
defaultReasoning?: ReasoningConfig | null;
|
|
21
|
+
envPath: string;
|
|
22
|
+
envNotice?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface UsageTotals {
|
|
25
|
+
inputTokens: number;
|
|
26
|
+
outputTokens: number;
|
|
27
|
+
totalTokens: number;
|
|
28
|
+
reasoningTokens: number;
|
|
29
|
+
cachedTokens: number;
|
|
30
|
+
requests: number;
|
|
31
|
+
computedTotalTokens: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare class SessionUsageTracker {
|
|
34
|
+
private totals;
|
|
35
|
+
private lastUsage?;
|
|
36
|
+
add(usage: ModelUsage): void;
|
|
37
|
+
reset(): void;
|
|
38
|
+
snapshot(): UsageTotals;
|
|
39
|
+
}
|
|
40
|
+
interface UiLineImage {
|
|
41
|
+
src: string;
|
|
42
|
+
label?: string;
|
|
43
|
+
mimeType: string;
|
|
44
|
+
}
|
|
45
|
+
interface UiLine {
|
|
46
|
+
id: number;
|
|
47
|
+
kind: "system" | "user" | "assistant" | "thinking" | "tool" | "error" | "meta";
|
|
48
|
+
text: string;
|
|
49
|
+
title?: string;
|
|
50
|
+
bodyTitle?: string;
|
|
51
|
+
titleStatus?: "success" | "failure";
|
|
52
|
+
format?: "markdown" | "ansi" | "plain" | "diff";
|
|
53
|
+
previewStyle?: "summary";
|
|
54
|
+
summaryMaxLines?: number;
|
|
55
|
+
live?: boolean;
|
|
56
|
+
pendingReplacement?: boolean;
|
|
57
|
+
collapsible?: boolean;
|
|
58
|
+
image?: UiLineImage;
|
|
59
|
+
}
|
|
60
|
+
interface UiStatus {
|
|
61
|
+
phase: string;
|
|
62
|
+
detail?: string;
|
|
63
|
+
metrics?: ContextMetrics;
|
|
64
|
+
usage?: ModelUsage;
|
|
65
|
+
streamedOutputTokens: number;
|
|
66
|
+
activityTick: number;
|
|
67
|
+
inputTokenUpdatedAt?: number;
|
|
68
|
+
outputTokenUpdatedAt?: number;
|
|
69
|
+
retryCooldownUntil?: number;
|
|
70
|
+
}
|
|
71
|
+
export interface WebServerOptions {
|
|
72
|
+
host: string;
|
|
73
|
+
port: number;
|
|
74
|
+
}
|
|
75
|
+
export interface CreateWebRuntimeOptions {
|
|
76
|
+
/** Override the initial session id for this runtime. */
|
|
77
|
+
sessionId?: string;
|
|
78
|
+
/** Override whether the initial session should resume transcript history. */
|
|
79
|
+
resume?: boolean;
|
|
80
|
+
/** Override the QueryEngine agent id. Defaults to main. */
|
|
81
|
+
agentId?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface WebRuntimeScope {
|
|
84
|
+
/** Browser-tab or client-instance identifier. Omit for the legacy singleton runtime. */
|
|
85
|
+
tabId?: string;
|
|
86
|
+
/** Optional session id used when a scoped runtime is created after page refresh/process restart. */
|
|
87
|
+
sessionId?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface WebRuntimeRouterOptions {
|
|
90
|
+
createRuntime?: (options?: CreateWebRuntimeOptions) => Promise<WebRuntime>;
|
|
91
|
+
createRepl?: (runtime: WebRuntime) => WebRepl;
|
|
92
|
+
}
|
|
93
|
+
type LoginProviderName = ModelProviderName;
|
|
94
|
+
interface LoginFieldDefinition {
|
|
95
|
+
key: string;
|
|
96
|
+
label: string;
|
|
97
|
+
envKey: string;
|
|
98
|
+
scope: "provider" | "shared";
|
|
99
|
+
required?: boolean;
|
|
100
|
+
secret?: boolean;
|
|
101
|
+
placeholder?: string;
|
|
102
|
+
options?: readonly string[];
|
|
103
|
+
}
|
|
104
|
+
interface LoginFormPayload {
|
|
105
|
+
envPath: string;
|
|
106
|
+
providers: LoginProviderName[];
|
|
107
|
+
provider: LoginProviderName;
|
|
108
|
+
fields: LoginFieldDefinition[];
|
|
109
|
+
values: Record<string, string>;
|
|
110
|
+
}
|
|
111
|
+
interface WebAttachmentPayload {
|
|
112
|
+
kind: "image";
|
|
113
|
+
label: string;
|
|
114
|
+
mimeType: string;
|
|
115
|
+
data: string;
|
|
116
|
+
}
|
|
2
117
|
export declare function runWebServer(argv?: string[]): Promise<void>;
|
|
118
|
+
export declare function createWebRuntime(options?: CreateWebRuntimeOptions): Promise<WebRuntime>;
|
|
119
|
+
export declare class WebRuntimeRouter {
|
|
120
|
+
private readonly repls;
|
|
121
|
+
private readonly createRuntime;
|
|
122
|
+
private readonly createRepl;
|
|
123
|
+
constructor(options?: WebRuntimeRouterOptions);
|
|
124
|
+
get(scope?: WebRuntimeScope): Promise<WebRepl>;
|
|
125
|
+
snapshot(scope?: WebRuntimeScope, includeCatalog?: boolean): Promise<ReturnType<WebRepl["snapshot"]>>;
|
|
126
|
+
activeScopes(): string[];
|
|
127
|
+
}
|
|
128
|
+
export declare function createWebRuntimeRouter(options?: WebRuntimeRouterOptions): Promise<WebRuntimeRouter>;
|
|
129
|
+
export declare class WebRepl {
|
|
130
|
+
private runtime;
|
|
131
|
+
private readonly subscribers;
|
|
132
|
+
private lineId;
|
|
133
|
+
private assistantLineId;
|
|
134
|
+
private thinkingLineId;
|
|
135
|
+
private finalizedThinkingLineId;
|
|
136
|
+
private activeAbortController;
|
|
137
|
+
private interruptArmed;
|
|
138
|
+
private readonly toolLineIds;
|
|
139
|
+
private lines;
|
|
140
|
+
private status;
|
|
141
|
+
private busy;
|
|
142
|
+
private queuedInput;
|
|
143
|
+
private foregroundRun;
|
|
144
|
+
private foregroundRunToken;
|
|
145
|
+
private readonly backgroundSessionRuns;
|
|
146
|
+
private readonly suppressReattachedStreaming;
|
|
147
|
+
private backgroundTaskCount;
|
|
148
|
+
constructor(runtime: WebRuntime);
|
|
149
|
+
subscribe(res: ServerResponse): void;
|
|
150
|
+
snapshot(includeCatalog?: boolean): {
|
|
151
|
+
lines: UiLine[];
|
|
152
|
+
status: UiStatus;
|
|
153
|
+
busy: boolean;
|
|
154
|
+
queuedInput: string | undefined;
|
|
155
|
+
backgroundTaskCount: number;
|
|
156
|
+
backgroundTasks: {
|
|
157
|
+
taskId: string;
|
|
158
|
+
agentId: string;
|
|
159
|
+
type: import("../index.js").LocalAgentTaskType;
|
|
160
|
+
status: import("../index.js").LocalAgentTaskStatus;
|
|
161
|
+
description: string;
|
|
162
|
+
createdAt: string;
|
|
163
|
+
}[];
|
|
164
|
+
backgroundSessionRunCount: number;
|
|
165
|
+
runningSessionIds: string[];
|
|
166
|
+
session: import("../index.js").SessionStoreSnapshot | undefined;
|
|
167
|
+
catalog: {
|
|
168
|
+
commands: import("../repl/commands.js").ReplCommandDefinition[];
|
|
169
|
+
modelIds: string[];
|
|
170
|
+
reasoning: string[];
|
|
171
|
+
envPath: string;
|
|
172
|
+
} | undefined;
|
|
173
|
+
interactive: {
|
|
174
|
+
sessions: boolean;
|
|
175
|
+
login: LoginFormPayload;
|
|
176
|
+
} | undefined;
|
|
177
|
+
tips: import("../tips.js").AppTip[] | undefined;
|
|
178
|
+
tipIndex: number;
|
|
179
|
+
};
|
|
180
|
+
submit(text: string, attachments?: WebAttachmentPayload[]): Promise<{
|
|
181
|
+
ok: true;
|
|
182
|
+
} | {
|
|
183
|
+
ok: false;
|
|
184
|
+
error: string;
|
|
185
|
+
}>;
|
|
186
|
+
listSessions(): Promise<{
|
|
187
|
+
sessions: import("../index.js").SessionSummary[];
|
|
188
|
+
runningSessionIds: string[];
|
|
189
|
+
}>;
|
|
190
|
+
resumeSession(sessionId: string): Promise<{
|
|
191
|
+
ok: true;
|
|
192
|
+
} | {
|
|
193
|
+
ok: false;
|
|
194
|
+
error: string;
|
|
195
|
+
}>;
|
|
196
|
+
newSession(): Promise<{
|
|
197
|
+
ok: true;
|
|
198
|
+
} | {
|
|
199
|
+
ok: false;
|
|
200
|
+
error: string;
|
|
201
|
+
}>;
|
|
202
|
+
private refreshSessionView;
|
|
203
|
+
deleteSession(sessionId: string): Promise<{
|
|
204
|
+
ok: true;
|
|
205
|
+
} | {
|
|
206
|
+
ok: false;
|
|
207
|
+
error: string;
|
|
208
|
+
}>;
|
|
209
|
+
loginForm(providerValue?: string): LoginFormPayload;
|
|
210
|
+
saveLogin(providerValue: string, values: Record<string, string>): Promise<{
|
|
211
|
+
ok: true;
|
|
212
|
+
} | {
|
|
213
|
+
ok: false;
|
|
214
|
+
error: string;
|
|
215
|
+
}>;
|
|
216
|
+
interrupt(): {
|
|
217
|
+
ok: true;
|
|
218
|
+
interrupted: boolean;
|
|
219
|
+
};
|
|
220
|
+
private append;
|
|
221
|
+
private updateLine;
|
|
222
|
+
private replaceLineText;
|
|
223
|
+
private replaceLine;
|
|
224
|
+
private setBusy;
|
|
225
|
+
private setStatus;
|
|
226
|
+
private finalizeForegroundView;
|
|
227
|
+
private stopForegroundRun;
|
|
228
|
+
private backgroundTasks;
|
|
229
|
+
private detachRunningForeground;
|
|
230
|
+
private reattachRunningSession;
|
|
231
|
+
private reduce;
|
|
232
|
+
private finalizeLiveLine;
|
|
233
|
+
private finalizeThinkingLine;
|
|
234
|
+
private finalizeActiveToolLines;
|
|
235
|
+
private handleEvent;
|
|
236
|
+
private handleCommandOrPrompt;
|
|
237
|
+
private runCompaction;
|
|
238
|
+
private send;
|
|
239
|
+
private broadcastSync;
|
|
240
|
+
}
|
|
241
|
+
export {};
|
package/dist/web/index.js
CHANGED
|
@@ -34,7 +34,7 @@ const highlightPackageDir = path.dirname(require.resolve("@highlightjs/cdn-asset
|
|
|
34
34
|
const markedAssetPath = path.join(markedPackageDir, "lib", "marked.esm.js");
|
|
35
35
|
const highlightAssetPath = path.join(highlightPackageDir, "highlight.min.js");
|
|
36
36
|
const highlightThemeAssetPath = path.join(highlightPackageDir, "styles", "atom-one-dark.min.css");
|
|
37
|
-
class SessionUsageTracker {
|
|
37
|
+
export class SessionUsageTracker {
|
|
38
38
|
totals = emptyUsageTotals();
|
|
39
39
|
lastUsage;
|
|
40
40
|
add(usage) {
|
|
@@ -78,11 +78,11 @@ function sumUsageTokens(left, right) {
|
|
|
78
78
|
return undefined;
|
|
79
79
|
return (left ?? 0) + (right ?? 0);
|
|
80
80
|
}
|
|
81
|
+
const DEFAULT_WEB_RUNTIME_KEY = "__default__";
|
|
81
82
|
export async function runWebServer(argv = process.argv.slice(2)) {
|
|
82
83
|
const options = parseWebArgs(argv);
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const server = http.createServer((req, res) => void route(req, res, repl));
|
|
84
|
+
const router = await createWebRuntimeRouter();
|
|
85
|
+
const server = http.createServer((req, res) => void route(req, res, router));
|
|
86
86
|
await new Promise((resolve) => server.listen(options.port, options.host, resolve));
|
|
87
87
|
const address = server.address();
|
|
88
88
|
const actualPort = typeof address === "object" && address ? address.port : options.port;
|
|
@@ -106,7 +106,7 @@ function parseWebArgs(argv) {
|
|
|
106
106
|
port = 3000;
|
|
107
107
|
return { host, port: Math.round(port) };
|
|
108
108
|
}
|
|
109
|
-
async function
|
|
109
|
+
export async function createWebRuntime(options = {}) {
|
|
110
110
|
const envLoad = loadDefaultDotEnvFiles({ override: true });
|
|
111
111
|
const modelConfig = readModelProviderConfig(process.env);
|
|
112
112
|
const communicationLogger = new CommunicationLogger();
|
|
@@ -137,7 +137,7 @@ async function createRuntime() {
|
|
|
137
137
|
for (const tool of createTaskTools(taskStore, resumeHandler))
|
|
138
138
|
tools.register(tool);
|
|
139
139
|
const engine = new QueryEngine({
|
|
140
|
-
agentId: "main",
|
|
140
|
+
agentId: options.agentId ?? "main",
|
|
141
141
|
model: modelConfig?.model,
|
|
142
142
|
fallbackModel: modelConfig?.fallbackModel,
|
|
143
143
|
reasoning: modelConfig?.defaultReasoning,
|
|
@@ -148,9 +148,9 @@ async function createRuntime() {
|
|
|
148
148
|
commands: replCommandDefinitions.map((command) => command.usage),
|
|
149
149
|
session: {
|
|
150
150
|
enabled: process.env.AGENT_SESSION_TRANSCRIPT !== "0",
|
|
151
|
-
sessionId: process.env.AGENT_SESSION_ID,
|
|
151
|
+
sessionId: options.sessionId ?? process.env.AGENT_SESSION_ID,
|
|
152
152
|
rootDir: process.env.AGENT_SESSION_DIR,
|
|
153
|
-
resume: parseResumeFlag(process.env.AGENT_SESSION_RESUME),
|
|
153
|
+
resume: options.resume ?? parseResumeFlag(process.env.AGENT_SESSION_RESUME),
|
|
154
154
|
toolResultThresholdChars: process.env.AGENT_TOOL_RESULT_THRESHOLD_CHARS ? Number(process.env.AGENT_TOOL_RESULT_THRESHOLD_CHARS) : undefined,
|
|
155
155
|
},
|
|
156
156
|
});
|
|
@@ -199,7 +199,46 @@ function parseResumeFlag(value) {
|
|
|
199
199
|
return false;
|
|
200
200
|
return ["1", "true", "yes", "latest"].includes(value.toLowerCase());
|
|
201
201
|
}
|
|
202
|
-
class
|
|
202
|
+
export class WebRuntimeRouter {
|
|
203
|
+
repls = new Map();
|
|
204
|
+
createRuntime;
|
|
205
|
+
createRepl;
|
|
206
|
+
constructor(options = {}) {
|
|
207
|
+
this.createRuntime = options.createRuntime ?? createWebRuntime;
|
|
208
|
+
this.createRepl = options.createRepl ?? ((runtime) => new WebRepl(runtime));
|
|
209
|
+
}
|
|
210
|
+
get(scope = {}) {
|
|
211
|
+
const key = webRuntimeScopeKey(scope);
|
|
212
|
+
let repl = this.repls.get(key);
|
|
213
|
+
if (!repl) {
|
|
214
|
+
repl = this.createRuntime({ sessionId: scope.sessionId, resume: scope.sessionId ? true : scope.tabId ? false : undefined }).then((runtime) => this.createRepl(runtime));
|
|
215
|
+
this.repls.set(key, repl);
|
|
216
|
+
repl.catch(() => this.repls.delete(key));
|
|
217
|
+
}
|
|
218
|
+
return repl;
|
|
219
|
+
}
|
|
220
|
+
async snapshot(scope = {}, includeCatalog = true) {
|
|
221
|
+
return (await this.get(scope)).snapshot(includeCatalog);
|
|
222
|
+
}
|
|
223
|
+
activeScopes() {
|
|
224
|
+
return [...this.repls.keys()];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
export async function createWebRuntimeRouter(options = {}) {
|
|
228
|
+
const router = new WebRuntimeRouter(options);
|
|
229
|
+
await router.get();
|
|
230
|
+
return router;
|
|
231
|
+
}
|
|
232
|
+
function webRuntimeScopeKey(scope) {
|
|
233
|
+
const tabId = scope.tabId?.trim();
|
|
234
|
+
if (tabId)
|
|
235
|
+
return `tab:${tabId}`;
|
|
236
|
+
const sessionId = scope.sessionId?.trim();
|
|
237
|
+
if (sessionId)
|
|
238
|
+
return `session:${sessionId}`;
|
|
239
|
+
return DEFAULT_WEB_RUNTIME_KEY;
|
|
240
|
+
}
|
|
241
|
+
export class WebRepl {
|
|
203
242
|
runtime;
|
|
204
243
|
subscribers = new Set();
|
|
205
244
|
lineId = 0;
|
|
@@ -801,7 +840,7 @@ function reqKeepAlive(res) {
|
|
|
801
840
|
timer.unref?.();
|
|
802
841
|
res.on("close", () => clearInterval(timer));
|
|
803
842
|
}
|
|
804
|
-
async function route(req, res,
|
|
843
|
+
async function route(req, res, router) {
|
|
805
844
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
806
845
|
try {
|
|
807
846
|
if (req.method === "GET" && url.pathname === "/")
|
|
@@ -812,6 +851,8 @@ async function route(req, res, repl) {
|
|
|
812
851
|
return sendFile(res, highlightAssetPath, "text/javascript; charset=utf-8");
|
|
813
852
|
if (req.method === "GET" && url.pathname === "/vendor/highlight-theme.css")
|
|
814
853
|
return sendFile(res, highlightThemeAssetPath, "text/css; charset=utf-8");
|
|
854
|
+
const scope = webRuntimeScopeFromUrl(url);
|
|
855
|
+
const repl = await router.get(scope);
|
|
815
856
|
if (req.method === "GET" && url.pathname === "/events")
|
|
816
857
|
return repl.subscribe(res);
|
|
817
858
|
if (req.method === "GET" && url.pathname === "/api/state")
|
|
@@ -846,6 +887,16 @@ async function route(req, res, repl) {
|
|
|
846
887
|
sendJson(res, { error: error instanceof Error ? error.message : String(error) }, 500);
|
|
847
888
|
}
|
|
848
889
|
}
|
|
890
|
+
function webRuntimeScopeFromUrl(url) {
|
|
891
|
+
return {
|
|
892
|
+
tabId: optionalSearchParam(url, "tabId"),
|
|
893
|
+
sessionId: optionalSearchParam(url, "sessionId"),
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
function optionalSearchParam(url, key) {
|
|
897
|
+
const value = url.searchParams.get(key)?.trim();
|
|
898
|
+
return value ? value : undefined;
|
|
899
|
+
}
|
|
849
900
|
function sendHtml(res, body) {
|
|
850
901
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" });
|
|
851
902
|
res.end(body);
|