@fangyb/ahchat-bridge 0.1.35 → 0.1.37
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 +968 -184
- package/dist/feedbackWorkerCli.cjs +165 -8
- package/dist/index.js +963 -184
- package/dist/seedanceMcpCli.cjs +53 -7
- package/dist/seedreamMcpCli.cjs +53 -7
- 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}`);
|
|
@@ -94683,6 +94764,9 @@ function createMessageId() {
|
|
|
94683
94764
|
function createTraceId() {
|
|
94684
94765
|
return `tr_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94685
94766
|
}
|
|
94767
|
+
function createFallbackId() {
|
|
94768
|
+
return `flb_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94769
|
+
}
|
|
94686
94770
|
function createRequestId() {
|
|
94687
94771
|
return `req_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94688
94772
|
}
|
|
@@ -94692,6 +94776,12 @@ function createCronReplyMessageId() {
|
|
|
94692
94776
|
function createInboxFlushReplyMessageId() {
|
|
94693
94777
|
return `msg_inbox_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94694
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
|
+
}
|
|
94695
94785
|
function createCronTraceId() {
|
|
94696
94786
|
return `tr_cron_${Date.now().toString(36)}_${nanoid(6)}`;
|
|
94697
94787
|
}
|
|
@@ -94750,6 +94840,10 @@ function assertStringPayloadOneOf(type, payload, field, allowed) {
|
|
|
94750
94840
|
throw invalidWsMessage(type, field);
|
|
94751
94841
|
}
|
|
94752
94842
|
}
|
|
94843
|
+
function assertOptionalStringPayloadOneOf(type, payload, field, allowed) {
|
|
94844
|
+
if (payload[field] === void 0) return;
|
|
94845
|
+
assertStringPayloadOneOf(type, payload, field, allowed);
|
|
94846
|
+
}
|
|
94753
94847
|
function assertArrayPayloadField(type, payload, field) {
|
|
94754
94848
|
if (!Array.isArray(payload[field])) {
|
|
94755
94849
|
throw invalidWsMessage(type, field);
|
|
@@ -94830,6 +94924,7 @@ function validateWSMessageShape(msg) {
|
|
|
94830
94924
|
case "agent:error": {
|
|
94831
94925
|
assertPayloadRecord(type, payload);
|
|
94832
94926
|
validateRequiredStrings(type, payload, ["ackId", "agentId", "conversationId", "error", "traceId"]);
|
|
94927
|
+
assertOptionalStringPayloadOneOf(type, payload, "reason", ["user_quota_exceeded", "company_quota_exceeded"]);
|
|
94833
94928
|
return;
|
|
94834
94929
|
}
|
|
94835
94930
|
case "directory:register": {
|
|
@@ -96209,6 +96304,9 @@ init_cjs_shims();
|
|
|
96209
96304
|
// ../shared/src/utils/serverUrl.ts
|
|
96210
96305
|
init_cjs_shims();
|
|
96211
96306
|
|
|
96307
|
+
// ../shared/src/utils/phone.ts
|
|
96308
|
+
init_cjs_shims();
|
|
96309
|
+
|
|
96212
96310
|
// ../shared/src/utils/mediaPreviewHtml.ts
|
|
96213
96311
|
init_cjs_shims();
|
|
96214
96312
|
|
|
@@ -96454,6 +96552,60 @@ var readpageScrapeTool = {
|
|
|
96454
96552
|
enabled: true,
|
|
96455
96553
|
permissionPolicy: "always_allow"
|
|
96456
96554
|
};
|
|
96555
|
+
var seedreamGenerateImageTool = {
|
|
96556
|
+
name: "generate_image",
|
|
96557
|
+
displayName: "Seedream \u751F\u56FE",
|
|
96558
|
+
description: "\u4F7F\u7528\u706B\u5C71\u65B9\u821F Seedream \u751F\u6210\u5355\u5F20\u56FE\u7247\uFF0C\u652F\u6301\u6587\u672C\u751F\u56FE\u4E0E\u53C2\u8003\u56FE\u751F\u56FE\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002",
|
|
96559
|
+
category: "media",
|
|
96560
|
+
riskLevel: "medium",
|
|
96561
|
+
enabled: true,
|
|
96562
|
+
permissionPolicy: "always_ask"
|
|
96563
|
+
};
|
|
96564
|
+
var seedreamEditImageTool = {
|
|
96565
|
+
name: "edit_image",
|
|
96566
|
+
displayName: "Seedream \u6539\u56FE",
|
|
96567
|
+
description: "\u4F7F\u7528\u706B\u5C71\u65B9\u821F Seedream \u6839\u636E\u53C2\u8003\u56FE\u548C\u63D0\u793A\u8BCD\u7F16\u8F91\u6216\u91CD\u7ED8\u5355\u5F20\u56FE\u7247\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002",
|
|
96568
|
+
category: "media",
|
|
96569
|
+
riskLevel: "medium",
|
|
96570
|
+
enabled: true,
|
|
96571
|
+
permissionPolicy: "always_ask"
|
|
96572
|
+
};
|
|
96573
|
+
var seedreamGenerateImageGroupTool = {
|
|
96574
|
+
name: "generate_image_group",
|
|
96575
|
+
displayName: "Seedream \u5355\u56FE",
|
|
96576
|
+
description: "\u517C\u5BB9\u65E7\u540D\u79F0\u7684 Seedream \u5355\u56FE\u751F\u6210\u5DE5\u5177\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002\u5F53\u524D\u6BCF\u6B21\u8BF7\u6C42\u53EA\u751F\u6210 1 \u5F20\u56FE\u7247\u3002",
|
|
96577
|
+
category: "media",
|
|
96578
|
+
riskLevel: "medium",
|
|
96579
|
+
enabled: true,
|
|
96580
|
+
permissionPolicy: "always_ask"
|
|
96581
|
+
};
|
|
96582
|
+
var seedanceUsageGuideTool = {
|
|
96583
|
+
name: "seedance_usage_guide",
|
|
96584
|
+
displayName: "Seedance \u4F7F\u7528\u8BF4\u660E",
|
|
96585
|
+
description: "\u67E5\u770B Seedance \u89C6\u9891\u751F\u6210\u6D41\u7A0B\u4E0E\u53C2\u6570\u8BF4\u660E\uFF0C\u4E0D\u521B\u5EFA\u65B0\u7684\u751F\u6210\u4EFB\u52A1\u3002",
|
|
96586
|
+
category: "media",
|
|
96587
|
+
riskLevel: "low",
|
|
96588
|
+
enabled: true,
|
|
96589
|
+
permissionPolicy: "always_allow"
|
|
96590
|
+
};
|
|
96591
|
+
var seedanceCreateTaskTool = {
|
|
96592
|
+
name: "seedance_create_task",
|
|
96593
|
+
displayName: "Seedance \u751F\u89C6\u9891",
|
|
96594
|
+
description: "\u4F7F\u7528\u706B\u5C71\u65B9\u821F Seedance \u521B\u5EFA\u5355\u4E2A\u89C6\u9891\u751F\u6210\u4EFB\u52A1\uFF0C\u4F1A\u4EA7\u751F\u516C\u53F8 Ark \u8D26\u53F7\u7528\u91CF\u3002\u5F53\u524D\u6BCF\u6B21\u8BF7\u6C42\u53EA\u751F\u6210 1 \u4E2A\u89C6\u9891\u3002",
|
|
96595
|
+
category: "media",
|
|
96596
|
+
riskLevel: "high",
|
|
96597
|
+
enabled: true,
|
|
96598
|
+
permissionPolicy: "always_ask"
|
|
96599
|
+
};
|
|
96600
|
+
var seedanceCheckTaskTool = {
|
|
96601
|
+
name: "seedance_check_task",
|
|
96602
|
+
displayName: "Seedance \u67E5\u7ED3\u679C",
|
|
96603
|
+
description: "\u67E5\u8BE2 Seedance \u89C6\u9891\u751F\u6210\u4EFB\u52A1\u72B6\u6001\u4E0E\u89C6\u9891 URL\uFF0C\u4E0D\u521B\u5EFA\u65B0\u7684\u751F\u6210\u4EFB\u52A1\u3002",
|
|
96604
|
+
category: "media",
|
|
96605
|
+
riskLevel: "low",
|
|
96606
|
+
enabled: true,
|
|
96607
|
+
permissionPolicy: "always_allow"
|
|
96608
|
+
};
|
|
96457
96609
|
var context7ResolveLibraryTool = {
|
|
96458
96610
|
name: "resolve-library-id",
|
|
96459
96611
|
displayName: "\u89E3\u6790\u6587\u6863\u5E93",
|
|
@@ -96760,8 +96912,56 @@ var ALIYUN_IQS_MCP_PROVIDERS = [
|
|
|
96760
96912
|
tools: [readpageBasicTool, readpageScrapeTool]
|
|
96761
96913
|
}
|
|
96762
96914
|
];
|
|
96915
|
+
var VOLCENGINE_SEEDREAM_MCP_PROVIDER = {
|
|
96916
|
+
providerId: "volcengine_seedream",
|
|
96917
|
+
name: "Volcengine Seedream",
|
|
96918
|
+
summary: "\u706B\u5C71\u65B9\u821F Seedream \u56FE\u7247\u751F\u6210/\u7F16\u8F91 MCP\uFF0C\u4F7F\u7528\u516C\u53F8\u7EDF\u4E00 Ark Key\uFF0C\u5E76\u8FDB\u5165 AHChat \u8C03\u7528\u5BA1\u8BA1\u3002",
|
|
96919
|
+
serverName: "seedream",
|
|
96920
|
+
transport: "stdio",
|
|
96921
|
+
url: null,
|
|
96922
|
+
command: "ahchat-builtin",
|
|
96923
|
+
args: ["seedream-mcp"],
|
|
96924
|
+
env: {
|
|
96925
|
+
ARK_API_KEY: "",
|
|
96926
|
+
ARK_BASE_URL: "https://ark.cn-beijing.volces.com/api/v3"
|
|
96927
|
+
},
|
|
96928
|
+
authType: "x_api_key",
|
|
96929
|
+
customHeaders: [],
|
|
96930
|
+
enabled: true,
|
|
96931
|
+
alwaysLoad: true,
|
|
96932
|
+
tools: [
|
|
96933
|
+
seedreamGenerateImageTool,
|
|
96934
|
+
seedreamEditImageTool,
|
|
96935
|
+
seedreamGenerateImageGroupTool
|
|
96936
|
+
]
|
|
96937
|
+
};
|
|
96938
|
+
var VOLCENGINE_SEEDANCE_MCP_PROVIDER = {
|
|
96939
|
+
providerId: "volcengine_seedance",
|
|
96940
|
+
name: "Volcengine Seedance",
|
|
96941
|
+
summary: "\u706B\u5C71\u65B9\u821F Seedance \u89C6\u9891\u751F\u6210 MCP\uFF0C\u4F7F\u7528\u516C\u53F8\u7EDF\u4E00 Ark Key\uFF0C\u5E76\u8FDB\u5165 AHChat \u8C03\u7528\u5BA1\u8BA1\u3002",
|
|
96942
|
+
serverName: "seedance",
|
|
96943
|
+
transport: "stdio",
|
|
96944
|
+
url: null,
|
|
96945
|
+
command: "ahchat-builtin",
|
|
96946
|
+
args: ["seedance-mcp"],
|
|
96947
|
+
env: {
|
|
96948
|
+
ARK_API_KEY: "",
|
|
96949
|
+
ARK_BASE_URL: "https://ark.cn-beijing.volces.com/api/v3"
|
|
96950
|
+
},
|
|
96951
|
+
authType: "x_api_key",
|
|
96952
|
+
customHeaders: [],
|
|
96953
|
+
enabled: true,
|
|
96954
|
+
alwaysLoad: true,
|
|
96955
|
+
tools: [
|
|
96956
|
+
seedanceUsageGuideTool,
|
|
96957
|
+
seedanceCreateTaskTool,
|
|
96958
|
+
seedanceCheckTaskTool
|
|
96959
|
+
]
|
|
96960
|
+
};
|
|
96763
96961
|
var OFFICIAL_MCP_PROVIDERS = [
|
|
96764
|
-
...ALIYUN_IQS_MCP_PROVIDERS
|
|
96962
|
+
...ALIYUN_IQS_MCP_PROVIDERS,
|
|
96963
|
+
VOLCENGINE_SEEDREAM_MCP_PROVIDER,
|
|
96964
|
+
VOLCENGINE_SEEDANCE_MCP_PROVIDER
|
|
96765
96965
|
];
|
|
96766
96966
|
var MCP_STORE_PROVIDERS = [
|
|
96767
96967
|
{
|
|
@@ -97573,8 +97773,7 @@ var AskQuestionRegistry = class {
|
|
|
97573
97773
|
questionId,
|
|
97574
97774
|
agentId: entry.agentId,
|
|
97575
97775
|
waitedMs: Date.now() - entry.askedAt,
|
|
97576
|
-
answerLen: answerText2.length
|
|
97577
|
-
answerSample: answerText2.slice(0, 200)
|
|
97776
|
+
answerLen: answerText2.length
|
|
97578
97777
|
});
|
|
97579
97778
|
entry.resolve(answerText2);
|
|
97580
97779
|
return true;
|
|
@@ -97719,7 +97918,7 @@ function makeAskUserQuestionGuard(deps) {
|
|
|
97719
97918
|
bundleIndex,
|
|
97720
97919
|
bundleSize,
|
|
97721
97920
|
replyMessageId: task.replyMessageId,
|
|
97722
|
-
|
|
97921
|
+
questionLen: q.question.length,
|
|
97723
97922
|
optionCount: options.length,
|
|
97724
97923
|
multiSelect,
|
|
97725
97924
|
traceId: task.traceId
|
|
@@ -97818,7 +98017,7 @@ function makeAskUserQuestionGuard(deps) {
|
|
|
97818
98017
|
bundleId,
|
|
97819
98018
|
bundleSize,
|
|
97820
98019
|
replyMessageId: task.replyMessageId,
|
|
97821
|
-
|
|
98020
|
+
combinedLen: combined.length,
|
|
97822
98021
|
traceId: task.traceId
|
|
97823
98022
|
});
|
|
97824
98023
|
return { behavior: "deny", message: combined };
|
|
@@ -112803,6 +113002,17 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
112803
113002
|
".yaml",
|
|
112804
113003
|
".yml"
|
|
112805
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;
|
|
112806
113016
|
var DEFAULT_MAX_CHARS = 5e5;
|
|
112807
113017
|
var DEFAULT_TIMEOUT_MS = 45e3;
|
|
112808
113018
|
function isReadableDocumentPath(filePath) {
|
|
@@ -112822,9 +113032,6 @@ function resolveDocumentPath(inputPath, cwd) {
|
|
|
112822
113032
|
async function readDocumentAsMarkdown(inputPath, opts = {}) {
|
|
112823
113033
|
const resolvedPath = opts.cwd ? resolveDocumentPath(inputPath, opts.cwd) : import_node_path10.default.resolve(resolveUserPath(inputPath));
|
|
112824
113034
|
const ext = import_node_path10.default.extname(resolvedPath).toLowerCase();
|
|
112825
|
-
if (!isReadableDocumentPath(resolvedPath)) {
|
|
112826
|
-
throw new Error(`unsupported document type: ${ext || "(no extension)"}`);
|
|
112827
|
-
}
|
|
112828
113035
|
const stat3 = await import_promises2.default.stat(resolvedPath);
|
|
112829
113036
|
if (!stat3.isFile()) throw new Error("path is not a file");
|
|
112830
113037
|
const warnings = [];
|
|
@@ -112833,8 +113040,10 @@ async function readDocumentAsMarkdown(inputPath, opts = {}) {
|
|
|
112833
113040
|
markdown = await import_promises2.default.readFile(resolvedPath, "utf-8");
|
|
112834
113041
|
} else if (ext === ".xls") {
|
|
112835
113042
|
markdown = await convertLegacyExcelDocument(resolvedPath);
|
|
112836
|
-
} else {
|
|
113043
|
+
} else if (OFFICE_DOCUMENT_EXTENSIONS.has(ext)) {
|
|
112837
113044
|
markdown = await convertOfficeDocument(resolvedPath, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
113045
|
+
} else {
|
|
113046
|
+
markdown = await readPlainTextDocument(resolvedPath, ext);
|
|
112838
113047
|
}
|
|
112839
113048
|
markdown = normalizeDocumentText(markdown);
|
|
112840
113049
|
const maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;
|
|
@@ -112973,6 +113182,14 @@ async function convertDocxWithOfficeCli(filePath, timeoutMs) {
|
|
|
112973
113182
|
});
|
|
112974
113183
|
return text;
|
|
112975
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
|
+
}
|
|
112976
113193
|
async function convertLegacyExcelDocument(filePath) {
|
|
112977
113194
|
const XLSX2 = await Promise.resolve().then(() => (init_xlsx(), xlsx_exports));
|
|
112978
113195
|
const workbook = XLSX2.readFile(filePath, { cellDates: true });
|
|
@@ -113442,8 +113659,7 @@ async function createNeuralMcpServer(deps) {
|
|
|
113442
113659
|
agentId: deps.agentId,
|
|
113443
113660
|
fromScope: currentScopeKey,
|
|
113444
113661
|
rawTargetScope: args.target_scope,
|
|
113445
|
-
messageLen: args.message.length
|
|
113446
|
-
messageSample: args.message.slice(0, 120)
|
|
113662
|
+
messageLen: args.message.length
|
|
113447
113663
|
});
|
|
113448
113664
|
const trimmed = args.message.trim();
|
|
113449
113665
|
if (!trimmed) {
|
|
@@ -113537,7 +113753,7 @@ async function createNeuralMcpServer(deps) {
|
|
|
113537
113753
|
toScope: resolvedKey,
|
|
113538
113754
|
repeatsInWindow: sendHistory.length,
|
|
113539
113755
|
windowMs: NEURAL_DEDUP_WINDOW_MS,
|
|
113540
|
-
|
|
113756
|
+
messageLen: trimmed.length
|
|
113541
113757
|
});
|
|
113542
113758
|
return {
|
|
113543
113759
|
content: [{
|
|
@@ -113564,8 +113780,7 @@ async function createNeuralMcpServer(deps) {
|
|
|
113564
113780
|
agentId: deps.agentId,
|
|
113565
113781
|
fromScope: currentScopeKey,
|
|
113566
113782
|
toScope: resolvedKey,
|
|
113567
|
-
messageLen: trimmed.length
|
|
113568
|
-
messageSample: trimmed.slice(0, 120)
|
|
113783
|
+
messageLen: trimmed.length
|
|
113569
113784
|
});
|
|
113570
113785
|
return {
|
|
113571
113786
|
content: [{ type: "text", text: `[neural_send] \u5DF2\u9001\u8FBE\u5230\u300C${toLabel}\u300D(scope: ${resolvedKey})\u3002` }]
|
|
@@ -113922,6 +114137,7 @@ action="append" \u8FFD\u52A0\u65B0\u5185\u5BB9\uFF08\u6700\u5E38\u7528\uFF0Ccont
|
|
|
113922
114137
|
`Read a document from the current working directory and return extracted Markdown text.
|
|
113923
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.
|
|
113924
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.
|
|
113925
114141
|
Pass either a relative path from the current working directory or an absolute path inside it.`,
|
|
113926
114142
|
{
|
|
113927
114143
|
path: external_exports.string().min(1).describe("Document path, relative to the current working directory or absolute inside it."),
|
|
@@ -116645,9 +116861,12 @@ function isAuthFailureText(text, sdkError) {
|
|
|
116645
116861
|
function isProviderApiErrorText(text) {
|
|
116646
116862
|
return /^API Error:\s*\d+/i.test(text.trim());
|
|
116647
116863
|
}
|
|
116648
|
-
function
|
|
116864
|
+
function isSdkSyntheticNoResponseText(normalizedText) {
|
|
116865
|
+
return normalizedText.replace(/[.!。]+$/g, "") === "no response requested";
|
|
116866
|
+
}
|
|
116867
|
+
function isNoReplyText(text, opts) {
|
|
116649
116868
|
const normalized = text.trim().replace(/^`+|`+$/g, "").trim().toLowerCase();
|
|
116650
|
-
return normalized === NO_REPLY_TOKEN || normalized === "<no-reply>" || normalized === "no-reply" || normalized === "no_reply" || normalized === "no reply";
|
|
116869
|
+
return normalized === NO_REPLY_TOKEN || normalized === "<no-reply>" || normalized === "no-reply" || normalized === "no_reply" || normalized === "no reply" || opts?.allowSdkSyntheticNoResponse === true && isSdkSyntheticNoResponseText(normalized);
|
|
116651
116870
|
}
|
|
116652
116871
|
function decodeJsonStringFragment(raw) {
|
|
116653
116872
|
let out = "";
|
|
@@ -116985,6 +117204,9 @@ function emitUsageReported(proc, emit, base, usage, messageId) {
|
|
|
116985
117204
|
function isGroupTask(proc) {
|
|
116986
117205
|
return proc.currentTask?.groupId != null;
|
|
116987
117206
|
}
|
|
117207
|
+
function shouldStreamInternals(proc) {
|
|
117208
|
+
return !isGroupTask(proc) || proc.spectating === true;
|
|
117209
|
+
}
|
|
116988
117210
|
function extractTodosFromInput(input) {
|
|
116989
117211
|
if (!input || typeof input !== "object") return null;
|
|
116990
117212
|
const raw = input.todos;
|
|
@@ -117116,7 +117338,6 @@ function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = f
|
|
|
117116
117338
|
contentLen: content.length,
|
|
117117
117339
|
blockCount: contentBlocks.length,
|
|
117118
117340
|
blockTypes: contentBlocks.map((b) => b.type),
|
|
117119
|
-
contentSample: content.slice(0, 200),
|
|
117120
117341
|
traceId: base.traceId,
|
|
117121
117342
|
isAuditOnly: content.length === 0,
|
|
117122
117343
|
isSilent
|
|
@@ -117135,7 +117356,7 @@ function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = f
|
|
|
117135
117356
|
}
|
|
117136
117357
|
function flushTextSegmentOnBlockStop(proc, emit, base) {
|
|
117137
117358
|
const trimmed = proc.segmentBuffer.trim();
|
|
117138
|
-
const isSilent = isNoReplyText(trimmed);
|
|
117359
|
+
const isSilent = isNoReplyText(trimmed, { allowSdkSyntheticNoResponse: true });
|
|
117139
117360
|
const isEmpty = trimmed.length === 0;
|
|
117140
117361
|
if (!isEmpty) {
|
|
117141
117362
|
const blocksForSegment = [...proc.contentBlocks, { type: "text", content: proc.segmentBuffer }];
|
|
@@ -117172,9 +117393,24 @@ function flushTextSegmentOnBlockStop(proc, emit, base) {
|
|
|
117172
117393
|
}
|
|
117173
117394
|
proc.segmentBuffer = "";
|
|
117174
117395
|
}
|
|
117396
|
+
function describeSdkEvent(message) {
|
|
117397
|
+
const rec = message;
|
|
117398
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
117399
|
+
return {
|
|
117400
|
+
type: str(rec.type) ?? "unknown",
|
|
117401
|
+
subtype: str(rec.subtype),
|
|
117402
|
+
toolName: str(rec.last_tool_name),
|
|
117403
|
+
subagentType: str(rec.subagent_type),
|
|
117404
|
+
toolUseId: str(rec.tool_use_id),
|
|
117405
|
+
taskId: str(rec.task_id),
|
|
117406
|
+
at: Date.now()
|
|
117407
|
+
};
|
|
117408
|
+
}
|
|
117175
117409
|
function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProviderApiError) {
|
|
117176
117410
|
const emit = rawEmit;
|
|
117177
117411
|
proc.lastSdkEventAt = Date.now();
|
|
117412
|
+
proc.lastSdkEventInfo = describeSdkEvent(message);
|
|
117413
|
+
proc.stallWarned = false;
|
|
117178
117414
|
switch (message.type) {
|
|
117179
117415
|
case "system": {
|
|
117180
117416
|
const sysMsg = message;
|
|
@@ -117213,11 +117449,29 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117213
117449
|
sessionId: proc.ccSessionId
|
|
117214
117450
|
});
|
|
117215
117451
|
} else {
|
|
117452
|
+
const sysRec = sysMsg;
|
|
117453
|
+
const pick2 = (k) => typeof sysRec[k] === "string" || typeof sysRec[k] === "number" ? sysRec[k] : void 0;
|
|
117454
|
+
const descriptionLen = typeof sysRec.description === "string" ? sysRec.description.length : void 0;
|
|
117455
|
+
const subagentTaskId = typeof sysRec.task_id === "string" ? sysRec.task_id : void 0;
|
|
117456
|
+
if (subagentTaskId) {
|
|
117457
|
+
if (sysMsg.subtype === "task_started") {
|
|
117458
|
+
(proc.activeSubagentTaskIds ??= /* @__PURE__ */ new Set()).add(subagentTaskId);
|
|
117459
|
+
} else if (sysMsg.subtype === "task_notification") {
|
|
117460
|
+
proc.activeSubagentTaskIds?.delete(subagentTaskId);
|
|
117461
|
+
}
|
|
117462
|
+
}
|
|
117216
117463
|
logger11.info("SDK system subtype unhandled", {
|
|
117217
117464
|
agentId: proc.agentId,
|
|
117218
117465
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117219
117466
|
subtype: sysMsg.subtype ?? "(none)",
|
|
117220
|
-
|
|
117467
|
+
taskId: pick2("task_id"),
|
|
117468
|
+
toolUseId: pick2("tool_use_id"),
|
|
117469
|
+
subagentType: pick2("subagent_type"),
|
|
117470
|
+
taskType: pick2("task_type"),
|
|
117471
|
+
lastToolName: pick2("last_tool_name"),
|
|
117472
|
+
hasDescription: descriptionLen != null,
|
|
117473
|
+
descriptionLen,
|
|
117474
|
+
keys: Object.keys(sysMsg).slice(0, 16)
|
|
117221
117475
|
});
|
|
117222
117476
|
}
|
|
117223
117477
|
break;
|
|
@@ -117243,13 +117497,14 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117243
117497
|
} else if (block.type === "tool_use") {
|
|
117244
117498
|
proc.currentBlockType = "tool_use";
|
|
117245
117499
|
proc.currentToolName = block.name ?? "unknown";
|
|
117500
|
+
proc.activeToolUseStartedAt = Date.now();
|
|
117246
117501
|
proc.accumulatedToolInput = "";
|
|
117247
117502
|
const toolName = block.name ?? "unknown";
|
|
117248
117503
|
proc.suppressCurrentToolUse = proc.officialMediaGenerationSatisfied === true && isOfficialMediaGenerationToolName(toolName);
|
|
117249
117504
|
const isMcpTool = parseMcpRuntimeToolName(toolName) != null;
|
|
117250
117505
|
proc.currentMcpInvocationId = isMcpTool ? createMcpToolInvocationId() : null;
|
|
117251
117506
|
proc.currentMcpInvocationStartedAt = isMcpTool ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
117252
|
-
if (
|
|
117507
|
+
if (shouldStreamInternals(proc) && !proc.suppressCurrentToolUse && toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
117253
117508
|
emit({
|
|
117254
117509
|
type: "agent:tool_use",
|
|
117255
117510
|
payload: {
|
|
@@ -117274,7 +117529,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117274
117529
|
if (delta.type === "thinking_delta" && typeof delta.thinking === "string") {
|
|
117275
117530
|
if (proc.suppressCurrentThinking) break;
|
|
117276
117531
|
proc.accumulatedThinking += delta.thinking;
|
|
117277
|
-
if (
|
|
117532
|
+
if (shouldStreamInternals(proc)) {
|
|
117278
117533
|
emit({
|
|
117279
117534
|
type: "agent:thinking_chunk",
|
|
117280
117535
|
payload: { ...wireBase(base), chunk: delta.thinking }
|
|
@@ -117285,7 +117540,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117285
117540
|
if (typeof partial2 === "string") {
|
|
117286
117541
|
proc.accumulatedToolInput += partial2;
|
|
117287
117542
|
const liveInput = extractLiveToolInput(proc.currentToolName, proc.accumulatedToolInput);
|
|
117288
|
-
if (
|
|
117543
|
+
if (shouldStreamInternals(proc) && liveInput && proc.currentToolName != null) {
|
|
117289
117544
|
emit({
|
|
117290
117545
|
type: "agent:tool_input_update",
|
|
117291
117546
|
payload: {
|
|
@@ -117319,7 +117574,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117319
117574
|
}
|
|
117320
117575
|
case "content_block_stop": {
|
|
117321
117576
|
if (proc.currentBlockType === "thinking") {
|
|
117322
|
-
if (
|
|
117577
|
+
if (shouldStreamInternals(proc) && !proc.suppressCurrentThinking) {
|
|
117323
117578
|
emit({
|
|
117324
117579
|
type: "agent:thinking_done",
|
|
117325
117580
|
payload: wireBase(getTaskBase(proc))
|
|
@@ -117344,8 +117599,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117344
117599
|
error: error51,
|
|
117345
117600
|
agentId: proc.agentId,
|
|
117346
117601
|
toolName: proc.currentToolName,
|
|
117347
|
-
inputLen: proc.accumulatedToolInput.length
|
|
117348
|
-
sample: proc.accumulatedToolInput.slice(0, 200)
|
|
117602
|
+
inputLen: proc.accumulatedToolInput.length
|
|
117349
117603
|
});
|
|
117350
117604
|
}
|
|
117351
117605
|
}
|
|
@@ -117354,7 +117608,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117354
117608
|
if (lastToolUse && lastToolUse.type === "tool_use") {
|
|
117355
117609
|
lastToolUse.input = parsedInput;
|
|
117356
117610
|
}
|
|
117357
|
-
if (
|
|
117611
|
+
if (shouldStreamInternals(proc) && proc.currentToolName != null && LIVE_INPUT_PREVIEW_TOOLS.has(proc.currentToolName) && Object.keys(parsedInput).length > 0) {
|
|
117358
117612
|
emit({
|
|
117359
117613
|
type: "agent:tool_input_update",
|
|
117360
117614
|
payload: {
|
|
@@ -117478,7 +117732,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117478
117732
|
blockTypes,
|
|
117479
117733
|
hasToolResult,
|
|
117480
117734
|
hasPlainText,
|
|
117481
|
-
|
|
117735
|
+
contentLen: typeof content === "string" ? content.length : JSON.stringify(content).length
|
|
117482
117736
|
});
|
|
117483
117737
|
break;
|
|
117484
117738
|
}
|
|
@@ -117487,7 +117741,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117487
117741
|
agentId: proc.agentId,
|
|
117488
117742
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117489
117743
|
blockTypes,
|
|
117490
|
-
|
|
117744
|
+
contentLen: JSON.stringify(content).length,
|
|
117491
117745
|
replyMessageId: base.replyMessageId
|
|
117492
117746
|
});
|
|
117493
117747
|
}
|
|
@@ -117508,6 +117762,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117508
117762
|
});
|
|
117509
117763
|
proc.currentMcpInvocationId = null;
|
|
117510
117764
|
proc.currentMcpInvocationStartedAt = null;
|
|
117765
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117511
117766
|
proc.currentToolName = null;
|
|
117512
117767
|
continue;
|
|
117513
117768
|
}
|
|
@@ -117515,6 +117770,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117515
117770
|
proc.officialMediaGenerationSatisfied = true;
|
|
117516
117771
|
}
|
|
117517
117772
|
if (isAskUserQuestionToolName(toolName)) {
|
|
117773
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117518
117774
|
proc.currentToolName = null;
|
|
117519
117775
|
continue;
|
|
117520
117776
|
}
|
|
@@ -117542,7 +117798,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117542
117798
|
proc.currentMcpInvocationId = null;
|
|
117543
117799
|
proc.currentMcpInvocationStartedAt = null;
|
|
117544
117800
|
}
|
|
117545
|
-
if (
|
|
117801
|
+
if (shouldStreamInternals(proc)) {
|
|
117546
117802
|
emit({
|
|
117547
117803
|
type: "agent:tool_result",
|
|
117548
117804
|
payload: {
|
|
@@ -117566,6 +117822,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117566
117822
|
}
|
|
117567
117823
|
}
|
|
117568
117824
|
}
|
|
117825
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117569
117826
|
}
|
|
117570
117827
|
}
|
|
117571
117828
|
}
|
|
@@ -117622,7 +117879,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117622
117879
|
const groupMode = groupId != null;
|
|
117623
117880
|
const usage = extractUsage(successMsg);
|
|
117624
117881
|
const watermarkUsage = proc.peakContextUsage ?? usage;
|
|
117625
|
-
if (isNoReplyText(trimmed)) {
|
|
117882
|
+
if (isNoReplyText(trimmed, { allowSdkSyntheticNoResponse: groupMode })) {
|
|
117626
117883
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
117627
117884
|
emitUsageReported(proc, emit, base, usage);
|
|
117628
117885
|
if (groupMode && proc.contentBlocks.length > 0) {
|
|
@@ -117644,7 +117901,6 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117644
117901
|
groupId,
|
|
117645
117902
|
compactScheduled: proc.compactRequested === true,
|
|
117646
117903
|
fullTextLen: proc.accumulatedText.length,
|
|
117647
|
-
fullTextSample: proc.accumulatedText.slice(0, 200),
|
|
117648
117904
|
accumulatedBlockCount: proc.contentBlocks.length,
|
|
117649
117905
|
accumulatedBlockTypes: proc.contentBlocks.map((b) => b.type),
|
|
117650
117906
|
silentSegmentEmitted: groupMode
|
|
@@ -117688,7 +117944,6 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117688
117944
|
segmentCount: proc.segmentCount,
|
|
117689
117945
|
compactScheduled: proc.compactRequested === true,
|
|
117690
117946
|
fullTextLen: proc.accumulatedText.length,
|
|
117691
|
-
fullTextSample: proc.accumulatedText.slice(0, 200),
|
|
117692
117947
|
traceId: base.traceId
|
|
117693
117948
|
});
|
|
117694
117949
|
emit({
|
|
@@ -117739,7 +117994,6 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117739
117994
|
ackId: base.replyMessageId,
|
|
117740
117995
|
messageId: carrierMessageId,
|
|
117741
117996
|
textLen: proc.accumulatedText.length,
|
|
117742
|
-
textSample: proc.accumulatedText.slice(0, 200),
|
|
117743
117997
|
tokenCount: usage.tokenCount,
|
|
117744
117998
|
traceId: base.traceId
|
|
117745
117999
|
});
|
|
@@ -117932,8 +118186,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onProv
|
|
|
117932
118186
|
logger11.info("Captured non-streamed assistant message", {
|
|
117933
118187
|
agentId: proc.agentId,
|
|
117934
118188
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117935
|
-
textLen: text.length
|
|
117936
|
-
textSample: text.slice(0, 100)
|
|
118189
|
+
textLen: text.length
|
|
117937
118190
|
});
|
|
117938
118191
|
} else {
|
|
117939
118192
|
proc.lastAssistantContentDescription = describeAssistantContent(am.message?.content);
|
|
@@ -117957,6 +118210,7 @@ function resetAccumulators(proc) {
|
|
|
117957
118210
|
proc.currentToolName = null;
|
|
117958
118211
|
proc.currentMcpInvocationId = null;
|
|
117959
118212
|
proc.currentMcpInvocationStartedAt = null;
|
|
118213
|
+
proc.activeToolUseStartedAt = void 0;
|
|
117960
118214
|
proc.segmentBuffer = "";
|
|
117961
118215
|
proc.segmentCount = 0;
|
|
117962
118216
|
proc.accumulatedToolInput = "";
|
|
@@ -117966,6 +118220,7 @@ function resetAccumulators(proc) {
|
|
|
117966
118220
|
proc.officialMediaGenerationSatisfied = false;
|
|
117967
118221
|
proc.suppressCurrentThinking = false;
|
|
117968
118222
|
proc.suppressCurrentToolUse = false;
|
|
118223
|
+
proc.activeSubagentTaskIds?.clear();
|
|
117969
118224
|
}
|
|
117970
118225
|
|
|
117971
118226
|
// src/forkHistoryReplay.ts
|
|
@@ -118157,7 +118412,7 @@ function missingSubscriptionMessage(subscriptionId) {
|
|
|
118157
118412
|
}
|
|
118158
118413
|
var NODE_USER_UID = 1e3;
|
|
118159
118414
|
var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
|
|
118160
|
-
var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-prompt-
|
|
118415
|
+
var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-mcp-abi-prompt-v4";
|
|
118161
118416
|
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;
|
|
118162
118417
|
var DOCUMENT_READING_RULES = `DOCUMENT READING:
|
|
118163
118418
|
- The built-in Read tool cannot read binary office documents such as .docx, .xls, .xlsx, .pptx, .pdf, .odt, .ods, .odp, or .rtf.
|
|
@@ -118172,6 +118427,16 @@ var MEDIA_GENERATION_RULES = `MEDIA GENERATION:
|
|
|
118172
118427
|
- 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.
|
|
118173
118428
|
- 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.
|
|
118174
118429
|
- 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.`;
|
|
118430
|
+
function stableFingerprintValue(value) {
|
|
118431
|
+
if (Array.isArray(value)) return value.map(stableFingerprintValue);
|
|
118432
|
+
if (!value || typeof value !== "object") return value;
|
|
118433
|
+
const out = {};
|
|
118434
|
+
for (const key of Object.keys(value).sort()) {
|
|
118435
|
+
const normalized = stableFingerprintValue(value[key]);
|
|
118436
|
+
if (normalized !== void 0) out[key] = normalized;
|
|
118437
|
+
}
|
|
118438
|
+
return out;
|
|
118439
|
+
}
|
|
118175
118440
|
function isRecoveryDispatchTask(task) {
|
|
118176
118441
|
return task.dispatchKind === "manual_continue" || task.dispatchKind === "regenerate";
|
|
118177
118442
|
}
|
|
@@ -118429,13 +118694,15 @@ var AgentManager = class {
|
|
|
118429
118694
|
agents = /* @__PURE__ */ new Map();
|
|
118430
118695
|
lastUsedAt = /* @__PURE__ */ new Map();
|
|
118431
118696
|
/** Scopes 被 zombie_watchdog 关闭后的"入睡"标记,acquire 重建时清除并 emit awake。 */
|
|
118432
|
-
dormantScopes = /* @__PURE__ */ new
|
|
118697
|
+
dormantScopes = /* @__PURE__ */ new Map();
|
|
118433
118698
|
/**
|
|
118434
118699
|
* zombie_watchdog 拆 runtime 时,把该 (agentId, scope) 的 groupInbox 快照到这里,
|
|
118435
118700
|
* 让下一次 getOrCreate 重建 runtime 时可以恢复未读消息。仅 in-memory;
|
|
118436
118701
|
* bridge 进程崩溃 / shutdownAll 时丢失,与现有 inbox 内存语义一致。
|
|
118437
118702
|
*/
|
|
118438
118703
|
dormantGroupInboxes = /* @__PURE__ */ new Map();
|
|
118704
|
+
/** Spectate requested before runtime existed; value = activatedAt epoch ms. */
|
|
118705
|
+
pendingSpectate = /* @__PURE__ */ new Map();
|
|
118439
118706
|
sessionStore;
|
|
118440
118707
|
dispatchMemory = new GroupDispatchMemoryStore();
|
|
118441
118708
|
dataDir;
|
|
@@ -118601,6 +118868,7 @@ var AgentManager = class {
|
|
|
118601
118868
|
}
|
|
118602
118869
|
async resolveRuntimeCwd(agentConfig, scope, requestedCwd) {
|
|
118603
118870
|
let cwd = this.remapServerWorkspaceCwd(agentConfig, scope, requestedCwd);
|
|
118871
|
+
let fallbackForensicsId;
|
|
118604
118872
|
if (!isFullyQualifiedAbsolutePath(cwd)) {
|
|
118605
118873
|
const fallback = import_node_path13.default.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
|
|
118606
118874
|
logger14.error(
|
|
@@ -118615,6 +118883,23 @@ var AgentManager = class {
|
|
|
118615
118883
|
error: new Error("workdir_not_usable_on_this_machine")
|
|
118616
118884
|
}
|
|
118617
118885
|
);
|
|
118886
|
+
fallbackForensicsId = createFallbackId();
|
|
118887
|
+
logFallback(logger14, {
|
|
118888
|
+
fallbackId: fallbackForensicsId,
|
|
118889
|
+
type: "cwd_sandbox",
|
|
118890
|
+
phase: "applied",
|
|
118891
|
+
expected: false,
|
|
118892
|
+
context: {
|
|
118893
|
+
agentId: agentConfig.id,
|
|
118894
|
+
scope: scopeKey(scope),
|
|
118895
|
+
platform: process.platform,
|
|
118896
|
+
requested: requestedCwd,
|
|
118897
|
+
resolved: cwd,
|
|
118898
|
+
reason: "not_fully_qualified",
|
|
118899
|
+
fallback
|
|
118900
|
+
},
|
|
118901
|
+
outcome: { result: "sandbox_fallback" }
|
|
118902
|
+
});
|
|
118618
118903
|
cwd = fallback;
|
|
118619
118904
|
}
|
|
118620
118905
|
if (isRunningAsRoot() && cwd.startsWith("/root/")) {
|
|
@@ -118633,6 +118918,21 @@ var AgentManager = class {
|
|
|
118633
118918
|
fallback,
|
|
118634
118919
|
error: e
|
|
118635
118920
|
});
|
|
118921
|
+
const fbId = fallbackForensicsId ?? createFallbackId();
|
|
118922
|
+
logFallback(logger14, {
|
|
118923
|
+
fallbackId: fbId,
|
|
118924
|
+
type: "cwd_sandbox",
|
|
118925
|
+
phase: "applied",
|
|
118926
|
+
expected: false,
|
|
118927
|
+
context: {
|
|
118928
|
+
agentId: agentConfig.id,
|
|
118929
|
+
scope: scopeKey(scope),
|
|
118930
|
+
reason: "mkdir_failed",
|
|
118931
|
+
requested: cwd,
|
|
118932
|
+
fallback
|
|
118933
|
+
},
|
|
118934
|
+
outcome: { result: "second_layer_fallback" }
|
|
118935
|
+
});
|
|
118636
118936
|
await import_promises3.default.mkdir(fallback, { recursive: true });
|
|
118637
118937
|
return fallback;
|
|
118638
118938
|
}
|
|
@@ -118855,17 +119155,24 @@ var AgentManager = class {
|
|
|
118855
119155
|
});
|
|
118856
119156
|
return null;
|
|
118857
119157
|
}
|
|
118858
|
-
scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection) {
|
|
118859
|
-
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");
|
|
119158
|
+
scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection, externalMcpFingerprint) {
|
|
119159
|
+
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");
|
|
119160
|
+
}
|
|
119161
|
+
externalMcpFingerprint(externalMcp) {
|
|
119162
|
+
const serverNames = Object.keys(externalMcp.mcpServers).sort();
|
|
119163
|
+
const allowedTools = [...externalMcp.allowedTools].sort();
|
|
119164
|
+
const toolAbi = [...externalMcp.toolAbi ?? []].sort((a, b) => a.serverName.localeCompare(b.serverName)).map(stableFingerprintValue);
|
|
119165
|
+
if (serverNames.length === 0 && allowedTools.length === 0 && toolAbi.length === 0) return "";
|
|
119166
|
+
return JSON.stringify({ serverNames, allowedTools, toolAbi });
|
|
118860
119167
|
}
|
|
118861
|
-
discardSessionIfScopePromptChanged(agentConfig, scope, sessionId, fingerprint) {
|
|
119168
|
+
discardSessionIfScopePromptChanged(agentConfig, scope, sessionId, fingerprint, options = {}) {
|
|
118862
119169
|
const previous = this.sessionStore.getPromptFingerprint(agentConfig.id, scope);
|
|
118863
119170
|
if (!sessionId) {
|
|
118864
119171
|
this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
|
|
118865
119172
|
return null;
|
|
118866
119173
|
}
|
|
118867
119174
|
if (previous === fingerprint) return sessionId;
|
|
118868
|
-
if (!previous && scope.kind === "single") {
|
|
119175
|
+
if (!previous && scope.kind === "single" && options.clearLegacySingleSession !== true) {
|
|
118869
119176
|
this.sessionStore.setPromptFingerprint(agentConfig.id, scope, fingerprint);
|
|
118870
119177
|
logger14.info("Retaining legacy single-scope session while recording prompt fingerprint", {
|
|
118871
119178
|
agentId: agentConfig.id,
|
|
@@ -118885,7 +119192,8 @@ var AgentManager = class {
|
|
|
118885
119192
|
sessionId,
|
|
118886
119193
|
previousFingerprint: previous,
|
|
118887
119194
|
nextFingerprint: fingerprint,
|
|
118888
|
-
revision: SCOPE_PROMPT_FINGERPRINT_REVISION
|
|
119195
|
+
revision: SCOPE_PROMPT_FINGERPRINT_REVISION,
|
|
119196
|
+
reason: options.reason ?? "scope_prompt_changed"
|
|
118889
119197
|
});
|
|
118890
119198
|
return null;
|
|
118891
119199
|
}
|
|
@@ -118934,6 +119242,7 @@ var AgentManager = class {
|
|
|
118934
119242
|
logger14.info("Evicting idle Agent query", { agentId: proc.agentId, scope: scopeKey(proc.scope) });
|
|
118935
119243
|
const runtime = this.asRuntime(proc);
|
|
118936
119244
|
this.clearQuietFlushTimer(runtime);
|
|
119245
|
+
this.teardownSpectate(runtime);
|
|
118937
119246
|
try {
|
|
118938
119247
|
runtime.inputController.close();
|
|
118939
119248
|
await this.awaitQueryReturn(runtime.query, 5e3, proc.agentId);
|
|
@@ -118953,6 +119262,7 @@ var AgentManager = class {
|
|
|
118953
119262
|
const runtime = this.asRuntime(proc);
|
|
118954
119263
|
const key = runtimeKey(proc.agentId, proc.scope);
|
|
118955
119264
|
this.clearQuietFlushTimer(runtime);
|
|
119265
|
+
this.teardownSpectate(runtime);
|
|
118956
119266
|
runtime.currentTask = null;
|
|
118957
119267
|
runtime.injectedTasks = [];
|
|
118958
119268
|
runtime.mergedTasks = [];
|
|
@@ -118989,6 +119299,7 @@ var AgentManager = class {
|
|
|
118989
119299
|
evictIdle() {
|
|
118990
119300
|
const now = Date.now();
|
|
118991
119301
|
const { idleTimeoutMs, workingSilenceTimeoutMs } = this.queryConfig;
|
|
119302
|
+
const stallWarnAfterMs = Math.min(9e4, this.queryConfig.replyStallTimeoutMs);
|
|
118992
119303
|
for (const [key, proc] of this.agents) {
|
|
118993
119304
|
if (!this.isEvictable(proc)) continue;
|
|
118994
119305
|
const runtime = this.asRuntime(proc);
|
|
@@ -118999,26 +119310,62 @@ var AgentManager = class {
|
|
|
118999
119310
|
for (const [, proc] of this.agents) {
|
|
119000
119311
|
if (proc.status !== "working") continue;
|
|
119001
119312
|
const runtime = this.asRuntime(proc);
|
|
119313
|
+
if (runtime.currentTask) {
|
|
119314
|
+
const sinceEventMs = now - proc.lastSdkEventAt;
|
|
119315
|
+
if (sinceEventMs > stallWarnAfterMs && !proc.stallWarned) {
|
|
119316
|
+
proc.stallWarned = true;
|
|
119317
|
+
const openTool = this.latestOpenToolUse(proc);
|
|
119318
|
+
logger14.warn("Reply stall onset: in-flight reply silent", {
|
|
119319
|
+
agentId: proc.agentId,
|
|
119320
|
+
scope: scopeKey(proc.scope),
|
|
119321
|
+
sinceEventMs,
|
|
119322
|
+
replyStallTimeoutMs: this.queryConfig.replyStallTimeoutMs,
|
|
119323
|
+
workingSilenceTimeoutMs,
|
|
119324
|
+
busySilenceTimeoutMs: this.queryConfig.busySilenceTimeoutMs ?? null,
|
|
119325
|
+
replyMessageId: runtime.currentTask.replyMessageId,
|
|
119326
|
+
model: proc.model ?? "(unknown)",
|
|
119327
|
+
lastSdkEvent: proc.lastSdkEventInfo,
|
|
119328
|
+
hasActiveToolUse: runtime.activeToolUseStartedAt != null || openTool != null,
|
|
119329
|
+
activeToolUseAgeMs: runtime.activeToolUseStartedAt != null ? now - runtime.activeToolUseStartedAt : null,
|
|
119330
|
+
openToolName: openTool?.toolName ?? proc.currentToolName ?? null,
|
|
119331
|
+
openMcpInvocationId: proc.currentMcpInvocationId ?? null,
|
|
119332
|
+
subagentInFlight: (runtime.activeSubagentTaskIds?.size ?? 0) > 0,
|
|
119333
|
+
activeSubagentCount: runtime.activeSubagentTaskIds?.size ?? 0,
|
|
119334
|
+
busyReason: this.busyReason(proc)
|
|
119335
|
+
});
|
|
119336
|
+
}
|
|
119337
|
+
}
|
|
119338
|
+
const busyReason = this.busyReason(runtime);
|
|
119339
|
+
const busy = busyReason !== null;
|
|
119340
|
+
if (runtime.currentTask && !busy && now - proc.lastSdkEventAt > this.queryConfig.replyStallTimeoutMs) {
|
|
119341
|
+
void this.recoverStalledReply(proc, now - proc.lastSdkEventAt);
|
|
119342
|
+
continue;
|
|
119343
|
+
}
|
|
119002
119344
|
const hasInjectedBacklog = runtime.injectedTasks.length > 0;
|
|
119003
|
-
const
|
|
119345
|
+
const baseCeilingMs = busy ? Math.max(workingSilenceTimeoutMs, this.queryConfig.busySilenceTimeoutMs ?? 0) : workingSilenceTimeoutMs;
|
|
119346
|
+
const effectiveTimeoutMs = hasInjectedBacklog ? baseCeilingMs * 2 : baseCeilingMs;
|
|
119004
119347
|
const silentMs = now - proc.lastSdkEventAt;
|
|
119005
119348
|
if (silentMs <= effectiveTimeoutMs) {
|
|
119006
|
-
if (
|
|
119007
|
-
logger14.warn(
|
|
119008
|
-
|
|
119009
|
-
|
|
119010
|
-
|
|
119011
|
-
|
|
119012
|
-
|
|
119013
|
-
|
|
119014
|
-
|
|
119015
|
-
|
|
119016
|
-
|
|
119017
|
-
|
|
119018
|
-
|
|
119349
|
+
if (silentMs > workingSilenceTimeoutMs) {
|
|
119350
|
+
logger14.warn("Zombie watchdog: working runtime silent past base timeout; granting extended grace", {
|
|
119351
|
+
agentId: proc.agentId,
|
|
119352
|
+
scope: scopeKey(proc.scope),
|
|
119353
|
+
silentMs,
|
|
119354
|
+
baseTimeoutMs: workingSilenceTimeoutMs,
|
|
119355
|
+
baseCeilingMs,
|
|
119356
|
+
busySilenceTimeoutMs: this.queryConfig.busySilenceTimeoutMs ?? null,
|
|
119357
|
+
effectiveTimeoutMs,
|
|
119358
|
+
busy,
|
|
119359
|
+
busyReason,
|
|
119360
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
119361
|
+
replyMessageId: proc.currentTask?.replyMessageId
|
|
119362
|
+
});
|
|
119019
119363
|
}
|
|
119020
119364
|
continue;
|
|
119021
119365
|
}
|
|
119366
|
+
const zombieOpenTool = this.latestOpenToolUse(proc);
|
|
119367
|
+
const watchdogDetectedAt = Date.now();
|
|
119368
|
+
const watchdogFallbackId = createFallbackId();
|
|
119022
119369
|
logger14.warn("Zombie watchdog: working runtime silent too long, tearing down", {
|
|
119023
119370
|
agentId: proc.agentId,
|
|
119024
119371
|
scope: scopeKey(proc.scope),
|
|
@@ -119026,12 +119373,46 @@ var AgentManager = class {
|
|
|
119026
119373
|
lastSdkEventAt: new Date(proc.lastSdkEventAt).toISOString(),
|
|
119027
119374
|
workingSilenceTimeoutMs,
|
|
119028
119375
|
effectiveTimeoutMs,
|
|
119376
|
+
baseCeilingMs,
|
|
119377
|
+
busy,
|
|
119378
|
+
busySilenceTimeoutMs: this.queryConfig.busySilenceTimeoutMs ?? null,
|
|
119029
119379
|
replyMessageId: proc.currentTask?.replyMessageId,
|
|
119030
119380
|
injectedTaskCount: runtime.injectedTasks.length,
|
|
119031
119381
|
hadInjectedBacklog: hasInjectedBacklog,
|
|
119032
|
-
inboxSize: proc.groupInbox.length
|
|
119382
|
+
inboxSize: proc.groupInbox.length,
|
|
119383
|
+
fallbackId: watchdogFallbackId,
|
|
119384
|
+
// Breadcrumb: what the turn was waiting on when it timed out. A hung subagent
|
|
119385
|
+
// (open `Task` tool_use) lands here now that the fast path skips active tools.
|
|
119386
|
+
model: proc.model ?? "(unknown)",
|
|
119387
|
+
lastSdkEvent: proc.lastSdkEventInfo,
|
|
119388
|
+
openToolName: zombieOpenTool?.toolName ?? proc.currentToolName ?? null,
|
|
119389
|
+
activeToolUseAgeMs: runtime.activeToolUseStartedAt != null ? now - runtime.activeToolUseStartedAt : null,
|
|
119390
|
+
openMcpInvocationId: proc.currentMcpInvocationId ?? null,
|
|
119391
|
+
subagentInFlight: (runtime.activeSubagentTaskIds?.size ?? 0) > 0,
|
|
119392
|
+
activeSubagentCount: runtime.activeSubagentTaskIds?.size ?? 0,
|
|
119393
|
+
busyReason: this.busyReason(proc)
|
|
119394
|
+
});
|
|
119395
|
+
logFallback(logger14, {
|
|
119396
|
+
fallbackId: watchdogFallbackId,
|
|
119397
|
+
type: "zombie_watchdog",
|
|
119398
|
+
phase: "detected",
|
|
119399
|
+
expected: false,
|
|
119400
|
+
traceId: proc.currentTask?.traceId,
|
|
119401
|
+
context: {
|
|
119402
|
+
agentId: proc.agentId,
|
|
119403
|
+
scope: scopeKey(proc.scope),
|
|
119404
|
+
silentMs,
|
|
119405
|
+
replyMessageId: proc.currentTask?.replyMessageId ?? null,
|
|
119406
|
+
openToolName: zombieOpenTool?.toolName ?? proc.currentToolName ?? null,
|
|
119407
|
+
lastSdkEventType: proc.lastSdkEventInfo?.type ?? null,
|
|
119408
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
119409
|
+
inboxSize: proc.groupInbox.length
|
|
119410
|
+
}
|
|
119411
|
+
});
|
|
119412
|
+
void this.closeRuntime(proc, "zombie_watchdog", {
|
|
119413
|
+
fallbackId: watchdogFallbackId,
|
|
119414
|
+
detectedAt: watchdogDetectedAt
|
|
119033
119415
|
});
|
|
119034
|
-
void this.closeRuntime(proc, "zombie_watchdog");
|
|
119035
119416
|
}
|
|
119036
119417
|
}
|
|
119037
119418
|
/**
|
|
@@ -119278,7 +119659,7 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119278
119659
|
agentId: agentConfig.id,
|
|
119279
119660
|
capabilityTier: cfg.capabilityTier,
|
|
119280
119661
|
isSmith: smithAgent
|
|
119281
|
-
}) ?? { mcpServers: {}, allowedTools: [] };
|
|
119662
|
+
}) ?? { mcpServers: {}, allowedTools: [], toolAbi: [] };
|
|
119282
119663
|
logger14.info("External MCP resolved for runtime", {
|
|
119283
119664
|
agentId: agentConfig.id,
|
|
119284
119665
|
scope: scopeKey(scope),
|
|
@@ -119295,11 +119676,16 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119295
119676
|
}
|
|
119296
119677
|
const notebookSection = this.buildNotebookSection(agentConfig.id);
|
|
119297
119678
|
const scopesSection = this.buildScopesSection(agentConfig, scope, agentCwd);
|
|
119679
|
+
const externalMcpFingerprint = this.externalMcpFingerprint(externalMcp);
|
|
119298
119680
|
savedSessionId = this.discardSessionIfScopePromptChanged(
|
|
119299
119681
|
agentConfig,
|
|
119300
119682
|
scope,
|
|
119301
119683
|
savedSessionId,
|
|
119302
|
-
this.scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection)
|
|
119684
|
+
this.scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection, externalMcpFingerprint),
|
|
119685
|
+
{
|
|
119686
|
+
clearLegacySingleSession: externalMcpFingerprint.length > 0,
|
|
119687
|
+
reason: externalMcpFingerprint.length > 0 ? "external_mcp_abi_changed" : "scope_prompt_changed"
|
|
119688
|
+
}
|
|
119303
119689
|
);
|
|
119304
119690
|
let forkHistorySection = "";
|
|
119305
119691
|
if (!savedSessionId && scope.kind === "single") {
|
|
@@ -119320,6 +119706,8 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119320
119706
|
}
|
|
119321
119707
|
}
|
|
119322
119708
|
const cronLockSnapshot = readCronLockSnapshot();
|
|
119709
|
+
const builtinWebSearchAllowed = this.queryConfig.allowBuiltinWebSearch;
|
|
119710
|
+
const disallowedToolsForRuntime = builtinWebSearchAllowed ? [] : ["WebSearch"];
|
|
119323
119711
|
logger14.info("Creating Agent query", {
|
|
119324
119712
|
agentId: agentConfig.id,
|
|
119325
119713
|
scope: scopeKey(scope),
|
|
@@ -119328,6 +119716,8 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119328
119716
|
sessionId: savedSessionId,
|
|
119329
119717
|
forkHistoryReplay: forkHistorySection.length > 0,
|
|
119330
119718
|
model: cfg.model ?? "(default)",
|
|
119719
|
+
builtinWebSearchAllowed,
|
|
119720
|
+
disallowedTools: disallowedToolsForRuntime,
|
|
119331
119721
|
// Diagnostic: who currently owns Claude's global cron lock (~/.claude/scheduled_tasks.lock).
|
|
119332
119722
|
// Cron is process-internal but the binary uses this singleton lock to elect ONE scheduler
|
|
119333
119723
|
// among concurrent claude subprocesses. If lock is held by another session at spawn time,
|
|
@@ -119339,7 +119729,6 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119339
119729
|
});
|
|
119340
119730
|
const planModeRef = { active: false, denyCount: 0 };
|
|
119341
119731
|
const mediaGenerationTurnGuard = createOfficialMediaGenerationTurnGuard();
|
|
119342
|
-
const builtinWebSearchAllowed = this.queryConfig.allowBuiltinWebSearch;
|
|
119343
119732
|
const options = {
|
|
119344
119733
|
cwd: agentCwd,
|
|
119345
119734
|
systemPrompt: {
|
|
@@ -119406,6 +119795,8 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119406
119795
|
] : [],
|
|
119407
119796
|
...externalMcp.allowedTools
|
|
119408
119797
|
],
|
|
119798
|
+
// Server-side WebSearch bypasses canUseTool; disallowedTools removes it from model context.
|
|
119799
|
+
disallowedTools: disallowedToolsForRuntime,
|
|
119409
119800
|
mcpServers: { ...externalMcp.mcpServers, neural: neuralServer },
|
|
119410
119801
|
includePartialMessages: true,
|
|
119411
119802
|
// Plan mode custom workflow instructions. When setPermissionMode('plan') is
|
|
@@ -119732,6 +120123,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119732
120123
|
currentTask: null,
|
|
119733
120124
|
currentTaskStartedAt: 0,
|
|
119734
120125
|
lastSdkEventAt: Date.now(),
|
|
120126
|
+
model: (typeof options.model === "string" ? options.model : cfg.model) ?? null,
|
|
119735
120127
|
compactRequested: false,
|
|
119736
120128
|
compactInProgress: false,
|
|
119737
120129
|
contextOverflowLockedUntil: 0,
|
|
@@ -119743,13 +120135,18 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119743
120135
|
currentToolName: null,
|
|
119744
120136
|
currentMcpInvocationId: null,
|
|
119745
120137
|
currentMcpInvocationStartedAt: null,
|
|
120138
|
+
activeSubagentTaskIds: /* @__PURE__ */ new Set(),
|
|
119746
120139
|
mcpAuditRecorder: this.mcpAuditRecorder,
|
|
119747
120140
|
segmentBuffer: "",
|
|
119748
120141
|
segmentCount: 0,
|
|
119749
120142
|
accumulatedToolInput: "",
|
|
119750
120143
|
planModeRef,
|
|
119751
120144
|
mediaGenerationTurnGuard,
|
|
119752
|
-
groupInbox: []
|
|
120145
|
+
groupInbox: [],
|
|
120146
|
+
spectating: false,
|
|
120147
|
+
spectateActivatedAt: 0,
|
|
120148
|
+
spectateViewing: false,
|
|
120149
|
+
spectateTtlExpired: false
|
|
119753
120150
|
};
|
|
119754
120151
|
const runtime = Object.assign(proc, {
|
|
119755
120152
|
query: agentQuery,
|
|
@@ -119761,7 +120158,8 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119761
120158
|
createdAt: Date.now(),
|
|
119762
120159
|
supportsVision: modelInputMode === "vision" && cfg.supportsVision !== false,
|
|
119763
120160
|
modelInputMode,
|
|
119764
|
-
quietFlushTimer: null
|
|
120161
|
+
quietFlushTimer: null,
|
|
120162
|
+
spectateRevertTimer: null
|
|
119765
120163
|
});
|
|
119766
120164
|
logger14.info("Agent model input mode resolved", {
|
|
119767
120165
|
agentId: agentConfig.id,
|
|
@@ -119786,6 +120184,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119786
120184
|
} else {
|
|
119787
120185
|
this.dormantGroupInboxes.delete(key);
|
|
119788
120186
|
}
|
|
120187
|
+
const dormantMeta = this.dormantScopes.get(key);
|
|
119789
120188
|
if (this.dormantScopes.delete(key)) {
|
|
119790
120189
|
this.emit({
|
|
119791
120190
|
type: "agent:awake",
|
|
@@ -119797,7 +120196,44 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
119797
120196
|
});
|
|
119798
120197
|
logger14.info("Agent scope awakened after dormant", {
|
|
119799
120198
|
agentId: agentConfig.id,
|
|
119800
|
-
scope: scopeKey(scope)
|
|
120199
|
+
scope: scopeKey(scope),
|
|
120200
|
+
...dormantMeta ? {
|
|
120201
|
+
fallbackId: dormantMeta.fallbackId,
|
|
120202
|
+
dormantDurationMs: Date.now() - dormantMeta.detectedAt,
|
|
120203
|
+
dataLossSuspected: dormantMeta.droppedTaskCount > 0
|
|
120204
|
+
} : {}
|
|
120205
|
+
});
|
|
120206
|
+
if (dormantMeta) {
|
|
120207
|
+
logFallback(logger14, {
|
|
120208
|
+
fallbackId: dormantMeta.fallbackId,
|
|
120209
|
+
type: "zombie_watchdog",
|
|
120210
|
+
phase: "outcome",
|
|
120211
|
+
expected: false,
|
|
120212
|
+
context: {
|
|
120213
|
+
agentId: agentConfig.id,
|
|
120214
|
+
scope: scopeKey(scope)
|
|
120215
|
+
},
|
|
120216
|
+
outcome: {
|
|
120217
|
+
result: "recovered_rebuilt",
|
|
120218
|
+
durationMs: Date.now() - dormantMeta.detectedAt,
|
|
120219
|
+
dataLossSuspected: dormantMeta.droppedTaskCount > 0
|
|
120220
|
+
}
|
|
120221
|
+
});
|
|
120222
|
+
}
|
|
120223
|
+
}
|
|
120224
|
+
const pendingSpectateAt = this.pendingSpectate.get(key);
|
|
120225
|
+
if (pendingSpectateAt != null) {
|
|
120226
|
+
this.pendingSpectate.delete(key);
|
|
120227
|
+
runtime.spectating = true;
|
|
120228
|
+
runtime.spectateViewing = false;
|
|
120229
|
+
runtime.spectateActivatedAt = pendingSpectateAt;
|
|
120230
|
+
runtime.spectateTtlExpired = false;
|
|
120231
|
+
this.armSpectateTimer(runtime);
|
|
120232
|
+
this.emitSpectateState(runtime, true, "started");
|
|
120233
|
+
logger14.info("Applied pending spectate on runtime create", {
|
|
120234
|
+
agentId: agentConfig.id,
|
|
120235
|
+
scope: scopeKey(scope),
|
|
120236
|
+
activatedAt: pendingSpectateAt
|
|
119801
120237
|
});
|
|
119802
120238
|
}
|
|
119803
120239
|
if (proc.groupInbox.length > 0 && this.isRuntimeIdleForInboxFlush(runtime)) {
|
|
@@ -120935,7 +121371,6 @@ ${lines.join("\n")}`;
|
|
|
120935
121371
|
compactTrigger: "context_watermark",
|
|
120936
121372
|
injectedTasksWaiting: runtime.injectedTasks.length,
|
|
120937
121373
|
compactPromptLen: compactPrompt.length,
|
|
120938
|
-
promptSample: compactPrompt.slice(0, 80),
|
|
120939
121374
|
traceId: compactTraceId
|
|
120940
121375
|
});
|
|
120941
121376
|
runtime.inputController.push(compactPrompt, runtime.ccSessionId ?? "");
|
|
@@ -121217,7 +121652,7 @@ ${lines.join("\n")}`;
|
|
|
121217
121652
|
const enveloped = buildInnerVoiceEnvelope(payloadWithTrigger, ctx);
|
|
121218
121653
|
const task = {
|
|
121219
121654
|
content: enveloped,
|
|
121220
|
-
replyMessageId:
|
|
121655
|
+
replyMessageId: createNeuralSendReplyMessageId(),
|
|
121221
121656
|
conversationId: payload.conversationId,
|
|
121222
121657
|
traceId: createTraceId(),
|
|
121223
121658
|
groupId: payload.groupId
|
|
@@ -121463,7 +121898,7 @@ ${lines.join("\n")}`;
|
|
|
121463
121898
|
this.dormantScopes.delete(key);
|
|
121464
121899
|
this.dormantGroupInboxes.delete(key);
|
|
121465
121900
|
}
|
|
121466
|
-
for (const key of [...this.dormantScopes].filter(
|
|
121901
|
+
for (const key of [...this.dormantScopes.keys()].filter(
|
|
121467
121902
|
(k) => k === agentId || k.startsWith(`${agentId}::`)
|
|
121468
121903
|
)) {
|
|
121469
121904
|
this.dormantScopes.delete(key);
|
|
@@ -121511,7 +121946,7 @@ ${lines.join("\n")}`;
|
|
|
121511
121946
|
async reloadAgentScopes(agentId, reason) {
|
|
121512
121947
|
this.sessionStore.deleteAllForAgent(agentId);
|
|
121513
121948
|
this.dispatchMemory.deleteAllForAgent(agentId);
|
|
121514
|
-
for (const key of [...this.dormantScopes].filter(
|
|
121949
|
+
for (const key of [...this.dormantScopes.keys()].filter(
|
|
121515
121950
|
(k) => k === agentId || k.startsWith(`${agentId}::`)
|
|
121516
121951
|
)) {
|
|
121517
121952
|
this.dormantScopes.delete(key);
|
|
@@ -121663,6 +122098,125 @@ ${lines.join("\n")}`;
|
|
|
121663
122098
|
void this.terminateScope(proc.agentId, proc.scope);
|
|
121664
122099
|
}
|
|
121665
122100
|
}
|
|
122101
|
+
/** Control spectate capture/push for one scoped runtime. */
|
|
122102
|
+
async setSpectate(agentId, scope, action) {
|
|
122103
|
+
const key = runtimeKey(agentId, scope);
|
|
122104
|
+
const proc = this.agents.get(key);
|
|
122105
|
+
if (!proc || proc.status === "dead") {
|
|
122106
|
+
if (action === "start") {
|
|
122107
|
+
this.pendingSpectate.set(key, Date.now());
|
|
122108
|
+
logger14.info("setSpectate: runtime missing, pending start", { agentId, scope: scopeKey(scope) });
|
|
122109
|
+
}
|
|
122110
|
+
return;
|
|
122111
|
+
}
|
|
122112
|
+
const runtime = this.asRuntime(proc);
|
|
122113
|
+
switch (action) {
|
|
122114
|
+
case "start":
|
|
122115
|
+
runtime.spectating = true;
|
|
122116
|
+
runtime.spectateViewing = true;
|
|
122117
|
+
runtime.spectateActivatedAt = Date.now();
|
|
122118
|
+
runtime.spectateTtlExpired = false;
|
|
122119
|
+
this.pendingSpectate.delete(key);
|
|
122120
|
+
this.armSpectateTimer(runtime);
|
|
122121
|
+
this.emitSpectateState(runtime, true, "started");
|
|
122122
|
+
logger14.info("Spectate started", { agentId, scope: scopeKey(scope) });
|
|
122123
|
+
break;
|
|
122124
|
+
case "enter_view":
|
|
122125
|
+
runtime.spectateViewing = true;
|
|
122126
|
+
logger14.info("Spectate enter_view", { agentId, scope: scopeKey(scope) });
|
|
122127
|
+
break;
|
|
122128
|
+
case "leave_view":
|
|
122129
|
+
runtime.spectateViewing = false;
|
|
122130
|
+
logger14.info("Spectate leave_view", {
|
|
122131
|
+
agentId,
|
|
122132
|
+
scope: scopeKey(scope),
|
|
122133
|
+
ttlExpired: runtime.spectateTtlExpired
|
|
122134
|
+
});
|
|
122135
|
+
if (runtime.spectateTtlExpired) {
|
|
122136
|
+
this.stopSpectate(runtime, "ttl_expired");
|
|
122137
|
+
}
|
|
122138
|
+
break;
|
|
122139
|
+
case "stop":
|
|
122140
|
+
this.stopSpectate(runtime, "stopped");
|
|
122141
|
+
this.pendingSpectate.delete(key);
|
|
122142
|
+
logger14.info("Spectate stopped", { agentId, scope: scopeKey(scope) });
|
|
122143
|
+
break;
|
|
122144
|
+
default:
|
|
122145
|
+
break;
|
|
122146
|
+
}
|
|
122147
|
+
}
|
|
122148
|
+
spectateTtlMs() {
|
|
122149
|
+
return Number(process.env.AHCHAT_BRIDGE_SPECTATE_TTL_MS) || 36e5;
|
|
122150
|
+
}
|
|
122151
|
+
armSpectateTimer(runtime) {
|
|
122152
|
+
this.clearSpectateTimer(runtime);
|
|
122153
|
+
if (!runtime.spectating || runtime.spectateActivatedAt <= 0) return;
|
|
122154
|
+
const ttlMs = this.spectateTtlMs();
|
|
122155
|
+
const elapsed = Date.now() - runtime.spectateActivatedAt;
|
|
122156
|
+
const delay = Math.max(0, ttlMs - elapsed);
|
|
122157
|
+
runtime.spectateRevertTimer = setTimeout(() => {
|
|
122158
|
+
runtime.spectateRevertTimer = null;
|
|
122159
|
+
runtime.spectateTtlExpired = true;
|
|
122160
|
+
logger14.info("Spectate TTL expired", {
|
|
122161
|
+
agentId: runtime.agentId,
|
|
122162
|
+
scope: scopeKey(runtime.scope),
|
|
122163
|
+
viewing: runtime.spectateViewing
|
|
122164
|
+
});
|
|
122165
|
+
if (!runtime.spectateViewing) {
|
|
122166
|
+
this.stopSpectate(runtime, "ttl_expired");
|
|
122167
|
+
}
|
|
122168
|
+
}, delay);
|
|
122169
|
+
}
|
|
122170
|
+
clearSpectateTimer(runtime) {
|
|
122171
|
+
if (runtime.spectateRevertTimer != null) {
|
|
122172
|
+
clearTimeout(runtime.spectateRevertTimer);
|
|
122173
|
+
runtime.spectateRevertTimer = null;
|
|
122174
|
+
}
|
|
122175
|
+
}
|
|
122176
|
+
stopSpectate(runtime, reason) {
|
|
122177
|
+
const wasActive = runtime.spectating;
|
|
122178
|
+
this.clearSpectateTimer(runtime);
|
|
122179
|
+
runtime.spectating = false;
|
|
122180
|
+
runtime.spectateViewing = false;
|
|
122181
|
+
runtime.spectateTtlExpired = false;
|
|
122182
|
+
runtime.spectateActivatedAt = 0;
|
|
122183
|
+
if (wasActive) {
|
|
122184
|
+
this.emitSpectateState(runtime, false, reason);
|
|
122185
|
+
logger14.info("Spectate deactivated", {
|
|
122186
|
+
agentId: runtime.agentId,
|
|
122187
|
+
scope: scopeKey(runtime.scope),
|
|
122188
|
+
reason
|
|
122189
|
+
});
|
|
122190
|
+
}
|
|
122191
|
+
}
|
|
122192
|
+
emitSpectateState(runtime, active, reason) {
|
|
122193
|
+
const scopePayload = runtime.scope.kind === "single" ? { kind: "single" } : { kind: "group", groupId: runtime.scope.groupId };
|
|
122194
|
+
this.emit({
|
|
122195
|
+
type: "spectate:state",
|
|
122196
|
+
payload: {
|
|
122197
|
+
agentId: runtime.agentId,
|
|
122198
|
+
scope: scopePayload,
|
|
122199
|
+
active,
|
|
122200
|
+
expiresAt: active ? runtime.spectateActivatedAt + this.spectateTtlMs() : void 0,
|
|
122201
|
+
reason,
|
|
122202
|
+
traceId: createTraceId()
|
|
122203
|
+
}
|
|
122204
|
+
});
|
|
122205
|
+
logger14.info("Spectate state emitted", {
|
|
122206
|
+
agentId: runtime.agentId,
|
|
122207
|
+
scope: scopeKey(runtime.scope),
|
|
122208
|
+
active,
|
|
122209
|
+
reason,
|
|
122210
|
+
expiresAt: active ? runtime.spectateActivatedAt + this.spectateTtlMs() : void 0
|
|
122211
|
+
});
|
|
122212
|
+
}
|
|
122213
|
+
teardownSpectate(runtime) {
|
|
122214
|
+
if (runtime.spectating) {
|
|
122215
|
+
this.stopSpectate(runtime, "runtime_gone");
|
|
122216
|
+
} else {
|
|
122217
|
+
this.clearSpectateTimer(runtime);
|
|
122218
|
+
}
|
|
122219
|
+
}
|
|
121666
122220
|
/** Stop one scoped SDK runtime (workdir change). */
|
|
121667
122221
|
async terminateScope(agentId, scope) {
|
|
121668
122222
|
const key = runtimeKey(agentId, scope);
|
|
@@ -121671,6 +122225,7 @@ ${lines.join("\n")}`;
|
|
|
121671
122225
|
logger14.info("terminateScope: no active runtime", { agentId, scope: scopeKey(scope) });
|
|
121672
122226
|
this.dormantScopes.delete(key);
|
|
121673
122227
|
this.dormantGroupInboxes.delete(key);
|
|
122228
|
+
this.pendingSpectate.delete(key);
|
|
121674
122229
|
this.sessionStore.delete(agentId, scope);
|
|
121675
122230
|
this.dispatchMemory.deleteScope(agentId, scope);
|
|
121676
122231
|
return;
|
|
@@ -121693,7 +122248,7 @@ ${lines.join("\n")}`;
|
|
|
121693
122248
|
this.dispatchMemory.deleteScope(agentId, scope);
|
|
121694
122249
|
logger14.info("terminateScope: scoped query removed", { agentId, scope: scopeKey(scope) });
|
|
121695
122250
|
}
|
|
121696
|
-
async closeRuntime(proc, reason) {
|
|
122251
|
+
async closeRuntime(proc, reason, watchdogForensics) {
|
|
121697
122252
|
const key = runtimeKey(proc.agentId, proc.scope);
|
|
121698
122253
|
if (proc.status === "dead") return;
|
|
121699
122254
|
const runtime = this.asRuntime(proc);
|
|
@@ -121770,12 +122325,13 @@ ${lines.join("\n")}`;
|
|
|
121770
122325
|
runtime.currentTask = null;
|
|
121771
122326
|
if (isWatchdog) {
|
|
121772
122327
|
const preservedInbox = proc.groupInbox;
|
|
121773
|
-
|
|
122328
|
+
const preservedInboxSize = preservedInbox.length;
|
|
122329
|
+
if (preservedInboxSize > 0) {
|
|
121774
122330
|
this.dormantGroupInboxes.set(key, [...preservedInbox]);
|
|
121775
122331
|
logger14.info("Preserving groupInbox for dormant agent", {
|
|
121776
122332
|
agentId,
|
|
121777
122333
|
scope: scopeKey(proc.scope),
|
|
121778
|
-
preservedInboxSize
|
|
122334
|
+
preservedInboxSize,
|
|
121779
122335
|
preservedEntries: preservedInbox.map((e) => ({
|
|
121780
122336
|
ackId: e.ackId,
|
|
121781
122337
|
sender: e.senderName,
|
|
@@ -121784,7 +122340,26 @@ ${lines.join("\n")}`;
|
|
|
121784
122340
|
}))
|
|
121785
122341
|
});
|
|
121786
122342
|
}
|
|
121787
|
-
|
|
122343
|
+
const effectiveFallbackId = watchdogForensics?.fallbackId ?? createFallbackId();
|
|
122344
|
+
logFallback(logger14, {
|
|
122345
|
+
fallbackId: effectiveFallbackId,
|
|
122346
|
+
type: "zombie_watchdog",
|
|
122347
|
+
phase: "applied",
|
|
122348
|
+
expected: false,
|
|
122349
|
+
traceId: dormantTraceId,
|
|
122350
|
+
context: {
|
|
122351
|
+
agentId,
|
|
122352
|
+
scope: scopeKey(proc.scope),
|
|
122353
|
+
droppedTaskCount: droppedAckIds.length,
|
|
122354
|
+
preservedInboxSize,
|
|
122355
|
+
sessionDeleted: false
|
|
122356
|
+
}
|
|
122357
|
+
});
|
|
122358
|
+
this.dormantScopes.set(key, {
|
|
122359
|
+
fallbackId: effectiveFallbackId,
|
|
122360
|
+
detectedAt: watchdogForensics?.detectedAt ?? Date.now(),
|
|
122361
|
+
droppedTaskCount: droppedAckIds.length
|
|
122362
|
+
});
|
|
121788
122363
|
this.emit({
|
|
121789
122364
|
type: "agent:dormant",
|
|
121790
122365
|
payload: {
|
|
@@ -121799,13 +122374,15 @@ ${lines.join("\n")}`;
|
|
|
121799
122374
|
agentId,
|
|
121800
122375
|
scope: scopeKey(proc.scope),
|
|
121801
122376
|
droppedTaskCount: droppedAckIds.length,
|
|
121802
|
-
preservedInboxSize: this.dormantGroupInboxes.get(key)?.length ?? 0
|
|
122377
|
+
preservedInboxSize: this.dormantGroupInboxes.get(key)?.length ?? 0,
|
|
122378
|
+
fallbackId: effectiveFallbackId
|
|
121803
122379
|
});
|
|
121804
122380
|
}
|
|
121805
122381
|
proc.status = "dead";
|
|
121806
122382
|
this.agents.delete(key);
|
|
121807
122383
|
this.lastUsedAt.delete(key);
|
|
121808
122384
|
this.clearQuietFlushTimer(runtime);
|
|
122385
|
+
this.teardownSpectate(runtime);
|
|
121809
122386
|
try {
|
|
121810
122387
|
runtime.inputController.close();
|
|
121811
122388
|
await this.awaitQueryReturn(runtime.query, 5e3, agentId);
|
|
@@ -121822,6 +122399,165 @@ ${lines.join("\n")}`;
|
|
|
121822
122399
|
cwd: proc.cwd
|
|
121823
122400
|
});
|
|
121824
122401
|
}
|
|
122402
|
+
/**
|
|
122403
|
+
* Emit `agent:error` for the active reply and every queued/merged/buffered task,
|
|
122404
|
+
* then clear those queues. Used by both the SDK stream-crash path and the
|
|
122405
|
+
* reply-stall watchdog so a torn-down runtime never leaves a carrier reply
|
|
122406
|
+
* stuck in-flight on the server (which would keep absorbing new user messages
|
|
122407
|
+
* as steers of a dead turn).
|
|
122408
|
+
*/
|
|
122409
|
+
failPendingTasksWithError(runtime, errorText, fallbackId) {
|
|
122410
|
+
const pending = [];
|
|
122411
|
+
if (runtime.currentTask) pending.push(runtime.currentTask);
|
|
122412
|
+
pending.push(...runtime.injectedTasks, ...runtime.mergedTasks, ...runtime.planModeBuffer);
|
|
122413
|
+
runtime.currentTask = null;
|
|
122414
|
+
runtime.injectedTasks = [];
|
|
122415
|
+
runtime.mergedTasks = [];
|
|
122416
|
+
runtime.planModeBuffer = [];
|
|
122417
|
+
if (pending.length === 0) return { pendingCount: 0 };
|
|
122418
|
+
const carrier = pending[0];
|
|
122419
|
+
const mergedTasks = pending.slice(1);
|
|
122420
|
+
logger14.warn("Pending tasks failure consolidated", {
|
|
122421
|
+
agentId: runtime.agentId,
|
|
122422
|
+
scope: scopeKey(runtime.scope),
|
|
122423
|
+
pendingCount: pending.length,
|
|
122424
|
+
carrierAckId: carrier.replyMessageId,
|
|
122425
|
+
mergedAckIds: mergedTasks.map((t) => t.replyMessageId),
|
|
122426
|
+
traceId: carrier.traceId,
|
|
122427
|
+
...fallbackId ? { fallbackId } : {}
|
|
122428
|
+
});
|
|
122429
|
+
this.emit({
|
|
122430
|
+
type: "agent:error",
|
|
122431
|
+
payload: {
|
|
122432
|
+
agentId: runtime.agentId,
|
|
122433
|
+
conversationId: carrier.conversationId,
|
|
122434
|
+
ackId: carrier.replyMessageId,
|
|
122435
|
+
traceId: carrier.traceId,
|
|
122436
|
+
error: errorText
|
|
122437
|
+
}
|
|
122438
|
+
});
|
|
122439
|
+
for (const task of mergedTasks) {
|
|
122440
|
+
this.emit({
|
|
122441
|
+
type: "agent:merged",
|
|
122442
|
+
payload: {
|
|
122443
|
+
agentId: runtime.agentId,
|
|
122444
|
+
conversationId: task.conversationId,
|
|
122445
|
+
ackId: task.replyMessageId,
|
|
122446
|
+
mergedIntoAckId: carrier.replyMessageId,
|
|
122447
|
+
groupId: task.groupId,
|
|
122448
|
+
traceId: task.traceId
|
|
122449
|
+
}
|
|
122450
|
+
});
|
|
122451
|
+
}
|
|
122452
|
+
return { pendingCount: pending.length };
|
|
122453
|
+
}
|
|
122454
|
+
/**
|
|
122455
|
+
* Recover an in-flight reply that started but went silent past
|
|
122456
|
+
* `replyStallTimeoutMs` (see the reply-stall fast path in `evictIdle`). The
|
|
122457
|
+
* underlying SDK turn is wedged with no observable progress and no error, so:
|
|
122458
|
+
* 1. clear the (likely interrupted/dangling) session so the next dispatch
|
|
122459
|
+
* starts fresh instead of resuming the same wedged transcript;
|
|
122460
|
+
* 2. release the carrier reply + queued steers via `agent:error` so the
|
|
122461
|
+
* client stops waiting and the next user message starts a brand-new reply;
|
|
122462
|
+
* 3. tear the wedged runtime down.
|
|
122463
|
+
*/
|
|
122464
|
+
async recoverStalledReply(proc, silentMs) {
|
|
122465
|
+
if (proc.status === "dead") return;
|
|
122466
|
+
const runtime = this.asRuntime(proc);
|
|
122467
|
+
const key = runtimeKey(proc.agentId, proc.scope);
|
|
122468
|
+
const replyStallFallbackId = createFallbackId();
|
|
122469
|
+
const stallTraceId = proc.currentTask?.traceId;
|
|
122470
|
+
logger14.warn("Reply stall watchdog: in-flight reply silent too long, recovering", {
|
|
122471
|
+
agentId: proc.agentId,
|
|
122472
|
+
scope: scopeKey(proc.scope),
|
|
122473
|
+
silentMs,
|
|
122474
|
+
replyStallTimeoutMs: this.queryConfig.replyStallTimeoutMs,
|
|
122475
|
+
replyMessageId: proc.currentTask?.replyMessageId,
|
|
122476
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
122477
|
+
lastSdkEventAt: new Date(proc.lastSdkEventAt).toISOString(),
|
|
122478
|
+
fallbackId: replyStallFallbackId,
|
|
122479
|
+
// Breadcrumb: what the wedged turn was doing the instant it went silent.
|
|
122480
|
+
// (subagent Task call? mid tool_use? which provider?) — the difference
|
|
122481
|
+
// between a one-off and a systemic provider/tool stall.
|
|
122482
|
+
model: proc.model ?? "(unknown)",
|
|
122483
|
+
lastSdkEvent: proc.lastSdkEventInfo,
|
|
122484
|
+
currentBlockType: proc.currentBlockType,
|
|
122485
|
+
currentToolName: proc.currentToolName,
|
|
122486
|
+
openMcpInvocationId: proc.currentMcpInvocationId ?? null
|
|
122487
|
+
});
|
|
122488
|
+
logFallback(logger14, {
|
|
122489
|
+
fallbackId: replyStallFallbackId,
|
|
122490
|
+
type: "reply_stall",
|
|
122491
|
+
phase: "detected",
|
|
122492
|
+
expected: false,
|
|
122493
|
+
traceId: stallTraceId,
|
|
122494
|
+
context: {
|
|
122495
|
+
agentId: proc.agentId,
|
|
122496
|
+
scope: scopeKey(proc.scope),
|
|
122497
|
+
silentMs,
|
|
122498
|
+
model: proc.model ?? "(unknown)",
|
|
122499
|
+
replyMessageId: proc.currentTask?.replyMessageId ?? null,
|
|
122500
|
+
currentToolName: proc.currentToolName ?? null,
|
|
122501
|
+
lastSdkEventType: proc.lastSdkEventInfo?.type ?? null,
|
|
122502
|
+
injectedTaskCount: runtime.injectedTasks.length,
|
|
122503
|
+
mergedTaskCount: runtime.mergedTasks.length,
|
|
122504
|
+
planModeBufferCount: runtime.planModeBuffer.length
|
|
122505
|
+
}
|
|
122506
|
+
});
|
|
122507
|
+
this.sessionStore.delete(proc.agentId, proc.scope);
|
|
122508
|
+
this.dispatchMemory.deleteScope(proc.agentId, proc.scope);
|
|
122509
|
+
const failSummary = this.failPendingTasksWithError(
|
|
122510
|
+
runtime,
|
|
122511
|
+
"\u56DE\u590D\u957F\u65F6\u95F4\u65E0\u54CD\u5E94\uFF0C\u5DF2\u91CD\u7F6E\u8BE5\u4F1A\u8BDD\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6D88\u606F\u3002",
|
|
122512
|
+
replyStallFallbackId
|
|
122513
|
+
);
|
|
122514
|
+
proc.status = "dead";
|
|
122515
|
+
this.agents.delete(key);
|
|
122516
|
+
this.lastUsedAt.delete(key);
|
|
122517
|
+
this.clearQuietFlushTimer(runtime);
|
|
122518
|
+
let queryCloseOk = true;
|
|
122519
|
+
try {
|
|
122520
|
+
runtime.inputController.close();
|
|
122521
|
+
await this.awaitQueryReturn(runtime.query, 5e3, proc.agentId);
|
|
122522
|
+
} catch (e) {
|
|
122523
|
+
queryCloseOk = false;
|
|
122524
|
+
logger14.error("reply_stall: close query failed", {
|
|
122525
|
+
agentId: proc.agentId,
|
|
122526
|
+
scope: scopeKey(proc.scope),
|
|
122527
|
+
error: e
|
|
122528
|
+
});
|
|
122529
|
+
}
|
|
122530
|
+
logFallback(logger14, {
|
|
122531
|
+
fallbackId: replyStallFallbackId,
|
|
122532
|
+
type: "reply_stall",
|
|
122533
|
+
phase: "applied",
|
|
122534
|
+
expected: false,
|
|
122535
|
+
traceId: stallTraceId,
|
|
122536
|
+
context: {
|
|
122537
|
+
agentId: proc.agentId,
|
|
122538
|
+
scope: scopeKey(proc.scope),
|
|
122539
|
+
sessionDeleted: true,
|
|
122540
|
+
failedTaskCount: failSummary.pendingCount,
|
|
122541
|
+
queryClosed: queryCloseOk
|
|
122542
|
+
}
|
|
122543
|
+
});
|
|
122544
|
+
logFallback(logger14, {
|
|
122545
|
+
fallbackId: replyStallFallbackId,
|
|
122546
|
+
type: "reply_stall",
|
|
122547
|
+
phase: "outcome",
|
|
122548
|
+
expected: false,
|
|
122549
|
+
traceId: stallTraceId,
|
|
122550
|
+
context: {
|
|
122551
|
+
agentId: proc.agentId,
|
|
122552
|
+
scope: scopeKey(proc.scope),
|
|
122553
|
+
failedTaskCount: failSummary.pendingCount
|
|
122554
|
+
},
|
|
122555
|
+
outcome: {
|
|
122556
|
+
result: "session_reset_awaiting_user",
|
|
122557
|
+
dataLossSuspected: failSummary.pendingCount > 0
|
|
122558
|
+
}
|
|
122559
|
+
});
|
|
122560
|
+
}
|
|
121825
122561
|
async recoverFromRestart(agents) {
|
|
121826
122562
|
const lockSnapshot = readCronLockSnapshot();
|
|
121827
122563
|
logger14.info("Recovering Agent sessions after restart", {
|
|
@@ -121944,58 +122680,7 @@ ${lines.join("\n")}`;
|
|
|
121944
122680
|
this.lastUsedAt.delete(key);
|
|
121945
122681
|
const errorText = isResumeFail ? `\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6D88\u606F\uFF08${errMsg}\uFF09` : `Agent query crashed: ${errMsg}`;
|
|
121946
122682
|
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;
|
|
121947
|
-
|
|
121948
|
-
this.emit({
|
|
121949
|
-
type: "agent:error",
|
|
121950
|
-
payload: {
|
|
121951
|
-
agentId: runtime.agentId,
|
|
121952
|
-
conversationId: runtime.currentTask.conversationId,
|
|
121953
|
-
ackId: runtime.currentTask.replyMessageId,
|
|
121954
|
-
traceId: runtime.currentTask.traceId,
|
|
121955
|
-
error: emittedErrorText
|
|
121956
|
-
}
|
|
121957
|
-
});
|
|
121958
|
-
runtime.currentTask = null;
|
|
121959
|
-
}
|
|
121960
|
-
for (const task of runtime.injectedTasks) {
|
|
121961
|
-
this.emit({
|
|
121962
|
-
type: "agent:error",
|
|
121963
|
-
payload: {
|
|
121964
|
-
agentId: runtime.agentId,
|
|
121965
|
-
conversationId: task.conversationId,
|
|
121966
|
-
ackId: task.replyMessageId,
|
|
121967
|
-
traceId: task.traceId,
|
|
121968
|
-
error: emittedErrorText
|
|
121969
|
-
}
|
|
121970
|
-
});
|
|
121971
|
-
}
|
|
121972
|
-
runtime.injectedTasks = [];
|
|
121973
|
-
for (const task of runtime.mergedTasks) {
|
|
121974
|
-
this.emit({
|
|
121975
|
-
type: "agent:error",
|
|
121976
|
-
payload: {
|
|
121977
|
-
agentId: runtime.agentId,
|
|
121978
|
-
conversationId: task.conversationId,
|
|
121979
|
-
ackId: task.replyMessageId,
|
|
121980
|
-
traceId: task.traceId,
|
|
121981
|
-
error: emittedErrorText
|
|
121982
|
-
}
|
|
121983
|
-
});
|
|
121984
|
-
}
|
|
121985
|
-
runtime.mergedTasks = [];
|
|
121986
|
-
for (const task of runtime.planModeBuffer) {
|
|
121987
|
-
this.emit({
|
|
121988
|
-
type: "agent:error",
|
|
121989
|
-
payload: {
|
|
121990
|
-
agentId: runtime.agentId,
|
|
121991
|
-
conversationId: task.conversationId,
|
|
121992
|
-
ackId: task.replyMessageId,
|
|
121993
|
-
traceId: task.traceId,
|
|
121994
|
-
error: emittedErrorText
|
|
121995
|
-
}
|
|
121996
|
-
});
|
|
121997
|
-
}
|
|
121998
|
-
runtime.planModeBuffer = [];
|
|
122683
|
+
this.failPendingTasksWithError(runtime, emittedErrorText);
|
|
121999
122684
|
}
|
|
122000
122685
|
}
|
|
122001
122686
|
getStatus(agentId, scope = { kind: "single" }) {
|
|
@@ -122009,6 +122694,18 @@ ${lines.join("\n")}`;
|
|
|
122009
122694
|
}
|
|
122010
122695
|
return [...ids];
|
|
122011
122696
|
}
|
|
122697
|
+
/** Unified signal: is the turn legitimately waiting on a live external call that emits no
|
|
122698
|
+
* parent heartbeat? Used by BOTH the reply-stall fast path and the zombie watchdog so neither
|
|
122699
|
+
* tears down a turn that is merely slow. Returns the reason for diagnostics, or null when idle.
|
|
122700
|
+
* - open_tool: regular tool, MCP tool, AskUserQuestion wait, or ExitPlanMode (tool_use open).
|
|
122701
|
+
* - subagent: Task/Agent in flight (its inner tool_results clear activeToolUseStartedAt).
|
|
122702
|
+
* - compact: bridge-injected /compact running. */
|
|
122703
|
+
busyReason(proc) {
|
|
122704
|
+
if (proc.activeToolUseStartedAt != null || this.latestOpenToolUse(proc) != null) return "open_tool";
|
|
122705
|
+
if ((proc.activeSubagentTaskIds?.size ?? 0) > 0) return "subagent";
|
|
122706
|
+
if (proc.compactInProgress === true) return "compact";
|
|
122707
|
+
return null;
|
|
122708
|
+
}
|
|
122012
122709
|
latestOpenToolUse(proc) {
|
|
122013
122710
|
for (let i = proc.contentBlocks.length - 1; i >= 0; i -= 1) {
|
|
122014
122711
|
const block = proc.contentBlocks[i];
|
|
@@ -122157,7 +122854,7 @@ ${lines.join("\n")}`;
|
|
|
122157
122854
|
}
|
|
122158
122855
|
const task = {
|
|
122159
122856
|
content: notice,
|
|
122160
|
-
replyMessageId:
|
|
122857
|
+
replyMessageId: createScopeNoticeReplyMessageId(),
|
|
122161
122858
|
conversationId,
|
|
122162
122859
|
traceId: createTraceId(),
|
|
122163
122860
|
groupId: proc.scope.kind === "group" ? proc.scope.groupId : void 0
|
|
@@ -123244,6 +123941,7 @@ var HttpMcpRegistry = class {
|
|
|
123244
123941
|
buildForAgent(ctx) {
|
|
123245
123942
|
const mcpServers = {};
|
|
123246
123943
|
const allowedTools = [];
|
|
123944
|
+
const toolAbi = [];
|
|
123247
123945
|
const usedNames = /* @__PURE__ */ new Set();
|
|
123248
123946
|
for (const connection of this.allConnections()) {
|
|
123249
123947
|
if (!this.connectionAppliesToAgent(connection, ctx)) continue;
|
|
@@ -123252,12 +123950,18 @@ var HttpMcpRegistry = class {
|
|
|
123252
123950
|
const serverName = uniqueServerName(normalizeMcpServerName(connection.serverName), usedNames);
|
|
123253
123951
|
usedNames.add(serverName);
|
|
123254
123952
|
mcpServers[serverName] = sdkConfig;
|
|
123255
|
-
|
|
123256
|
-
|
|
123257
|
-
|
|
123258
|
-
|
|
123953
|
+
const visibleTools = connection.tools.filter((tool2) => tool2.enabled && tool2.permissionPolicy !== "always_deny");
|
|
123954
|
+
for (const tool2 of visibleTools) allowedTools.push(mcpRuntimeToolName(serverName, tool2.name));
|
|
123955
|
+
toolAbi.push({
|
|
123956
|
+
serverName,
|
|
123957
|
+
providerId: connection.providerId,
|
|
123958
|
+
transport: connection.transport,
|
|
123959
|
+
alwaysLoad: connection.alwaysLoad,
|
|
123960
|
+
isBuiltin: connection.isBuiltin,
|
|
123961
|
+
tools: visibleTools.map((tool2) => runtimeToolAbi(serverName, tool2)).sort((a, b) => a.runtimeToolName.localeCompare(b.runtimeToolName))
|
|
123962
|
+
});
|
|
123259
123963
|
}
|
|
123260
|
-
return { mcpServers, allowedTools };
|
|
123964
|
+
return { mcpServers, allowedTools, toolAbi };
|
|
123261
123965
|
}
|
|
123262
123966
|
allConnections() {
|
|
123263
123967
|
return [...this.serverConnections.values(), ...this.localConnections.values()];
|
|
@@ -123443,6 +124147,18 @@ function uniqueServerName(serverName, usedNames) {
|
|
|
123443
124147
|
while (usedNames.has(`${serverName}_${idx}`)) idx += 1;
|
|
123444
124148
|
return `${serverName}_${idx}`;
|
|
123445
124149
|
}
|
|
124150
|
+
function runtimeToolAbi(serverName, tool2) {
|
|
124151
|
+
return {
|
|
124152
|
+
name: tool2.name,
|
|
124153
|
+
runtimeToolName: mcpRuntimeToolName(serverName, tool2.name),
|
|
124154
|
+
displayName: tool2.displayName,
|
|
124155
|
+
description: tool2.description,
|
|
124156
|
+
category: tool2.category,
|
|
124157
|
+
riskLevel: tool2.riskLevel,
|
|
124158
|
+
permissionPolicy: tool2.permissionPolicy,
|
|
124159
|
+
...tool2.inputSchema !== void 0 ? { inputSchema: tool2.inputSchema } : {}
|
|
124160
|
+
};
|
|
124161
|
+
}
|
|
123446
124162
|
function buildHeaders(authType, authSecret, customHeaders) {
|
|
123447
124163
|
const headers = {};
|
|
123448
124164
|
for (const header of customHeaders) {
|
|
@@ -124099,6 +124815,7 @@ var ServerConnector = class {
|
|
|
124099
124815
|
case "agent:terminate":
|
|
124100
124816
|
case "agent:runtime_reload":
|
|
124101
124817
|
case "agent:terminate_scope":
|
|
124818
|
+
case "spectate:set":
|
|
124102
124819
|
case "agent:created":
|
|
124103
124820
|
case "agent:updated":
|
|
124104
124821
|
case "agent:workdir-updated":
|
|
@@ -125076,24 +125793,6 @@ function normalizeLocalPath(targetPath) {
|
|
|
125076
125793
|
const expanded = trimmed === "~" || trimmed.startsWith("~/") || trimmed.startsWith("~\\") ? import_node_path18.default.join(import_node_os10.default.homedir(), trimmed.slice(2)) : trimmed;
|
|
125077
125794
|
return import_node_path18.default.normalize(import_node_path18.default.resolve(expanded));
|
|
125078
125795
|
}
|
|
125079
|
-
function isAbsoluteLocalPathCandidate(value) {
|
|
125080
|
-
if (process.platform === "win32") {
|
|
125081
|
-
return /^[a-zA-Z]:[\\/]/.test(value) || /^\\\\[^\\]/.test(value);
|
|
125082
|
-
}
|
|
125083
|
-
return value.startsWith("/");
|
|
125084
|
-
}
|
|
125085
|
-
function clipboardTextToPathCandidates(value) {
|
|
125086
|
-
return value.replace(/\0/g, "\n").split(/\r?\n/).map((line) => line.trim().replace(/^"(.+)"$/, "$1")).map((line) => {
|
|
125087
|
-
if (!line.toLowerCase().startsWith("file://")) return line;
|
|
125088
|
-
try {
|
|
125089
|
-
const url2 = new URL(line);
|
|
125090
|
-
return decodeURIComponent(url2.pathname.replace(/^\/([a-zA-Z]:\/)/, "$1"));
|
|
125091
|
-
} catch (e) {
|
|
125092
|
-
logger25.debug("Failed to parse clipboard file URL", { error: e });
|
|
125093
|
-
return "";
|
|
125094
|
-
}
|
|
125095
|
-
}).filter((line) => line.length > 0 && isAbsoluteLocalPathCandidate(line));
|
|
125096
|
-
}
|
|
125097
125796
|
function normalizeClipboardIdentityKey(value) {
|
|
125098
125797
|
return process.platform === "win32" ? value.toLowerCase() : value;
|
|
125099
125798
|
}
|
|
@@ -125131,18 +125830,15 @@ function mimeTypeForFileName(fileName) {
|
|
|
125131
125830
|
}
|
|
125132
125831
|
function parseWindowsClipboardResult(stdout) {
|
|
125133
125832
|
const raw = stdout.trim();
|
|
125134
|
-
if (!raw) return { files: []
|
|
125833
|
+
if (!raw) return { files: [] };
|
|
125135
125834
|
try {
|
|
125136
125835
|
const parsed = JSON.parse(raw);
|
|
125137
|
-
if (!isRecord5(parsed)) return { files: []
|
|
125836
|
+
if (!isRecord5(parsed)) return { files: [] };
|
|
125138
125837
|
const files = Array.isArray(parsed.files) ? parsed.files.filter((item) => typeof item === "string") : [];
|
|
125139
|
-
return {
|
|
125140
|
-
files,
|
|
125141
|
-
text: typeof parsed.text === "string" ? parsed.text : ""
|
|
125142
|
-
};
|
|
125838
|
+
return { files };
|
|
125143
125839
|
} catch (e) {
|
|
125144
125840
|
logger25.debug("Windows clipboard JSON parse skipped", { error: e });
|
|
125145
|
-
return { files:
|
|
125841
|
+
return { files: [] };
|
|
125146
125842
|
}
|
|
125147
125843
|
}
|
|
125148
125844
|
async function readWindowsClipboardPathCandidates() {
|
|
@@ -125155,9 +125851,7 @@ async function readWindowsClipboardPathCandidates() {
|
|
|
125155
125851
|
" $drop = [System.Windows.Forms.Clipboard]::GetFileDropList();",
|
|
125156
125852
|
" foreach ($file in $drop) { $files += [string]$file }",
|
|
125157
125853
|
"} catch {}",
|
|
125158
|
-
|
|
125159
|
-
"try { $text = [System.Windows.Forms.Clipboard]::GetText() } catch {}",
|
|
125160
|
-
"[pscustomobject]@{ files = $files; text = $text } | ConvertTo-Json -Compress;"
|
|
125854
|
+
"[pscustomobject]@{ files = $files } | ConvertTo-Json -Compress;"
|
|
125161
125855
|
].join(" ");
|
|
125162
125856
|
try {
|
|
125163
125857
|
const { stdout } = await execFileAsync2("powershell.exe", [
|
|
@@ -125175,7 +125869,7 @@ async function readWindowsClipboardPathCandidates() {
|
|
|
125175
125869
|
maxBuffer: 1024 * 1024
|
|
125176
125870
|
});
|
|
125177
125871
|
const result = parseWindowsClipboardResult(stdout);
|
|
125178
|
-
return
|
|
125872
|
+
return result.files;
|
|
125179
125873
|
} catch (e) {
|
|
125180
125874
|
logger25.debug("Windows clipboard file read skipped", { error: e });
|
|
125181
125875
|
return [];
|
|
@@ -125581,7 +126275,7 @@ async function readStreamText(filePath, start) {
|
|
|
125581
126275
|
function parseProcessedLines(raw, cursor, fileName, fingerprint) {
|
|
125582
126276
|
const lastNewline = raw.lastIndexOf("\n");
|
|
125583
126277
|
if (lastNewline < 0) {
|
|
125584
|
-
return { entries: [], nextCursor: cursor, advanced: false };
|
|
126278
|
+
return { entries: [], nextCursor: cursor, advanced: false, reason: "partial_line" };
|
|
125585
126279
|
}
|
|
125586
126280
|
const processed = raw.slice(0, lastNewline + 1);
|
|
125587
126281
|
const lines = processed.split(/\r?\n/);
|
|
@@ -125607,7 +126301,8 @@ function parseProcessedLines(raw, cursor, fileName, fingerprint) {
|
|
|
125607
126301
|
lineNum,
|
|
125608
126302
|
...fingerprint ? { fingerprint } : {}
|
|
125609
126303
|
},
|
|
125610
|
-
advanced: true
|
|
126304
|
+
advanced: true,
|
|
126305
|
+
reason: "advanced"
|
|
125611
126306
|
};
|
|
125612
126307
|
}
|
|
125613
126308
|
function chunkEntries(entries, size) {
|
|
@@ -125665,24 +126360,55 @@ var BridgeLogUploader = class {
|
|
|
125665
126360
|
async flushOnce() {
|
|
125666
126361
|
if (this.running || this.stopped) return;
|
|
125667
126362
|
this.running = true;
|
|
126363
|
+
const startedAt = Date.now();
|
|
126364
|
+
const summary = {
|
|
126365
|
+
targetCount: 0,
|
|
126366
|
+
advancedTargetCount: 0,
|
|
126367
|
+
missingTargetCount: 0,
|
|
126368
|
+
idleTargetCount: 0,
|
|
126369
|
+
partialLineTargetCount: 0,
|
|
126370
|
+
failedTargetCount: 0,
|
|
126371
|
+
parsedEntryCount: 0,
|
|
126372
|
+
bridgeEntryCount: 0,
|
|
126373
|
+
uploadedChunkCount: 0,
|
|
126374
|
+
accepted: 0,
|
|
126375
|
+
skipped: 0
|
|
126376
|
+
};
|
|
125668
126377
|
try {
|
|
125669
126378
|
const targets = await this.resolveTargets();
|
|
126379
|
+
summary.targetCount = targets.length;
|
|
125670
126380
|
for (const target of targets) {
|
|
125671
126381
|
try {
|
|
125672
126382
|
const cursor = await readCursor(target.cursorFile);
|
|
125673
126383
|
const batch = await this.readNewEntries(target, cursor);
|
|
125674
|
-
if (!batch.advanced)
|
|
126384
|
+
if (!batch.advanced) {
|
|
126385
|
+
summary.idleTargetCount += 1;
|
|
126386
|
+
if (batch.reason === "missing_file") summary.missingTargetCount += 1;
|
|
126387
|
+
if (batch.reason === "partial_line") summary.partialLineTargetCount += 1;
|
|
126388
|
+
continue;
|
|
126389
|
+
}
|
|
126390
|
+
summary.advancedTargetCount += 1;
|
|
126391
|
+
summary.parsedEntryCount += batch.entries.length;
|
|
125675
126392
|
if (batch.entries.length > 0) {
|
|
125676
|
-
await this.uploadEntries(batch.entries);
|
|
126393
|
+
const result = await this.uploadEntries(batch.entries);
|
|
126394
|
+
summary.bridgeEntryCount += result.bridgeEntryCount;
|
|
126395
|
+
summary.uploadedChunkCount += result.uploadedChunkCount;
|
|
126396
|
+
summary.accepted += result.accepted;
|
|
126397
|
+
summary.skipped += result.skipped;
|
|
125677
126398
|
}
|
|
125678
126399
|
await writeCursor(target.cursorFile, batch.nextCursor);
|
|
125679
126400
|
} catch (e) {
|
|
126401
|
+
summary.failedTargetCount += 1;
|
|
125680
126402
|
logger28.warn("Bridge log upload target failed", { error: e, logFile: target.logFile });
|
|
125681
126403
|
}
|
|
125682
126404
|
}
|
|
125683
126405
|
} catch (e) {
|
|
125684
126406
|
logger28.warn("Bridge log upload cycle failed", { error: e });
|
|
125685
126407
|
} finally {
|
|
126408
|
+
logger28.info("Bridge log upload cycle summary", {
|
|
126409
|
+
...summary,
|
|
126410
|
+
durationMs: Date.now() - startedAt
|
|
126411
|
+
});
|
|
125686
126412
|
this.running = false;
|
|
125687
126413
|
}
|
|
125688
126414
|
}
|
|
@@ -125705,7 +126431,7 @@ var BridgeLogUploader = class {
|
|
|
125705
126431
|
} catch (e) {
|
|
125706
126432
|
if (e instanceof Error && "code" in e && e.code === "ENOENT") {
|
|
125707
126433
|
logger28.debug("Bridge log file not found for upload yet", { logFile: target.logFile });
|
|
125708
|
-
return { entries: [], nextCursor: cursor, advanced: false };
|
|
126434
|
+
return { entries: [], nextCursor: cursor, advanced: false, reason: "missing_file" };
|
|
125709
126435
|
}
|
|
125710
126436
|
throw e;
|
|
125711
126437
|
}
|
|
@@ -125713,13 +126439,19 @@ var BridgeLogUploader = class {
|
|
|
125713
126439
|
const samePhysicalFile = !fingerprint || !cursor.fingerprint || cursor.fingerprint === fingerprint;
|
|
125714
126440
|
const normalizedCursor = stat3.size < cursor.offset || !samePhysicalFile ? { offset: 0, lineNum: 0, ...fingerprint ? { fingerprint } : {} } : { ...cursor, ...fingerprint ? { fingerprint } : {} };
|
|
125715
126441
|
if (stat3.size <= normalizedCursor.offset) {
|
|
125716
|
-
return { entries: [], nextCursor: normalizedCursor, advanced: false };
|
|
126442
|
+
return { entries: [], nextCursor: normalizedCursor, advanced: false, reason: "no_new_entries" };
|
|
125717
126443
|
}
|
|
125718
126444
|
const raw = await readStreamText(target.logFile, normalizedCursor.offset);
|
|
125719
126445
|
return parseProcessedLines(raw, normalizedCursor, target.uploadedFileName, fingerprint);
|
|
125720
126446
|
}
|
|
125721
126447
|
async uploadEntries(entries) {
|
|
125722
126448
|
const bridgeEntries = entries.filter((entry) => entry.source === "bridge");
|
|
126449
|
+
const result = {
|
|
126450
|
+
bridgeEntryCount: bridgeEntries.length,
|
|
126451
|
+
uploadedChunkCount: 0,
|
|
126452
|
+
accepted: 0,
|
|
126453
|
+
skipped: 0
|
|
126454
|
+
};
|
|
125723
126455
|
for (const chunk of chunkEntries(bridgeEntries, this.options.batchSize)) {
|
|
125724
126456
|
const res = await fetch(`${this.options.serverApiUrl}/api/logs/upload`, {
|
|
125725
126457
|
method: "POST",
|
|
@@ -125734,14 +126466,18 @@ var BridgeLogUploader = class {
|
|
|
125734
126466
|
})
|
|
125735
126467
|
});
|
|
125736
126468
|
if (!res.ok) {
|
|
125737
|
-
const
|
|
126469
|
+
const body2 = await res.text().catch((e) => {
|
|
125738
126470
|
logger28.debug("Failed to read log upload error body", { error: e });
|
|
125739
126471
|
return "";
|
|
125740
126472
|
});
|
|
125741
|
-
throw new Error(`upload failed HTTP ${res.status}: ${
|
|
126473
|
+
throw new Error(`upload failed HTTP ${res.status}: ${body2.slice(0, 160)}`);
|
|
125742
126474
|
}
|
|
125743
|
-
await res.json();
|
|
126475
|
+
const body = await res.json();
|
|
126476
|
+
result.uploadedChunkCount += 1;
|
|
126477
|
+
result.accepted += typeof body.accepted === "number" ? body.accepted : 0;
|
|
126478
|
+
result.skipped += typeof body.skipped === "number" ? body.skipped : 0;
|
|
125744
126479
|
}
|
|
126480
|
+
return result;
|
|
125745
126481
|
}
|
|
125746
126482
|
};
|
|
125747
126483
|
|
|
@@ -127739,6 +128475,33 @@ function syncLocalRuntimeSkills(skillStore, localSkills, options = {}) {
|
|
|
127739
128475
|
]);
|
|
127740
128476
|
}
|
|
127741
128477
|
|
|
128478
|
+
// src/processOutput.ts
|
|
128479
|
+
init_cjs_shims();
|
|
128480
|
+
var protectedStreams2 = /* @__PURE__ */ new WeakSet();
|
|
128481
|
+
var reportedErrors = /* @__PURE__ */ new WeakSet();
|
|
128482
|
+
function reportWriteError(error51, onError) {
|
|
128483
|
+
if (typeof error51 === "object" && error51 !== null) {
|
|
128484
|
+
if (reportedErrors.has(error51)) return;
|
|
128485
|
+
reportedErrors.add(error51);
|
|
128486
|
+
}
|
|
128487
|
+
onError(error51);
|
|
128488
|
+
}
|
|
128489
|
+
function safeWriteProcessOutput(stream, text, onError) {
|
|
128490
|
+
if (!stream) return;
|
|
128491
|
+
if (stream.destroyed || stream.writableEnded) return;
|
|
128492
|
+
if (typeof stream === "object" && typeof stream.on === "function" && !protectedStreams2.has(stream)) {
|
|
128493
|
+
protectedStreams2.add(stream);
|
|
128494
|
+
stream.on("error", (e) => reportWriteError(e, onError));
|
|
128495
|
+
}
|
|
128496
|
+
try {
|
|
128497
|
+
stream.write(text, (error51) => {
|
|
128498
|
+
if (error51) reportWriteError(error51, onError);
|
|
128499
|
+
});
|
|
128500
|
+
} catch (e) {
|
|
128501
|
+
reportWriteError(e, onError);
|
|
128502
|
+
}
|
|
128503
|
+
}
|
|
128504
|
+
|
|
127742
128505
|
// src/start.ts
|
|
127743
128506
|
var logger41 = createModuleLogger("bridge");
|
|
127744
128507
|
var NODE_USER_UID2 = 1e3;
|
|
@@ -127825,14 +128588,16 @@ async function startBridge(config2) {
|
|
|
127825
128588
|
const claudeRuntime = resolveClaudeRuntime();
|
|
127826
128589
|
logClaudeRuntimeResolution(claudeRuntime);
|
|
127827
128590
|
if (!claudeRuntime.ok || !claudeRuntime.path) {
|
|
127828
|
-
|
|
128591
|
+
safeWriteProcessOutput(
|
|
128592
|
+
process.stderr,
|
|
127829
128593
|
`
|
|
127830
128594
|
Claude runtime is unavailable.
|
|
127831
128595
|
|
|
127832
128596
|
${claudeRuntime.error ?? "Install Claude Code manually or use the bundled desktop runtime."}
|
|
127833
128597
|
|
|
127834
128598
|
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.
|
|
127835
|
-
|
|
128599
|
+
`,
|
|
128600
|
+
(e) => logger41.error("Bridge process stderr write failed", { error: e })
|
|
127836
128601
|
);
|
|
127837
128602
|
process.exit(1);
|
|
127838
128603
|
}
|
|
@@ -127889,12 +128654,14 @@ Reinstall @fangyb/ahchat-bridge with npm optional dependencies, set AHCHAT_CLAUD
|
|
|
127889
128654
|
claudeRuntimeVersion: claudeRuntime.version ?? null
|
|
127890
128655
|
});
|
|
127891
128656
|
const shouldPrintRawBridgeToken = process.stdout.isTTY && process.env.AHCHAT_SUPPRESS_BRIDGE_TOKEN_STDOUT !== "1";
|
|
127892
|
-
|
|
128657
|
+
safeWriteProcessOutput(
|
|
128658
|
+
process.stdout,
|
|
127893
128659
|
`
|
|
127894
128660
|
Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\u673A\u5668):
|
|
127895
128661
|
${shouldPrintRawBridgeToken ? config2.bridgeToken : "***"}
|
|
127896
128662
|
|
|
127897
|
-
|
|
128663
|
+
`,
|
|
128664
|
+
(e) => logger41.error("Bridge process stdout write failed", { error: e })
|
|
127898
128665
|
);
|
|
127899
128666
|
wsMetrics.start(5e3);
|
|
127900
128667
|
const sessionStore = new SessionStore(config2.dataDir);
|
|
@@ -128693,6 +129460,19 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
128693
129460
|
});
|
|
128694
129461
|
await agentManager.terminateScope(msg.payload.agentId, msg.payload.scope);
|
|
128695
129462
|
break;
|
|
129463
|
+
case "spectate:set":
|
|
129464
|
+
logger41.info("spectate:set received", {
|
|
129465
|
+
agentId: msg.payload.agentId,
|
|
129466
|
+
scope: msg.payload.scope,
|
|
129467
|
+
action: msg.payload.action,
|
|
129468
|
+
traceId: msg.payload.traceId
|
|
129469
|
+
});
|
|
129470
|
+
await agentManager.setSpectate(
|
|
129471
|
+
msg.payload.agentId,
|
|
129472
|
+
msg.payload.scope,
|
|
129473
|
+
msg.payload.action
|
|
129474
|
+
);
|
|
129475
|
+
break;
|
|
128696
129476
|
case "agent:created":
|
|
128697
129477
|
agentRegistry.upsert(msg.payload.agent);
|
|
128698
129478
|
ensureLocalWorkdirPath(msg.payload.agent.workingDirectory, "agent:created", {
|
|
@@ -128910,8 +129690,12 @@ function writeAlreadyRunningMessage(error51) {
|
|
|
128910
129690
|
` ${buildStopCommand(error51.pid)}`,
|
|
128911
129691
|
""
|
|
128912
129692
|
];
|
|
128913
|
-
|
|
128914
|
-
|
|
129693
|
+
safeWriteProcessOutput(
|
|
129694
|
+
process.stdout,
|
|
129695
|
+
`${lines.join("\n")}
|
|
129696
|
+
`,
|
|
129697
|
+
(e) => logger42.error("Bridge already-running message write failed", { error: e })
|
|
129698
|
+
);
|
|
128915
129699
|
}
|
|
128916
129700
|
function handleBridgeStartError(e, message) {
|
|
128917
129701
|
if (isBridgeAlreadyRunningError(e)) {
|