@fangyb/ahchat-bridge 0.1.34 → 0.1.36
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/cli.cjs +902 -184
- package/dist/feedbackWorkerCli.cjs +99 -9
- package/dist/index.js +894 -184
- package/dist/seedanceMcpCli.cjs +1785 -134
- package/dist/seedreamMcpCli.cjs +1801 -144
- package/package.json +3 -2
package/dist/cli.cjs
CHANGED
|
@@ -91836,6 +91836,8 @@ var DEFAULT_QUERY_CONFIG = {
|
|
|
91836
91836
|
maxActive: 5040,
|
|
91837
91837
|
idleTimeoutMs: 6e5,
|
|
91838
91838
|
workingSilenceTimeoutMs: 12e5,
|
|
91839
|
+
replyStallTimeoutMs: 3e5,
|
|
91840
|
+
busySilenceTimeoutMs: 18e5,
|
|
91839
91841
|
evictionIntervalMs: 6e4,
|
|
91840
91842
|
statusReportIntervalMs: 6e4,
|
|
91841
91843
|
allowBuiltinWebSearch: false,
|
|
@@ -91893,6 +91895,14 @@ function mergeQueryConfig(file2) {
|
|
|
91893
91895
|
"AHCHAT_BRIDGE_WORKING_SILENCE_TIMEOUT_MS",
|
|
91894
91896
|
q?.workingSilenceTimeoutMs ?? DEFAULT_QUERY_CONFIG.workingSilenceTimeoutMs
|
|
91895
91897
|
),
|
|
91898
|
+
replyStallTimeoutMs: readEnvInt(
|
|
91899
|
+
"AHCHAT_BRIDGE_REPLY_STALL_TIMEOUT_MS",
|
|
91900
|
+
q?.replyStallTimeoutMs ?? DEFAULT_QUERY_CONFIG.replyStallTimeoutMs
|
|
91901
|
+
),
|
|
91902
|
+
busySilenceTimeoutMs: readEnvInt(
|
|
91903
|
+
"AHCHAT_BRIDGE_BUSY_SILENCE_TIMEOUT_MS",
|
|
91904
|
+
q?.busySilenceTimeoutMs ?? DEFAULT_QUERY_CONFIG.busySilenceTimeoutMs ?? 18e5
|
|
91905
|
+
),
|
|
91896
91906
|
evictionIntervalMs: readEnvInt(
|
|
91897
91907
|
"AHCHAT_BRIDGE_EVICTION_INTERVAL_MS",
|
|
91898
91908
|
q?.evictionIntervalMs ?? DEFAULT_QUERY_CONFIG.evictionIntervalMs
|
|
@@ -91973,7 +91983,11 @@ function loadBridgeConfig(opts) {
|
|
|
91973
91983
|
) || null,
|
|
91974
91984
|
logUploadIntervalMs: readEnvInt(
|
|
91975
91985
|
"AHCHAT_LOG_UPLOAD_INTERVAL_MS",
|
|
91976
|
-
|
|
91986
|
+
// Flush every 60s instead of once a day. Daily flushing let logs pile up for hours,
|
|
91987
|
+
// then dumped tens of thousands of entries in one cycle on the next process start,
|
|
91988
|
+
// blowing past the server's per-minute upload quota (3000 entries / 3MB) and getting
|
|
91989
|
+
// 429'd. Small frequent batches stay well under that ceiling.
|
|
91990
|
+
fileConfig.logUploadIntervalMs ?? 6e4
|
|
91977
91991
|
),
|
|
91978
91992
|
queryConfig: mergeQueryConfig(fileConfig)
|
|
91979
91993
|
};
|
|
@@ -92709,9 +92723,34 @@ ${entry.error.stack}` : ""}`
|
|
|
92709
92723
|
return `${ts} ${level} ${scope} ${entry.msg}${data}${trace}${errPart}`;
|
|
92710
92724
|
};
|
|
92711
92725
|
|
|
92726
|
+
// ../logger/src/fallback.ts
|
|
92727
|
+
init_cjs_shims();
|
|
92728
|
+
function logFallback(logger45, event) {
|
|
92729
|
+
const payload = {
|
|
92730
|
+
...event.traceId ? { traceId: event.traceId } : {},
|
|
92731
|
+
fallback: {
|
|
92732
|
+
fallbackId: event.fallbackId,
|
|
92733
|
+
type: event.type,
|
|
92734
|
+
phase: event.phase,
|
|
92735
|
+
expected: event.expected,
|
|
92736
|
+
...event.context ? { context: event.context } : {},
|
|
92737
|
+
...event.outcome ? { outcome: event.outcome } : {}
|
|
92738
|
+
}
|
|
92739
|
+
};
|
|
92740
|
+
const msg = `[FALLBACK] ${event.type}:${event.phase}`;
|
|
92741
|
+
const useDebug = event.expected && event.phase !== "outcome";
|
|
92742
|
+
if (useDebug) {
|
|
92743
|
+
logger45.debug(msg, payload);
|
|
92744
|
+
} else {
|
|
92745
|
+
logger45.warn(msg, payload);
|
|
92746
|
+
}
|
|
92747
|
+
}
|
|
92748
|
+
|
|
92712
92749
|
// ../logger/src/transports/console.ts
|
|
92713
92750
|
init_cjs_shims();
|
|
92714
92751
|
var protectedStreams = /* @__PURE__ */ new WeakSet();
|
|
92752
|
+
function ignoreWriteError(_error) {
|
|
92753
|
+
}
|
|
92715
92754
|
function defaultStream(kind) {
|
|
92716
92755
|
const maybeGlobal = globalThis;
|
|
92717
92756
|
return maybeGlobal.process?.[kind];
|
|
@@ -92724,12 +92763,13 @@ function safeWriteLine(stream, line, fallback) {
|
|
|
92724
92763
|
if (stream.destroyed || stream.writableEnded) return;
|
|
92725
92764
|
if (typeof stream === "object" && typeof stream.on === "function" && !protectedStreams.has(stream)) {
|
|
92726
92765
|
protectedStreams.add(stream);
|
|
92727
|
-
stream.on("error",
|
|
92766
|
+
stream.on("error", ignoreWriteError);
|
|
92728
92767
|
}
|
|
92729
92768
|
try {
|
|
92730
92769
|
stream.write(`${line}
|
|
92731
|
-
`,
|
|
92732
|
-
} catch {
|
|
92770
|
+
`, ignoreWriteError);
|
|
92771
|
+
} catch (e) {
|
|
92772
|
+
ignoreWriteError(e);
|
|
92733
92773
|
}
|
|
92734
92774
|
}
|
|
92735
92775
|
function consoleTransport(opts) {
|
|
@@ -93364,8 +93404,31 @@ function parseSize(maxSize) {
|
|
|
93364
93404
|
return trimmed;
|
|
93365
93405
|
}
|
|
93366
93406
|
var streamCache = /* @__PURE__ */ new Map();
|
|
93407
|
+
var droppedEntryCount = 0;
|
|
93408
|
+
var lastReportedDroppedTotal = 0;
|
|
93409
|
+
function buildLogDroppedSentinel(fmt, source, droppedTotal) {
|
|
93410
|
+
const entry = {
|
|
93411
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
93412
|
+
level: "WARN",
|
|
93413
|
+
source,
|
|
93414
|
+
module: "logger.file",
|
|
93415
|
+
msg: "log_dropped",
|
|
93416
|
+
data: { droppedTotal }
|
|
93417
|
+
};
|
|
93418
|
+
return fmt(entry);
|
|
93419
|
+
}
|
|
93420
|
+
function writeWithDroppedSentinel(stream, fmt, line, source) {
|
|
93421
|
+
stream.write(`${line}
|
|
93422
|
+
`);
|
|
93423
|
+
if (droppedEntryCount > lastReportedDroppedTotal) {
|
|
93424
|
+
lastReportedDroppedTotal = droppedEntryCount;
|
|
93425
|
+
stream.write(`${buildLogDroppedSentinel(fmt, source, droppedEntryCount)}
|
|
93426
|
+
`);
|
|
93427
|
+
}
|
|
93428
|
+
}
|
|
93367
93429
|
function fileTransport(opts) {
|
|
93368
93430
|
const fmt = opts.formatter ?? jsonFormatter;
|
|
93431
|
+
const logSource = opts.source ?? "server";
|
|
93369
93432
|
const resolved = import_node_path2.default.resolve(opts.path);
|
|
93370
93433
|
let cached2 = streamCache.get(resolved);
|
|
93371
93434
|
if (!cached2) {
|
|
@@ -93380,11 +93443,14 @@ function fileTransport(opts) {
|
|
|
93380
93443
|
streamCache.set(resolved, cached2);
|
|
93381
93444
|
}
|
|
93382
93445
|
return (entry) => {
|
|
93383
|
-
if (cached2.closed || cached2.stream.destroyed || cached2.stream.writableEnded)
|
|
93446
|
+
if (cached2.closed || cached2.stream.destroyed || cached2.stream.writableEnded) {
|
|
93447
|
+
droppedEntryCount += 1;
|
|
93448
|
+
return;
|
|
93449
|
+
}
|
|
93384
93450
|
try {
|
|
93385
|
-
cached2.stream
|
|
93386
|
-
`);
|
|
93451
|
+
writeWithDroppedSentinel(cached2.stream, fmt, fmt(entry), logSource);
|
|
93387
93452
|
} catch {
|
|
93453
|
+
droppedEntryCount += 1;
|
|
93388
93454
|
}
|
|
93389
93455
|
};
|
|
93390
93456
|
}
|
|
@@ -93770,8 +93836,10 @@ function resolvePnpmRuntimeBinary(sdkDir, target) {
|
|
|
93770
93836
|
} catch {
|
|
93771
93837
|
return void 0;
|
|
93772
93838
|
}
|
|
93839
|
+
const matches = [];
|
|
93773
93840
|
for (const entry of entries) {
|
|
93774
93841
|
if (!entry.startsWith(`${encodedName}@`)) continue;
|
|
93842
|
+
const version4 = entry.slice(encodedName.length + 1);
|
|
93775
93843
|
const candidate = import_node_path5.default.join(
|
|
93776
93844
|
pnpmStoreDir,
|
|
93777
93845
|
entry,
|
|
@@ -93779,9 +93847,22 @@ function resolvePnpmRuntimeBinary(sdkDir, target) {
|
|
|
93779
93847
|
...target.packageName.split("/"),
|
|
93780
93848
|
target.binaryName
|
|
93781
93849
|
);
|
|
93782
|
-
if ((0, import_node_fs3.existsSync)(candidate))
|
|
93850
|
+
if ((0, import_node_fs3.existsSync)(candidate)) matches.push({ version: version4, candidate });
|
|
93783
93851
|
}
|
|
93784
|
-
return void 0;
|
|
93852
|
+
if (matches.length === 0) return void 0;
|
|
93853
|
+
matches.sort((a, b) => compareRuntimeVersion(b.version, a.version));
|
|
93854
|
+
return matches[0].candidate;
|
|
93855
|
+
}
|
|
93856
|
+
function compareRuntimeVersion(a, b) {
|
|
93857
|
+
const parse3 = (v) => v.split(/[.+_-]/).map((n) => Number.parseInt(n, 10));
|
|
93858
|
+
const pa = parse3(a);
|
|
93859
|
+
const pb = parse3(b);
|
|
93860
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i += 1) {
|
|
93861
|
+
const da = Number.isFinite(pa[i]) ? pa[i] : 0;
|
|
93862
|
+
const db = Number.isFinite(pb[i]) ? pb[i] : 0;
|
|
93863
|
+
if (da !== db) return da - db;
|
|
93864
|
+
}
|
|
93865
|
+
return 0;
|
|
93785
93866
|
}
|
|
93786
93867
|
function resolveSdkRuntimeBinary(target) {
|
|
93787
93868
|
const directPath = safeResolve(`${target.packageName}/${target.binaryName}`);
|
|
@@ -94608,6 +94689,9 @@ init_cjs_shims();
|
|
|
94608
94689
|
// ../shared/src/types/index.ts
|
|
94609
94690
|
init_cjs_shims();
|
|
94610
94691
|
|
|
94692
|
+
// ../shared/src/types/usage.ts
|
|
94693
|
+
init_cjs_shims();
|
|
94694
|
+
|
|
94611
94695
|
// ../shared/src/types/message.ts
|
|
94612
94696
|
init_cjs_shims();
|
|
94613
94697
|
|
|
@@ -94680,6 +94764,9 @@ function createMessageId() {
|
|
|
94680
94764
|
function createTraceId() {
|
|
94681
94765
|
return `tr_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94682
94766
|
}
|
|
94767
|
+
function createFallbackId() {
|
|
94768
|
+
return `flb_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94769
|
+
}
|
|
94683
94770
|
function createRequestId() {
|
|
94684
94771
|
return `req_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94685
94772
|
}
|
|
@@ -94689,6 +94776,12 @@ function createCronReplyMessageId() {
|
|
|
94689
94776
|
function createInboxFlushReplyMessageId() {
|
|
94690
94777
|
return `msg_inbox_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94691
94778
|
}
|
|
94779
|
+
function createNeuralSendReplyMessageId() {
|
|
94780
|
+
return `msg_nsend_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94781
|
+
}
|
|
94782
|
+
function createScopeNoticeReplyMessageId() {
|
|
94783
|
+
return `msg_scopenotice_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94784
|
+
}
|
|
94692
94785
|
function createCronTraceId() {
|
|
94693
94786
|
return `tr_cron_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94694
94787
|
}
|
|
@@ -94733,6 +94826,24 @@ function assertNumberPayloadField(type, payload, field) {
|
|
|
94733
94826
|
throw invalidWsMessage(type, field);
|
|
94734
94827
|
}
|
|
94735
94828
|
}
|
|
94829
|
+
function assertOptionalNumberPayloadField(type, payload, field) {
|
|
94830
|
+
if (payload[field] === void 0) return;
|
|
94831
|
+
assertNumberPayloadField(type, payload, field);
|
|
94832
|
+
}
|
|
94833
|
+
function assertNullableStringPayloadField(type, payload, field) {
|
|
94834
|
+
if (payload[field] === null) return;
|
|
94835
|
+
assertStringPayloadField(type, payload, field);
|
|
94836
|
+
}
|
|
94837
|
+
function assertStringPayloadOneOf(type, payload, field, allowed) {
|
|
94838
|
+
assertStringPayloadField(type, payload, field);
|
|
94839
|
+
if (!allowed.includes(payload[field])) {
|
|
94840
|
+
throw invalidWsMessage(type, field);
|
|
94841
|
+
}
|
|
94842
|
+
}
|
|
94843
|
+
function assertOptionalStringPayloadOneOf(type, payload, field, allowed) {
|
|
94844
|
+
if (payload[field] === void 0) return;
|
|
94845
|
+
assertStringPayloadOneOf(type, payload, field, allowed);
|
|
94846
|
+
}
|
|
94736
94847
|
function assertArrayPayloadField(type, payload, field) {
|
|
94737
94848
|
if (!Array.isArray(payload[field])) {
|
|
94738
94849
|
throw invalidWsMessage(type, field);
|
|
@@ -94813,6 +94924,25 @@ function validateWSMessageShape(msg) {
|
|
|
94813
94924
|
case "agent:error": {
|
|
94814
94925
|
assertPayloadRecord(type, payload);
|
|
94815
94926
|
validateRequiredStrings(type, payload, ["ackId", "agentId", "conversationId", "error", "traceId"]);
|
|
94927
|
+
assertOptionalStringPayloadOneOf(type, payload, "reason", ["user_quota_exceeded", "company_quota_exceeded"]);
|
|
94928
|
+
return;
|
|
94929
|
+
}
|
|
94930
|
+
case "directory:register": {
|
|
94931
|
+
assertPayloadRecord(type, payload);
|
|
94932
|
+
validateRequiredStrings(type, payload, ["handle", "viaChild", "traceId"]);
|
|
94933
|
+
assertStringPayloadOneOf(type, payload, "op", ["add", "remove", "move"]);
|
|
94934
|
+
return;
|
|
94935
|
+
}
|
|
94936
|
+
case "directory:resolve": {
|
|
94937
|
+
assertPayloadRecord(type, payload);
|
|
94938
|
+
validateRequiredStrings(type, payload, ["handle", "fromNode", "traceId"]);
|
|
94939
|
+
assertOptionalNumberPayloadField(type, payload, "hop");
|
|
94940
|
+
return;
|
|
94941
|
+
}
|
|
94942
|
+
case "directory:resolve_result": {
|
|
94943
|
+
assertPayloadRecord(type, payload);
|
|
94944
|
+
validateRequiredStrings(type, payload, ["handle", "traceId"]);
|
|
94945
|
+
assertNullableStringPayloadField(type, payload, "canonicalAddress");
|
|
94816
94946
|
return;
|
|
94817
94947
|
}
|
|
94818
94948
|
default:
|
|
@@ -96174,6 +96304,9 @@ init_cjs_shims();
|
|
|
96174
96304
|
// ../shared/src/utils/serverUrl.ts
|
|
96175
96305
|
init_cjs_shims();
|
|
96176
96306
|
|
|
96307
|
+
// ../shared/src/utils/phone.ts
|
|
96308
|
+
init_cjs_shims();
|
|
96309
|
+
|
|
96177
96310
|
// ../shared/src/utils/mediaPreviewHtml.ts
|
|
96178
96311
|
init_cjs_shims();
|
|
96179
96312
|
|
|
@@ -96827,8 +96960,8 @@ var VOLCENGINE_SEEDANCE_MCP_PROVIDER = {
|
|
|
96827
96960
|
};
|
|
96828
96961
|
var OFFICIAL_MCP_PROVIDERS = [
|
|
96829
96962
|
...ALIYUN_IQS_MCP_PROVIDERS,
|
|
96830
|
-
|
|
96831
|
-
|
|
96963
|
+
VOLCENGINE_SEEDREAM_MCP_PROVIDER,
|
|
96964
|
+
VOLCENGINE_SEEDANCE_MCP_PROVIDER
|
|
96832
96965
|
];
|
|
96833
96966
|
var MCP_STORE_PROVIDERS = [
|
|
96834
96967
|
{
|
|
@@ -97640,8 +97773,7 @@ var AskQuestionRegistry = class {
|
|
|
97640
97773
|
questionId,
|
|
97641
97774
|
agentId: entry.agentId,
|
|
97642
97775
|
waitedMs: Date.now() - entry.askedAt,
|
|
97643
|
-
answerLen: answerText2.length
|
|
97644
|
-
answerSample: answerText2.slice(0, 200)
|
|
97776
|
+
answerLen: answerText2.length
|
|
97645
97777
|
});
|
|
97646
97778
|
entry.resolve(answerText2);
|
|
97647
97779
|
return true;
|
|
@@ -97786,7 +97918,7 @@ function makeAskUserQuestionGuard(deps) {
|
|
|
97786
97918
|
bundleIndex,
|
|
97787
97919
|
bundleSize,
|
|
97788
97920
|
replyMessageId: task.replyMessageId,
|
|
97789
|
-
|
|
97921
|
+
questionLen: q.question.length,
|
|
97790
97922
|
optionCount: options.length,
|
|
97791
97923
|
multiSelect,
|
|
97792
97924
|
traceId: task.traceId
|
|
@@ -97885,7 +98017,7 @@ function makeAskUserQuestionGuard(deps) {
|
|
|
97885
98017
|
bundleId,
|
|
97886
98018
|
bundleSize,
|
|
97887
98019
|
replyMessageId: task.replyMessageId,
|
|
97888
|
-
|
|
98020
|
+
combinedLen: combined.length,
|
|
97889
98021
|
traceId: task.traceId
|
|
97890
98022
|
});
|
|
97891
98023
|
return { behavior: "deny", message: combined };
|
|
@@ -112870,6 +113002,17 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
112870
113002
|
".yaml",
|
|
112871
113003
|
".yml"
|
|
112872
113004
|
]);
|
|
113005
|
+
var OFFICE_DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
113006
|
+
".docx",
|
|
113007
|
+
".xlsx",
|
|
113008
|
+
".pptx",
|
|
113009
|
+
".pdf",
|
|
113010
|
+
".odt",
|
|
113011
|
+
".ods",
|
|
113012
|
+
".odp",
|
|
113013
|
+
".rtf"
|
|
113014
|
+
]);
|
|
113015
|
+
var PLAIN_TEXT_BINARY_SNIFF_BYTES = 8192;
|
|
112873
113016
|
var DEFAULT_MAX_CHARS = 5e5;
|
|
112874
113017
|
var DEFAULT_TIMEOUT_MS = 45e3;
|
|
112875
113018
|
function isReadableDocumentPath(filePath) {
|
|
@@ -112889,9 +113032,6 @@ function resolveDocumentPath(inputPath, cwd) {
|
|
|
112889
113032
|
async function readDocumentAsMarkdown(inputPath, opts = {}) {
|
|
112890
113033
|
const resolvedPath = opts.cwd ? resolveDocumentPath(inputPath, opts.cwd) : import_node_path10.default.resolve(resolveUserPath(inputPath));
|
|
112891
113034
|
const ext = import_node_path10.default.extname(resolvedPath).toLowerCase();
|
|
112892
|
-
if (!isReadableDocumentPath(resolvedPath)) {
|
|
112893
|
-
throw new Error(`unsupported document type: ${ext || "(no extension)"}`);
|
|
112894
|
-
}
|
|
112895
113035
|
const stat3 = await import_promises2.default.stat(resolvedPath);
|
|
112896
113036
|
if (!stat3.isFile()) throw new Error("path is not a file");
|
|
112897
113037
|
const warnings = [];
|
|
@@ -112900,8 +113040,10 @@ async function readDocumentAsMarkdown(inputPath, opts = {}) {
|
|
|
112900
113040
|
markdown = await import_promises2.default.readFile(resolvedPath, "utf-8");
|
|
112901
113041
|
} else if (ext === ".xls") {
|
|
112902
113042
|
markdown = await convertLegacyExcelDocument(resolvedPath);
|
|
112903
|
-
} else {
|
|
113043
|
+
} else if (OFFICE_DOCUMENT_EXTENSIONS.has(ext)) {
|
|
112904
113044
|
markdown = await convertOfficeDocument(resolvedPath, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
113045
|
+
} else {
|
|
113046
|
+
markdown = await readPlainTextDocument(resolvedPath, ext);
|
|
112905
113047
|
}
|
|
112906
113048
|
markdown = normalizeDocumentText(markdown);
|
|
112907
113049
|
const maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;
|
|
@@ -113040,6 +113182,14 @@ async function convertDocxWithOfficeCli(filePath, timeoutMs) {
|
|
|
113040
113182
|
});
|
|
113041
113183
|
return text;
|
|
113042
113184
|
}
|
|
113185
|
+
async function readPlainTextDocument(filePath, ext) {
|
|
113186
|
+
const buffer = await import_promises2.default.readFile(filePath);
|
|
113187
|
+
const sample = buffer.subarray(0, Math.min(buffer.length, PLAIN_TEXT_BINARY_SNIFF_BYTES));
|
|
113188
|
+
if (sample.includes(0)) {
|
|
113189
|
+
throw new Error(`unsupported document type: ${ext || "(no extension)"}`);
|
|
113190
|
+
}
|
|
113191
|
+
return buffer.toString("utf-8");
|
|
113192
|
+
}
|
|
113043
113193
|
async function convertLegacyExcelDocument(filePath) {
|
|
113044
113194
|
const XLSX2 = await Promise.resolve().then(() => (init_xlsx(), xlsx_exports));
|
|
113045
113195
|
const workbook = XLSX2.readFile(filePath, { cellDates: true });
|
|
@@ -113509,8 +113659,7 @@ async function createNeuralMcpServer(deps) {
|
|
|
113509
113659
|
agentId: deps.agentId,
|
|
113510
113660
|
fromScope: currentScopeKey,
|
|
113511
113661
|
rawTargetScope: args.target_scope,
|
|
113512
|
-
messageLen: args.message.length
|
|
113513
|
-
messageSample: args.message.slice(0, 120)
|
|
113662
|
+
messageLen: args.message.length
|
|
113514
113663
|
});
|
|
113515
113664
|
const trimmed = args.message.trim();
|
|
113516
113665
|
if (!trimmed) {
|
|
@@ -113604,7 +113753,7 @@ async function createNeuralMcpServer(deps) {
|
|
|
113604
113753
|
toScope: resolvedKey,
|
|
113605
113754
|
repeatsInWindow: sendHistory.length,
|
|
113606
113755
|
windowMs: NEURAL_DEDUP_WINDOW_MS,
|
|
113607
|
-
|
|
113756
|
+
messageLen: trimmed.length
|
|
113608
113757
|
});
|
|
113609
113758
|
return {
|
|
113610
113759
|
content: [{
|
|
@@ -113631,8 +113780,7 @@ async function createNeuralMcpServer(deps) {
|
|
|
113631
113780
|
agentId: deps.agentId,
|
|
113632
113781
|
fromScope: currentScopeKey,
|
|
113633
113782
|
toScope: resolvedKey,
|
|
113634
|
-
messageLen: trimmed.length
|
|
113635
|
-
messageSample: trimmed.slice(0, 120)
|
|
113783
|
+
messageLen: trimmed.length
|
|
113636
113784
|
});
|
|
113637
113785
|
return {
|
|
113638
113786
|
content: [{ type: "text", text: `[neural_send] \u5DF2\u9001\u8FBE\u5230\u300C${toLabel}\u300D(scope: ${resolvedKey})\u3002` }]
|
|
@@ -113989,6 +114137,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
|
|
|
113989
114137
|
`Read a document from the current working directory and return extracted Markdown text.
|
|
113990
114138
|
Use this instead of the built-in Read tool for binary documents such as .docx, .xls, .xlsx, .pptx, .pdf, .odt, .ods, .odp, or .rtf.
|
|
113991
114139
|
Also supports text-like files such as .csv, .md, .txt, .json, .xml, .yaml, and .html.
|
|
114140
|
+
Plain-text and source/config files (e.g. .py, .ts, Makefile, Dockerfile, and other extension-less text files) are read as-is; only true binaries are rejected.
|
|
113992
114141
|
Pass either a relative path from the current working directory or an absolute path inside it.`,
|
|
113993
114142
|
{
|
|
113994
114143
|
path: external_exports.string().min(1).describe("Document path, relative to the current working directory or absolute inside it."),
|
|
@@ -116686,7 +116835,11 @@ function parseJsonRecord(text) {
|
|
|
116686
116835
|
try {
|
|
116687
116836
|
const parsed = JSON.parse(text);
|
|
116688
116837
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
116689
|
-
} catch {
|
|
116838
|
+
} catch (error51) {
|
|
116839
|
+
logger11.warn("SDK tool result output was not JSON", {
|
|
116840
|
+
error: error51,
|
|
116841
|
+
outputLength: text.length
|
|
116842
|
+
});
|
|
116690
116843
|
return null;
|
|
116691
116844
|
}
|
|
116692
116845
|
}
|
|
@@ -117048,6 +117201,9 @@ function emitUsageReported(proc, emit, base, usage, messageId) {
|
|
|
117048
117201
|
function isGroupTask(proc) {
|
|
117049
117202
|
return proc.currentTask?.groupId != null;
|
|
117050
117203
|
}
|
|
117204
|
+
function shouldStreamInternals(proc) {
|
|
117205
|
+
return !isGroupTask(proc) || proc.spectating === true;
|
|
117206
|
+
}
|
|
117051
117207
|
function extractTodosFromInput(input) {
|
|
117052
117208
|
if (!input || typeof input !== "object") return null;
|
|
117053
117209
|
const raw = input.todos;
|
|
@@ -117179,7 +117335,6 @@ function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = f
|
|
|
117179
117335
|
contentLen: content.length,
|
|
117180
117336
|
blockCount: contentBlocks.length,
|
|
117181
117337
|
blockTypes: contentBlocks.map((b) => b.type),
|
|
117182
|
-
contentSample: content.slice(0, 200),
|
|
117183
117338
|
traceId: base.traceId,
|
|
117184
117339
|
isAuditOnly: content.length === 0,
|
|
117185
117340
|
isSilent
|
|
@@ -117235,9 +117390,24 @@ function flushTextSegmentOnBlockStop(proc, emit, base) {
|
|
|
117235
117390
|
}
|
|
117236
117391
|
proc.segmentBuffer = "";
|
|
117237
117392
|
}
|
|
117393
|
+
function describeSdkEvent(message) {
|
|
117394
|
+
const rec = message;
|
|
117395
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
117396
|
+
return {
|
|
117397
|
+
type: str(rec.type) ?? "unknown",
|
|
117398
|
+
subtype: str(rec.subtype),
|
|
117399
|
+
toolName: str(rec.last_tool_name),
|
|
117400
|
+
subagentType: str(rec.subagent_type),
|
|
117401
|
+
toolUseId: str(rec.tool_use_id),
|
|
117402
|
+
taskId: str(rec.task_id),
|
|
117403
|
+
at: Date.now()
|
|
117404
|
+
};
|
|
117405
|
+
}
|
|
117238
117406
|
function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProviderApiError) {
|
|
117239
117407
|
const emit = rawEmit;
|
|
117240
117408
|
proc.lastSdkEventAt = Date.now();
|
|
117409
|
+
proc.lastSdkEventInfo = describeSdkEvent(message);
|
|
117410
|
+
proc.stallWarned = false;
|
|
117241
117411
|
switch (message.type) {
|
|
117242
117412
|
case "system": {
|
|
117243
117413
|
const sysMsg = message;
|
|
@@ -117276,11 +117446,29 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117276
117446
|
sessionId: proc.ccSessionId
|
|
117277
117447
|
});
|
|
117278
117448
|
} else {
|
|
117449
|
+
const sysRec = sysMsg;
|
|
117450
|
+
const pick2 = (k) => typeof sysRec[k] === "string" || typeof sysRec[k] === "number" ? sysRec[k] : void 0;
|
|
117451
|
+
const descriptionLen = typeof sysRec.description === "string" ? sysRec.description.length : void 0;
|
|
117452
|
+
const subagentTaskId = typeof sysRec.task_id === "string" ? sysRec.task_id : void 0;
|
|
117453
|
+
if (subagentTaskId) {
|
|
117454
|
+
if (sysMsg.subtype === "task_started") {
|
|
117455
|
+
(proc.activeSubagentTaskIds ??= /* @__PURE__ */ new Set()).add(subagentTaskId);
|
|
117456
|
+
} else if (sysMsg.subtype === "task_notification") {
|
|
117457
|
+
proc.activeSubagentTaskIds?.delete(subagentTaskId);
|
|
117458
|
+
}
|
|
117459
|
+
}
|
|
117279
117460
|
logger11.info("SDK system subtype unhandled", {
|
|
117280
117461
|
agentId: proc.agentId,
|
|
117281
117462
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117282
117463
|
subtype: sysMsg.subtype ?? "(none)",
|
|
117283
|
-
|
|
117464
|
+
taskId: pick2("task_id"),
|
|
117465
|
+
toolUseId: pick2("tool_use_id"),
|
|
117466
|
+
subagentType: pick2("subagent_type"),
|
|
117467
|
+
taskType: pick2("task_type"),
|
|
117468
|
+
lastToolName: pick2("last_tool_name"),
|
|
117469
|
+
hasDescription: descriptionLen != null,
|
|
117470
|
+
descriptionLen,
|
|
117471
|
+
keys: Object.keys(sysMsg).slice(0, 16)
|
|
117284
117472
|
});
|
|
117285
117473
|
}
|
|
117286
117474
|
break;
|
|
@@ -117306,13 +117494,14 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117306
117494
|
} else if (block.type === "tool_use") {
|
|
117307
117495
|
proc.currentBlockType = "tool_use";
|
|
117308
117496
|
proc.currentToolName = block.name ?? "unknown";
|
|
117497
|
+
proc.activeToolUseStartedAt = Date.now();
|
|
117309
117498
|
proc.accumulatedToolInput = "";
|
|
117310
117499
|
const toolName = block.name ?? "unknown";
|
|
117311
117500
|
proc.suppressCurrentToolUse = proc.officialMediaGenerationSatisfied === true && isOfficialMediaGenerationToolName(toolName);
|
|
117312
117501
|
const isMcpTool = parseMcpRuntimeToolName(toolName) != null;
|
|
117313
117502
|
proc.currentMcpInvocationId = isMcpTool ? createMcpToolInvocationId() : null;
|
|
117314
117503
|
proc.currentMcpInvocationStartedAt = isMcpTool ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
117315
|
-
if (
|
|
117504
|
+
if (shouldStreamInternals(proc) && !proc.suppressCurrentToolUse && toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
117316
117505
|
emit({
|
|
117317
117506
|
type: "agent:tool_use",
|
|
117318
117507
|
payload: {
|
|
@@ -117337,7 +117526,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117337
117526
|
if (delta.type === "thinking_delta" && typeof delta.thinking === "string") {
|
|
117338
117527
|
if (proc.suppressCurrentThinking) break;
|
|
117339
117528
|
proc.accumulatedThinking += delta.thinking;
|
|
117340
|
-
if (
|
|
117529
|
+
if (shouldStreamInternals(proc)) {
|
|
117341
117530
|
emit({
|
|
117342
117531
|
type: "agent:thinking_chunk",
|
|
117343
117532
|
payload: { ...wireBase(base), chunk: delta.thinking }
|
|
@@ -117348,7 +117537,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117348
117537
|
if (typeof partial2 === "string") {
|
|
117349
117538
|
proc.accumulatedToolInput += partial2;
|
|
117350
117539
|
const liveInput = extractLiveToolInput(proc.currentToolName, proc.accumulatedToolInput);
|
|
117351
|
-
if (
|
|
117540
|
+
if (shouldStreamInternals(proc) && liveInput && proc.currentToolName != null) {
|
|
117352
117541
|
emit({
|
|
117353
117542
|
type: "agent:tool_input_update",
|
|
117354
117543
|
payload: {
|
|
@@ -117382,7 +117571,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117382
117571
|
}
|
|
117383
117572
|
case "content_block_stop": {
|
|
117384
117573
|
if (proc.currentBlockType === "thinking") {
|
|
117385
|
-
if (
|
|
117574
|
+
if (shouldStreamInternals(proc) && !proc.suppressCurrentThinking) {
|
|
117386
117575
|
emit({
|
|
117387
117576
|
type: "agent:thinking_done",
|
|
117388
117577
|
payload: wireBase(getTaskBase(proc))
|
|
@@ -117402,12 +117591,12 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117402
117591
|
if (proc.accumulatedToolInput.length > 0) {
|
|
117403
117592
|
try {
|
|
117404
117593
|
parsedInput = JSON.parse(proc.accumulatedToolInput);
|
|
117405
|
-
} catch {
|
|
117594
|
+
} catch (error51) {
|
|
117406
117595
|
logger11.warn("Failed to parse tool input JSON", {
|
|
117596
|
+
error: error51,
|
|
117407
117597
|
agentId: proc.agentId,
|
|
117408
117598
|
toolName: proc.currentToolName,
|
|
117409
|
-
inputLen: proc.accumulatedToolInput.length
|
|
117410
|
-
sample: proc.accumulatedToolInput.slice(0, 200)
|
|
117599
|
+
inputLen: proc.accumulatedToolInput.length
|
|
117411
117600
|
});
|
|
117412
117601
|
}
|
|
117413
117602
|
}
|
|
@@ -117416,7 +117605,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117416
117605
|
if (lastToolUse && lastToolUse.type === "tool_use") {
|
|
117417
117606
|
lastToolUse.input = parsedInput;
|
|
117418
117607
|
}
|
|
117419
|
-
if (
|
|
117608
|
+
if (shouldStreamInternals(proc) && proc.currentToolName != null && LIVE_INPUT_PREVIEW_TOOLS.has(proc.currentToolName) && Object.keys(parsedInput).length > 0) {
|
|
117420
117609
|
emit({
|
|
117421
117610
|
type: "agent:tool_input_update",
|
|
117422
117611
|
payload: {
|
|
@@ -117540,7 +117729,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117540
117729
|
blockTypes,
|
|
117541
117730
|
hasToolResult,
|
|
117542
117731
|
hasPlainText,
|
|
117543
|
-
|
|
117732
|
+
contentLen: typeof content === "string" ? content.length : JSON.stringify(content).length
|
|
117544
117733
|
});
|
|
117545
117734
|
break;
|
|
117546
117735
|
}
|
|
@@ -117549,7 +117738,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117549
117738
|
agentId: proc.agentId,
|
|
117550
117739
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117551
117740
|
blockTypes,
|
|
117552
|
-
|
|
117741
|
+
contentLen: JSON.stringify(content).length,
|
|
117553
117742
|
replyMessageId: base.replyMessageId
|
|
117554
117743
|
});
|
|
117555
117744
|
}
|
|
@@ -117570,14 +117759,15 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117570
117759
|
});
|
|
117571
117760
|
proc.currentMcpInvocationId = null;
|
|
117572
117761
|
proc.currentMcpInvocationStartedAt = null;
|
|
117762
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117573
117763
|
proc.currentToolName = null;
|
|
117574
117764
|
continue;
|
|
117575
117765
|
}
|
|
117576
117766
|
if (isSuccessfulOfficialMediaOutput(toolName, output)) {
|
|
117577
117767
|
proc.officialMediaGenerationSatisfied = true;
|
|
117578
|
-
proc.officialMediaSessionRecycleRequested = true;
|
|
117579
117768
|
}
|
|
117580
117769
|
if (isAskUserQuestionToolName(toolName)) {
|
|
117770
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117581
117771
|
proc.currentToolName = null;
|
|
117582
117772
|
continue;
|
|
117583
117773
|
}
|
|
@@ -117605,7 +117795,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117605
117795
|
proc.currentMcpInvocationId = null;
|
|
117606
117796
|
proc.currentMcpInvocationStartedAt = null;
|
|
117607
117797
|
}
|
|
117608
|
-
if (
|
|
117798
|
+
if (shouldStreamInternals(proc)) {
|
|
117609
117799
|
emit({
|
|
117610
117800
|
type: "agent:tool_result",
|
|
117611
117801
|
payload: {
|
|
@@ -117629,6 +117819,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117629
117819
|
}
|
|
117630
117820
|
}
|
|
117631
117821
|
}
|
|
117822
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117632
117823
|
}
|
|
117633
117824
|
}
|
|
117634
117825
|
}
|
|
@@ -117707,7 +117898,6 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117707
117898
|
groupId,
|
|
117708
117899
|
compactScheduled: proc.compactRequested === true,
|
|
117709
117900
|
fullTextLen: proc.accumulatedText.length,
|
|
117710
|
-
fullTextSample: proc.accumulatedText.slice(0, 200),
|
|
117711
117901
|
accumulatedBlockCount: proc.contentBlocks.length,
|
|
117712
117902
|
accumulatedBlockTypes: proc.contentBlocks.map((b) => b.type),
|
|
117713
117903
|
silentSegmentEmitted: groupMode
|
|
@@ -117751,7 +117941,6 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117751
117941
|
segmentCount: proc.segmentCount,
|
|
117752
117942
|
compactScheduled: proc.compactRequested === true,
|
|
117753
117943
|
fullTextLen: proc.accumulatedText.length,
|
|
117754
|
-
fullTextSample: proc.accumulatedText.slice(0, 200),
|
|
117755
117944
|
traceId: base.traceId
|
|
117756
117945
|
});
|
|
117757
117946
|
emit({
|
|
@@ -117802,7 +117991,6 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117802
117991
|
ackId: base.replyMessageId,
|
|
117803
117992
|
messageId: carrierMessageId,
|
|
117804
117993
|
textLen: proc.accumulatedText.length,
|
|
117805
|
-
textSample: proc.accumulatedText.slice(0, 200),
|
|
117806
117994
|
tokenCount: usage.tokenCount,
|
|
117807
117995
|
traceId: base.traceId
|
|
117808
117996
|
});
|
|
@@ -117995,8 +118183,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117995
118183
|
logger11.info("Captured non-streamed assistant message", {
|
|
117996
118184
|
agentId: proc.agentId,
|
|
117997
118185
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117998
|
-
textLen: text.length
|
|
117999
|
-
textSample: text.slice(0, 100)
|
|
118186
|
+
textLen: text.length
|
|
118000
118187
|
});
|
|
118001
118188
|
} else {
|
|
118002
118189
|
proc.lastAssistantContentDescription = describeAssistantContent(am.message?.content);
|
|
@@ -118020,6 +118207,7 @@ function resetAccumulators(proc) {
|
|
|
118020
118207
|
proc.currentToolName = null;
|
|
118021
118208
|
proc.currentMcpInvocationId = null;
|
|
118022
118209
|
proc.currentMcpInvocationStartedAt = null;
|
|
118210
|
+
proc.activeToolUseStartedAt = void 0;
|
|
118023
118211
|
proc.segmentBuffer = "";
|
|
118024
118212
|
proc.segmentCount = 0;
|
|
118025
118213
|
proc.accumulatedToolInput = "";
|
|
@@ -118029,6 +118217,7 @@ function resetAccumulators(proc) {
|
|
|
118029
118217
|
proc.officialMediaGenerationSatisfied = false;
|
|
118030
118218
|
proc.suppressCurrentThinking = false;
|
|
118031
118219
|
proc.suppressCurrentToolUse = false;
|
|
118220
|
+
proc.activeSubagentTaskIds?.clear();
|
|
118032
118221
|
}
|
|
118033
118222
|
|
|
118034
118223
|
// src/forkHistoryReplay.ts
|
|
@@ -118220,7 +118409,7 @@ function missingSubscriptionMessage(subscriptionId) {
|
|
|
118220
118409
|
}
|
|
118221
118410
|
var NODE_USER_UID = 1e3;
|
|
118222
118411
|
var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
|
|
118223
|
-
var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-prompt-
|
|
118412
|
+
var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-mcp-abi-prompt-v4";
|
|
118224
118413
|
var BINARY_ATTACHMENT_EXT_RE = /\.(?:7z|bmp|csv|doc|docx|gif|jpeg|jpg|m4a|mov|mp3|mp4|pdf|png|ppt|pptx|rar|rtf|wav|webm|webp|xls|xlsx|zip)$/i;
|
|
118225
118414
|
var DOCUMENT_READING_RULES = `DOCUMENT READING:
|
|
118226
118415
|
- The built-in Read tool cannot read binary office documents such as .docx, .xls, .xlsx, .pptx, .pdf, .odt, .ods, .odp, or .rtf.
|
|
@@ -118235,6 +118424,16 @@ var MEDIA_GENERATION_RULES = `MEDIA GENERATION:
|
|
|
118235
118424
|
- Keep media replies short. Do not print raw media URLs, request_id, task_id, polling logs, or "let me check again" narration unless the user explicitly asks for diagnostics.
|
|
118236
118425
|
- When a media task is submitted or completed, write only a natural one-line note such as "\u5DF2\u5F00\u59CB\u751F\u6210\uFF0C\u6211\u4F1A\u5728\u8FD9\u91CC\u66F4\u65B0\u7ED3\u679C\u3002" or "\u751F\u6210\u597D\u4E86\uFF0C\u53EF\u4EE5\u5728\u5361\u7247\u91CC\u67E5\u770B\u3002"; let the media card show status, preview, download, copy, and regenerate actions.
|
|
118237
118426
|
- If the user asks whether a Seedance task is ready, call mcp__seedance__seedance_check_task once and answer from that result. Do not loop, sleep, or invent external Seedance API endpoints.`;
|
|
118427
|
+
function stableFingerprintValue(value) {
|
|
118428
|
+
if (Array.isArray(value)) return value.map(stableFingerprintValue);
|
|
118429
|
+
if (!value || typeof value !== "object") return value;
|
|
118430
|
+
const out = {};
|
|
118431
|
+
for (const key of Object.keys(value).sort()) {
|
|
118432
|
+
const normalized = stableFingerprintValue(value[key]);
|
|
118433
|
+
if (normalized !== void 0) out[key] = normalized;
|
|
118434
|
+
}
|
|
118435
|
+
return out;
|
|
118436
|
+
}
|
|
118238
118437
|
function isRecoveryDispatchTask(task) {
|
|
118239
118438
|
return task.dispatchKind === "manual_continue" || task.dispatchKind === "regenerate";
|
|
118240
118439
|
}
|
|
@@ -118492,13 +118691,15 @@ var AgentManager = class {
|
|
|
118492
118691
|
agents = /* @__PURE__ */ new Map();
|
|
118493
118692
|
lastUsedAt = /* @__PURE__ */ new Map();
|
|
118494
118693
|
/** Scopes 被 zombie_watchdog 关闭后的"入睡"标记,acquire 重建时清除并 emit awake。 */
|
|
118495
|
-
dormantScopes = /* @__PURE__ */ new
|
|
118694
|
+
dormantScopes = /* @__PURE__ */ new Map();
|
|
118496
118695
|
/**
|
|
118497
118696
|
* zombie_watchdog 拆 runtime 时,把该 (agentId, scope) 的 groupInbox 快照到这里,
|
|
118498
118697
|
* 让下一次 getOrCreate 重建 runtime 时可以恢复未读消息。仅 in-memory;
|
|
118499
118698
|
* bridge 进程崩溃 / shutdownAll 时丢失,与现有 inbox 内存语义一致。
|
|
118500
118699
|
*/
|
|
118501
118700
|
dormantGroupInboxes = /* @__PURE__ */ new Map();
|
|
118701
|
+
/** Spectate requested before runtime existed; value = activatedAt epoch ms. */
|
|
118702
|
+
pendingSpectate = /* @__PURE__ */ new Map();
|
|
118502
118703
|
sessionStore;
|
|
118503
118704
|
dispatchMemory = new GroupDispatchMemoryStore();
|
|
118504
118705
|
dataDir;
|
|
@@ -118664,6 +118865,7 @@ var AgentManager = class {
|
|
|
118664
118865
|
}
|
|
118665
118866
|
async resolveRuntimeCwd(agentConfig, scope, requestedCwd) {
|
|
118666
118867
|
let cwd = this.remapServerWorkspaceCwd(agentConfig, scope, requestedCwd);
|
|
118868
|
+
let fallbackForensicsId;
|
|
118667
118869
|
if (!isFullyQualifiedAbsolutePath(cwd)) {
|
|
118668
118870
|
const fallback = import_node_path13.default.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
|
|
118669
118871
|
logger14.error(
|
|
@@ -118678,6 +118880,23 @@ var AgentManager = class {
|
|
|
118678
118880
|
error: new Error("workdir_not_usable_on_this_machine")
|
|
118679
118881
|
}
|
|
118680
118882
|
);
|
|
118883
|
+
fallbackForensicsId = createFallbackId();
|
|
118884
|
+
logFallback(logger14, {
|
|
118885
|
+
fallbackId: fallbackForensicsId,
|
|
118886
|
+
type: "cwd_sandbox",
|
|
118887
|
+
phase: "applied",
|
|
118888
|
+
expected: false,
|
|
118889
|
+
context: {
|
|
118890
|
+
agentId: agentConfig.id,
|
|
118891
|
+
scope: scopeKey(scope),
|
|
118892
|
+
platform: process.platform,
|
|
118893
|
+
requested: requestedCwd,
|
|
118894
|
+
resolved: cwd,
|
|
118895
|
+
reason: "not_fully_qualified",
|
|
118896
|
+
fallback
|
|
118897
|
+
},
|
|
118898
|
+
outcome: { result: "sandbox_fallback" }
|
|
118899
|
+
});
|
|
118681
118900
|
cwd = fallback;
|
|
118682
118901
|
}
|
|
118683
118902
|
if (isRunningAsRoot() && cwd.startsWith("/root/")) {
|
|
@@ -118696,6 +118915,21 @@ var AgentManager = class {
|
|
|
118696
118915
|
fallback,
|
|
118697
118916
|
error: e
|
|
118698
118917
|
});
|
|
118918
|
+
const fbId = fallbackForensicsId ?? createFallbackId();
|
|
118919
|
+
logFallback(logger14, {
|
|
118920
|
+
fallbackId: fbId,
|
|
118921
|
+
type: "cwd_sandbox",
|
|
118922
|
+
phase: "applied",
|
|
118923
|
+
expected: false,
|
|
118924
|
+
context: {
|
|
118925
|
+
agentId: agentConfig.id,
|
|
118926
|
+
scope: scopeKey(scope),
|
|
118927
|
+
reason: "mkdir_failed",
|
|
118928
|
+
requested: cwd,
|
|
118929
|
+
fallback
|
|
118930
|
+
},
|
|
118931
|
+
outcome: { result: "second_layer_fallback" }
|
|
118932
|
+
});
|
|
118699
118933
|
await import_promises3.default.mkdir(fallback, { recursive: true });
|
|
118700
118934
|
return fallback;
|
|
118701
118935
|
}
|
|
@@ -118918,17 +119152,24 @@ var AgentManager = class {
|
|
|
118918
119152
|
});
|
|
118919
119153
|
return null;
|
|
118920
119154
|
}
|
|
118921
|
-
scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection) {
|
|
118922
|
-
return (0, import_node_crypto3.createHash)("sha256").update(SCOPE_PROMPT_FINGERPRINT_REVISION).update("\0").update(agentConfig.id).update("\0").update(agentConfig.name).update("\0").update(scopeKey(scope)).update("\0").update(import_node_path13.default.normalize(agentCwd)).update("\0").update(scopesSection).digest("hex");
|
|
119155
|
+
scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection, externalMcpFingerprint) {
|
|
119156
|
+
return (0, import_node_crypto3.createHash)("sha256").update(SCOPE_PROMPT_FINGERPRINT_REVISION).update("\0").update(agentConfig.id).update("\0").update(agentConfig.name).update("\0").update(scopeKey(scope)).update("\0").update(import_node_path13.default.normalize(agentCwd)).update("\0").update(scopesSection).update("\0").update(externalMcpFingerprint).digest("hex");
|
|
119157
|
+
}
|
|
119158
|
+
externalMcpFingerprint(externalMcp) {
|
|
119159
|
+
const serverNames = Object.keys(externalMcp.mcpServers).sort();
|
|
119160
|
+
const allowedTools = [...externalMcp.allowedTools].sort();
|
|
119161
|
+
const toolAbi = [...externalMcp.toolAbi ?? []].sort((a, b) => a.serverName.localeCompare(b.serverName)).map(stableFingerprintValue);
|
|
119162
|
+
if (serverNames.length === 0 && allowedTools.length === 0 && toolAbi.length === 0) return "";
|
|
119163
|
+
return JSON.stringify({ serverNames, allowedTools, toolAbi });
|
|
118923
119164
|
}
|
|
118924
|
-
discardSessionIfScopePromptChanged(agentConfig, scope, sessionId, fingerprint) {
|
|
119165
|
+
discardSessionIfScopePromptChanged(agentConfig, scope, sessionId, fingerprint, options = {}) {
|
|
118925
119166
|
const previous = this.sessionStore.getPromptFingerprint(agentConfig.id, scope);
|
|
118926
119167
|
if (!sessionId) {
|
|
118927
119168
|
this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
|
|
118928
119169
|
return null;
|
|
118929
119170
|
}
|
|
118930
119171
|
if (previous === fingerprint) return sessionId;
|
|
118931
|
-
if (!previous && scope.kind === "single") {
|
|
119172
|
+
if (!previous && scope.kind === "single" && options.clearLegacySingleSession !== true) {
|
|
118932
119173
|
this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
|
|
118933
119174
|
logger14.info("Retaining legacy single-scope session while recording prompt fingerprint", {
|
|
118934
119175
|
agentId: agentConfig.id,
|
|
@@ -118948,7 +119189,8 @@ var AgentManager = class {
|
|
|
118948
119189
|
sessionId,
|
|
118949
119190
|
previousFingerprint: previous,
|
|
118950
119191
|
nextFingerprint: fingerprint,
|
|
118951
|
-
revision: SCOPE_PROMPT_FINGERPRINT_REVISION
|
|
119192
|
+
revision: SCOPE_PROMPT_FINGERPRINT_REVISION,
|
|
119193
|
+
reason: options.reason ?? "scope_prompt_changed"
|
|
118952
119194
|
});
|
|
118953
119195
|
return null;
|
|
118954
119196
|
}
|
|
@@ -118997,6 +119239,7 @@ var AgentManager = class {
|
|
|
118997
119239
|
logger14.info("Evicting idle Agent query", { agentId: proc.agentId, scope: scopeKey(proc.scope) });
|
|
118998
119240
|
const runtime = this.asRuntime(proc);
|
|
118999
119241
|
this.clearQuietFlushTimer(runtime);
|
|
119242
|
+
this.teardownSpectate(runtime);
|
|
119000
119243
|
try {
|
|
119001
119244
|
runtime.inputController.close();
|
|
119002
119245
|
await this.awaitQueryReturn(runtime.query, 5e3, proc.agentId);
|
|
@@ -119016,6 +119259,7 @@ var AgentManager = class {
|
|
|
119016
119259
|
const runtime = this.asRuntime(proc);
|
|
119017
119260
|
const key = runtimeKey(proc.agentId, proc.scope);
|
|
119018
119261
|
this.clearQuietFlushTimer(runtime);
|
|
119262
|
+
this.teardownSpectate(runtime);
|
|
119019
119263
|
runtime.currentTask = null;
|
|
119020
119264
|
runtime.injectedTasks = [];
|
|
119021
119265
|
runtime.mergedTasks = [];
|
|
@@ -119052,6 +119296,7 @@ var AgentManager = class {
|
|
|
119052
119296
|
evictIdle() {
|
|
119053
119297
|
const now = Date.now();
|
|
119054
119298
|
const { idleTimeoutMs, workingSilenceTimeoutMs } = this.queryConfig;
|
|
119299
|
+
const stallWarnAfterMs = Math.min(9e4, this.queryConfig.replyStallTimeoutMs);
|
|
119055
119300
|
for (const [key, proc] of this.agents) {
|
|
119056
119301
|
if (!this.isEvictable(proc)) continue;
|
|
119057
119302
|
const runtime = this.asRuntime(proc);
|
|
@@ -119062,26 +119307,62 @@ var AgentManager = class {
|
|
|
119062
119307
|
for (const [, proc] of this.agents) {
|
|
119063
119308
|
if (proc.status !== "working") continue;
|
|
119064
119309
|
const runtime = this.asRuntime(proc);
|
|
119310
|
+
if (runtime.currentTask) {
|
|
119311
|
+
const sinceEventMs = now - proc.lastSdkEventAt;
|
|
119312
|
+
if (sinceEventMs > stallWarnAfterMs && !proc.stallWarned) {
|
|
119313
|
+
proc.stallWarned = true;
|
|
119314
|
+
const openTool = this.latestOpenToolUse(proc);
|
|
119315
|
+
logger14.warn("Reply stall onset: in-flight reply silent", {
|
|
119316
|
+
agentId: proc.agentId,
|
|
119317
|
+
scope: scopeKey(proc.scope),
|
|
119318
|
+
sinceEventMs,
|
|
119319
|
+
replyStallTimeoutMs: this.queryConfig.replyStallTimeoutMs,
|
|
119320
|
+
workingSilenceTimeoutMs,
|
|
119321
|
+
busySilenceTimeoutMs: this.queryConfig.busySilenceTimeoutMs ?? null,
|
|
119322
|
+
replyMessageId: runtime.currentTask.replyMessageId,
|
|
119323
|
+
model: proc.model ?? "(unknown)",
|
|
119324
|
+
lastSdkEvent: proc.lastSdkEventInfo,
|
|
119325
|
+
hasActiveToolUse: runtime.activeToolUseStartedAt != null || openTool != null,
|
|
119326
|
+
activeToolUseAgeMs: runtime.activeToolUseStartedAt != null ? now - runtime.activeToolUseStartedAt : null,
|
|
119327
|
+
openToolName: openTool?.toolName ?? proc.currentToolName ?? null,
|
|
119328
|
+
openMcpInvocationId: proc.currentMcpInvocationId ?? null,
|
|
119329
|
+
subagentInFlight: (runtime.activeSubagentTaskIds?.size ?? 0) > 0,
|
|
119330
|
+
activeSubagentCount: runtime.activeSubagentTaskIds?.size ?? 0,
|
|
119331
|
+
busyReason: this.busyReason(proc)
|
|
119332
|
+
});
|
|
119333
|
+
}
|
|
119334
|
+
}
|
|
119335
|
+
const busyReason = this.busyReason(runtime);
|
|
119336
|
+
const busy = busyReason !== null;
|
|
119337
|
+
if (runtime.currentTask && !busy && now - proc.lastSdkEventAt > this.queryConfig.replyStallTimeoutMs) {
|
|
119338
|
+
void this.recoverStalledReply(proc, now - proc.lastSdkEventAt);
|
|
119339
|
+
continue;
|
|
119340
|
+
}
|
|
119065
119341
|
const hasInjectedBacklog = runtime.injectedTasks.length > 0;
|
|
119066
|
-
const
|
|
119342
|
+
const baseCeilingMs = busy ? Math.max(workingSilenceTimeoutMs, this.queryConfig.busySilenceTimeoutMs ?? 0) : workingSilenceTimeoutMs;
|
|
119343
|
+
const effectiveTimeoutMs = hasInjectedBacklog ? baseCeilingMs * 2 : baseCeilingMs;
|
|
119067
119344
|
const silentMs = now - proc.lastSdkEventAt;
|
|
119068
119345
|
if (silentMs <= effectiveTimeoutMs) {
|
|
119069
|
-
if (
|
|
119070
|
-
logger14.warn(
|
|
119071
|
-
|
|
119072
|
-
|
|
119073
|
-
|
|
119074
|
-
|
|
119075
|
-
|
|
119076
|
-
|
|
119077
|
-
|
|
119078
|
-
|
|
119079
|
-
|
|
119080
|
-
|
|
119081
|
-
|
|
119346
|
+
if (silentMs > workingSilenceTimeoutMs) {
|
|
119347
|
+
logger14.warn("Zombie watchdog: working runtime silent past base timeout; granting extended grace", {
|
|
119348
|
+
agentId: proc.agentId,
|
|
119349
|
+
scope: scopeKey(proc.scope),
|
|
119350
|
+
silentMs,
|
|
119351
|
+
baseTimeoutMs: workingSilenceTimeoutMs,
|
|
119352
|
+
baseCeilingMs,
|
|
119353
|
+
busySilenceTimeoutMs: this.queryConfig.busySilenceTimeoutMs ?? null,
|
|
119354
|
+
effectiveTimeoutMs,
|
|
119355
|
+
busy,
|
|
119356
|
+
busyReason,
|
|
119357
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
119358
|
+
replyMessageId: proc.currentTask?.replyMessageId
|
|
119359
|
+
});
|
|
119082
119360
|
}
|
|
119083
119361
|
continue;
|
|
119084
119362
|
}
|
|
119363
|
+
const zombieOpenTool = this.latestOpenToolUse(proc);
|
|
119364
|
+
const watchdogDetectedAt = Date.now();
|
|
119365
|
+
const watchdogFallbackId = createFallbackId();
|
|
119085
119366
|
logger14.warn("Zombie watchdog: working runtime silent too long, tearing down", {
|
|
119086
119367
|
agentId: proc.agentId,
|
|
119087
119368
|
scope: scopeKey(proc.scope),
|
|
@@ -119089,12 +119370,46 @@ var AgentManager = class {
|
|
|
119089
119370
|
lastSdkEventAt: new Date(proc.lastSdkEventAt).toISOString(),
|
|
119090
119371
|
workingSilenceTimeoutMs,
|
|
119091
119372
|
effectiveTimeoutMs,
|
|
119373
|
+
baseCeilingMs,
|
|
119374
|
+
busy,
|
|
119375
|
+
busySilenceTimeoutMs: this.queryConfig.busySilenceTimeoutMs ?? null,
|
|
119092
119376
|
replyMessageId: proc.currentTask?.replyMessageId,
|
|
119093
119377
|
injectedTaskCount: runtime.injectedTasks.length,
|
|
119094
119378
|
hadInjectedBacklog: hasInjectedBacklog,
|
|
119095
|
-
inboxSize: proc.groupInbox.length
|
|
119379
|
+
inboxSize: proc.groupInbox.length,
|
|
119380
|
+
fallbackId: watchdogFallbackId,
|
|
119381
|
+
// Breadcrumb: what the turn was waiting on when it timed out. A hung subagent
|
|
119382
|
+
// (open `Task` tool_use) lands here now that the fast path skips active tools.
|
|
119383
|
+
model: proc.model ?? "(unknown)",
|
|
119384
|
+
lastSdkEvent: proc.lastSdkEventInfo,
|
|
119385
|
+
openToolName: zombieOpenTool?.toolName ?? proc.currentToolName ?? null,
|
|
119386
|
+
activeToolUseAgeMs: runtime.activeToolUseStartedAt != null ? now - runtime.activeToolUseStartedAt : null,
|
|
119387
|
+
openMcpInvocationId: proc.currentMcpInvocationId ?? null,
|
|
119388
|
+
subagentInFlight: (runtime.activeSubagentTaskIds?.size ?? 0) > 0,
|
|
119389
|
+
activeSubagentCount: runtime.activeSubagentTaskIds?.size ?? 0,
|
|
119390
|
+
busyReason: this.busyReason(proc)
|
|
119391
|
+
});
|
|
119392
|
+
logFallback(logger14, {
|
|
119393
|
+
fallbackId: watchdogFallbackId,
|
|
119394
|
+
type: "zombie_watchdog",
|
|
119395
|
+
phase: "detected",
|
|
119396
|
+
expected: false,
|
|
119397
|
+
traceId: proc.currentTask?.traceId,
|
|
119398
|
+
context: {
|
|
119399
|
+
agentId: proc.agentId,
|
|
119400
|
+
scope: scopeKey(proc.scope),
|
|
119401
|
+
silentMs,
|
|
119402
|
+
replyMessageId: proc.currentTask?.replyMessageId ?? null,
|
|
119403
|
+
openToolName: zombieOpenTool?.toolName ?? proc.currentToolName ?? null,
|
|
119404
|
+
lastSdkEventType: proc.lastSdkEventInfo?.type ?? null,
|
|
119405
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
119406
|
+
inboxSize: proc.groupInbox.length
|
|
119407
|
+
}
|
|
119408
|
+
});
|
|
119409
|
+
void this.closeRuntime(proc, "zombie_watchdog", {
|
|
119410
|
+
fallbackId: watchdogFallbackId,
|
|
119411
|
+
detectedAt: watchdogDetectedAt
|
|
119096
119412
|
});
|
|
119097
|
-
void this.closeRuntime(proc, "zombie_watchdog");
|
|
119098
119413
|
}
|
|
119099
119414
|
}
|
|
119100
119415
|
/**
|
|
@@ -119341,7 +119656,7 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119341
119656
|
agentId: agentConfig.id,
|
|
119342
119657
|
capabilityTier: cfg.capabilityTier,
|
|
119343
119658
|
isSmith: smithAgent
|
|
119344
|
-
}) ?? { mcpServers: {}, allowedTools: [] };
|
|
119659
|
+
}) ?? { mcpServers: {}, allowedTools: [], toolAbi: [] };
|
|
119345
119660
|
logger14.info("External MCP resolved for runtime", {
|
|
119346
119661
|
agentId: agentConfig.id,
|
|
119347
119662
|
scope: scopeKey(scope),
|
|
@@ -119358,11 +119673,16 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119358
119673
|
}
|
|
119359
119674
|
const notebookSection = this.buildNotebookSection(agentConfig.id);
|
|
119360
119675
|
const scopesSection = this.buildScopesSection(agentConfig, scope, agentCwd);
|
|
119676
|
+
const externalMcpFingerprint = this.externalMcpFingerprint(externalMcp);
|
|
119361
119677
|
savedSessionId = this.discardSessionIfScopePromptChanged(
|
|
119362
119678
|
agentConfig,
|
|
119363
119679
|
scope,
|
|
119364
119680
|
savedSessionId,
|
|
119365
|
-
this.scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection)
|
|
119681
|
+
this.scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection, externalMcpFingerprint),
|
|
119682
|
+
{
|
|
119683
|
+
clearLegacySingleSession: externalMcpFingerprint.length > 0,
|
|
119684
|
+
reason: externalMcpFingerprint.length > 0 ? "external_mcp_abi_changed" : "scope_prompt_changed"
|
|
119685
|
+
}
|
|
119366
119686
|
);
|
|
119367
119687
|
let forkHistorySection = "";
|
|
119368
119688
|
if (!savedSessionId && scope.kind === "single") {
|
|
@@ -119383,6 +119703,8 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119383
119703
|
}
|
|
119384
119704
|
}
|
|
119385
119705
|
const cronLockSnapshot = readCronLockSnapshot();
|
|
119706
|
+
const builtinWebSearchAllowed = this.queryConfig.allowBuiltinWebSearch;
|
|
119707
|
+
const disallowedToolsForRuntime = builtinWebSearchAllowed ? [] : ["WebSearch"];
|
|
119386
119708
|
logger14.info("Creating Agent query", {
|
|
119387
119709
|
agentId: agentConfig.id,
|
|
119388
119710
|
scope: scopeKey(scope),
|
|
@@ -119391,6 +119713,8 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119391
119713
|
sessionId: savedSessionId,
|
|
119392
119714
|
forkHistoryReplay: forkHistorySection.length > 0,
|
|
119393
119715
|
model: cfg.model ?? "(default)",
|
|
119716
|
+
builtinWebSearchAllowed,
|
|
119717
|
+
disallowedTools: disallowedToolsForRuntime,
|
|
119394
119718
|
// Diagnostic: who currently owns Claude's global cron lock (~/.claude/scheduled_tasks.lock).
|
|
119395
119719
|
// Cron is process-internal but the binary uses this singleton lock to elect ONE scheduler
|
|
119396
119720
|
// among concurrent claude subprocesses. If lock is held by another session at spawn time,
|
|
@@ -119402,7 +119726,6 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119402
119726
|
});
|
|
119403
119727
|
const planModeRef = { active: false, denyCount: 0 };
|
|
119404
119728
|
const mediaGenerationTurnGuard = createOfficialMediaGenerationTurnGuard();
|
|
119405
|
-
const builtinWebSearchAllowed = this.queryConfig.allowBuiltinWebSearch;
|
|
119406
119729
|
const options = {
|
|
119407
119730
|
cwd: agentCwd,
|
|
119408
119731
|
systemPrompt: {
|
|
@@ -119469,6 +119792,8 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119469
119792
|
] : [],
|
|
119470
119793
|
...externalMcp.allowedTools
|
|
119471
119794
|
],
|
|
119795
|
+
// Server-side WebSearch bypasses canUseTool; disallowedTools removes it from model context.
|
|
119796
|
+
disallowedTools: disallowedToolsForRuntime,
|
|
119472
119797
|
mcpServers: { ...externalMcp.mcpServers, neural: neuralServer },
|
|
119473
119798
|
includePartialMessages: true,
|
|
119474
119799
|
// Plan mode custom workflow instructions. When setPermissionMode('plan') is
|
|
@@ -119795,6 +120120,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119795
120120
|
currentTask: null,
|
|
119796
120121
|
currentTaskStartedAt: 0,
|
|
119797
120122
|
lastSdkEventAt: Date.now(),
|
|
120123
|
+
model: (typeof options.model === "string" ? options.model : cfg.model) ?? null,
|
|
119798
120124
|
compactRequested: false,
|
|
119799
120125
|
compactInProgress: false,
|
|
119800
120126
|
contextOverflowLockedUntil: 0,
|
|
@@ -119806,13 +120132,18 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119806
120132
|
currentToolName: null,
|
|
119807
120133
|
currentMcpInvocationId: null,
|
|
119808
120134
|
currentMcpInvocationStartedAt: null,
|
|
120135
|
+
activeSubagentTaskIds: /* @__PURE__ */ new Set(),
|
|
119809
120136
|
mcpAuditRecorder: this.mcpAuditRecorder,
|
|
119810
120137
|
segmentBuffer: "",
|
|
119811
120138
|
segmentCount: 0,
|
|
119812
120139
|
accumulatedToolInput: "",
|
|
119813
120140
|
planModeRef,
|
|
119814
120141
|
mediaGenerationTurnGuard,
|
|
119815
|
-
groupInbox: []
|
|
120142
|
+
groupInbox: [],
|
|
120143
|
+
spectating: false,
|
|
120144
|
+
spectateActivatedAt: 0,
|
|
120145
|
+
spectateViewing: false,
|
|
120146
|
+
spectateTtlExpired: false
|
|
119816
120147
|
};
|
|
119817
120148
|
const runtime = Object.assign(proc, {
|
|
119818
120149
|
query: agentQuery,
|
|
@@ -119824,7 +120155,8 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119824
120155
|
createdAt: Date.now(),
|
|
119825
120156
|
supportsVision: modelInputMode === "vision" && cfg.supportsVision !== false,
|
|
119826
120157
|
modelInputMode,
|
|
119827
|
-
quietFlushTimer: null
|
|
120158
|
+
quietFlushTimer: null,
|
|
120159
|
+
spectateRevertTimer: null
|
|
119828
120160
|
});
|
|
119829
120161
|
logger14.info("Agent model input mode resolved", {
|
|
119830
120162
|
agentId: agentConfig.id,
|
|
@@ -119849,6 +120181,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119849
120181
|
} else {
|
|
119850
120182
|
this.dormantGroupInboxes.delete(key);
|
|
119851
120183
|
}
|
|
120184
|
+
const dormantMeta = this.dormantScopes.get(key);
|
|
119852
120185
|
if (this.dormantScopes.delete(key)) {
|
|
119853
120186
|
this.emit({
|
|
119854
120187
|
type: "agent:awake",
|
|
@@ -119860,7 +120193,44 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119860
120193
|
});
|
|
119861
120194
|
logger14.info("Agent scope awakened after dormant", {
|
|
119862
120195
|
agentId: agentConfig.id,
|
|
119863
|
-
scope: scopeKey(scope)
|
|
120196
|
+
scope: scopeKey(scope),
|
|
120197
|
+
...dormantMeta ? {
|
|
120198
|
+
fallbackId: dormantMeta.fallbackId,
|
|
120199
|
+
dormantDurationMs: Date.now() - dormantMeta.detectedAt,
|
|
120200
|
+
dataLossSuspected: dormantMeta.droppedTaskCount > 0
|
|
120201
|
+
} : {}
|
|
120202
|
+
});
|
|
120203
|
+
if (dormantMeta) {
|
|
120204
|
+
logFallback(logger14, {
|
|
120205
|
+
fallbackId: dormantMeta.fallbackId,
|
|
120206
|
+
type: "zombie_watchdog",
|
|
120207
|
+
phase: "outcome",
|
|
120208
|
+
expected: false,
|
|
120209
|
+
context: {
|
|
120210
|
+
agentId: agentConfig.id,
|
|
120211
|
+
scope: scopeKey(scope)
|
|
120212
|
+
},
|
|
120213
|
+
outcome: {
|
|
120214
|
+
result: "recovered_rebuilt",
|
|
120215
|
+
durationMs: Date.now() - dormantMeta.detectedAt,
|
|
120216
|
+
dataLossSuspected: dormantMeta.droppedTaskCount > 0
|
|
120217
|
+
}
|
|
120218
|
+
});
|
|
120219
|
+
}
|
|
120220
|
+
}
|
|
120221
|
+
const pendingSpectateAt = this.pendingSpectate.get(key);
|
|
120222
|
+
if (pendingSpectateAt != null) {
|
|
120223
|
+
this.pendingSpectate.delete(key);
|
|
120224
|
+
runtime.spectating = true;
|
|
120225
|
+
runtime.spectateViewing = false;
|
|
120226
|
+
runtime.spectateActivatedAt = pendingSpectateAt;
|
|
120227
|
+
runtime.spectateTtlExpired = false;
|
|
120228
|
+
this.armSpectateTimer(runtime);
|
|
120229
|
+
this.emitSpectateState(runtime, true, "started");
|
|
120230
|
+
logger14.info("Applied pending spectate on runtime create", {
|
|
120231
|
+
agentId: agentConfig.id,
|
|
120232
|
+
scope: scopeKey(scope),
|
|
120233
|
+
activatedAt: pendingSpectateAt
|
|
119864
120234
|
});
|
|
119865
120235
|
}
|
|
119866
120236
|
if (proc.groupInbox.length > 0 && this.isRuntimeIdleForInboxFlush(runtime)) {
|
|
@@ -120998,7 +121368,6 @@ ${lines.join("\n")}`;
|
|
|
120998
121368
|
compactTrigger: "context_watermark",
|
|
120999
121369
|
injectedTasksWaiting: runtime.injectedTasks.length,
|
|
121000
121370
|
compactPromptLen: compactPrompt.length,
|
|
121001
|
-
promptSample: compactPrompt.slice(0, 80),
|
|
121002
121371
|
traceId: compactTraceId
|
|
121003
121372
|
});
|
|
121004
121373
|
runtime.inputController.push(compactPrompt, runtime.ccSessionId ?? "");
|
|
@@ -121280,7 +121649,7 @@ ${lines.join("\n")}`;
|
|
|
121280
121649
|
const enveloped = buildInnerVoiceEnvelope(payloadWithTrigger, ctx);
|
|
121281
121650
|
const task = {
|
|
121282
121651
|
content: enveloped,
|
|
121283
|
-
replyMessageId:
|
|
121652
|
+
replyMessageId: createNeuralSendReplyMessageId(),
|
|
121284
121653
|
conversationId: payload.conversationId,
|
|
121285
121654
|
traceId: createTraceId(),
|
|
121286
121655
|
groupId: payload.groupId
|
|
@@ -121526,7 +121895,7 @@ ${lines.join("\n")}`;
|
|
|
121526
121895
|
this.dormantScopes.delete(key);
|
|
121527
121896
|
this.dormantGroupInboxes.delete(key);
|
|
121528
121897
|
}
|
|
121529
|
-
for (const key of [...this.dormantScopes].filter(
|
|
121898
|
+
for (const key of [...this.dormantScopes.keys()].filter(
|
|
121530
121899
|
(k) => k === agentId || k.startsWith(`${agentId}::`)
|
|
121531
121900
|
)) {
|
|
121532
121901
|
this.dormantScopes.delete(key);
|
|
@@ -121574,7 +121943,7 @@ ${lines.join("\n")}`;
|
|
|
121574
121943
|
async reloadAgentScopes(agentId, reason) {
|
|
121575
121944
|
this.sessionStore.deleteAllForAgent(agentId);
|
|
121576
121945
|
this.dispatchMemory.deleteAllForAgent(agentId);
|
|
121577
|
-
for (const key of [...this.dormantScopes].filter(
|
|
121946
|
+
for (const key of [...this.dormantScopes.keys()].filter(
|
|
121578
121947
|
(k) => k === agentId || k.startsWith(`${agentId}::`)
|
|
121579
121948
|
)) {
|
|
121580
121949
|
this.dormantScopes.delete(key);
|
|
@@ -121726,6 +122095,125 @@ ${lines.join("\n")}`;
|
|
|
121726
122095
|
void this.terminateScope(proc.agentId, proc.scope);
|
|
121727
122096
|
}
|
|
121728
122097
|
}
|
|
122098
|
+
/** Control spectate capture/push for one scoped runtime. */
|
|
122099
|
+
async setSpectate(agentId, scope, action) {
|
|
122100
|
+
const key = runtimeKey(agentId, scope);
|
|
122101
|
+
const proc = this.agents.get(key);
|
|
122102
|
+
if (!proc || proc.status === "dead") {
|
|
122103
|
+
if (action === "start") {
|
|
122104
|
+
this.pendingSpectate.set(key, Date.now());
|
|
122105
|
+
logger14.info("setSpectate: runtime missing, pending start", { agentId, scope: scopeKey(scope) });
|
|
122106
|
+
}
|
|
122107
|
+
return;
|
|
122108
|
+
}
|
|
122109
|
+
const runtime = this.asRuntime(proc);
|
|
122110
|
+
switch (action) {
|
|
122111
|
+
case "start":
|
|
122112
|
+
runtime.spectating = true;
|
|
122113
|
+
runtime.spectateViewing = true;
|
|
122114
|
+
runtime.spectateActivatedAt = Date.now();
|
|
122115
|
+
runtime.spectateTtlExpired = false;
|
|
122116
|
+
this.pendingSpectate.delete(key);
|
|
122117
|
+
this.armSpectateTimer(runtime);
|
|
122118
|
+
this.emitSpectateState(runtime, true, "started");
|
|
122119
|
+
logger14.info("Spectate started", { agentId, scope: scopeKey(scope) });
|
|
122120
|
+
break;
|
|
122121
|
+
case "enter_view":
|
|
122122
|
+
runtime.spectateViewing = true;
|
|
122123
|
+
logger14.info("Spectate enter_view", { agentId, scope: scopeKey(scope) });
|
|
122124
|
+
break;
|
|
122125
|
+
case "leave_view":
|
|
122126
|
+
runtime.spectateViewing = false;
|
|
122127
|
+
logger14.info("Spectate leave_view", {
|
|
122128
|
+
agentId,
|
|
122129
|
+
scope: scopeKey(scope),
|
|
122130
|
+
ttlExpired: runtime.spectateTtlExpired
|
|
122131
|
+
});
|
|
122132
|
+
if (runtime.spectateTtlExpired) {
|
|
122133
|
+
this.stopSpectate(runtime, "ttl_expired");
|
|
122134
|
+
}
|
|
122135
|
+
break;
|
|
122136
|
+
case "stop":
|
|
122137
|
+
this.stopSpectate(runtime, "stopped");
|
|
122138
|
+
this.pendingSpectate.delete(key);
|
|
122139
|
+
logger14.info("Spectate stopped", { agentId, scope: scopeKey(scope) });
|
|
122140
|
+
break;
|
|
122141
|
+
default:
|
|
122142
|
+
break;
|
|
122143
|
+
}
|
|
122144
|
+
}
|
|
122145
|
+
spectateTtlMs() {
|
|
122146
|
+
return Number(process.env.AHCHAT_BRIDGE_SPECTATE_TTL_MS) || 36e5;
|
|
122147
|
+
}
|
|
122148
|
+
armSpectateTimer(runtime) {
|
|
122149
|
+
this.clearSpectateTimer(runtime);
|
|
122150
|
+
if (!runtime.spectating || runtime.spectateActivatedAt <= 0) return;
|
|
122151
|
+
const ttlMs = this.spectateTtlMs();
|
|
122152
|
+
const elapsed = Date.now() - runtime.spectateActivatedAt;
|
|
122153
|
+
const delay = Math.max(0, ttlMs - elapsed);
|
|
122154
|
+
runtime.spectateRevertTimer = setTimeout(() => {
|
|
122155
|
+
runtime.spectateRevertTimer = null;
|
|
122156
|
+
runtime.spectateTtlExpired = true;
|
|
122157
|
+
logger14.info("Spectate TTL expired", {
|
|
122158
|
+
agentId: runtime.agentId,
|
|
122159
|
+
scope: scopeKey(runtime.scope),
|
|
122160
|
+
viewing: runtime.spectateViewing
|
|
122161
|
+
});
|
|
122162
|
+
if (!runtime.spectateViewing) {
|
|
122163
|
+
this.stopSpectate(runtime, "ttl_expired");
|
|
122164
|
+
}
|
|
122165
|
+
}, delay);
|
|
122166
|
+
}
|
|
122167
|
+
clearSpectateTimer(runtime) {
|
|
122168
|
+
if (runtime.spectateRevertTimer != null) {
|
|
122169
|
+
clearTimeout(runtime.spectateRevertTimer);
|
|
122170
|
+
runtime.spectateRevertTimer = null;
|
|
122171
|
+
}
|
|
122172
|
+
}
|
|
122173
|
+
stopSpectate(runtime, reason) {
|
|
122174
|
+
const wasActive = runtime.spectating;
|
|
122175
|
+
this.clearSpectateTimer(runtime);
|
|
122176
|
+
runtime.spectating = false;
|
|
122177
|
+
runtime.spectateViewing = false;
|
|
122178
|
+
runtime.spectateTtlExpired = false;
|
|
122179
|
+
runtime.spectateActivatedAt = 0;
|
|
122180
|
+
if (wasActive) {
|
|
122181
|
+
this.emitSpectateState(runtime, false, reason);
|
|
122182
|
+
logger14.info("Spectate deactivated", {
|
|
122183
|
+
agentId: runtime.agentId,
|
|
122184
|
+
scope: scopeKey(runtime.scope),
|
|
122185
|
+
reason
|
|
122186
|
+
});
|
|
122187
|
+
}
|
|
122188
|
+
}
|
|
122189
|
+
emitSpectateState(runtime, active, reason) {
|
|
122190
|
+
const scopePayload = runtime.scope.kind === "single" ? { kind: "single" } : { kind: "group", groupId: runtime.scope.groupId };
|
|
122191
|
+
this.emit({
|
|
122192
|
+
type: "spectate:state",
|
|
122193
|
+
payload: {
|
|
122194
|
+
agentId: runtime.agentId,
|
|
122195
|
+
scope: scopePayload,
|
|
122196
|
+
active,
|
|
122197
|
+
expiresAt: active ? runtime.spectateActivatedAt + this.spectateTtlMs() : void 0,
|
|
122198
|
+
reason,
|
|
122199
|
+
traceId: createTraceId()
|
|
122200
|
+
}
|
|
122201
|
+
});
|
|
122202
|
+
logger14.info("Spectate state emitted", {
|
|
122203
|
+
agentId: runtime.agentId,
|
|
122204
|
+
scope: scopeKey(runtime.scope),
|
|
122205
|
+
active,
|
|
122206
|
+
reason,
|
|
122207
|
+
expiresAt: active ? runtime.spectateActivatedAt + this.spectateTtlMs() : void 0
|
|
122208
|
+
});
|
|
122209
|
+
}
|
|
122210
|
+
teardownSpectate(runtime) {
|
|
122211
|
+
if (runtime.spectating) {
|
|
122212
|
+
this.stopSpectate(runtime, "runtime_gone");
|
|
122213
|
+
} else {
|
|
122214
|
+
this.clearSpectateTimer(runtime);
|
|
122215
|
+
}
|
|
122216
|
+
}
|
|
121729
122217
|
/** Stop one scoped SDK runtime (workdir change). */
|
|
121730
122218
|
async terminateScope(agentId, scope) {
|
|
121731
122219
|
const key = runtimeKey(agentId, scope);
|
|
@@ -121734,6 +122222,7 @@ ${lines.join("\n")}`;
|
|
|
121734
122222
|
logger14.info("terminateScope: no active runtime", { agentId, scope: scopeKey(scope) });
|
|
121735
122223
|
this.dormantScopes.delete(key);
|
|
121736
122224
|
this.dormantGroupInboxes.delete(key);
|
|
122225
|
+
this.pendingSpectate.delete(key);
|
|
121737
122226
|
this.sessionStore.delete(agentId, scope);
|
|
121738
122227
|
this.dispatchMemory.deleteScope(agentId, scope);
|
|
121739
122228
|
return;
|
|
@@ -121756,7 +122245,7 @@ ${lines.join("\n")}`;
|
|
|
121756
122245
|
this.dispatchMemory.deleteScope(agentId, scope);
|
|
121757
122246
|
logger14.info("terminateScope: scoped query removed", { agentId, scope: scopeKey(scope) });
|
|
121758
122247
|
}
|
|
121759
|
-
async closeRuntime(proc, reason) {
|
|
122248
|
+
async closeRuntime(proc, reason, watchdogForensics) {
|
|
121760
122249
|
const key = runtimeKey(proc.agentId, proc.scope);
|
|
121761
122250
|
if (proc.status === "dead") return;
|
|
121762
122251
|
const runtime = this.asRuntime(proc);
|
|
@@ -121833,12 +122322,13 @@ ${lines.join("\n")}`;
|
|
|
121833
122322
|
runtime.currentTask = null;
|
|
121834
122323
|
if (isWatchdog) {
|
|
121835
122324
|
const preservedInbox = proc.groupInbox;
|
|
121836
|
-
|
|
122325
|
+
const preservedInboxSize = preservedInbox.length;
|
|
122326
|
+
if (preservedInboxSize > 0) {
|
|
121837
122327
|
this.dormantGroupInboxes.set(key, [...preservedInbox]);
|
|
121838
122328
|
logger14.info("Preserving groupInbox for dormant agent", {
|
|
121839
122329
|
agentId,
|
|
121840
122330
|
scope: scopeKey(proc.scope),
|
|
121841
|
-
preservedInboxSize
|
|
122331
|
+
preservedInboxSize,
|
|
121842
122332
|
preservedEntries: preservedInbox.map((e) => ({
|
|
121843
122333
|
ackId: e.ackId,
|
|
121844
122334
|
sender: e.senderName,
|
|
@@ -121847,7 +122337,26 @@ ${lines.join("\n")}`;
|
|
|
121847
122337
|
}))
|
|
121848
122338
|
});
|
|
121849
122339
|
}
|
|
121850
|
-
|
|
122340
|
+
const effectiveFallbackId = watchdogForensics?.fallbackId ?? createFallbackId();
|
|
122341
|
+
logFallback(logger14, {
|
|
122342
|
+
fallbackId: effectiveFallbackId,
|
|
122343
|
+
type: "zombie_watchdog",
|
|
122344
|
+
phase: "applied",
|
|
122345
|
+
expected: false,
|
|
122346
|
+
traceId: dormantTraceId,
|
|
122347
|
+
context: {
|
|
122348
|
+
agentId,
|
|
122349
|
+
scope: scopeKey(proc.scope),
|
|
122350
|
+
droppedTaskCount: droppedAckIds.length,
|
|
122351
|
+
preservedInboxSize,
|
|
122352
|
+
sessionDeleted: false
|
|
122353
|
+
}
|
|
122354
|
+
});
|
|
122355
|
+
this.dormantScopes.set(key, {
|
|
122356
|
+
fallbackId: effectiveFallbackId,
|
|
122357
|
+
detectedAt: watchdogForensics?.detectedAt ?? Date.now(),
|
|
122358
|
+
droppedTaskCount: droppedAckIds.length
|
|
122359
|
+
});
|
|
121851
122360
|
this.emit({
|
|
121852
122361
|
type: "agent:dormant",
|
|
121853
122362
|
payload: {
|
|
@@ -121862,13 +122371,15 @@ ${lines.join("\n")}`;
|
|
|
121862
122371
|
agentId,
|
|
121863
122372
|
scope: scopeKey(proc.scope),
|
|
121864
122373
|
droppedTaskCount: droppedAckIds.length,
|
|
121865
|
-
preservedInboxSize: this.dormantGroupInboxes.get(key)?.length ?? 0
|
|
122374
|
+
preservedInboxSize: this.dormantGroupInboxes.get(key)?.length ?? 0,
|
|
122375
|
+
fallbackId: effectiveFallbackId
|
|
121866
122376
|
});
|
|
121867
122377
|
}
|
|
121868
122378
|
proc.status = "dead";
|
|
121869
122379
|
this.agents.delete(key);
|
|
121870
122380
|
this.lastUsedAt.delete(key);
|
|
121871
122381
|
this.clearQuietFlushTimer(runtime);
|
|
122382
|
+
this.teardownSpectate(runtime);
|
|
121872
122383
|
try {
|
|
121873
122384
|
runtime.inputController.close();
|
|
121874
122385
|
await this.awaitQueryReturn(runtime.query, 5e3, agentId);
|
|
@@ -121885,6 +122396,165 @@ ${lines.join("\n")}`;
|
|
|
121885
122396
|
cwd: proc.cwd
|
|
121886
122397
|
});
|
|
121887
122398
|
}
|
|
122399
|
+
/**
|
|
122400
|
+
* Emit `agent:error` for the active reply and every queued/merged/buffered task,
|
|
122401
|
+
* then clear those queues. Used by both the SDK stream-crash path and the
|
|
122402
|
+
* reply-stall watchdog so a torn-down runtime never leaves a carrier reply
|
|
122403
|
+
* stuck in-flight on the server (which would keep absorbing new user messages
|
|
122404
|
+
* as steers of a dead turn).
|
|
122405
|
+
*/
|
|
122406
|
+
failPendingTasksWithError(runtime, errorText, fallbackId) {
|
|
122407
|
+
const pending = [];
|
|
122408
|
+
if (runtime.currentTask) pending.push(runtime.currentTask);
|
|
122409
|
+
pending.push(...runtime.injectedTasks, ...runtime.mergedTasks, ...runtime.planModeBuffer);
|
|
122410
|
+
runtime.currentTask = null;
|
|
122411
|
+
runtime.injectedTasks = [];
|
|
122412
|
+
runtime.mergedTasks = [];
|
|
122413
|
+
runtime.planModeBuffer = [];
|
|
122414
|
+
if (pending.length === 0) return { pendingCount: 0 };
|
|
122415
|
+
const carrier = pending[0];
|
|
122416
|
+
const mergedTasks = pending.slice(1);
|
|
122417
|
+
logger14.warn("Pending tasks failure consolidated", {
|
|
122418
|
+
agentId: runtime.agentId,
|
|
122419
|
+
scope: scopeKey(runtime.scope),
|
|
122420
|
+
pendingCount: pending.length,
|
|
122421
|
+
carrierAckId: carrier.replyMessageId,
|
|
122422
|
+
mergedAckIds: mergedTasks.map((t) => t.replyMessageId),
|
|
122423
|
+
traceId: carrier.traceId,
|
|
122424
|
+
...fallbackId ? { fallbackId } : {}
|
|
122425
|
+
});
|
|
122426
|
+
this.emit({
|
|
122427
|
+
type: "agent:error",
|
|
122428
|
+
payload: {
|
|
122429
|
+
agentId: runtime.agentId,
|
|
122430
|
+
conversationId: carrier.conversationId,
|
|
122431
|
+
ackId: carrier.replyMessageId,
|
|
122432
|
+
traceId: carrier.traceId,
|
|
122433
|
+
error: errorText
|
|
122434
|
+
}
|
|
122435
|
+
});
|
|
122436
|
+
for (const task of mergedTasks) {
|
|
122437
|
+
this.emit({
|
|
122438
|
+
type: "agent:merged",
|
|
122439
|
+
payload: {
|
|
122440
|
+
agentId: runtime.agentId,
|
|
122441
|
+
conversationId: task.conversationId,
|
|
122442
|
+
ackId: task.replyMessageId,
|
|
122443
|
+
mergedIntoAckId: carrier.replyMessageId,
|
|
122444
|
+
groupId: task.groupId,
|
|
122445
|
+
traceId: task.traceId
|
|
122446
|
+
}
|
|
122447
|
+
});
|
|
122448
|
+
}
|
|
122449
|
+
return { pendingCount: pending.length };
|
|
122450
|
+
}
|
|
122451
|
+
/**
|
|
122452
|
+
* Recover an in-flight reply that started but went silent past
|
|
122453
|
+
* `replyStallTimeoutMs` (see the reply-stall fast path in `evictIdle`). The
|
|
122454
|
+
* underlying SDK turn is wedged with no observable progress and no error, so:
|
|
122455
|
+
* 1. clear the (likely interrupted/dangling) session so the next dispatch
|
|
122456
|
+
* starts fresh instead of resuming the same wedged transcript;
|
|
122457
|
+
* 2. release the carrier reply + queued steers via `agent:error` so the
|
|
122458
|
+
* client stops waiting and the next user message starts a brand-new reply;
|
|
122459
|
+
* 3. tear the wedged runtime down.
|
|
122460
|
+
*/
|
|
122461
|
+
async recoverStalledReply(proc, silentMs) {
|
|
122462
|
+
if (proc.status === "dead") return;
|
|
122463
|
+
const runtime = this.asRuntime(proc);
|
|
122464
|
+
const key = runtimeKey(proc.agentId, proc.scope);
|
|
122465
|
+
const replyStallFallbackId = createFallbackId();
|
|
122466
|
+
const stallTraceId = proc.currentTask?.traceId;
|
|
122467
|
+
logger14.warn("Reply stall watchdog: in-flight reply silent too long, recovering", {
|
|
122468
|
+
agentId: proc.agentId,
|
|
122469
|
+
scope: scopeKey(proc.scope),
|
|
122470
|
+
silentMs,
|
|
122471
|
+
replyStallTimeoutMs: this.queryConfig.replyStallTimeoutMs,
|
|
122472
|
+
replyMessageId: proc.currentTask?.replyMessageId,
|
|
122473
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
122474
|
+
lastSdkEventAt: new Date(proc.lastSdkEventAt).toISOString(),
|
|
122475
|
+
fallbackId: replyStallFallbackId,
|
|
122476
|
+
// Breadcrumb: what the wedged turn was doing the instant it went silent.
|
|
122477
|
+
// (subagent Task call? mid tool_use? which provider?) — the difference
|
|
122478
|
+
// between a one-off and a systemic provider/tool stall.
|
|
122479
|
+
model: proc.model ?? "(unknown)",
|
|
122480
|
+
lastSdkEvent: proc.lastSdkEventInfo,
|
|
122481
|
+
currentBlockType: proc.currentBlockType,
|
|
122482
|
+
currentToolName: proc.currentToolName,
|
|
122483
|
+
openMcpInvocationId: proc.currentMcpInvocationId ?? null
|
|
122484
|
+
});
|
|
122485
|
+
logFallback(logger14, {
|
|
122486
|
+
fallbackId: replyStallFallbackId,
|
|
122487
|
+
type: "reply_stall",
|
|
122488
|
+
phase: "detected",
|
|
122489
|
+
expected: false,
|
|
122490
|
+
traceId: stallTraceId,
|
|
122491
|
+
context: {
|
|
122492
|
+
agentId: proc.agentId,
|
|
122493
|
+
scope: scopeKey(proc.scope),
|
|
122494
|
+
silentMs,
|
|
122495
|
+
model: proc.model ?? "(unknown)",
|
|
122496
|
+
replyMessageId: proc.currentTask?.replyMessageId ?? null,
|
|
122497
|
+
currentToolName: proc.currentToolName ?? null,
|
|
122498
|
+
lastSdkEventType: proc.lastSdkEventInfo?.type ?? null,
|
|
122499
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
122500
|
+
mergedTaskCount: runtime.mergedTasks.length,
|
|
122501
|
+
planModeBufferCount: runtime.planModeBuffer.length
|
|
122502
|
+
}
|
|
122503
|
+
});
|
|
122504
|
+
this.sessionStore.delete(proc.agentId, proc.scope);
|
|
122505
|
+
this.dispatchMemory.deleteScope(proc.agentId, proc.scope);
|
|
122506
|
+
const failSummary = this.failPendingTasksWithError(
|
|
122507
|
+
runtime,
|
|
122508
|
+
"\u56DE\u590D\u957F\u65F6\u95F4\u65E0\u54CD\u5E94\uFF0C\u5DF2\u91CD\u7F6E\u8BE5\u4F1A\u8BDD\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6D88\u606F\u3002",
|
|
122509
|
+
replyStallFallbackId
|
|
122510
|
+
);
|
|
122511
|
+
proc.status = "dead";
|
|
122512
|
+
this.agents.delete(key);
|
|
122513
|
+
this.lastUsedAt.delete(key);
|
|
122514
|
+
this.clearQuietFlushTimer(runtime);
|
|
122515
|
+
let queryCloseOk = true;
|
|
122516
|
+
try {
|
|
122517
|
+
runtime.inputController.close();
|
|
122518
|
+
await this.awaitQueryReturn(runtime.query, 5e3, proc.agentId);
|
|
122519
|
+
} catch (e) {
|
|
122520
|
+
queryCloseOk = false;
|
|
122521
|
+
logger14.error("reply_stall: close query failed", {
|
|
122522
|
+
agentId: proc.agentId,
|
|
122523
|
+
scope: scopeKey(proc.scope),
|
|
122524
|
+
error: e
|
|
122525
|
+
});
|
|
122526
|
+
}
|
|
122527
|
+
logFallback(logger14, {
|
|
122528
|
+
fallbackId: replyStallFallbackId,
|
|
122529
|
+
type: "reply_stall",
|
|
122530
|
+
phase: "applied",
|
|
122531
|
+
expected: false,
|
|
122532
|
+
traceId: stallTraceId,
|
|
122533
|
+
context: {
|
|
122534
|
+
agentId: proc.agentId,
|
|
122535
|
+
scope: scopeKey(proc.scope),
|
|
122536
|
+
sessionDeleted: true,
|
|
122537
|
+
failedTaskCount: failSummary.pendingCount,
|
|
122538
|
+
queryClosed: queryCloseOk
|
|
122539
|
+
}
|
|
122540
|
+
});
|
|
122541
|
+
logFallback(logger14, {
|
|
122542
|
+
fallbackId: replyStallFallbackId,
|
|
122543
|
+
type: "reply_stall",
|
|
122544
|
+
phase: "outcome",
|
|
122545
|
+
expected: false,
|
|
122546
|
+
traceId: stallTraceId,
|
|
122547
|
+
context: {
|
|
122548
|
+
agentId: proc.agentId,
|
|
122549
|
+
scope: scopeKey(proc.scope),
|
|
122550
|
+
failedTaskCount: failSummary.pendingCount
|
|
122551
|
+
},
|
|
122552
|
+
outcome: {
|
|
122553
|
+
result: "session_reset_awaiting_user",
|
|
122554
|
+
dataLossSuspected: failSummary.pendingCount > 0
|
|
122555
|
+
}
|
|
122556
|
+
});
|
|
122557
|
+
}
|
|
121888
122558
|
async recoverFromRestart(agents) {
|
|
121889
122559
|
const lockSnapshot = readCronLockSnapshot();
|
|
121890
122560
|
logger14.info("Recovering Agent sessions after restart", {
|
|
@@ -122007,58 +122677,7 @@ ${lines.join("\n")}`;
|
|
|
122007
122677
|
this.lastUsedAt.delete(key);
|
|
122008
122678
|
const errorText = isResumeFail ? `\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6D88\u606F\uFF08${errMsg}\uFF09` : `Agent query crashed: ${errMsg}`;
|
|
122009
122679
|
const emittedErrorText = isUnsupportedVisionInput ? "Current model/backend does not support image multimodal input. This image message failed; AHChat has cleared this scope session and future messages will send attachments as paths/text references." : errorText;
|
|
122010
|
-
|
|
122011
|
-
this.emit({
|
|
122012
|
-
type: "agent:error",
|
|
122013
|
-
payload: {
|
|
122014
|
-
agentId: runtime.agentId,
|
|
122015
|
-
conversationId: runtime.currentTask.conversationId,
|
|
122016
|
-
ackId: runtime.currentTask.replyMessageId,
|
|
122017
|
-
traceId: runtime.currentTask.traceId,
|
|
122018
|
-
error: emittedErrorText
|
|
122019
|
-
}
|
|
122020
|
-
});
|
|
122021
|
-
runtime.currentTask = null;
|
|
122022
|
-
}
|
|
122023
|
-
for (const task of runtime.injectedTasks) {
|
|
122024
|
-
this.emit({
|
|
122025
|
-
type: "agent:error",
|
|
122026
|
-
payload: {
|
|
122027
|
-
agentId: runtime.agentId,
|
|
122028
|
-
conversationId: task.conversationId,
|
|
122029
|
-
ackId: task.replyMessageId,
|
|
122030
|
-
traceId: task.traceId,
|
|
122031
|
-
error: emittedErrorText
|
|
122032
|
-
}
|
|
122033
|
-
});
|
|
122034
|
-
}
|
|
122035
|
-
runtime.injectedTasks = [];
|
|
122036
|
-
for (const task of runtime.mergedTasks) {
|
|
122037
|
-
this.emit({
|
|
122038
|
-
type: "agent:error",
|
|
122039
|
-
payload: {
|
|
122040
|
-
agentId: runtime.agentId,
|
|
122041
|
-
conversationId: task.conversationId,
|
|
122042
|
-
ackId: task.replyMessageId,
|
|
122043
|
-
traceId: task.traceId,
|
|
122044
|
-
error: emittedErrorText
|
|
122045
|
-
}
|
|
122046
|
-
});
|
|
122047
|
-
}
|
|
122048
|
-
runtime.mergedTasks = [];
|
|
122049
|
-
for (const task of runtime.planModeBuffer) {
|
|
122050
|
-
this.emit({
|
|
122051
|
-
type: "agent:error",
|
|
122052
|
-
payload: {
|
|
122053
|
-
agentId: runtime.agentId,
|
|
122054
|
-
conversationId: task.conversationId,
|
|
122055
|
-
ackId: task.replyMessageId,
|
|
122056
|
-
traceId: task.traceId,
|
|
122057
|
-
error: emittedErrorText
|
|
122058
|
-
}
|
|
122059
|
-
});
|
|
122060
|
-
}
|
|
122061
|
-
runtime.planModeBuffer = [];
|
|
122680
|
+
this.failPendingTasksWithError(runtime, emittedErrorText);
|
|
122062
122681
|
}
|
|
122063
122682
|
}
|
|
122064
122683
|
getStatus(agentId, scope = { kind: "single" }) {
|
|
@@ -122072,6 +122691,18 @@ ${lines.join("\n")}`;
|
|
|
122072
122691
|
}
|
|
122073
122692
|
return [...ids];
|
|
122074
122693
|
}
|
|
122694
|
+
/** Unified signal: is the turn legitimately waiting on a live external call that emits no
|
|
122695
|
+
* parent heartbeat? Used by BOTH the reply-stall fast path and the zombie watchdog so neither
|
|
122696
|
+
* tears down a turn that is merely slow. Returns the reason for diagnostics, or null when idle.
|
|
122697
|
+
* - open_tool: regular tool, MCP tool, AskUserQuestion wait, or ExitPlanMode (tool_use open).
|
|
122698
|
+
* - subagent: Task/Agent in flight (its inner tool_results clear activeToolUseStartedAt).
|
|
122699
|
+
* - compact: bridge-injected /compact running. */
|
|
122700
|
+
busyReason(proc) {
|
|
122701
|
+
if (proc.activeToolUseStartedAt != null || this.latestOpenToolUse(proc) != null) return "open_tool";
|
|
122702
|
+
if ((proc.activeSubagentTaskIds?.size ?? 0) > 0) return "subagent";
|
|
122703
|
+
if (proc.compactInProgress === true) return "compact";
|
|
122704
|
+
return null;
|
|
122705
|
+
}
|
|
122075
122706
|
latestOpenToolUse(proc) {
|
|
122076
122707
|
for (let i = proc.contentBlocks.length - 1; i >= 0; i -= 1) {
|
|
122077
122708
|
const block = proc.contentBlocks[i];
|
|
@@ -122220,7 +122851,7 @@ ${lines.join("\n")}`;
|
|
|
122220
122851
|
}
|
|
122221
122852
|
const task = {
|
|
122222
122853
|
content: notice,
|
|
122223
|
-
replyMessageId:
|
|
122854
|
+
replyMessageId: createScopeNoticeReplyMessageId(),
|
|
122224
122855
|
conversationId,
|
|
122225
122856
|
traceId: createTraceId(),
|
|
122226
122857
|
groupId: proc.scope.kind === "group" ? proc.scope.groupId : void 0
|
|
@@ -123307,6 +123938,7 @@ var HttpMcpRegistry = class {
|
|
|
123307
123938
|
buildForAgent(ctx) {
|
|
123308
123939
|
const mcpServers = {};
|
|
123309
123940
|
const allowedTools = [];
|
|
123941
|
+
const toolAbi = [];
|
|
123310
123942
|
const usedNames = /* @__PURE__ */ new Set();
|
|
123311
123943
|
for (const connection of this.allConnections()) {
|
|
123312
123944
|
if (!this.connectionAppliesToAgent(connection, ctx)) continue;
|
|
@@ -123315,12 +123947,18 @@ var HttpMcpRegistry = class {
|
|
|
123315
123947
|
const serverName = uniqueServerName(normalizeMcpServerName(connection.serverName), usedNames);
|
|
123316
123948
|
usedNames.add(serverName);
|
|
123317
123949
|
mcpServers[serverName] = sdkConfig;
|
|
123318
|
-
|
|
123319
|
-
|
|
123320
|
-
|
|
123321
|
-
|
|
123950
|
+
const visibleTools = connection.tools.filter((tool2) => tool2.enabled && tool2.permissionPolicy !== "always_deny");
|
|
123951
|
+
for (const tool2 of visibleTools) allowedTools.push(mcpRuntimeToolName(serverName, tool2.name));
|
|
123952
|
+
toolAbi.push({
|
|
123953
|
+
serverName,
|
|
123954
|
+
providerId: connection.providerId,
|
|
123955
|
+
transport: connection.transport,
|
|
123956
|
+
alwaysLoad: connection.alwaysLoad,
|
|
123957
|
+
isBuiltin: connection.isBuiltin,
|
|
123958
|
+
tools: visibleTools.map((tool2) => runtimeToolAbi(serverName, tool2)).sort((a, b) => a.runtimeToolName.localeCompare(b.runtimeToolName))
|
|
123959
|
+
});
|
|
123322
123960
|
}
|
|
123323
|
-
return { mcpServers, allowedTools };
|
|
123961
|
+
return { mcpServers, allowedTools, toolAbi };
|
|
123324
123962
|
}
|
|
123325
123963
|
allConnections() {
|
|
123326
123964
|
return [...this.serverConnections.values(), ...this.localConnections.values()];
|
|
@@ -123506,6 +124144,18 @@ function uniqueServerName(serverName, usedNames) {
|
|
|
123506
124144
|
while (usedNames.has(`${serverName}_${idx}`)) idx += 1;
|
|
123507
124145
|
return `${serverName}_${idx}`;
|
|
123508
124146
|
}
|
|
124147
|
+
function runtimeToolAbi(serverName, tool2) {
|
|
124148
|
+
return {
|
|
124149
|
+
name: tool2.name,
|
|
124150
|
+
runtimeToolName: mcpRuntimeToolName(serverName, tool2.name),
|
|
124151
|
+
displayName: tool2.displayName,
|
|
124152
|
+
description: tool2.description,
|
|
124153
|
+
category: tool2.category,
|
|
124154
|
+
riskLevel: tool2.riskLevel,
|
|
124155
|
+
permissionPolicy: tool2.permissionPolicy,
|
|
124156
|
+
...tool2.inputSchema !== void 0 ? { inputSchema: tool2.inputSchema } : {}
|
|
124157
|
+
};
|
|
124158
|
+
}
|
|
123509
124159
|
function buildHeaders(authType, authSecret, customHeaders) {
|
|
123510
124160
|
const headers = {};
|
|
123511
124161
|
for (const header of customHeaders) {
|
|
@@ -124162,6 +124812,7 @@ var ServerConnector = class {
|
|
|
124162
124812
|
case "agent:terminate":
|
|
124163
124813
|
case "agent:runtime_reload":
|
|
124164
124814
|
case "agent:terminate_scope":
|
|
124815
|
+
case "spectate:set":
|
|
124165
124816
|
case "agent:created":
|
|
124166
124817
|
case "agent:updated":
|
|
124167
124818
|
case "agent:workdir-updated":
|
|
@@ -125139,24 +125790,6 @@ function normalizeLocalPath(targetPath) {
|
|
|
125139
125790
|
const expanded = trimmed === "~" || trimmed.startsWith("~/") || trimmed.startsWith("~\\") ? import_node_path18.default.join(import_node_os10.default.homedir(), trimmed.slice(2)) : trimmed;
|
|
125140
125791
|
return import_node_path18.default.normalize(import_node_path18.default.resolve(expanded));
|
|
125141
125792
|
}
|
|
125142
|
-
function isAbsoluteLocalPathCandidate(value) {
|
|
125143
|
-
if (process.platform === "win32") {
|
|
125144
|
-
return /^[a-zA-Z]:[\\/]/.test(value) || /^\\\\[^\\]/.test(value);
|
|
125145
|
-
}
|
|
125146
|
-
return value.startsWith("/");
|
|
125147
|
-
}
|
|
125148
|
-
function clipboardTextToPathCandidates(value) {
|
|
125149
|
-
return value.replace(/\0/g, "\n").split(/\r?\n/).map((line) => line.trim().replace(/^"(.+)"$/, "$1")).map((line) => {
|
|
125150
|
-
if (!line.toLowerCase().startsWith("file://")) return line;
|
|
125151
|
-
try {
|
|
125152
|
-
const url2 = new URL(line);
|
|
125153
|
-
return decodeURIComponent(url2.pathname.replace(/^\/([a-zA-Z]:\/)/, "$1"));
|
|
125154
|
-
} catch (e) {
|
|
125155
|
-
logger25.debug("Failed to parse clipboard file URL", { error: e });
|
|
125156
|
-
return "";
|
|
125157
|
-
}
|
|
125158
|
-
}).filter((line) => line.length > 0 && isAbsoluteLocalPathCandidate(line));
|
|
125159
|
-
}
|
|
125160
125793
|
function normalizeClipboardIdentityKey(value) {
|
|
125161
125794
|
return process.platform === "win32" ? value.toLowerCase() : value;
|
|
125162
125795
|
}
|
|
@@ -125194,18 +125827,15 @@ function mimeTypeForFileName(fileName) {
|
|
|
125194
125827
|
}
|
|
125195
125828
|
function parseWindowsClipboardResult(stdout) {
|
|
125196
125829
|
const raw = stdout.trim();
|
|
125197
|
-
if (!raw) return { files: []
|
|
125830
|
+
if (!raw) return { files: [] };
|
|
125198
125831
|
try {
|
|
125199
125832
|
const parsed = JSON.parse(raw);
|
|
125200
|
-
if (!isRecord5(parsed)) return { files: []
|
|
125833
|
+
if (!isRecord5(parsed)) return { files: [] };
|
|
125201
125834
|
const files = Array.isArray(parsed.files) ? parsed.files.filter((item) => typeof item === "string") : [];
|
|
125202
|
-
return {
|
|
125203
|
-
files,
|
|
125204
|
-
text: typeof parsed.text === "string" ? parsed.text : ""
|
|
125205
|
-
};
|
|
125835
|
+
return { files };
|
|
125206
125836
|
} catch (e) {
|
|
125207
125837
|
logger25.debug("Windows clipboard JSON parse skipped", { error: e });
|
|
125208
|
-
return { files:
|
|
125838
|
+
return { files: [] };
|
|
125209
125839
|
}
|
|
125210
125840
|
}
|
|
125211
125841
|
async function readWindowsClipboardPathCandidates() {
|
|
@@ -125218,9 +125848,7 @@ async function readWindowsClipboardPathCandidates() {
|
|
|
125218
125848
|
" $drop = [System.Windows.Forms.Clipboard]::GetFileDropList();",
|
|
125219
125849
|
" foreach ($file in $drop) { $files += [string]$file }",
|
|
125220
125850
|
"} catch {}",
|
|
125221
|
-
|
|
125222
|
-
"try { $text = [System.Windows.Forms.Clipboard]::GetText() } catch {}",
|
|
125223
|
-
"[pscustomobject]@{ files = $files; text = $text } | ConvertTo-Json -Compress;"
|
|
125851
|
+
"[pscustomobject]@{ files = $files } | ConvertTo-Json -Compress;"
|
|
125224
125852
|
].join(" ");
|
|
125225
125853
|
try {
|
|
125226
125854
|
const { stdout } = await execFileAsync2("powershell.exe", [
|
|
@@ -125238,7 +125866,7 @@ async function readWindowsClipboardPathCandidates() {
|
|
|
125238
125866
|
maxBuffer: 1024 * 1024
|
|
125239
125867
|
});
|
|
125240
125868
|
const result = parseWindowsClipboardResult(stdout);
|
|
125241
|
-
return
|
|
125869
|
+
return result.files;
|
|
125242
125870
|
} catch (e) {
|
|
125243
125871
|
logger25.debug("Windows clipboard file read skipped", { error: e });
|
|
125244
125872
|
return [];
|
|
@@ -125644,7 +126272,7 @@ async function readStreamText(filePath, start) {
|
|
|
125644
126272
|
function parseProcessedLines(raw, cursor, fileName, fingerprint) {
|
|
125645
126273
|
const lastNewline = raw.lastIndexOf("\n");
|
|
125646
126274
|
if (lastNewline < 0) {
|
|
125647
|
-
return { entries: [], nextCursor: cursor, advanced: false };
|
|
126275
|
+
return { entries: [], nextCursor: cursor, advanced: false, reason: "partial_line" };
|
|
125648
126276
|
}
|
|
125649
126277
|
const processed = raw.slice(0, lastNewline + 1);
|
|
125650
126278
|
const lines = processed.split(/\r?\n/);
|
|
@@ -125670,7 +126298,8 @@ function parseProcessedLines(raw, cursor, fileName, fingerprint) {
|
|
|
125670
126298
|
lineNum,
|
|
125671
126299
|
...fingerprint ? { fingerprint } : {}
|
|
125672
126300
|
},
|
|
125673
|
-
advanced: true
|
|
126301
|
+
advanced: true,
|
|
126302
|
+
reason: "advanced"
|
|
125674
126303
|
};
|
|
125675
126304
|
}
|
|
125676
126305
|
function chunkEntries(entries, size) {
|
|
@@ -125728,24 +126357,55 @@ var BridgeLogUploader = class {
|
|
|
125728
126357
|
async flushOnce() {
|
|
125729
126358
|
if (this.running || this.stopped) return;
|
|
125730
126359
|
this.running = true;
|
|
126360
|
+
const startedAt = Date.now();
|
|
126361
|
+
const summary = {
|
|
126362
|
+
targetCount: 0,
|
|
126363
|
+
advancedTargetCount: 0,
|
|
126364
|
+
missingTargetCount: 0,
|
|
126365
|
+
idleTargetCount: 0,
|
|
126366
|
+
partialLineTargetCount: 0,
|
|
126367
|
+
failedTargetCount: 0,
|
|
126368
|
+
parsedEntryCount: 0,
|
|
126369
|
+
bridgeEntryCount: 0,
|
|
126370
|
+
uploadedChunkCount: 0,
|
|
126371
|
+
accepted: 0,
|
|
126372
|
+
skipped: 0
|
|
126373
|
+
};
|
|
125731
126374
|
try {
|
|
125732
126375
|
const targets = await this.resolveTargets();
|
|
126376
|
+
summary.targetCount = targets.length;
|
|
125733
126377
|
for (const target of targets) {
|
|
125734
126378
|
try {
|
|
125735
126379
|
const cursor = await readCursor(target.cursorFile);
|
|
125736
126380
|
const batch = await this.readNewEntries(target, cursor);
|
|
125737
|
-
if (!batch.advanced)
|
|
126381
|
+
if (!batch.advanced) {
|
|
126382
|
+
summary.idleTargetCount += 1;
|
|
126383
|
+
if (batch.reason === "missing_file") summary.missingTargetCount += 1;
|
|
126384
|
+
if (batch.reason === "partial_line") summary.partialLineTargetCount += 1;
|
|
126385
|
+
continue;
|
|
126386
|
+
}
|
|
126387
|
+
summary.advancedTargetCount += 1;
|
|
126388
|
+
summary.parsedEntryCount += batch.entries.length;
|
|
125738
126389
|
if (batch.entries.length > 0) {
|
|
125739
|
-
await this.uploadEntries(batch.entries);
|
|
126390
|
+
const result = await this.uploadEntries(batch.entries);
|
|
126391
|
+
summary.bridgeEntryCount += result.bridgeEntryCount;
|
|
126392
|
+
summary.uploadedChunkCount += result.uploadedChunkCount;
|
|
126393
|
+
summary.accepted += result.accepted;
|
|
126394
|
+
summary.skipped += result.skipped;
|
|
125740
126395
|
}
|
|
125741
126396
|
await writeCursor(target.cursorFile, batch.nextCursor);
|
|
125742
126397
|
} catch (e) {
|
|
126398
|
+
summary.failedTargetCount += 1;
|
|
125743
126399
|
logger28.warn("Bridge log upload target failed", { error: e, logFile: target.logFile });
|
|
125744
126400
|
}
|
|
125745
126401
|
}
|
|
125746
126402
|
} catch (e) {
|
|
125747
126403
|
logger28.warn("Bridge log upload cycle failed", { error: e });
|
|
125748
126404
|
} finally {
|
|
126405
|
+
logger28.info("Bridge log upload cycle summary", {
|
|
126406
|
+
...summary,
|
|
126407
|
+
durationMs: Date.now() - startedAt
|
|
126408
|
+
});
|
|
125749
126409
|
this.running = false;
|
|
125750
126410
|
}
|
|
125751
126411
|
}
|
|
@@ -125768,7 +126428,7 @@ var BridgeLogUploader = class {
|
|
|
125768
126428
|
} catch (e) {
|
|
125769
126429
|
if (e instanceof Error && "code" in e && e.code === "ENOENT") {
|
|
125770
126430
|
logger28.debug("Bridge log file not found for upload yet", { logFile: target.logFile });
|
|
125771
|
-
return { entries: [], nextCursor: cursor, advanced: false };
|
|
126431
|
+
return { entries: [], nextCursor: cursor, advanced: false, reason: "missing_file" };
|
|
125772
126432
|
}
|
|
125773
126433
|
throw e;
|
|
125774
126434
|
}
|
|
@@ -125776,13 +126436,19 @@ var BridgeLogUploader = class {
|
|
|
125776
126436
|
const samePhysicalFile = !fingerprint || !cursor.fingerprint || cursor.fingerprint === fingerprint;
|
|
125777
126437
|
const normalizedCursor = stat3.size < cursor.offset || !samePhysicalFile ? { offset: 0, lineNum: 0, ...fingerprint ? { fingerprint } : {} } : { ...cursor, ...fingerprint ? { fingerprint } : {} };
|
|
125778
126438
|
if (stat3.size <= normalizedCursor.offset) {
|
|
125779
|
-
return { entries: [], nextCursor: normalizedCursor, advanced: false };
|
|
126439
|
+
return { entries: [], nextCursor: normalizedCursor, advanced: false, reason: "no_new_entries" };
|
|
125780
126440
|
}
|
|
125781
126441
|
const raw = await readStreamText(target.logFile, normalizedCursor.offset);
|
|
125782
126442
|
return parseProcessedLines(raw, normalizedCursor, target.uploadedFileName, fingerprint);
|
|
125783
126443
|
}
|
|
125784
126444
|
async uploadEntries(entries) {
|
|
125785
126445
|
const bridgeEntries = entries.filter((entry) => entry.source === "bridge");
|
|
126446
|
+
const result = {
|
|
126447
|
+
bridgeEntryCount: bridgeEntries.length,
|
|
126448
|
+
uploadedChunkCount: 0,
|
|
126449
|
+
accepted: 0,
|
|
126450
|
+
skipped: 0
|
|
126451
|
+
};
|
|
125786
126452
|
for (const chunk of chunkEntries(bridgeEntries, this.options.batchSize)) {
|
|
125787
126453
|
const res = await fetch(`${this.options.serverApiUrl}/api/logs/upload`, {
|
|
125788
126454
|
method: "POST",
|
|
@@ -125797,14 +126463,18 @@ var BridgeLogUploader = class {
|
|
|
125797
126463
|
})
|
|
125798
126464
|
});
|
|
125799
126465
|
if (!res.ok) {
|
|
125800
|
-
const
|
|
126466
|
+
const body2 = await res.text().catch((e) => {
|
|
125801
126467
|
logger28.debug("Failed to read log upload error body", { error: e });
|
|
125802
126468
|
return "";
|
|
125803
126469
|
});
|
|
125804
|
-
throw new Error(`upload failed HTTP ${res.status}: ${
|
|
126470
|
+
throw new Error(`upload failed HTTP ${res.status}: ${body2.slice(0, 160)}`);
|
|
125805
126471
|
}
|
|
125806
|
-
await res.json();
|
|
126472
|
+
const body = await res.json();
|
|
126473
|
+
result.uploadedChunkCount += 1;
|
|
126474
|
+
result.accepted += typeof body.accepted === "number" ? body.accepted : 0;
|
|
126475
|
+
result.skipped += typeof body.skipped === "number" ? body.skipped : 0;
|
|
125807
126476
|
}
|
|
126477
|
+
return result;
|
|
125808
126478
|
}
|
|
125809
126479
|
};
|
|
125810
126480
|
|
|
@@ -127802,6 +128472,33 @@ function syncLocalRuntimeSkills(skillStore, localSkills, options = {}) {
|
|
|
127802
128472
|
]);
|
|
127803
128473
|
}
|
|
127804
128474
|
|
|
128475
|
+
// src/processOutput.ts
|
|
128476
|
+
init_cjs_shims();
|
|
128477
|
+
var protectedStreams2 = /* @__PURE__ */ new WeakSet();
|
|
128478
|
+
var reportedErrors = /* @__PURE__ */ new WeakSet();
|
|
128479
|
+
function reportWriteError(error51, onError) {
|
|
128480
|
+
if (typeof error51 === "object" && error51 !== null) {
|
|
128481
|
+
if (reportedErrors.has(error51)) return;
|
|
128482
|
+
reportedErrors.add(error51);
|
|
128483
|
+
}
|
|
128484
|
+
onError(error51);
|
|
128485
|
+
}
|
|
128486
|
+
function safeWriteProcessOutput(stream, text, onError) {
|
|
128487
|
+
if (!stream) return;
|
|
128488
|
+
if (stream.destroyed || stream.writableEnded) return;
|
|
128489
|
+
if (typeof stream === "object" && typeof stream.on === "function" && !protectedStreams2.has(stream)) {
|
|
128490
|
+
protectedStreams2.add(stream);
|
|
128491
|
+
stream.on("error", (e) => reportWriteError(e, onError));
|
|
128492
|
+
}
|
|
128493
|
+
try {
|
|
128494
|
+
stream.write(text, (error51) => {
|
|
128495
|
+
if (error51) reportWriteError(error51, onError);
|
|
128496
|
+
});
|
|
128497
|
+
} catch (e) {
|
|
128498
|
+
reportWriteError(e, onError);
|
|
128499
|
+
}
|
|
128500
|
+
}
|
|
128501
|
+
|
|
127805
128502
|
// src/start.ts
|
|
127806
128503
|
var logger41 = createModuleLogger("bridge");
|
|
127807
128504
|
var NODE_USER_UID2 = 1e3;
|
|
@@ -127888,14 +128585,16 @@ async function startBridge(config2) {
|
|
|
127888
128585
|
const claudeRuntime = resolveClaudeRuntime();
|
|
127889
128586
|
logClaudeRuntimeResolution(claudeRuntime);
|
|
127890
128587
|
if (!claudeRuntime.ok || !claudeRuntime.path) {
|
|
127891
|
-
|
|
128588
|
+
safeWriteProcessOutput(
|
|
128589
|
+
process.stderr,
|
|
127892
128590
|
`
|
|
127893
128591
|
Claude runtime is unavailable.
|
|
127894
128592
|
|
|
127895
128593
|
${claudeRuntime.error ?? "Install Claude Code manually or use the bundled desktop runtime."}
|
|
127896
128594
|
|
|
127897
128595
|
Reinstall @fangyb/ahchat-bridge with npm optional dependencies, set AHCHAT_CLAUDE_EXECUTABLE to a valid Claude Code binary path, install Claude Code, or use ALL-CAN Desktop with its bundled runtime.
|
|
127898
|
-
|
|
128596
|
+
`,
|
|
128597
|
+
(e) => logger41.error("Bridge process stderr write failed", { error: e })
|
|
127899
128598
|
);
|
|
127900
128599
|
process.exit(1);
|
|
127901
128600
|
}
|
|
@@ -127952,12 +128651,14 @@ Reinstall @fangyb/ahchat-bridge with npm optional dependencies, set AHCHAT_CLAUD
|
|
|
127952
128651
|
claudeRuntimeVersion: claudeRuntime.version ?? null
|
|
127953
128652
|
});
|
|
127954
128653
|
const shouldPrintRawBridgeToken = process.stdout.isTTY && process.env.AHCHAT_SUPPRESS_BRIDGE_TOKEN_STDOUT !== "1";
|
|
127955
|
-
|
|
128654
|
+
safeWriteProcessOutput(
|
|
128655
|
+
process.stdout,
|
|
127956
128656
|
`
|
|
127957
128657
|
Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\u673A\u5668):
|
|
127958
128658
|
${shouldPrintRawBridgeToken ? config2.bridgeToken : "***"}
|
|
127959
128659
|
|
|
127960
|
-
|
|
128660
|
+
`,
|
|
128661
|
+
(e) => logger41.error("Bridge process stdout write failed", { error: e })
|
|
127961
128662
|
);
|
|
127962
128663
|
wsMetrics.start(5e3);
|
|
127963
128664
|
const sessionStore = new SessionStore(config2.dataDir);
|
|
@@ -128756,6 +129457,19 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
128756
129457
|
});
|
|
128757
129458
|
await agentManager.terminateScope(msg.payload.agentId, msg.payload.scope);
|
|
128758
129459
|
break;
|
|
129460
|
+
case "spectate:set":
|
|
129461
|
+
logger41.info("spectate:set received", {
|
|
129462
|
+
agentId: msg.payload.agentId,
|
|
129463
|
+
scope: msg.payload.scope,
|
|
129464
|
+
action: msg.payload.action,
|
|
129465
|
+
traceId: msg.payload.traceId
|
|
129466
|
+
});
|
|
129467
|
+
await agentManager.setSpectate(
|
|
129468
|
+
msg.payload.agentId,
|
|
129469
|
+
msg.payload.scope,
|
|
129470
|
+
msg.payload.action
|
|
129471
|
+
);
|
|
129472
|
+
break;
|
|
128759
129473
|
case "agent:created":
|
|
128760
129474
|
agentRegistry.upsert(msg.payload.agent);
|
|
128761
129475
|
ensureLocalWorkdirPath(msg.payload.agent.workingDirectory, "agent:created", {
|
|
@@ -128973,8 +129687,12 @@ function writeAlreadyRunningMessage(error51) {
|
|
|
128973
129687
|
` ${buildStopCommand(error51.pid)}`,
|
|
128974
129688
|
""
|
|
128975
129689
|
];
|
|
128976
|
-
|
|
128977
|
-
|
|
129690
|
+
safeWriteProcessOutput(
|
|
129691
|
+
process.stdout,
|
|
129692
|
+
`${lines.join("\n")}
|
|
129693
|
+
`,
|
|
129694
|
+
(e) => logger42.error("Bridge already-running message write failed", { error: e })
|
|
129695
|
+
);
|
|
128978
129696
|
}
|
|
128979
129697
|
function handleBridgeStartError(e, message) {
|
|
128980
129698
|
if (isBridgeAlreadyRunningError(e)) {
|