neoctl 0.2.38 → 0.2.40
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/context-manager.js +3 -2
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/prompt-config.test.js +4 -0
- package/dist/context/prompt-config.test.js.map +1 -1
- package/dist/context/prompts.d.ts +3 -0
- package/dist/context/prompts.js +10 -4
- package/dist/context/prompts.js.map +1 -1
- package/dist/context/system.md +1 -1
- package/dist/core/query-engine.d.ts +5 -2
- package/dist/core/query-engine.js +31 -13
- package/dist/core/query-engine.js.map +1 -1
- package/dist/core/query.js +2 -2
- package/dist/core/query.js.map +1 -1
- package/dist/core/session-prompt-inheritance.test.d.ts +1 -0
- package/dist/core/session-prompt-inheritance.test.js +132 -0
- package/dist/core/session-prompt-inheritance.test.js.map +1 -0
- package/dist/core/session-settings-prompt.d.ts +12 -4
- package/dist/core/session-settings-prompt.js +50 -27
- package/dist/core/session-settings-prompt.js.map +1 -1
- package/dist/core/session-settings-prompt.test.js +31 -22
- package/dist/core/session-settings-prompt.test.js.map +1 -1
- package/dist/execution/docker.d.ts +9 -0
- package/dist/execution/docker.js +75 -0
- package/dist/execution/docker.js.map +1 -0
- package/dist/execution/docker.test.d.ts +1 -0
- package/dist/execution/docker.test.js +57 -0
- package/dist/execution/docker.test.js.map +1 -0
- package/dist/execution/filesystem.d.ts +7 -0
- package/dist/execution/filesystem.js +76 -0
- package/dist/execution/filesystem.js.map +1 -0
- package/dist/execution/process.d.ts +8 -0
- package/dist/execution/process.js +62 -0
- package/dist/execution/process.js.map +1 -0
- package/dist/plugins/plugin-system.js +3 -0
- package/dist/plugins/plugin-system.js.map +1 -1
- package/dist/session/session-export.d.ts +4 -0
- package/dist/session/session-export.js.map +1 -1
- package/dist/session/session-store.js +4 -6
- package/dist/session/session-store.js.map +1 -1
- package/dist/session/tool-result-memory.js +9 -1
- package/dist/session/tool-result-memory.js.map +1 -1
- package/dist/tools/builtins/edit-tool.js +1 -1
- package/dist/tools/builtins/edit-tool.js.map +1 -1
- package/dist/tools/builtins/exec-process-manager.js +17 -11
- package/dist/tools/builtins/exec-process-manager.js.map +1 -1
- package/dist/tools/builtins/exec-tool.js +6 -3
- package/dist/tools/builtins/exec-tool.js.map +1 -1
- package/dist/tools/builtins/filesystem-tools.js +1 -1
- package/dist/tools/builtins/filesystem-tools.js.map +1 -1
- package/dist/tools/builtins/grep-tool.js +11 -4
- package/dist/tools/builtins/grep-tool.js.map +1 -1
- package/dist/tools/builtins/image-generation-tool.js +19 -6
- package/dist/tools/builtins/image-generation-tool.js.map +1 -1
- package/dist/tools/builtins/image-loader-tool.js +5 -3
- package/dist/tools/builtins/image-loader-tool.js.map +1 -1
- package/dist/web/index.d.ts +25 -8
- package/dist/web/index.js +126 -46
- package/dist/web/index.js.map +1 -1
- package/dist/web/session-prompt-integration.test.js +1 -1
- package/dist/web/session-prompt-integration.test.js.map +1 -1
- package/docs/prompt-config.md +19 -4
- package/package.json +1 -1
package/dist/web/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import http from "node:http";
|
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { dockerEnabled } from "../execution/docker.js";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { createRequire } from "node:module";
|
|
10
11
|
import { readSessionPrompt, updateSessionPrompt, SessionPromptError } from "./session-prompt-protocol.js";
|
|
@@ -104,7 +105,7 @@ const DEFAULT_WEB_RUNTIME_KEY = "__default__";
|
|
|
104
105
|
export async function runWebServer(argv = process.argv.slice(2), runtimeOptions = {}) {
|
|
105
106
|
const options = parseWebArgs(argv);
|
|
106
107
|
const router = await createWebRuntimeRouter(runtimeOptions);
|
|
107
|
-
const server = http.createServer((req, res) => void
|
|
108
|
+
const server = http.createServer((req, res) => void handleWebRequest(req, res, router));
|
|
108
109
|
await new Promise((resolve) => server.listen(options.port, options.host, resolve));
|
|
109
110
|
const address = server.address();
|
|
110
111
|
const actualPort = typeof address === "object" && address ? address.port : options.port;
|
|
@@ -194,6 +195,14 @@ export async function createWebRuntime(options = {}) {
|
|
|
194
195
|
modelGateway,
|
|
195
196
|
tools,
|
|
196
197
|
contextManagerFactory: (cwd) => new DefaultContextManager({ cwd }),
|
|
198
|
+
refreshTools: () => {
|
|
199
|
+
if (!options.resolveGlobalToolOverrides)
|
|
200
|
+
return;
|
|
201
|
+
if (runtime)
|
|
202
|
+
refreshGlobalToolOverrides(runtime);
|
|
203
|
+
else
|
|
204
|
+
applyToolOverrides(tools, toolCatalog, normalizeToolOverrides(options.resolveGlobalToolOverrides(), toolCatalog), sessionToolOverrides);
|
|
205
|
+
},
|
|
197
206
|
additionalPromptSections: [
|
|
198
207
|
...(options.externalPromptSections ?? []),
|
|
199
208
|
...activePlugins.flatMap((plugin) => plugin.promptSections ?? []),
|
|
@@ -207,7 +216,7 @@ export async function createWebRuntime(options = {}) {
|
|
|
207
216
|
session: {
|
|
208
217
|
enabled: process.env.AGENT_SESSION_TRANSCRIPT !== "0",
|
|
209
218
|
sessionId: options.sessionId ?? process.env.AGENT_SESSION_ID,
|
|
210
|
-
rootDir: process.env.AGENT_SESSION_DIR,
|
|
219
|
+
rootDir: options.sessionRootDir ?? process.env.AGENT_SESSION_DIR,
|
|
211
220
|
resume: options.resume ?? parseResumeFlag(process.env.AGENT_SESSION_RESUME),
|
|
212
221
|
toolResultThresholdChars: process.env.AGENT_TOOL_RESULT_THRESHOLD_CHARS ? Number(process.env.AGENT_TOOL_RESULT_THRESHOLD_CHARS) : undefined,
|
|
213
222
|
},
|
|
@@ -242,6 +251,7 @@ export async function createWebRuntime(options = {}) {
|
|
|
242
251
|
globalOverrides: globalToolOverrides,
|
|
243
252
|
sessionOverrides: sessionToolOverrides,
|
|
244
253
|
persistGlobal: options.persistGlobalToolOverrides,
|
|
254
|
+
resolveGlobal: options.resolveGlobalToolOverrides,
|
|
245
255
|
persistSession: options.persistSessionToolOverrides,
|
|
246
256
|
resolveSession: options.resolveSessionToolOverrides,
|
|
247
257
|
},
|
|
@@ -279,6 +289,14 @@ function applyToolOverrides(registry, catalog, globalOverrides, sessionOverrides
|
|
|
279
289
|
for (const tool of catalog)
|
|
280
290
|
registry.setEnabled(tool.name, sessionOverrides[tool.name] ?? globalOverrides[tool.name] ?? true);
|
|
281
291
|
}
|
|
292
|
+
/** Called only at a safe turn boundary or while idle, never during tool execution. */
|
|
293
|
+
export function refreshGlobalToolOverrides(runtime) {
|
|
294
|
+
const support = runtime.toolSupport;
|
|
295
|
+
if (!support?.resolveGlobal)
|
|
296
|
+
return;
|
|
297
|
+
support.globalOverrides = normalizeToolOverrides(support.resolveGlobal(), support.catalog);
|
|
298
|
+
applyToolOverrides(runtime.tools, support.catalog, support.globalOverrides, support.sessionOverrides);
|
|
299
|
+
}
|
|
282
300
|
/** Bind only the foreground view; never stop work owned by another session. */
|
|
283
301
|
export function activateSession(runtime) {
|
|
284
302
|
const sessionDir = runtime.engine.snapshot().session?.sessionDir || undefined;
|
|
@@ -367,6 +385,14 @@ export class WebRuntimeRouter {
|
|
|
367
385
|
async snapshot(scope = {}, includeCatalog = true) {
|
|
368
386
|
return (await this.get(scope)).snapshot(includeCatalog);
|
|
369
387
|
}
|
|
388
|
+
async reloadModelConfig() {
|
|
389
|
+
const repls = await Promise.all([...this.repls.values()]);
|
|
390
|
+
await Promise.all(repls.map(repl => repl.reloadModelConfig()));
|
|
391
|
+
}
|
|
392
|
+
async reloadGlobalTools(overrides) {
|
|
393
|
+
const repls = await Promise.all([...this.repls.values()]);
|
|
394
|
+
await Promise.all(repls.map(repl => repl.reloadGlobalTools(overrides)));
|
|
395
|
+
}
|
|
370
396
|
activeScopes() {
|
|
371
397
|
return [...this.repls.keys()];
|
|
372
398
|
}
|
|
@@ -427,6 +453,8 @@ export class WebRepl {
|
|
|
427
453
|
queuedAttachments;
|
|
428
454
|
foregroundRun;
|
|
429
455
|
foregroundRunToken = 0;
|
|
456
|
+
stoppingRun;
|
|
457
|
+
immediateSend;
|
|
430
458
|
pendingUserImageEchoIds;
|
|
431
459
|
pendingUserImageEchoMessageId;
|
|
432
460
|
runtimeContextRevision = 0;
|
|
@@ -561,6 +589,7 @@ export class WebRepl {
|
|
|
561
589
|
};
|
|
562
590
|
}
|
|
563
591
|
globalTools() {
|
|
592
|
+
this.runtime.engine.refreshToolsIfIdle();
|
|
564
593
|
const support = this.runtime.toolSupport;
|
|
565
594
|
if (!support)
|
|
566
595
|
return { items: [] };
|
|
@@ -572,6 +601,7 @@ export class WebRepl {
|
|
|
572
601
|
};
|
|
573
602
|
}
|
|
574
603
|
sessionTools() {
|
|
604
|
+
this.runtime.engine.refreshToolsIfIdle();
|
|
575
605
|
const support = this.runtime.toolSupport;
|
|
576
606
|
const sessionId = this.runtime.engine.snapshot().session?.sessionId;
|
|
577
607
|
if (!support)
|
|
@@ -608,18 +638,25 @@ export class WebRepl {
|
|
|
608
638
|
if (!normalized.ok)
|
|
609
639
|
return normalized;
|
|
610
640
|
try {
|
|
611
|
-
|
|
612
|
-
this.syncPluginToolRegistration();
|
|
613
|
-
applyToolOverrides(this.runtime.tools, support.catalog, support.globalOverrides, support.sessionOverrides);
|
|
641
|
+
// Persist before publishing so a failed write never changes active capabilities.
|
|
614
642
|
if (support.persistGlobal)
|
|
615
|
-
await support.persistGlobal(
|
|
616
|
-
await this.
|
|
643
|
+
await support.persistGlobal(normalized.value);
|
|
644
|
+
await this.reloadGlobalTools(normalized.value);
|
|
617
645
|
return { ok: true, state: this.globalTools() };
|
|
618
646
|
}
|
|
619
647
|
catch (error) {
|
|
620
648
|
return actionFailure("TOOL_UPDATE_FAILED", error instanceof Error ? error.message : String(error));
|
|
621
649
|
}
|
|
622
650
|
}
|
|
651
|
+
async reloadGlobalTools(overrides) {
|
|
652
|
+
const support = this.runtime.toolSupport;
|
|
653
|
+
if (!support)
|
|
654
|
+
return;
|
|
655
|
+
support.globalOverrides = normalizeToolOverrides(overrides, support.catalog);
|
|
656
|
+
this.syncPluginToolRegistration();
|
|
657
|
+
applyToolOverrides(this.runtime.tools, support.catalog, support.globalOverrides, support.sessionOverrides);
|
|
658
|
+
await this.refreshToolConfiguration();
|
|
659
|
+
}
|
|
623
660
|
async setSessionTools(value) {
|
|
624
661
|
if (this.busy)
|
|
625
662
|
return actionFailure("TOOL_UPDATE_BLOCKED", "cannot change session tools while a response is running");
|
|
@@ -710,12 +747,14 @@ export class WebRepl {
|
|
|
710
747
|
const support = this.runtime.toolSupport;
|
|
711
748
|
if (!support)
|
|
712
749
|
return;
|
|
713
|
-
|
|
714
|
-
this.syncPluginToolRegistration();
|
|
715
|
-
applyToolOverrides(this.runtime.tools, support.catalog, support.globalOverrides, support.sessionOverrides);
|
|
750
|
+
const normalized = normalizeToolOverrides(overrides, support.catalog);
|
|
716
751
|
const sessionId = this.runtime.engine.snapshot().session?.sessionId;
|
|
717
752
|
if (persist && sessionId && support.persistSession)
|
|
718
|
-
await support.persistSession(sessionId,
|
|
753
|
+
await support.persistSession(sessionId, normalized);
|
|
754
|
+
support.sessionOverrides = normalized;
|
|
755
|
+
this.runtime.engine.refreshToolsIfIdle();
|
|
756
|
+
this.syncPluginToolRegistration();
|
|
757
|
+
applyToolOverrides(this.runtime.tools, support.catalog, support.globalOverrides, support.sessionOverrides);
|
|
719
758
|
await this.refreshToolConfiguration();
|
|
720
759
|
}
|
|
721
760
|
syncPluginToolRegistration() {
|
|
@@ -764,6 +803,8 @@ export class WebRepl {
|
|
|
764
803
|
this.publishRuntimeContext();
|
|
765
804
|
}
|
|
766
805
|
async submit(text, attachments = []) {
|
|
806
|
+
if (this.stoppingRun || this.immediateSend)
|
|
807
|
+
return { ok: false, error: "正在停止上一轮请求,请稍后发送" };
|
|
767
808
|
const trimmed = text.trim();
|
|
768
809
|
if (!trimmed && attachments.length === 0)
|
|
769
810
|
return { ok: true };
|
|
@@ -783,7 +824,11 @@ export class WebRepl {
|
|
|
783
824
|
this.startRun(text, attachments);
|
|
784
825
|
return { ok: true };
|
|
785
826
|
}
|
|
786
|
-
submitImmediately(text, attachments = []) {
|
|
827
|
+
async submitImmediately(text, attachments = []) {
|
|
828
|
+
if (this.immediateSend)
|
|
829
|
+
return { ok: false, error: "正在发送,请勿重复提交" };
|
|
830
|
+
if (this.stoppingRun)
|
|
831
|
+
return { ok: false, error: "正在停止上一轮请求,请稍后发送" };
|
|
787
832
|
if (!this.busy) {
|
|
788
833
|
this.startRun(text, attachments);
|
|
789
834
|
return { ok: true, interrupted: false };
|
|
@@ -792,15 +837,21 @@ export class WebRepl {
|
|
|
792
837
|
return this.sendQueuedNow();
|
|
793
838
|
}
|
|
794
839
|
sendQueuedNow() {
|
|
840
|
+
if (this.immediateSend)
|
|
841
|
+
return this.immediateSend;
|
|
795
842
|
const queuedText = this.queuedInput;
|
|
796
843
|
const queuedAttachments = this.queuedAttachments ?? [];
|
|
797
844
|
if (queuedText === undefined)
|
|
798
|
-
return { ok: true, interrupted: false };
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
845
|
+
return Promise.resolve({ ok: true, interrupted: false });
|
|
846
|
+
const pending = (async () => {
|
|
847
|
+
const interrupted = await this.stopForegroundRun("Interrupted to send queued web input", true);
|
|
848
|
+
this.startRun(queuedText, queuedAttachments);
|
|
849
|
+
return { ok: true, interrupted };
|
|
850
|
+
})();
|
|
851
|
+
this.immediateSend = pending;
|
|
852
|
+
void pending.finally(() => { if (this.immediateSend === pending)
|
|
853
|
+
this.immediateSend = undefined; }).catch(() => undefined);
|
|
854
|
+
return pending;
|
|
804
855
|
}
|
|
805
856
|
enqueueInput(text, attachments) {
|
|
806
857
|
this.queuedInput = mergeWebQueuedInput(this.queuedInput, text);
|
|
@@ -916,12 +967,13 @@ export class WebRepl {
|
|
|
916
967
|
source: payload.source,
|
|
917
968
|
});
|
|
918
969
|
const usage = payload.usage?.trim();
|
|
919
|
-
if (!shouldClear
|
|
970
|
+
if (!shouldClear) {
|
|
920
971
|
this.append({
|
|
921
972
|
kind: "meta",
|
|
922
973
|
title: "提示词用法",
|
|
923
|
-
text: usage,
|
|
974
|
+
text: usage || "提示词已应用。请在下方输入框中描述你的需求,按提示词要求补充材料后发送;它会用于后续对话。可在提示词管理中切换或清除。",
|
|
924
975
|
format: "markdown",
|
|
976
|
+
presentationLevel: "primary",
|
|
925
977
|
});
|
|
926
978
|
}
|
|
927
979
|
this.broadcastSync();
|
|
@@ -1066,6 +1118,9 @@ export class WebRepl {
|
|
|
1066
1118
|
const provider = parseLoginProvider(providerValue);
|
|
1067
1119
|
if (!provider)
|
|
1068
1120
|
return actionFailure("LOGIN_INVALID", "provider must be openai");
|
|
1121
|
+
if (dockerEnabled() && !values.apiKey?.trim()) {
|
|
1122
|
+
values = { ...values, apiKey: parseEnvFileSafe(this.runtime.envPath).OPENAI_API_KEY || process.env.OPENAI_API_KEY || "" };
|
|
1123
|
+
}
|
|
1069
1124
|
const payload = { ...createLoginFormPayload(this.runtime.envPath, provider), provider, values };
|
|
1070
1125
|
const validationError = validateLoginFormPayload(payload);
|
|
1071
1126
|
if (validationError)
|
|
@@ -1073,18 +1128,7 @@ export class WebRepl {
|
|
|
1073
1128
|
try {
|
|
1074
1129
|
await saveLoginPayloadToEnv(payload);
|
|
1075
1130
|
applyLoginPayloadToProcessEnv(payload);
|
|
1076
|
-
|
|
1077
|
-
if (!config)
|
|
1078
|
-
throw new Error("Saved provider config could not be loaded from environment.");
|
|
1079
|
-
const innerGateway = createModelGatewayFromConfig(config);
|
|
1080
|
-
this.runtime.modelGateway.setInner(innerGateway);
|
|
1081
|
-
this.runtime.agentRuntime.modelGateway = this.runtime.modelGateway;
|
|
1082
|
-
this.runtime.engine.setModelProvider({ modelGateway: this.runtime.modelGateway, model: config.model, reasoning: config.defaultReasoning });
|
|
1083
|
-
syncImageGenerationTool(this.runtime, config.provider);
|
|
1084
|
-
this.runtime.defaultReasoning = config.defaultReasoning;
|
|
1085
|
-
const metrics = await this.runtime.engine.contextMetrics();
|
|
1086
|
-
this.setStatus({ ...this.status, metrics, activityTick: this.status.activityTick + 1 });
|
|
1087
|
-
this.publishRuntimeContext();
|
|
1131
|
+
await this.reloadModelConfig();
|
|
1088
1132
|
return { ok: true };
|
|
1089
1133
|
}
|
|
1090
1134
|
catch (error) {
|
|
@@ -1092,8 +1136,27 @@ export class WebRepl {
|
|
|
1092
1136
|
return actionFailure("LOGIN_SAVE_FAILED", message);
|
|
1093
1137
|
}
|
|
1094
1138
|
}
|
|
1095
|
-
|
|
1096
|
-
const
|
|
1139
|
+
async reloadModelConfig() {
|
|
1140
|
+
const config = readModelProviderConfig(process.env);
|
|
1141
|
+
if (!config)
|
|
1142
|
+
throw new Error("Saved provider config could not be loaded from environment.");
|
|
1143
|
+
const innerGateway = createModelGatewayFromConfig(config);
|
|
1144
|
+
this.runtime.modelGateway.setInner(innerGateway);
|
|
1145
|
+
this.runtime.agentRuntime.modelGateway = this.runtime.modelGateway;
|
|
1146
|
+
this.runtime.engine.setModelProvider({ modelGateway: this.runtime.modelGateway, model: config.model, reasoning: config.defaultReasoning });
|
|
1147
|
+
for (const run of this.backgroundSessionRuns.values()) {
|
|
1148
|
+
run.engine.setModelProvider({ modelGateway: this.runtime.modelGateway, model: config.model, reasoning: config.defaultReasoning });
|
|
1149
|
+
}
|
|
1150
|
+
syncImageGenerationTool(this.runtime, config.provider);
|
|
1151
|
+
this.runtime.defaultReasoning = config.defaultReasoning;
|
|
1152
|
+
const metrics = await this.runtime.engine.contextMetrics();
|
|
1153
|
+
this.setStatus({ ...this.status, metrics, activityTick: this.status.activityTick + 1 });
|
|
1154
|
+
this.publishRuntimeContext();
|
|
1155
|
+
}
|
|
1156
|
+
async interrupt() {
|
|
1157
|
+
if (this.immediateSend)
|
|
1158
|
+
await this.immediateSend;
|
|
1159
|
+
const interrupted = await this.stopForegroundRun("Interrupted from neo web");
|
|
1097
1160
|
return { ok: true, interrupted };
|
|
1098
1161
|
}
|
|
1099
1162
|
cancelQueue() {
|
|
@@ -1146,15 +1209,15 @@ export class WebRepl {
|
|
|
1146
1209
|
this.assistantLineId = undefined;
|
|
1147
1210
|
this.finalizedThinkingLineId = undefined;
|
|
1148
1211
|
}
|
|
1149
|
-
stopForegroundRun(reason) {
|
|
1212
|
+
stopForegroundRun(reason, keepBusy = false) {
|
|
1213
|
+
if (this.stoppingRun)
|
|
1214
|
+
return this.stoppingRun;
|
|
1150
1215
|
const controller = this.activeAbortController;
|
|
1216
|
+
const run = this.foregroundRun;
|
|
1151
1217
|
const runWasActive = this.busy || Boolean(controller && !controller.signal.aborted);
|
|
1152
1218
|
this.foregroundRunToken += 1;
|
|
1153
|
-
this.foregroundRun = undefined;
|
|
1154
|
-
this.runtime.usage.reset();
|
|
1155
1219
|
if (controller && !controller.signal.aborted)
|
|
1156
1220
|
controller.abort(reason);
|
|
1157
|
-
this.activeAbortController = undefined;
|
|
1158
1221
|
this.interruptArmed = false;
|
|
1159
1222
|
this.queuedInput = undefined;
|
|
1160
1223
|
this.queuedAttachments = undefined;
|
|
@@ -1162,10 +1225,26 @@ export class WebRepl {
|
|
|
1162
1225
|
this.pendingUserImageEchoMessageId = undefined;
|
|
1163
1226
|
this.finalizeForegroundView();
|
|
1164
1227
|
this.cancelLiveToolLines(reason);
|
|
1165
|
-
this.busy =
|
|
1166
|
-
this.status = { ...this.status, phase: "
|
|
1228
|
+
this.busy = true;
|
|
1229
|
+
this.status = { ...this.status, phase: "running", detail: "stopping", currentTool: undefined, retryCooldownUntil: undefined };
|
|
1167
1230
|
this.broadcastSync();
|
|
1168
|
-
|
|
1231
|
+
const pending = (async () => {
|
|
1232
|
+
// Abort is cooperative: the engine still owns its run until the iterator settles.
|
|
1233
|
+
await run;
|
|
1234
|
+
if (this.foregroundRun === run)
|
|
1235
|
+
this.foregroundRun = undefined;
|
|
1236
|
+
if (this.activeAbortController === controller)
|
|
1237
|
+
this.activeAbortController = undefined;
|
|
1238
|
+
this.runtime.usage.reset();
|
|
1239
|
+
this.busy = keepBusy;
|
|
1240
|
+
this.status = { ...this.status, phase: keepBusy ? "running" : "ready", detail: undefined, currentTool: undefined, inputTokenUpdatedAt: undefined, outputTokenUpdatedAt: undefined, retryCooldownUntil: undefined };
|
|
1241
|
+
this.broadcastSync();
|
|
1242
|
+
return runWasActive;
|
|
1243
|
+
})();
|
|
1244
|
+
this.stoppingRun = pending;
|
|
1245
|
+
void pending.finally(() => { if (this.stoppingRun === pending)
|
|
1246
|
+
this.stoppingRun = undefined; }).catch(() => undefined);
|
|
1247
|
+
return pending;
|
|
1169
1248
|
}
|
|
1170
1249
|
agentTaskSnapshot(task) {
|
|
1171
1250
|
const terminal = this.runtime.taskStore.isTerminal(task);
|
|
@@ -1993,7 +2072,8 @@ function reqKeepAlive(res) {
|
|
|
1993
2072
|
timer.unref?.();
|
|
1994
2073
|
res.on("close", () => clearInterval(timer));
|
|
1995
2074
|
}
|
|
1996
|
-
|
|
2075
|
+
/** Embed runtime HTTP routes behind an application's own authentication/authorization layer. */
|
|
2076
|
+
export async function handleWebRequest(req, res, router) {
|
|
1997
2077
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
1998
2078
|
try {
|
|
1999
2079
|
if (req.method === "GET" && url.pathname === "/")
|
|
@@ -2146,14 +2226,14 @@ async function route(req, res, router) {
|
|
|
2146
2226
|
}
|
|
2147
2227
|
if (req.method === "POST" && url.pathname === "/api/submit-now") {
|
|
2148
2228
|
const body = await readJsonBody(req);
|
|
2149
|
-
return sendJson(res, repl.submitImmediately(String(body.text ?? ""), sanitizeWebAttachments(body.attachments)));
|
|
2229
|
+
return sendJson(res, await repl.submitImmediately(String(body.text ?? ""), sanitizeWebAttachments(body.attachments)));
|
|
2150
2230
|
}
|
|
2151
2231
|
if (req.method === "POST" && url.pathname === "/api/interrupt")
|
|
2152
|
-
return sendJson(res, repl.interrupt());
|
|
2232
|
+
return sendJson(res, await repl.interrupt());
|
|
2153
2233
|
if (req.method === "POST" && url.pathname === "/api/queue/cancel")
|
|
2154
2234
|
return sendJson(res, repl.cancelQueue());
|
|
2155
2235
|
if (req.method === "POST" && url.pathname === "/api/queue/send-now")
|
|
2156
|
-
return sendJson(res, repl.sendQueuedNow());
|
|
2236
|
+
return sendJson(res, await repl.sendQueuedNow());
|
|
2157
2237
|
if (req.method === "GET" && url.pathname === "/api/sessions")
|
|
2158
2238
|
return sendJson(res, await repl.listSessions());
|
|
2159
2239
|
if (req.method === "POST" && url.pathname === "/api/sessions/resume") {
|
|
@@ -2631,7 +2711,7 @@ function createLoginFormPayload(envPath, provider) {
|
|
|
2631
2711
|
function loginValuesForProvider(provider, env) {
|
|
2632
2712
|
const values = {};
|
|
2633
2713
|
for (const field of LOGIN_FIELD_DEFINITIONS[provider])
|
|
2634
|
-
values[field.key] = env[field.envKey] ?? "";
|
|
2714
|
+
values[field.key] = dockerEnabled() && field.secret ? "" : env[field.envKey] ?? "";
|
|
2635
2715
|
if (!values.baseUrl)
|
|
2636
2716
|
values.baseUrl = defaultBaseUrlForLoginProvider(provider);
|
|
2637
2717
|
if (!values.model)
|