@fangyb/ahchat-bridge 0.1.25 → 0.1.26
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 +245 -51
- package/dist/index.js +244 -48
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -62227,6 +62227,14 @@ runtime\u3002\u5B83\u4EEC\u4E0D\u662F"\u4E0D\u540C\u7684\u4EBA"\u2014\u2014\u516
|
|
|
62227
62227
|
\`# \u3010\u6807\u9898\u3011\` (a single \`#\` followed by Chinese bracket-enclosed title).
|
|
62228
62228
|
For single-topic or short conversational replies, omit headings entirely.
|
|
62229
62229
|
|
|
62230
|
+
# AskUserQuestion tool
|
|
62231
|
+
- When you need the user to choose from options or answer a clarification question, call the real
|
|
62232
|
+
\`AskUserQuestion\` tool with a \`questions\` array.
|
|
62233
|
+
- Never output \`<AskUserQuestion>\`, \`</AskUserQuestion>\`, or raw JSON question payloads as chat text.
|
|
62234
|
+
Text like that is not an interactive panel and the user cannot answer it through the tool flow.
|
|
62235
|
+
- If you are not able to call \`AskUserQuestion\`, ask the question as plain natural language instead of
|
|
62236
|
+
emitting tool-shaped XML or JSON.
|
|
62237
|
+
|
|
62230
62238
|
# Runtime payload \u2014 how to read unread messages
|
|
62231
62239
|
|
|
62232
62240
|
\u6BCF\u4E2A turn \u91CC runtime \u4F1A\u7ED9\u4F60\u300C\u672A\u8BFB\u7FA4\u6D88\u606F\uFF08N \u6761\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09\u300D\u6BB5\u3002\u8BFB\u6CD5\uFF1A
|
|
@@ -62675,6 +62683,11 @@ function parseWSMessage(raw) {
|
|
|
62675
62683
|
}
|
|
62676
62684
|
return parsed;
|
|
62677
62685
|
}
|
|
62686
|
+
function isAskUserQuestionToolName(toolName) {
|
|
62687
|
+
if (!toolName) return false;
|
|
62688
|
+
const normalized = toolName.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
62689
|
+
return normalized === "askuserquestion" || normalized.endsWith("askuserquestion");
|
|
62690
|
+
}
|
|
62678
62691
|
|
|
62679
62692
|
// ../shared/src/utils/workdir.ts
|
|
62680
62693
|
init_cjs_shims();
|
|
@@ -62687,9 +62700,13 @@ init_cjs_shims();
|
|
|
62687
62700
|
|
|
62688
62701
|
// ../shared/src/utils/subscription.ts
|
|
62689
62702
|
init_cjs_shims();
|
|
62703
|
+
var PRIMARY_COMPANY_SUBSCRIPTION_ID = "sub_company_primary";
|
|
62690
62704
|
function isSubscriptionType(v) {
|
|
62691
62705
|
return v === "system" || v === "project";
|
|
62692
62706
|
}
|
|
62707
|
+
function isPrimaryCompanySubscriptionId(v) {
|
|
62708
|
+
return v === PRIMARY_COMPANY_SUBSCRIPTION_ID;
|
|
62709
|
+
}
|
|
62693
62710
|
|
|
62694
62711
|
// ../shared/src/utils/agentConfig.ts
|
|
62695
62712
|
function parseAgentConfig(raw) {
|
|
@@ -78285,6 +78302,14 @@ function normalizeDocumentText(value) {
|
|
|
78285
78302
|
return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
78286
78303
|
}
|
|
78287
78304
|
|
|
78305
|
+
// src/bridgeHttp.ts
|
|
78306
|
+
init_cjs_shims();
|
|
78307
|
+
var BRIDGE_TOKEN_HEADER = "X-AHChat-Bridge-Token";
|
|
78308
|
+
function bridgeAuthHeaders(bridgeToken) {
|
|
78309
|
+
const token = bridgeToken?.trim();
|
|
78310
|
+
return token ? { [BRIDGE_TOKEN_HEADER]: token } : {};
|
|
78311
|
+
}
|
|
78312
|
+
|
|
78288
78313
|
// src/neuralMcpServer.ts
|
|
78289
78314
|
var logger7 = createModuleLogger("neural.mcpServer");
|
|
78290
78315
|
function formatScopeLabel(key, groupName) {
|
|
@@ -78303,6 +78328,26 @@ function filterContactsByOwner(all, ownerId) {
|
|
|
78303
78328
|
(a) => a.kind === "system" || a.ownerId === ownerId || a.ownerId == null || a.kind === "human" && a.id === ownerId
|
|
78304
78329
|
);
|
|
78305
78330
|
}
|
|
78331
|
+
async function resolveTierSubscriptionPreference(preferredSubscriptionId, deps) {
|
|
78332
|
+
if (!preferredSubscriptionId || !isPrimaryCompanySubscriptionId(preferredSubscriptionId)) {
|
|
78333
|
+
return preferredSubscriptionId;
|
|
78334
|
+
}
|
|
78335
|
+
if (!deps.serverApiUrl) return preferredSubscriptionId;
|
|
78336
|
+
try {
|
|
78337
|
+
const base = deps.serverApiUrl.replace(/\/$/, "");
|
|
78338
|
+
const res = await fetch(`${base}/api/subscriptions`, {
|
|
78339
|
+
headers: bridgeAuthHeaders(deps.bridgeToken ?? null)
|
|
78340
|
+
});
|
|
78341
|
+
if (!res.ok) return preferredSubscriptionId;
|
|
78342
|
+
const subscriptions = await res.json();
|
|
78343
|
+
return subscriptions.find(
|
|
78344
|
+
(subscription) => subscription.billingMode === "company_billable" && subscription.isPrimaryCompany === true
|
|
78345
|
+
)?.id ?? preferredSubscriptionId;
|
|
78346
|
+
} catch (e) {
|
|
78347
|
+
logger7.warn("Primary company tier preference resolution failed", { error: e });
|
|
78348
|
+
return preferredSubscriptionId;
|
|
78349
|
+
}
|
|
78350
|
+
}
|
|
78306
78351
|
function resolveMyHuman(registry2, agentId) {
|
|
78307
78352
|
const all = registry2.getAll();
|
|
78308
78353
|
const myOwnerId = contactOwnerId(registry2, agentId);
|
|
@@ -79458,8 +79503,8 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
|
|
|
79458
79503
|
"fetch_logs",
|
|
79459
79504
|
`\u62C9\u53D6\u7CFB\u7EDF\u65E5\u5FD7\uFF08\u6309\u65F6\u95F4\u7A97 + \u53EF\u9009 traceId / module / level \u8FC7\u6EE4\uFF09\u3002
|
|
79460
79505
|
\u8BFB SKILL "log-analysis" \u540E\u624D\u7528\u8FD9\u4E2A\u5DE5\u5177\u3002\u4E00\u6B21\u8C03\u7528\u53EA\u80FD\u62C9\u4E00\u4E2A source\uFF08server \u6216 bridge\uFF09\uFF0C\u5168\u666F\u9700\u8981\u4E24\u6B21\u3002
|
|
79461
|
-
limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679C\u9876\u90E8\u5E26\u5206\u7EA7\u7EDF\u8BA1\uFF08ERROR/WARN/INFO \u5404\u591A\u5C11\u6761\uFF09\uFF0C\u6309\u65F6\u95F4\
|
|
79462
|
-
\u6CE8\u610F\uFF1A\u5982\u679C\
|
|
79506
|
+
limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5206\u9875\u3002\u8FD4\u56DE\u7ED3\u679C\u9876\u90E8\u5E26\u5206\u7EA7\u7EDF\u8BA1\uFF08ERROR/WARN/INFO \u5404\u591A\u5C11\u6761\uFF09\uFF0C\u6309\u65F6\u95F4\u5012\u5E8F\u6392\u5217\uFF0C\u6700\u65B0\u65E5\u5FD7\u5728\u524D\u3002\u6BCF\u884C\u5E26 file / lineNum\uFF0C\u5F15\u7528\u65E5\u5FD7\u65F6\u5FC5\u987B\u7CBE\u786E\u5199 [<file>:L<lineNum>]\u3002
|
|
79507
|
+
\u6CE8\u610F\uFF1A\u5982\u679C\u8FD8\u6709\u66F4\u591A\u7ED3\u679C\uFF0Cheader \u4F1A\u6807\u6CE8 nextOffset\uFF1B\u7EE7\u7EED\u67E5\u8BE2\u65F6\u5E26\u4E0A offset=nextOffset\u3002`,
|
|
79463
79508
|
{
|
|
79464
79509
|
source: external_exports.enum(["server", "bridge"]).describe('\u65E5\u5FD7\u6765\u6E90\uFF0C\u5FC5\u987B\u662F "server" \u6216 "bridge" \u4E4B\u4E00\u3002'),
|
|
79465
79510
|
start_iso: external_exports.string().describe('\u8D77\u59CB\u65F6\u95F4\uFF0CISO 8601 \u6216\u76F8\u5BF9\u683C\u5F0F\uFF1A"now-5m" / "now-1h" / "now-24h"\u3002'),
|
|
@@ -79468,7 +79513,8 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79468
79513
|
trace_id: external_exports.string().optional().describe("\u8FC7\u6EE4\u7279\u5B9A traceId\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3002"),
|
|
79469
79514
|
module: external_exports.string().optional().describe('\u8FC7\u6EE4 module \u524D\u7F00\uFF08\u5982 "ws.handler" / "agent.manager"\uFF09\u3002'),
|
|
79470
79515
|
msg_contains: external_exports.string().optional().describe("msg \u5B50\u4E32\u8FC7\u6EE4\uFF08\u533A\u5206\u5927\u5C0F\u5199\uFF09\u3002"),
|
|
79471
|
-
limit: external_exports.number().int().min(1).max(2e3).optional().describe("\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 500\uFF0C\u6700\u5927 2000\u3002")
|
|
79516
|
+
limit: external_exports.number().int().min(1).max(2e3).optional().describe("\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 500\uFF0C\u6700\u5927 2000\u3002"),
|
|
79517
|
+
offset: external_exports.number().int().min(0).optional().describe("\u5206\u9875\u504F\u79FB\u91CF\uFF1B\u9996\u6B21\u67E5\u8BE2\u4E0D\u4F20\uFF0C\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20\u4E0A\u6B21\u8FD4\u56DE\u7684 nextOffset\u3002")
|
|
79472
79518
|
},
|
|
79473
79519
|
async (args) => {
|
|
79474
79520
|
if (!deps.isSmith) {
|
|
@@ -79493,9 +79539,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79493
79539
|
traceId: args.trace_id,
|
|
79494
79540
|
module: args.module,
|
|
79495
79541
|
levelMin: args.level_min,
|
|
79496
|
-
limit: args.limit
|
|
79542
|
+
limit: args.limit,
|
|
79543
|
+
offset: args.offset
|
|
79497
79544
|
});
|
|
79498
79545
|
const parsedLimit = typeof args.limit === "number" && Number.isFinite(args.limit) ? args.limit : 500;
|
|
79546
|
+
const parsedOffset = typeof args.offset === "number" && Number.isFinite(args.offset) ? args.offset : 0;
|
|
79499
79547
|
try {
|
|
79500
79548
|
const url2 = `${deps.serverApiUrl.replace(/\/$/, "")}/api/admin/logs`;
|
|
79501
79549
|
const body = {
|
|
@@ -79506,7 +79554,8 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79506
79554
|
traceId: args.trace_id,
|
|
79507
79555
|
module: args.module,
|
|
79508
79556
|
msgContains: args.msg_contains,
|
|
79509
|
-
limit: Number.isFinite(parsedLimit) ? parsedLimit : 500
|
|
79557
|
+
limit: Number.isFinite(parsedLimit) ? parsedLimit : 500,
|
|
79558
|
+
offset: Number.isFinite(parsedOffset) ? parsedOffset : 0
|
|
79510
79559
|
};
|
|
79511
79560
|
const res = await fetch(url2, {
|
|
79512
79561
|
method: "POST",
|
|
@@ -79529,7 +79578,9 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79529
79578
|
source,
|
|
79530
79579
|
count: json2.entries.length,
|
|
79531
79580
|
truncated: json2.truncated,
|
|
79532
|
-
totalScanned: json2.totalScanned
|
|
79581
|
+
totalScanned: json2.totalScanned,
|
|
79582
|
+
totalMatched: json2.totalMatched,
|
|
79583
|
+
nextOffset: json2.nextOffset
|
|
79533
79584
|
});
|
|
79534
79585
|
const lines = json2.entries.map((e) => {
|
|
79535
79586
|
const dataStr = e.data ? ` data=${JSON.stringify(e.data).slice(0, 200)}` : "";
|
|
@@ -79542,9 +79593,10 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79542
79593
|
const infoCount = json2.entries.filter((e) => e.level === "INFO").length;
|
|
79543
79594
|
const traceCount = json2.entries.filter((e) => e.level === "TRACE" || e.level === "DEBUG").length;
|
|
79544
79595
|
const header = [
|
|
79545
|
-
`[${source}] \u5171\u626B ${json2.totalScanned} \u884C\uFF0C\u547D\u4E2D ${json2.entries.length} \u6761`,
|
|
79596
|
+
`[${source}] \u5171\u626B ${json2.totalScanned} \u884C\uFF0C\u5DF2\u8FD4\u56DE ${json2.entries.length} \u6761\uFF0C\u547D\u4E2D ${json2.totalMatched ?? json2.entries.length} \u6761`,
|
|
79546
79597
|
` ERROR/FATAL: ${errorCount} | WARN: ${warnCount} | INFO: ${infoCount} | TRACE/DEBUG: ${traceCount}`
|
|
79547
|
-
].join("\n") + (json2.
|
|
79598
|
+
].join("\n") + (json2.nextOffset != null ? `
|
|
79599
|
+
nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=${json2.nextOffset}\uFF09` : "");
|
|
79548
79600
|
const text = [header, "", ...lines].join("\n");
|
|
79549
79601
|
return { content: [{ type: "text", text }] };
|
|
79550
79602
|
} catch (e) {
|
|
@@ -79631,7 +79683,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79631
79683
|
const tiers = await tierRes.json();
|
|
79632
79684
|
const self = deps.agentRegistry?.getById(deps.agentId);
|
|
79633
79685
|
const preferredSubscriptionId = parseAgentConfig(self?.config).subscriptionId;
|
|
79634
|
-
const
|
|
79686
|
+
const resolvedPreferredSubscriptionId = await resolveTierSubscriptionPreference(
|
|
79687
|
+
preferredSubscriptionId,
|
|
79688
|
+
deps
|
|
79689
|
+
);
|
|
79690
|
+
const tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === resolvedPreferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
|
|
79635
79691
|
if (tierConfig) {
|
|
79636
79692
|
agentConfig = JSON.stringify({
|
|
79637
79693
|
capabilityTier: tier,
|
|
@@ -79786,7 +79842,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79786
79842
|
if (tierRes.ok) {
|
|
79787
79843
|
const tiers = await tierRes.json();
|
|
79788
79844
|
const preferredSubscriptionId = parseAgentConfig(existing.config).subscriptionId;
|
|
79789
|
-
const
|
|
79845
|
+
const resolvedPreferredSubscriptionId = await resolveTierSubscriptionPreference(
|
|
79846
|
+
preferredSubscriptionId,
|
|
79847
|
+
deps
|
|
79848
|
+
);
|
|
79849
|
+
const tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === resolvedPreferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
|
|
79790
79850
|
if (tierConfig) {
|
|
79791
79851
|
agentConfig = JSON.stringify({
|
|
79792
79852
|
capabilityTier: tier,
|
|
@@ -80419,6 +80479,8 @@ var GroupDispatchMemoryStore = class {
|
|
|
80419
80479
|
|
|
80420
80480
|
// src/groupInboxPromptBuilder.ts
|
|
80421
80481
|
init_cjs_shims();
|
|
80482
|
+
var MAX_SYSTEM_NOTE_COUNT = 8;
|
|
80483
|
+
var MAX_SYSTEM_NOTE_LEN = 1e3;
|
|
80422
80484
|
function formatHHMM(epochMs) {
|
|
80423
80485
|
const d = new Date(epochMs);
|
|
80424
80486
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -80429,6 +80491,37 @@ function truncate(text, maxLen) {
|
|
|
80429
80491
|
if (text.length <= maxLen) return text;
|
|
80430
80492
|
return `${text.slice(0, maxLen)}\u2026`;
|
|
80431
80493
|
}
|
|
80494
|
+
function formatIsoHHMM(iso) {
|
|
80495
|
+
const epochMs = Date.parse(iso);
|
|
80496
|
+
if (!Number.isFinite(epochMs)) return "";
|
|
80497
|
+
return formatHHMM(epochMs);
|
|
80498
|
+
}
|
|
80499
|
+
function collectSystemNotes(entries) {
|
|
80500
|
+
const byId = /* @__PURE__ */ new Map();
|
|
80501
|
+
for (const entry of entries) {
|
|
80502
|
+
for (const msg of entry.context) {
|
|
80503
|
+
if (msg.role !== "system") continue;
|
|
80504
|
+
byId.set(msg.id, {
|
|
80505
|
+
id: msg.id,
|
|
80506
|
+
time: formatIsoHHMM(msg.createdAt),
|
|
80507
|
+
content: truncate(msg.content, MAX_SYSTEM_NOTE_LEN)
|
|
80508
|
+
});
|
|
80509
|
+
}
|
|
80510
|
+
}
|
|
80511
|
+
return [...byId.values()].slice(-MAX_SYSTEM_NOTE_COUNT);
|
|
80512
|
+
}
|
|
80513
|
+
function appendSystemNotes(lines, entries) {
|
|
80514
|
+
const notes = collectSystemNotes(entries);
|
|
80515
|
+
if (notes.length === 0) return;
|
|
80516
|
+
lines.push(`--- \u7FA4\u5185\u7CFB\u7EDF\u8BB0\u5F55\uFF08${notes.length} \u6761\uFF0C\u4F9B\u4E0A\u4E0B\u6587\uFF1B\u975E\u666E\u901A\u804A\u5929\u5386\u53F2\uFF09---`);
|
|
80517
|
+
lines.push("\u8FD9\u4E9B\u8BB0\u5F55\u53EA\u7528\u4E8E\u7406\u89E3\u7528\u6237\u5DF2\u4F5C\u51FA\u7684 AskUserQuestion/\u7CFB\u7EDF\u51B3\u7B56\uFF1B\u4E0D\u8981\u76F4\u63A5\u56DE\u590D\u7CFB\u7EDF\u8BB0\u5F55\u672C\u8EAB\u3002");
|
|
80518
|
+
for (const note of notes) {
|
|
80519
|
+
const prefix = note.time ? `[${note.time}] system:` : "system:";
|
|
80520
|
+
lines.push(`${prefix} ${note.content}`);
|
|
80521
|
+
}
|
|
80522
|
+
lines.push("--- \u7FA4\u5185\u7CFB\u7EDF\u8BB0\u5F55 end ---");
|
|
80523
|
+
lines.push("");
|
|
80524
|
+
}
|
|
80432
80525
|
function appendBoardContext(lines, latest) {
|
|
80433
80526
|
if (latest.boardMeta?.vision) {
|
|
80434
80527
|
lines.push("--- project vision ---");
|
|
@@ -80497,6 +80590,7 @@ function buildGroupInboxPrompt(entries, opts = {}) {
|
|
|
80497
80590
|
);
|
|
80498
80591
|
}
|
|
80499
80592
|
lines.push("");
|
|
80593
|
+
appendSystemNotes(lines, entries);
|
|
80500
80594
|
lines.push(`--- \u672A\u8BFB\u7FA4\u6D88\u606F\uFF08${entries.length} \u6761\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09---`);
|
|
80501
80595
|
for (const e of entries) {
|
|
80502
80596
|
const ts = formatHHMM(e.arrivedAt);
|
|
@@ -80841,6 +80935,31 @@ function extractUsage(message) {
|
|
|
80841
80935
|
}
|
|
80842
80936
|
return result;
|
|
80843
80937
|
}
|
|
80938
|
+
function hasUsageValue(usage) {
|
|
80939
|
+
return typeof usage.tokenCount === "number" || typeof usage.inputTokens === "number" || typeof usage.cacheReadTokens === "number" || typeof usage.cacheCreationTokens === "number" || typeof usage.costUsd === "number";
|
|
80940
|
+
}
|
|
80941
|
+
function emitUsageReported(proc, emit, base, usage, messageId) {
|
|
80942
|
+
if (!hasUsageValue(usage)) return;
|
|
80943
|
+
const groupId = proc.currentTask?.groupId;
|
|
80944
|
+
const scopeKeyValue = proc.scope.kind === "group" ? `group:${proc.scope.groupId}` : "single";
|
|
80945
|
+
emit({
|
|
80946
|
+
type: "agent:usage_reported",
|
|
80947
|
+
payload: {
|
|
80948
|
+
...wireBase(base),
|
|
80949
|
+
...messageId ? { messageId } : {},
|
|
80950
|
+
...groupId ? { groupId } : {},
|
|
80951
|
+
scopeKey: scopeKeyValue,
|
|
80952
|
+
model: usage.model,
|
|
80953
|
+
usage: {
|
|
80954
|
+
inputTokens: usage.inputTokens,
|
|
80955
|
+
outputTokens: usage.tokenCount,
|
|
80956
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
80957
|
+
cacheCreationTokens: usage.cacheCreationTokens
|
|
80958
|
+
},
|
|
80959
|
+
providerCostUsd: usage.costUsd
|
|
80960
|
+
}
|
|
80961
|
+
});
|
|
80962
|
+
}
|
|
80844
80963
|
function isGroupTask(proc) {
|
|
80845
80964
|
return proc.currentTask?.groupId != null;
|
|
80846
80965
|
}
|
|
@@ -81102,7 +81221,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81102
81221
|
proc.currentToolName = block.name ?? "unknown";
|
|
81103
81222
|
proc.accumulatedToolInput = "";
|
|
81104
81223
|
const toolName = block.name ?? "unknown";
|
|
81105
|
-
if (toolName !== "ExitPlanMode" && toolName
|
|
81224
|
+
if (toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
81106
81225
|
emit({
|
|
81107
81226
|
type: "agent:tool_use",
|
|
81108
81227
|
payload: {
|
|
@@ -81266,9 +81385,9 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81266
81385
|
});
|
|
81267
81386
|
}
|
|
81268
81387
|
}
|
|
81269
|
-
if (proc.currentToolName
|
|
81388
|
+
if (isAskUserQuestionToolName(proc.currentToolName)) {
|
|
81270
81389
|
const last = proc.contentBlocks[proc.contentBlocks.length - 1];
|
|
81271
|
-
if (last?.type === "tool_use" && last.toolName
|
|
81390
|
+
if (last?.type === "tool_use" && isAskUserQuestionToolName(last.toolName)) {
|
|
81272
81391
|
proc.contentBlocks.pop();
|
|
81273
81392
|
}
|
|
81274
81393
|
}
|
|
@@ -81320,7 +81439,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81320
81439
|
const toolName = proc.currentToolName ?? "unknown";
|
|
81321
81440
|
const isError = toolName === "ExitPlanMode" ? false : !!b.is_error;
|
|
81322
81441
|
const output = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
|
|
81323
|
-
if (toolName
|
|
81442
|
+
if (isAskUserQuestionToolName(toolName)) {
|
|
81324
81443
|
proc.currentToolName = null;
|
|
81325
81444
|
continue;
|
|
81326
81445
|
}
|
|
@@ -81404,6 +81523,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81404
81523
|
const watermarkUsage = proc.peakContextUsage ?? usage;
|
|
81405
81524
|
if (trimmed === NO_REPLY_TOKEN) {
|
|
81406
81525
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
81526
|
+
emitUsageReported(proc, emit, base, usage);
|
|
81407
81527
|
if (groupMode && proc.contentBlocks.length > 0) {
|
|
81408
81528
|
emitGroupSegment(
|
|
81409
81529
|
proc,
|
|
@@ -81443,6 +81563,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81443
81563
|
}
|
|
81444
81564
|
if (groupMode) {
|
|
81445
81565
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
81566
|
+
emitUsageReported(proc, emit, base, usage);
|
|
81446
81567
|
if (proc.contentBlocks.length > 0) {
|
|
81447
81568
|
logger9.info("Group turn trailing audit segment", {
|
|
81448
81569
|
agentId: proc.agentId,
|
|
@@ -81477,6 +81598,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81477
81598
|
}
|
|
81478
81599
|
if (proc.accumulatedText.length === 0 && proc.contentBlocks.length === 0) {
|
|
81479
81600
|
cleanupPlanMode(proc, emit, base, "error");
|
|
81601
|
+
emitUsageReported(proc, emit, base, usage);
|
|
81480
81602
|
logger9.warn("SDK success produced empty assistant output; emitting agent:error", {
|
|
81481
81603
|
agentId: proc.agentId,
|
|
81482
81604
|
ackId: base.replyMessageId,
|
|
@@ -81504,6 +81626,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81504
81626
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
81505
81627
|
cleanupPlanMode(proc, emit, base, "success");
|
|
81506
81628
|
carrierMessageId = createMessageId();
|
|
81629
|
+
emitUsageReported(proc, emit, base, usage, carrierMessageId);
|
|
81507
81630
|
logger9.info("Agent task done, emitting agent:done", {
|
|
81508
81631
|
agentId: proc.agentId,
|
|
81509
81632
|
ackId: base.replyMessageId,
|
|
@@ -81524,6 +81647,11 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81524
81647
|
thinkingDuration: Date.now() - proc.currentTaskStartedAt,
|
|
81525
81648
|
toolCallCount: proc.contentBlocks.filter((b) => b.type === "tool_use").length,
|
|
81526
81649
|
tokenCount: usage.tokenCount,
|
|
81650
|
+
outputTokens: usage.tokenCount,
|
|
81651
|
+
inputTokens: usage.inputTokens,
|
|
81652
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
81653
|
+
cacheCreationTokens: usage.cacheCreationTokens,
|
|
81654
|
+
costUsd: usage.costUsd,
|
|
81527
81655
|
model: usage.model
|
|
81528
81656
|
}
|
|
81529
81657
|
}
|
|
@@ -81852,6 +81980,12 @@ var wsMetrics = new WsMetrics();
|
|
|
81852
81980
|
|
|
81853
81981
|
// src/agentManager.ts
|
|
81854
81982
|
var logger12 = createModuleLogger("agent.manager");
|
|
81983
|
+
function missingSubscriptionMessage(subscriptionId) {
|
|
81984
|
+
if (isPrimaryCompanySubscriptionId(subscriptionId)) {
|
|
81985
|
+
return "AHChat \u9ED8\u8BA4\u6A21\u578B\u6682\u65F6\u4E0D\u53EF\u7528\uFF1A\u8FD9\u53F0\u673A\u5668\u8FD8\u6CA1\u6709\u540C\u6B65\u5230\u7BA1\u7406\u5458\u542F\u7528\u7684\u9ED8\u8BA4\u6A21\u578B\uFF0C\u8BF7\u66F4\u65B0\u5E76\u91CD\u542F Bridge \u540E\u91CD\u8BD5\u3002";
|
|
81986
|
+
}
|
|
81987
|
+
return `\u8BA2\u9605\u6E90\u4E0D\u53EF\u7528\uFF1A${subscriptionId}\u3002\u8BF7\u91CD\u65B0\u9009\u62E9\u6A21\u578B\u6765\u6E90\uFF0C\u6216\u91CD\u542F Bridge \u540E\u91CD\u8BD5\u3002`;
|
|
81988
|
+
}
|
|
81855
81989
|
var NODE_USER_UID = 1e3;
|
|
81856
81990
|
var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
|
|
81857
81991
|
var DOCUMENT_READING_RULES = `DOCUMENT READING:
|
|
@@ -81916,6 +82050,27 @@ var BridgeBusyError = class extends Error {
|
|
|
81916
82050
|
this.name = "BridgeBusyError";
|
|
81917
82051
|
}
|
|
81918
82052
|
};
|
|
82053
|
+
function senderLabelForQuote(message) {
|
|
82054
|
+
if (message.senderAgentName) return message.senderAgentName;
|
|
82055
|
+
if (message.role === "user") return "user";
|
|
82056
|
+
if (message.role === "agent") return `agent:${message.senderAgentId ?? "unknown"}`;
|
|
82057
|
+
return "system";
|
|
82058
|
+
}
|
|
82059
|
+
function buildSingleReplyPrompt(task) {
|
|
82060
|
+
if (!task.replyToMessage) return task.content;
|
|
82061
|
+
const quoted = task.replyToMessage;
|
|
82062
|
+
const label = senderLabelForQuote(quoted);
|
|
82063
|
+
return [
|
|
82064
|
+
"--- reply-to message ---",
|
|
82065
|
+
`You are replying to this earlier message from [${label}]:`,
|
|
82066
|
+
quoted.content || (quoted.attachments?.length ? "[attachment]" : ""),
|
|
82067
|
+
"--- end reply-to message ---",
|
|
82068
|
+
"",
|
|
82069
|
+
"--- user message ---",
|
|
82070
|
+
task.content,
|
|
82071
|
+
"--- end user message ---"
|
|
82072
|
+
].join("\n");
|
|
82073
|
+
}
|
|
81919
82074
|
var AgentManager = class {
|
|
81920
82075
|
agents = /* @__PURE__ */ new Map();
|
|
81921
82076
|
lastUsedAt = /* @__PURE__ */ new Map();
|
|
@@ -82051,16 +82206,16 @@ var AgentManager = class {
|
|
|
82051
82206
|
agentId: agent.id,
|
|
82052
82207
|
subscriptionId: cfg.subscriptionId
|
|
82053
82208
|
});
|
|
82054
|
-
|
|
82209
|
+
throw new Error(missingSubscriptionMessage(cfg.subscriptionId));
|
|
82055
82210
|
}
|
|
82056
82211
|
let sub = this.subscriptionRegistry.getById(cfg.subscriptionId);
|
|
82057
82212
|
if (!sub) sub = await this.subscriptionRegistry.fetchById(cfg.subscriptionId);
|
|
82058
82213
|
if (!sub) {
|
|
82059
|
-
logger12.warn("Subscription not found;
|
|
82214
|
+
logger12.warn("Subscription not found; refusing native OAuth fallback", {
|
|
82060
82215
|
agentId: agent.id,
|
|
82061
82216
|
subscriptionId: cfg.subscriptionId
|
|
82062
82217
|
});
|
|
82063
|
-
|
|
82218
|
+
throw new Error(missingSubscriptionMessage(cfg.subscriptionId));
|
|
82064
82219
|
}
|
|
82065
82220
|
const isPinnedModel = cfg.model && cfg.model !== "default";
|
|
82066
82221
|
const resolvedModel = isPinnedModel ? cfg.model : sub.defaultModel;
|
|
@@ -83259,8 +83414,9 @@ ${lines.join("\n")}`;
|
|
|
83259
83414
|
});
|
|
83260
83415
|
}
|
|
83261
83416
|
async pushTaskContent(runtime, task, onYielded) {
|
|
83417
|
+
const textContent = buildSingleReplyPrompt(task);
|
|
83262
83418
|
if (!task.attachments || task.attachments.length === 0) {
|
|
83263
|
-
runtime.inputController.push(
|
|
83419
|
+
runtime.inputController.push(textContent, runtime.ccSessionId ?? "", onYielded);
|
|
83264
83420
|
return;
|
|
83265
83421
|
}
|
|
83266
83422
|
const supportsVision = await this.detectVisionSupport();
|
|
@@ -83272,7 +83428,7 @@ ${lines.join("\n")}`;
|
|
|
83272
83428
|
supportsVision
|
|
83273
83429
|
}
|
|
83274
83430
|
);
|
|
83275
|
-
const text =
|
|
83431
|
+
const text = textContent.trim() || "\u8BF7\u67E5\u770B\u6211\u53D1\u9001\u7684\u9644\u4EF6\u3002";
|
|
83276
83432
|
const contentParts = [
|
|
83277
83433
|
{ type: "text", text },
|
|
83278
83434
|
...attachmentBlocks
|
|
@@ -83310,9 +83466,12 @@ ${lines.join("\n")}`;
|
|
|
83310
83466
|
return materialized;
|
|
83311
83467
|
}
|
|
83312
83468
|
async resolveExistingWorkspaceAttachmentPath(runtime, attachment) {
|
|
83469
|
+
const localWorkspacePath = attachment.metadata?.localWorkspacePath;
|
|
83313
83470
|
const workspacePath = attachment.metadata?.workspacePath;
|
|
83314
|
-
|
|
83315
|
-
|
|
83471
|
+
const rawPath = typeof localWorkspacePath === "string" && localWorkspacePath.trim() ? localWorkspacePath : workspacePath;
|
|
83472
|
+
if (typeof rawPath !== "string" || !rawPath.trim()) return null;
|
|
83473
|
+
const remapped = remapServerWorkspacePath(rawPath, this.workspacesDir);
|
|
83474
|
+
const candidate = import_node_path11.default.resolve(remapped.path);
|
|
83316
83475
|
if (!this.isPathInsideBase(candidate, runtime.cwd)) return null;
|
|
83317
83476
|
try {
|
|
83318
83477
|
const stat3 = await import_promises3.default.stat(candidate);
|
|
@@ -83322,6 +83481,8 @@ ${lines.join("\n")}`;
|
|
|
83322
83481
|
agentId: runtime.agentId,
|
|
83323
83482
|
attachmentId: attachment.id,
|
|
83324
83483
|
workspacePath,
|
|
83484
|
+
localWorkspacePath,
|
|
83485
|
+
resolvedPath: candidate,
|
|
83325
83486
|
error: e
|
|
83326
83487
|
});
|
|
83327
83488
|
return null;
|
|
@@ -84521,7 +84682,7 @@ function computeBoardSignature(entry) {
|
|
|
84521
84682
|
// src/bridgeFetchAuth.ts
|
|
84522
84683
|
init_cjs_shims();
|
|
84523
84684
|
var logger13 = createModuleLogger("bridge.fetchAuth");
|
|
84524
|
-
var
|
|
84685
|
+
var BRIDGE_TOKEN_HEADER2 = "X-AHChat-Bridge-Token";
|
|
84525
84686
|
function installBridgeFetchAuth(serverApiUrl, token) {
|
|
84526
84687
|
if (typeof globalThis.fetch !== "function") {
|
|
84527
84688
|
logger13.warn("globalThis.fetch not available, cannot install bridge fetch auth");
|
|
@@ -84549,8 +84710,8 @@ function installBridgeFetchAuth(serverApiUrl, token) {
|
|
|
84549
84710
|
else url2 = input.url;
|
|
84550
84711
|
if (!shouldInject(url2)) return original(input, init);
|
|
84551
84712
|
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
84552
|
-
if (!headers.has(
|
|
84553
|
-
headers.set(
|
|
84713
|
+
if (!headers.has(BRIDGE_TOKEN_HEADER2)) {
|
|
84714
|
+
headers.set(BRIDGE_TOKEN_HEADER2, token);
|
|
84554
84715
|
}
|
|
84555
84716
|
return original(input, { ...init, headers });
|
|
84556
84717
|
});
|
|
@@ -84562,16 +84723,6 @@ function installBridgeFetchAuth(serverApiUrl, token) {
|
|
|
84562
84723
|
|
|
84563
84724
|
// src/agentRegistry.ts
|
|
84564
84725
|
init_cjs_shims();
|
|
84565
|
-
|
|
84566
|
-
// src/bridgeHttp.ts
|
|
84567
|
-
init_cjs_shims();
|
|
84568
|
-
var BRIDGE_TOKEN_HEADER2 = "X-AHChat-Bridge-Token";
|
|
84569
|
-
function bridgeAuthHeaders(bridgeToken) {
|
|
84570
|
-
const token = bridgeToken?.trim();
|
|
84571
|
-
return token ? { [BRIDGE_TOKEN_HEADER2]: token } : {};
|
|
84572
|
-
}
|
|
84573
|
-
|
|
84574
|
-
// src/agentRegistry.ts
|
|
84575
84726
|
var logger14 = createModuleLogger("agent.registry");
|
|
84576
84727
|
var HttpAgentRegistry = class {
|
|
84577
84728
|
constructor(serverApiUrl, bridgeToken = null) {
|
|
@@ -84685,6 +84836,23 @@ var HttpSubscriptionRegistry = class {
|
|
|
84685
84836
|
const path26 = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
84686
84837
|
return `${base}${path26}`;
|
|
84687
84838
|
}
|
|
84839
|
+
primaryAliasFrom(sub) {
|
|
84840
|
+
return {
|
|
84841
|
+
...sub,
|
|
84842
|
+
id: PRIMARY_COMPANY_SUBSCRIPTION_ID,
|
|
84843
|
+
name: "\u516C\u53F8\u4E3B\u8BA2\u9605",
|
|
84844
|
+
resolvedSubscriptionId: sub.id,
|
|
84845
|
+
isVirtual: true
|
|
84846
|
+
};
|
|
84847
|
+
}
|
|
84848
|
+
rebuildPrimaryAlias() {
|
|
84849
|
+
this.subscriptions.delete(PRIMARY_COMPANY_SUBSCRIPTION_ID);
|
|
84850
|
+
const primary = Array.from(this.subscriptions.values()).find(
|
|
84851
|
+
(sub) => sub.billingMode === "company_billable" && sub.isPrimaryCompany === true
|
|
84852
|
+
);
|
|
84853
|
+
if (!primary) return;
|
|
84854
|
+
this.subscriptions.set(PRIMARY_COMPANY_SUBSCRIPTION_ID, this.primaryAliasFrom(primary));
|
|
84855
|
+
}
|
|
84688
84856
|
async refresh() {
|
|
84689
84857
|
const attempt = async () => {
|
|
84690
84858
|
try {
|
|
@@ -84712,6 +84880,7 @@ var HttpSubscriptionRegistry = class {
|
|
|
84712
84880
|
const s = item;
|
|
84713
84881
|
if (s && typeof s.id === "string") this.subscriptions.set(s.id, s);
|
|
84714
84882
|
}
|
|
84883
|
+
this.rebuildPrimaryAlias();
|
|
84715
84884
|
logger15.info("Subscription registry refreshed", { count: this.subscriptions.size });
|
|
84716
84885
|
} catch (e) {
|
|
84717
84886
|
logger15.warn("Subscription registry parse failed", { error: e });
|
|
@@ -84721,6 +84890,10 @@ var HttpSubscriptionRegistry = class {
|
|
|
84721
84890
|
return this.subscriptions.get(id) ?? null;
|
|
84722
84891
|
}
|
|
84723
84892
|
async fetchById(id) {
|
|
84893
|
+
if (isPrimaryCompanySubscriptionId(id)) {
|
|
84894
|
+
await this.refresh();
|
|
84895
|
+
return this.getById(id);
|
|
84896
|
+
}
|
|
84724
84897
|
try {
|
|
84725
84898
|
const res = await fetch(this.apiUrl(`/api/subscriptions/${encodeURIComponent(id)}`), {
|
|
84726
84899
|
headers: bridgeAuthHeaders(this.bridgeToken)
|
|
@@ -84736,9 +84909,11 @@ var HttpSubscriptionRegistry = class {
|
|
|
84736
84909
|
}
|
|
84737
84910
|
upsert(sub) {
|
|
84738
84911
|
this.subscriptions.set(sub.id, sub);
|
|
84912
|
+
this.rebuildPrimaryAlias();
|
|
84739
84913
|
}
|
|
84740
84914
|
remove(id) {
|
|
84741
84915
|
this.subscriptions.delete(id);
|
|
84916
|
+
this.rebuildPrimaryAlias();
|
|
84742
84917
|
}
|
|
84743
84918
|
};
|
|
84744
84919
|
|
|
@@ -85683,7 +85858,6 @@ var import_node_path14 = __toESM(require("path"), 1);
|
|
|
85683
85858
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
85684
85859
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
85685
85860
|
var logger20 = createModuleLogger("bridge.logScanner");
|
|
85686
|
-
var DEFAULT_LIMIT = 500;
|
|
85687
85861
|
var MAX_LIMIT = 2e3;
|
|
85688
85862
|
function listLogFiles(logsDir, baseName) {
|
|
85689
85863
|
let names;
|
|
@@ -85696,7 +85870,7 @@ function listLogFiles(logsDir, baseName) {
|
|
|
85696
85870
|
const pattern = new RegExp(`^${baseName.replace(".", "\\.")}(\\.\\d+)?$`);
|
|
85697
85871
|
return names.filter((n) => pattern.test(n)).map((n) => import_node_path14.default.join(logsDir, n));
|
|
85698
85872
|
}
|
|
85699
|
-
async function scanFile(filePath, source, filter,
|
|
85873
|
+
async function scanFile(filePath, source, filter, state) {
|
|
85700
85874
|
const file2 = import_node_path14.default.basename(filePath);
|
|
85701
85875
|
const stream = import_node_fs6.default.createReadStream(filePath, { encoding: "utf-8" });
|
|
85702
85876
|
const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
@@ -85708,31 +85882,36 @@ async function scanFile(filePath, source, filter, limit, state) {
|
|
|
85708
85882
|
if (!parsed) continue;
|
|
85709
85883
|
if (parsed.source !== source) continue;
|
|
85710
85884
|
if (!matchesFilter(parsed, filter)) continue;
|
|
85711
|
-
state.hits.push({ ...parsed, file: file2, lineNum });
|
|
85712
|
-
if (state.hits.length > limit) {
|
|
85713
|
-
state.truncated = true;
|
|
85714
|
-
state.hits.length = limit;
|
|
85715
|
-
}
|
|
85885
|
+
state.hits.push({ ...parsed, raw: line, file: file2, lineNum });
|
|
85716
85886
|
}
|
|
85717
85887
|
}
|
|
85718
85888
|
async function scanLocalLogs(logsDir, baseName, filter) {
|
|
85719
85889
|
const source = filter.source;
|
|
85720
|
-
const limit = Math.min(Math.max(filter.limit
|
|
85890
|
+
const limit = filter.limit == null ? null : Math.min(Math.max(filter.limit, 1), MAX_LIMIT);
|
|
85891
|
+
const offset = Math.max(filter.offset ?? 0, 0);
|
|
85721
85892
|
const files = listLogFiles(logsDir, baseName);
|
|
85722
85893
|
const state = { hits: [], totalScanned: 0, truncated: false };
|
|
85723
85894
|
for (const filePath of files) {
|
|
85724
|
-
if (state.truncated) break;
|
|
85725
85895
|
try {
|
|
85726
|
-
await scanFile(filePath, source, filter,
|
|
85896
|
+
await scanFile(filePath, source, filter, state);
|
|
85727
85897
|
} catch (e) {
|
|
85728
85898
|
logger20.warn("scanLocalLogs: file read failed", { filePath, error: e });
|
|
85729
85899
|
}
|
|
85730
85900
|
}
|
|
85731
|
-
state.hits.sort((a, b) =>
|
|
85901
|
+
state.hits.sort((a, b) => b.ts.localeCompare(a.ts));
|
|
85902
|
+
const totalMatched = state.hits.length;
|
|
85903
|
+
const endOffset = limit === null ? totalMatched : offset + limit;
|
|
85904
|
+
const entries = state.hits.slice(offset, endOffset);
|
|
85905
|
+
const nextOffset = endOffset < totalMatched ? endOffset : void 0;
|
|
85906
|
+
if (nextOffset !== void 0) {
|
|
85907
|
+
state.truncated = true;
|
|
85908
|
+
}
|
|
85732
85909
|
return {
|
|
85733
|
-
entries
|
|
85910
|
+
entries,
|
|
85734
85911
|
truncated: state.truncated,
|
|
85735
|
-
totalScanned: state.totalScanned
|
|
85912
|
+
totalScanned: state.totalScanned,
|
|
85913
|
+
totalMatched,
|
|
85914
|
+
nextOffset
|
|
85736
85915
|
};
|
|
85737
85916
|
}
|
|
85738
85917
|
async function scanBridgeLogs(filter) {
|
|
@@ -85746,6 +85925,8 @@ async function scanBridgeLogs(filter) {
|
|
|
85746
85925
|
const result = await scanLocalLogs(logDir, "bridge.log", { ...filter, source: "bridge" });
|
|
85747
85926
|
logger20.info("scanBridgeLogs complete", {
|
|
85748
85927
|
hitCount: result.entries.length,
|
|
85928
|
+
totalMatched: result.totalMatched,
|
|
85929
|
+
nextOffset: result.nextOffset,
|
|
85749
85930
|
totalScanned: result.totalScanned,
|
|
85750
85931
|
truncated: result.truncated
|
|
85751
85932
|
});
|
|
@@ -85820,6 +86001,10 @@ function isProcessAlive(pid) {
|
|
|
85820
86001
|
} catch (e) {
|
|
85821
86002
|
const err = e;
|
|
85822
86003
|
if (err.code === "ESRCH") return false;
|
|
86004
|
+
if (err.code === "EPERM") {
|
|
86005
|
+
logger22.warn("Treating inaccessible lock PID as stale", { pid, error: e });
|
|
86006
|
+
return false;
|
|
86007
|
+
}
|
|
85823
86008
|
throw e;
|
|
85824
86009
|
}
|
|
85825
86010
|
}
|
|
@@ -85949,6 +86134,7 @@ function createTaskDispatchHandler(agentManager, agentRegistry, emit) {
|
|
|
85949
86134
|
conversationId: payload.conversationId,
|
|
85950
86135
|
content: payload.content,
|
|
85951
86136
|
attachments: payload.attachments ?? void 0,
|
|
86137
|
+
replyToMessage: payload.replyToMessage ?? void 0,
|
|
85952
86138
|
replyMessageId: payload.ackId,
|
|
85953
86139
|
traceId: payload.traceId,
|
|
85954
86140
|
planMode: payload.planMode ?? void 0
|
|
@@ -86759,6 +86945,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86759
86945
|
onConnected: async () => {
|
|
86760
86946
|
await agentRegistry.refresh();
|
|
86761
86947
|
await groupRegistry.refresh();
|
|
86948
|
+
await subscriptionRegistry.refresh();
|
|
86762
86949
|
await agentManager.recoverFromRestart(agentRegistry.getAll());
|
|
86763
86950
|
},
|
|
86764
86951
|
onServerPush: async (msg) => {
|
|
@@ -86886,7 +87073,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86886
87073
|
const entries = await listDirectoryEntries(resolved.path);
|
|
86887
87074
|
connector?.send({
|
|
86888
87075
|
type: "bridge:list_dir_response",
|
|
86889
|
-
payload: { requestId, entries }
|
|
87076
|
+
payload: { requestId, entries, localPath: resolved.path }
|
|
86890
87077
|
});
|
|
86891
87078
|
logger29.info("list_dir response sent", { requestId, count: entries.length });
|
|
86892
87079
|
} catch (e) {
|
|
@@ -86923,6 +87110,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86923
87110
|
payload: {
|
|
86924
87111
|
requestId,
|
|
86925
87112
|
path: written.path,
|
|
87113
|
+
bridgePath: written.path,
|
|
86926
87114
|
relativePath: written.relativePath,
|
|
86927
87115
|
size: written.size
|
|
86928
87116
|
}
|
|
@@ -87017,7 +87205,9 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
87017
87205
|
endIso: filter.endIso,
|
|
87018
87206
|
traceId: filter.traceId,
|
|
87019
87207
|
module: filter.module,
|
|
87020
|
-
levelMin: filter.levelMin
|
|
87208
|
+
levelMin: filter.levelMin,
|
|
87209
|
+
limit: filter.limit,
|
|
87210
|
+
offset: filter.offset
|
|
87021
87211
|
});
|
|
87022
87212
|
try {
|
|
87023
87213
|
const result = await scanBridgeLogs({ ...filter, source: "bridge" });
|
|
@@ -87027,13 +87217,17 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
87027
87217
|
requestId,
|
|
87028
87218
|
entries: result.entries,
|
|
87029
87219
|
truncated: result.truncated,
|
|
87030
|
-
totalScanned: result.totalScanned
|
|
87220
|
+
totalScanned: result.totalScanned,
|
|
87221
|
+
totalMatched: result.totalMatched,
|
|
87222
|
+
nextOffset: result.nextOffset
|
|
87031
87223
|
}
|
|
87032
87224
|
});
|
|
87033
87225
|
logger29.info("fetch_logs response sent", {
|
|
87034
87226
|
requestId,
|
|
87035
87227
|
count: result.entries.length,
|
|
87036
|
-
truncated: result.truncated
|
|
87228
|
+
truncated: result.truncated,
|
|
87229
|
+
totalMatched: result.totalMatched,
|
|
87230
|
+
nextOffset: result.nextOffset
|
|
87037
87231
|
});
|
|
87038
87232
|
} catch (e) {
|
|
87039
87233
|
const err = e instanceof Error ? e.message : String(e);
|
package/dist/index.js
CHANGED
|
@@ -5467,6 +5467,14 @@ runtime\u3002\u5B83\u4EEC\u4E0D\u662F"\u4E0D\u540C\u7684\u4EBA"\u2014\u2014\u516
|
|
|
5467
5467
|
\`# \u3010\u6807\u9898\u3011\` (a single \`#\` followed by Chinese bracket-enclosed title).
|
|
5468
5468
|
For single-topic or short conversational replies, omit headings entirely.
|
|
5469
5469
|
|
|
5470
|
+
# AskUserQuestion tool
|
|
5471
|
+
- When you need the user to choose from options or answer a clarification question, call the real
|
|
5472
|
+
\`AskUserQuestion\` tool with a \`questions\` array.
|
|
5473
|
+
- Never output \`<AskUserQuestion>\`, \`</AskUserQuestion>\`, or raw JSON question payloads as chat text.
|
|
5474
|
+
Text like that is not an interactive panel and the user cannot answer it through the tool flow.
|
|
5475
|
+
- If you are not able to call \`AskUserQuestion\`, ask the question as plain natural language instead of
|
|
5476
|
+
emitting tool-shaped XML or JSON.
|
|
5477
|
+
|
|
5470
5478
|
# Runtime payload \u2014 how to read unread messages
|
|
5471
5479
|
|
|
5472
5480
|
\u6BCF\u4E2A turn \u91CC runtime \u4F1A\u7ED9\u4F60\u300C\u672A\u8BFB\u7FA4\u6D88\u606F\uFF08N \u6761\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09\u300D\u6BB5\u3002\u8BFB\u6CD5\uFF1A
|
|
@@ -5896,11 +5904,20 @@ function parseWSMessage(raw) {
|
|
|
5896
5904
|
}
|
|
5897
5905
|
return parsed;
|
|
5898
5906
|
}
|
|
5907
|
+
function isAskUserQuestionToolName(toolName) {
|
|
5908
|
+
if (!toolName) return false;
|
|
5909
|
+
const normalized = toolName.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
5910
|
+
return normalized === "askuserquestion" || normalized.endsWith("askuserquestion");
|
|
5911
|
+
}
|
|
5899
5912
|
|
|
5900
5913
|
// ../shared/src/utils/subscription.ts
|
|
5914
|
+
var PRIMARY_COMPANY_SUBSCRIPTION_ID = "sub_company_primary";
|
|
5901
5915
|
function isSubscriptionType(v) {
|
|
5902
5916
|
return v === "system" || v === "project";
|
|
5903
5917
|
}
|
|
5918
|
+
function isPrimaryCompanySubscriptionId(v) {
|
|
5919
|
+
return v === PRIMARY_COMPANY_SUBSCRIPTION_ID;
|
|
5920
|
+
}
|
|
5904
5921
|
|
|
5905
5922
|
// ../shared/src/utils/agentConfig.ts
|
|
5906
5923
|
function parseAgentConfig(raw) {
|
|
@@ -21514,6 +21531,13 @@ function normalizeDocumentText(value) {
|
|
|
21514
21531
|
return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
21515
21532
|
}
|
|
21516
21533
|
|
|
21534
|
+
// src/bridgeHttp.ts
|
|
21535
|
+
var BRIDGE_TOKEN_HEADER = "X-AHChat-Bridge-Token";
|
|
21536
|
+
function bridgeAuthHeaders(bridgeToken) {
|
|
21537
|
+
const token = bridgeToken?.trim();
|
|
21538
|
+
return token ? { [BRIDGE_TOKEN_HEADER]: token } : {};
|
|
21539
|
+
}
|
|
21540
|
+
|
|
21517
21541
|
// src/neuralMcpServer.ts
|
|
21518
21542
|
var logger6 = createModuleLogger("neural.mcpServer");
|
|
21519
21543
|
function formatScopeLabel(key, groupName) {
|
|
@@ -21532,6 +21556,26 @@ function filterContactsByOwner(all, ownerId) {
|
|
|
21532
21556
|
(a) => a.kind === "system" || a.ownerId === ownerId || a.ownerId == null || a.kind === "human" && a.id === ownerId
|
|
21533
21557
|
);
|
|
21534
21558
|
}
|
|
21559
|
+
async function resolveTierSubscriptionPreference(preferredSubscriptionId, deps) {
|
|
21560
|
+
if (!preferredSubscriptionId || !isPrimaryCompanySubscriptionId(preferredSubscriptionId)) {
|
|
21561
|
+
return preferredSubscriptionId;
|
|
21562
|
+
}
|
|
21563
|
+
if (!deps.serverApiUrl) return preferredSubscriptionId;
|
|
21564
|
+
try {
|
|
21565
|
+
const base = deps.serverApiUrl.replace(/\/$/, "");
|
|
21566
|
+
const res = await fetch(`${base}/api/subscriptions`, {
|
|
21567
|
+
headers: bridgeAuthHeaders(deps.bridgeToken ?? null)
|
|
21568
|
+
});
|
|
21569
|
+
if (!res.ok) return preferredSubscriptionId;
|
|
21570
|
+
const subscriptions = await res.json();
|
|
21571
|
+
return subscriptions.find(
|
|
21572
|
+
(subscription) => subscription.billingMode === "company_billable" && subscription.isPrimaryCompany === true
|
|
21573
|
+
)?.id ?? preferredSubscriptionId;
|
|
21574
|
+
} catch (e) {
|
|
21575
|
+
logger6.warn("Primary company tier preference resolution failed", { error: e });
|
|
21576
|
+
return preferredSubscriptionId;
|
|
21577
|
+
}
|
|
21578
|
+
}
|
|
21535
21579
|
function resolveMyHuman(registry2, agentId) {
|
|
21536
21580
|
const all = registry2.getAll();
|
|
21537
21581
|
const myOwnerId = contactOwnerId(registry2, agentId);
|
|
@@ -22687,8 +22731,8 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
|
|
|
22687
22731
|
"fetch_logs",
|
|
22688
22732
|
`\u62C9\u53D6\u7CFB\u7EDF\u65E5\u5FD7\uFF08\u6309\u65F6\u95F4\u7A97 + \u53EF\u9009 traceId / module / level \u8FC7\u6EE4\uFF09\u3002
|
|
22689
22733
|
\u8BFB SKILL "log-analysis" \u540E\u624D\u7528\u8FD9\u4E2A\u5DE5\u5177\u3002\u4E00\u6B21\u8C03\u7528\u53EA\u80FD\u62C9\u4E00\u4E2A source\uFF08server \u6216 bridge\uFF09\uFF0C\u5168\u666F\u9700\u8981\u4E24\u6B21\u3002
|
|
22690
|
-
limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679C\u9876\u90E8\u5E26\u5206\u7EA7\u7EDF\u8BA1\uFF08ERROR/WARN/INFO \u5404\u591A\u5C11\u6761\uFF09\uFF0C\u6309\u65F6\u95F4\
|
|
22691
|
-
\u6CE8\u610F\uFF1A\u5982\u679C\
|
|
22734
|
+
limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5206\u9875\u3002\u8FD4\u56DE\u7ED3\u679C\u9876\u90E8\u5E26\u5206\u7EA7\u7EDF\u8BA1\uFF08ERROR/WARN/INFO \u5404\u591A\u5C11\u6761\uFF09\uFF0C\u6309\u65F6\u95F4\u5012\u5E8F\u6392\u5217\uFF0C\u6700\u65B0\u65E5\u5FD7\u5728\u524D\u3002\u6BCF\u884C\u5E26 file / lineNum\uFF0C\u5F15\u7528\u65E5\u5FD7\u65F6\u5FC5\u987B\u7CBE\u786E\u5199 [<file>:L<lineNum>]\u3002
|
|
22735
|
+
\u6CE8\u610F\uFF1A\u5982\u679C\u8FD8\u6709\u66F4\u591A\u7ED3\u679C\uFF0Cheader \u4F1A\u6807\u6CE8 nextOffset\uFF1B\u7EE7\u7EED\u67E5\u8BE2\u65F6\u5E26\u4E0A offset=nextOffset\u3002`,
|
|
22692
22736
|
{
|
|
22693
22737
|
source: external_exports.enum(["server", "bridge"]).describe('\u65E5\u5FD7\u6765\u6E90\uFF0C\u5FC5\u987B\u662F "server" \u6216 "bridge" \u4E4B\u4E00\u3002'),
|
|
22694
22738
|
start_iso: external_exports.string().describe('\u8D77\u59CB\u65F6\u95F4\uFF0CISO 8601 \u6216\u76F8\u5BF9\u683C\u5F0F\uFF1A"now-5m" / "now-1h" / "now-24h"\u3002'),
|
|
@@ -22697,7 +22741,8 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
22697
22741
|
trace_id: external_exports.string().optional().describe("\u8FC7\u6EE4\u7279\u5B9A traceId\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3002"),
|
|
22698
22742
|
module: external_exports.string().optional().describe('\u8FC7\u6EE4 module \u524D\u7F00\uFF08\u5982 "ws.handler" / "agent.manager"\uFF09\u3002'),
|
|
22699
22743
|
msg_contains: external_exports.string().optional().describe("msg \u5B50\u4E32\u8FC7\u6EE4\uFF08\u533A\u5206\u5927\u5C0F\u5199\uFF09\u3002"),
|
|
22700
|
-
limit: external_exports.number().int().min(1).max(2e3).optional().describe("\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 500\uFF0C\u6700\u5927 2000\u3002")
|
|
22744
|
+
limit: external_exports.number().int().min(1).max(2e3).optional().describe("\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 500\uFF0C\u6700\u5927 2000\u3002"),
|
|
22745
|
+
offset: external_exports.number().int().min(0).optional().describe("\u5206\u9875\u504F\u79FB\u91CF\uFF1B\u9996\u6B21\u67E5\u8BE2\u4E0D\u4F20\uFF0C\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20\u4E0A\u6B21\u8FD4\u56DE\u7684 nextOffset\u3002")
|
|
22701
22746
|
},
|
|
22702
22747
|
async (args) => {
|
|
22703
22748
|
if (!deps.isSmith) {
|
|
@@ -22722,9 +22767,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
22722
22767
|
traceId: args.trace_id,
|
|
22723
22768
|
module: args.module,
|
|
22724
22769
|
levelMin: args.level_min,
|
|
22725
|
-
limit: args.limit
|
|
22770
|
+
limit: args.limit,
|
|
22771
|
+
offset: args.offset
|
|
22726
22772
|
});
|
|
22727
22773
|
const parsedLimit = typeof args.limit === "number" && Number.isFinite(args.limit) ? args.limit : 500;
|
|
22774
|
+
const parsedOffset = typeof args.offset === "number" && Number.isFinite(args.offset) ? args.offset : 0;
|
|
22728
22775
|
try {
|
|
22729
22776
|
const url2 = `${deps.serverApiUrl.replace(/\/$/, "")}/api/admin/logs`;
|
|
22730
22777
|
const body = {
|
|
@@ -22735,7 +22782,8 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
22735
22782
|
traceId: args.trace_id,
|
|
22736
22783
|
module: args.module,
|
|
22737
22784
|
msgContains: args.msg_contains,
|
|
22738
|
-
limit: Number.isFinite(parsedLimit) ? parsedLimit : 500
|
|
22785
|
+
limit: Number.isFinite(parsedLimit) ? parsedLimit : 500,
|
|
22786
|
+
offset: Number.isFinite(parsedOffset) ? parsedOffset : 0
|
|
22739
22787
|
};
|
|
22740
22788
|
const res = await fetch(url2, {
|
|
22741
22789
|
method: "POST",
|
|
@@ -22758,7 +22806,9 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
22758
22806
|
source,
|
|
22759
22807
|
count: json2.entries.length,
|
|
22760
22808
|
truncated: json2.truncated,
|
|
22761
|
-
totalScanned: json2.totalScanned
|
|
22809
|
+
totalScanned: json2.totalScanned,
|
|
22810
|
+
totalMatched: json2.totalMatched,
|
|
22811
|
+
nextOffset: json2.nextOffset
|
|
22762
22812
|
});
|
|
22763
22813
|
const lines = json2.entries.map((e) => {
|
|
22764
22814
|
const dataStr = e.data ? ` data=${JSON.stringify(e.data).slice(0, 200)}` : "";
|
|
@@ -22771,9 +22821,10 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
22771
22821
|
const infoCount = json2.entries.filter((e) => e.level === "INFO").length;
|
|
22772
22822
|
const traceCount = json2.entries.filter((e) => e.level === "TRACE" || e.level === "DEBUG").length;
|
|
22773
22823
|
const header = [
|
|
22774
|
-
`[${source}] \u5171\u626B ${json2.totalScanned} \u884C\uFF0C\u547D\u4E2D ${json2.entries.length} \u6761`,
|
|
22824
|
+
`[${source}] \u5171\u626B ${json2.totalScanned} \u884C\uFF0C\u5DF2\u8FD4\u56DE ${json2.entries.length} \u6761\uFF0C\u547D\u4E2D ${json2.totalMatched ?? json2.entries.length} \u6761`,
|
|
22775
22825
|
` ERROR/FATAL: ${errorCount} | WARN: ${warnCount} | INFO: ${infoCount} | TRACE/DEBUG: ${traceCount}`
|
|
22776
|
-
].join("\n") + (json2.
|
|
22826
|
+
].join("\n") + (json2.nextOffset != null ? `
|
|
22827
|
+
nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=${json2.nextOffset}\uFF09` : "");
|
|
22777
22828
|
const text = [header, "", ...lines].join("\n");
|
|
22778
22829
|
return { content: [{ type: "text", text }] };
|
|
22779
22830
|
} catch (e) {
|
|
@@ -22860,7 +22911,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
22860
22911
|
const tiers = await tierRes.json();
|
|
22861
22912
|
const self = deps.agentRegistry?.getById(deps.agentId);
|
|
22862
22913
|
const preferredSubscriptionId = parseAgentConfig(self?.config).subscriptionId;
|
|
22863
|
-
const
|
|
22914
|
+
const resolvedPreferredSubscriptionId = await resolveTierSubscriptionPreference(
|
|
22915
|
+
preferredSubscriptionId,
|
|
22916
|
+
deps
|
|
22917
|
+
);
|
|
22918
|
+
const tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === resolvedPreferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
|
|
22864
22919
|
if (tierConfig) {
|
|
22865
22920
|
agentConfig = JSON.stringify({
|
|
22866
22921
|
capabilityTier: tier,
|
|
@@ -23015,7 +23070,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
23015
23070
|
if (tierRes.ok) {
|
|
23016
23071
|
const tiers = await tierRes.json();
|
|
23017
23072
|
const preferredSubscriptionId = parseAgentConfig(existing.config).subscriptionId;
|
|
23018
|
-
const
|
|
23073
|
+
const resolvedPreferredSubscriptionId = await resolveTierSubscriptionPreference(
|
|
23074
|
+
preferredSubscriptionId,
|
|
23075
|
+
deps
|
|
23076
|
+
);
|
|
23077
|
+
const tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === resolvedPreferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
|
|
23019
23078
|
if (tierConfig) {
|
|
23020
23079
|
agentConfig = JSON.stringify({
|
|
23021
23080
|
capabilityTier: tier,
|
|
@@ -23646,6 +23705,8 @@ var GroupDispatchMemoryStore = class {
|
|
|
23646
23705
|
};
|
|
23647
23706
|
|
|
23648
23707
|
// src/groupInboxPromptBuilder.ts
|
|
23708
|
+
var MAX_SYSTEM_NOTE_COUNT = 8;
|
|
23709
|
+
var MAX_SYSTEM_NOTE_LEN = 1e3;
|
|
23649
23710
|
function formatHHMM(epochMs) {
|
|
23650
23711
|
const d = new Date(epochMs);
|
|
23651
23712
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -23656,6 +23717,37 @@ function truncate(text, maxLen) {
|
|
|
23656
23717
|
if (text.length <= maxLen) return text;
|
|
23657
23718
|
return `${text.slice(0, maxLen)}\u2026`;
|
|
23658
23719
|
}
|
|
23720
|
+
function formatIsoHHMM(iso) {
|
|
23721
|
+
const epochMs = Date.parse(iso);
|
|
23722
|
+
if (!Number.isFinite(epochMs)) return "";
|
|
23723
|
+
return formatHHMM(epochMs);
|
|
23724
|
+
}
|
|
23725
|
+
function collectSystemNotes(entries) {
|
|
23726
|
+
const byId = /* @__PURE__ */ new Map();
|
|
23727
|
+
for (const entry of entries) {
|
|
23728
|
+
for (const msg of entry.context) {
|
|
23729
|
+
if (msg.role !== "system") continue;
|
|
23730
|
+
byId.set(msg.id, {
|
|
23731
|
+
id: msg.id,
|
|
23732
|
+
time: formatIsoHHMM(msg.createdAt),
|
|
23733
|
+
content: truncate(msg.content, MAX_SYSTEM_NOTE_LEN)
|
|
23734
|
+
});
|
|
23735
|
+
}
|
|
23736
|
+
}
|
|
23737
|
+
return [...byId.values()].slice(-MAX_SYSTEM_NOTE_COUNT);
|
|
23738
|
+
}
|
|
23739
|
+
function appendSystemNotes(lines, entries) {
|
|
23740
|
+
const notes = collectSystemNotes(entries);
|
|
23741
|
+
if (notes.length === 0) return;
|
|
23742
|
+
lines.push(`--- \u7FA4\u5185\u7CFB\u7EDF\u8BB0\u5F55\uFF08${notes.length} \u6761\uFF0C\u4F9B\u4E0A\u4E0B\u6587\uFF1B\u975E\u666E\u901A\u804A\u5929\u5386\u53F2\uFF09---`);
|
|
23743
|
+
lines.push("\u8FD9\u4E9B\u8BB0\u5F55\u53EA\u7528\u4E8E\u7406\u89E3\u7528\u6237\u5DF2\u4F5C\u51FA\u7684 AskUserQuestion/\u7CFB\u7EDF\u51B3\u7B56\uFF1B\u4E0D\u8981\u76F4\u63A5\u56DE\u590D\u7CFB\u7EDF\u8BB0\u5F55\u672C\u8EAB\u3002");
|
|
23744
|
+
for (const note of notes) {
|
|
23745
|
+
const prefix = note.time ? `[${note.time}] system:` : "system:";
|
|
23746
|
+
lines.push(`${prefix} ${note.content}`);
|
|
23747
|
+
}
|
|
23748
|
+
lines.push("--- \u7FA4\u5185\u7CFB\u7EDF\u8BB0\u5F55 end ---");
|
|
23749
|
+
lines.push("");
|
|
23750
|
+
}
|
|
23659
23751
|
function appendBoardContext(lines, latest) {
|
|
23660
23752
|
if (latest.boardMeta?.vision) {
|
|
23661
23753
|
lines.push("--- project vision ---");
|
|
@@ -23724,6 +23816,7 @@ function buildGroupInboxPrompt(entries, opts = {}) {
|
|
|
23724
23816
|
);
|
|
23725
23817
|
}
|
|
23726
23818
|
lines.push("");
|
|
23819
|
+
appendSystemNotes(lines, entries);
|
|
23727
23820
|
lines.push(`--- \u672A\u8BFB\u7FA4\u6D88\u606F\uFF08${entries.length} \u6761\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09---`);
|
|
23728
23821
|
for (const e of entries) {
|
|
23729
23822
|
const ts = formatHHMM(e.arrivedAt);
|
|
@@ -24067,6 +24160,31 @@ function extractUsage(message) {
|
|
|
24067
24160
|
}
|
|
24068
24161
|
return result;
|
|
24069
24162
|
}
|
|
24163
|
+
function hasUsageValue(usage) {
|
|
24164
|
+
return typeof usage.tokenCount === "number" || typeof usage.inputTokens === "number" || typeof usage.cacheReadTokens === "number" || typeof usage.cacheCreationTokens === "number" || typeof usage.costUsd === "number";
|
|
24165
|
+
}
|
|
24166
|
+
function emitUsageReported(proc, emit, base, usage, messageId) {
|
|
24167
|
+
if (!hasUsageValue(usage)) return;
|
|
24168
|
+
const groupId = proc.currentTask?.groupId;
|
|
24169
|
+
const scopeKeyValue = proc.scope.kind === "group" ? `group:${proc.scope.groupId}` : "single";
|
|
24170
|
+
emit({
|
|
24171
|
+
type: "agent:usage_reported",
|
|
24172
|
+
payload: {
|
|
24173
|
+
...wireBase(base),
|
|
24174
|
+
...messageId ? { messageId } : {},
|
|
24175
|
+
...groupId ? { groupId } : {},
|
|
24176
|
+
scopeKey: scopeKeyValue,
|
|
24177
|
+
model: usage.model,
|
|
24178
|
+
usage: {
|
|
24179
|
+
inputTokens: usage.inputTokens,
|
|
24180
|
+
outputTokens: usage.tokenCount,
|
|
24181
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
24182
|
+
cacheCreationTokens: usage.cacheCreationTokens
|
|
24183
|
+
},
|
|
24184
|
+
providerCostUsd: usage.costUsd
|
|
24185
|
+
}
|
|
24186
|
+
});
|
|
24187
|
+
}
|
|
24070
24188
|
function isGroupTask(proc) {
|
|
24071
24189
|
return proc.currentTask?.groupId != null;
|
|
24072
24190
|
}
|
|
@@ -24328,7 +24446,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24328
24446
|
proc.currentToolName = block.name ?? "unknown";
|
|
24329
24447
|
proc.accumulatedToolInput = "";
|
|
24330
24448
|
const toolName = block.name ?? "unknown";
|
|
24331
|
-
if (toolName !== "ExitPlanMode" && toolName
|
|
24449
|
+
if (toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
24332
24450
|
emit({
|
|
24333
24451
|
type: "agent:tool_use",
|
|
24334
24452
|
payload: {
|
|
@@ -24492,9 +24610,9 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24492
24610
|
});
|
|
24493
24611
|
}
|
|
24494
24612
|
}
|
|
24495
|
-
if (proc.currentToolName
|
|
24613
|
+
if (isAskUserQuestionToolName(proc.currentToolName)) {
|
|
24496
24614
|
const last = proc.contentBlocks[proc.contentBlocks.length - 1];
|
|
24497
|
-
if (last?.type === "tool_use" && last.toolName
|
|
24615
|
+
if (last?.type === "tool_use" && isAskUserQuestionToolName(last.toolName)) {
|
|
24498
24616
|
proc.contentBlocks.pop();
|
|
24499
24617
|
}
|
|
24500
24618
|
}
|
|
@@ -24546,7 +24664,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24546
24664
|
const toolName = proc.currentToolName ?? "unknown";
|
|
24547
24665
|
const isError = toolName === "ExitPlanMode" ? false : !!b.is_error;
|
|
24548
24666
|
const output = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
|
|
24549
|
-
if (toolName
|
|
24667
|
+
if (isAskUserQuestionToolName(toolName)) {
|
|
24550
24668
|
proc.currentToolName = null;
|
|
24551
24669
|
continue;
|
|
24552
24670
|
}
|
|
@@ -24630,6 +24748,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24630
24748
|
const watermarkUsage = proc.peakContextUsage ?? usage;
|
|
24631
24749
|
if (trimmed === NO_REPLY_TOKEN) {
|
|
24632
24750
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
24751
|
+
emitUsageReported(proc, emit, base, usage);
|
|
24633
24752
|
if (groupMode && proc.contentBlocks.length > 0) {
|
|
24634
24753
|
emitGroupSegment(
|
|
24635
24754
|
proc,
|
|
@@ -24669,6 +24788,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24669
24788
|
}
|
|
24670
24789
|
if (groupMode) {
|
|
24671
24790
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
24791
|
+
emitUsageReported(proc, emit, base, usage);
|
|
24672
24792
|
if (proc.contentBlocks.length > 0) {
|
|
24673
24793
|
logger8.info("Group turn trailing audit segment", {
|
|
24674
24794
|
agentId: proc.agentId,
|
|
@@ -24703,6 +24823,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24703
24823
|
}
|
|
24704
24824
|
if (proc.accumulatedText.length === 0 && proc.contentBlocks.length === 0) {
|
|
24705
24825
|
cleanupPlanMode(proc, emit, base, "error");
|
|
24826
|
+
emitUsageReported(proc, emit, base, usage);
|
|
24706
24827
|
logger8.warn("SDK success produced empty assistant output; emitting agent:error", {
|
|
24707
24828
|
agentId: proc.agentId,
|
|
24708
24829
|
ackId: base.replyMessageId,
|
|
@@ -24730,6 +24851,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24730
24851
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
24731
24852
|
cleanupPlanMode(proc, emit, base, "success");
|
|
24732
24853
|
carrierMessageId = createMessageId();
|
|
24854
|
+
emitUsageReported(proc, emit, base, usage, carrierMessageId);
|
|
24733
24855
|
logger8.info("Agent task done, emitting agent:done", {
|
|
24734
24856
|
agentId: proc.agentId,
|
|
24735
24857
|
ackId: base.replyMessageId,
|
|
@@ -24750,6 +24872,11 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
24750
24872
|
thinkingDuration: Date.now() - proc.currentTaskStartedAt,
|
|
24751
24873
|
toolCallCount: proc.contentBlocks.filter((b) => b.type === "tool_use").length,
|
|
24752
24874
|
tokenCount: usage.tokenCount,
|
|
24875
|
+
outputTokens: usage.tokenCount,
|
|
24876
|
+
inputTokens: usage.inputTokens,
|
|
24877
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
24878
|
+
cacheCreationTokens: usage.cacheCreationTokens,
|
|
24879
|
+
costUsd: usage.costUsd,
|
|
24753
24880
|
model: usage.model
|
|
24754
24881
|
}
|
|
24755
24882
|
}
|
|
@@ -25075,6 +25202,12 @@ var wsMetrics = new WsMetrics();
|
|
|
25075
25202
|
|
|
25076
25203
|
// src/agentManager.ts
|
|
25077
25204
|
var logger11 = createModuleLogger("agent.manager");
|
|
25205
|
+
function missingSubscriptionMessage(subscriptionId) {
|
|
25206
|
+
if (isPrimaryCompanySubscriptionId(subscriptionId)) {
|
|
25207
|
+
return "AHChat \u9ED8\u8BA4\u6A21\u578B\u6682\u65F6\u4E0D\u53EF\u7528\uFF1A\u8FD9\u53F0\u673A\u5668\u8FD8\u6CA1\u6709\u540C\u6B65\u5230\u7BA1\u7406\u5458\u542F\u7528\u7684\u9ED8\u8BA4\u6A21\u578B\uFF0C\u8BF7\u66F4\u65B0\u5E76\u91CD\u542F Bridge \u540E\u91CD\u8BD5\u3002";
|
|
25208
|
+
}
|
|
25209
|
+
return `\u8BA2\u9605\u6E90\u4E0D\u53EF\u7528\uFF1A${subscriptionId}\u3002\u8BF7\u91CD\u65B0\u9009\u62E9\u6A21\u578B\u6765\u6E90\uFF0C\u6216\u91CD\u542F Bridge \u540E\u91CD\u8BD5\u3002`;
|
|
25210
|
+
}
|
|
25078
25211
|
var NODE_USER_UID = 1e3;
|
|
25079
25212
|
var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
|
|
25080
25213
|
var DOCUMENT_READING_RULES = `DOCUMENT READING:
|
|
@@ -25139,6 +25272,27 @@ var BridgeBusyError = class extends Error {
|
|
|
25139
25272
|
this.name = "BridgeBusyError";
|
|
25140
25273
|
}
|
|
25141
25274
|
};
|
|
25275
|
+
function senderLabelForQuote(message) {
|
|
25276
|
+
if (message.senderAgentName) return message.senderAgentName;
|
|
25277
|
+
if (message.role === "user") return "user";
|
|
25278
|
+
if (message.role === "agent") return `agent:${message.senderAgentId ?? "unknown"}`;
|
|
25279
|
+
return "system";
|
|
25280
|
+
}
|
|
25281
|
+
function buildSingleReplyPrompt(task) {
|
|
25282
|
+
if (!task.replyToMessage) return task.content;
|
|
25283
|
+
const quoted = task.replyToMessage;
|
|
25284
|
+
const label = senderLabelForQuote(quoted);
|
|
25285
|
+
return [
|
|
25286
|
+
"--- reply-to message ---",
|
|
25287
|
+
`You are replying to this earlier message from [${label}]:`,
|
|
25288
|
+
quoted.content || (quoted.attachments?.length ? "[attachment]" : ""),
|
|
25289
|
+
"--- end reply-to message ---",
|
|
25290
|
+
"",
|
|
25291
|
+
"--- user message ---",
|
|
25292
|
+
task.content,
|
|
25293
|
+
"--- end user message ---"
|
|
25294
|
+
].join("\n");
|
|
25295
|
+
}
|
|
25142
25296
|
var AgentManager = class {
|
|
25143
25297
|
agents = /* @__PURE__ */ new Map();
|
|
25144
25298
|
lastUsedAt = /* @__PURE__ */ new Map();
|
|
@@ -25274,16 +25428,16 @@ var AgentManager = class {
|
|
|
25274
25428
|
agentId: agent.id,
|
|
25275
25429
|
subscriptionId: cfg.subscriptionId
|
|
25276
25430
|
});
|
|
25277
|
-
|
|
25431
|
+
throw new Error(missingSubscriptionMessage(cfg.subscriptionId));
|
|
25278
25432
|
}
|
|
25279
25433
|
let sub = this.subscriptionRegistry.getById(cfg.subscriptionId);
|
|
25280
25434
|
if (!sub) sub = await this.subscriptionRegistry.fetchById(cfg.subscriptionId);
|
|
25281
25435
|
if (!sub) {
|
|
25282
|
-
logger11.warn("Subscription not found;
|
|
25436
|
+
logger11.warn("Subscription not found; refusing native OAuth fallback", {
|
|
25283
25437
|
agentId: agent.id,
|
|
25284
25438
|
subscriptionId: cfg.subscriptionId
|
|
25285
25439
|
});
|
|
25286
|
-
|
|
25440
|
+
throw new Error(missingSubscriptionMessage(cfg.subscriptionId));
|
|
25287
25441
|
}
|
|
25288
25442
|
const isPinnedModel = cfg.model && cfg.model !== "default";
|
|
25289
25443
|
const resolvedModel = isPinnedModel ? cfg.model : sub.defaultModel;
|
|
@@ -26482,8 +26636,9 @@ ${lines.join("\n")}`;
|
|
|
26482
26636
|
});
|
|
26483
26637
|
}
|
|
26484
26638
|
async pushTaskContent(runtime, task, onYielded) {
|
|
26639
|
+
const textContent = buildSingleReplyPrompt(task);
|
|
26485
26640
|
if (!task.attachments || task.attachments.length === 0) {
|
|
26486
|
-
runtime.inputController.push(
|
|
26641
|
+
runtime.inputController.push(textContent, runtime.ccSessionId ?? "", onYielded);
|
|
26487
26642
|
return;
|
|
26488
26643
|
}
|
|
26489
26644
|
const supportsVision = await this.detectVisionSupport();
|
|
@@ -26495,7 +26650,7 @@ ${lines.join("\n")}`;
|
|
|
26495
26650
|
supportsVision
|
|
26496
26651
|
}
|
|
26497
26652
|
);
|
|
26498
|
-
const text =
|
|
26653
|
+
const text = textContent.trim() || "\u8BF7\u67E5\u770B\u6211\u53D1\u9001\u7684\u9644\u4EF6\u3002";
|
|
26499
26654
|
const contentParts = [
|
|
26500
26655
|
{ type: "text", text },
|
|
26501
26656
|
...attachmentBlocks
|
|
@@ -26533,9 +26688,12 @@ ${lines.join("\n")}`;
|
|
|
26533
26688
|
return materialized;
|
|
26534
26689
|
}
|
|
26535
26690
|
async resolveExistingWorkspaceAttachmentPath(runtime, attachment) {
|
|
26691
|
+
const localWorkspacePath = attachment.metadata?.localWorkspacePath;
|
|
26536
26692
|
const workspacePath = attachment.metadata?.workspacePath;
|
|
26537
|
-
|
|
26538
|
-
|
|
26693
|
+
const rawPath = typeof localWorkspacePath === "string" && localWorkspacePath.trim() ? localWorkspacePath : workspacePath;
|
|
26694
|
+
if (typeof rawPath !== "string" || !rawPath.trim()) return null;
|
|
26695
|
+
const remapped = remapServerWorkspacePath(rawPath, this.workspacesDir);
|
|
26696
|
+
const candidate = path11.resolve(remapped.path);
|
|
26539
26697
|
if (!this.isPathInsideBase(candidate, runtime.cwd)) return null;
|
|
26540
26698
|
try {
|
|
26541
26699
|
const stat3 = await fs5.stat(candidate);
|
|
@@ -26545,6 +26703,8 @@ ${lines.join("\n")}`;
|
|
|
26545
26703
|
agentId: runtime.agentId,
|
|
26546
26704
|
attachmentId: attachment.id,
|
|
26547
26705
|
workspacePath,
|
|
26706
|
+
localWorkspacePath,
|
|
26707
|
+
resolvedPath: candidate,
|
|
26548
26708
|
error: e
|
|
26549
26709
|
});
|
|
26550
26710
|
return null;
|
|
@@ -27743,7 +27903,7 @@ function computeBoardSignature(entry) {
|
|
|
27743
27903
|
|
|
27744
27904
|
// src/bridgeFetchAuth.ts
|
|
27745
27905
|
var logger12 = createModuleLogger("bridge.fetchAuth");
|
|
27746
|
-
var
|
|
27906
|
+
var BRIDGE_TOKEN_HEADER2 = "X-AHChat-Bridge-Token";
|
|
27747
27907
|
function installBridgeFetchAuth(serverApiUrl, token) {
|
|
27748
27908
|
if (typeof globalThis.fetch !== "function") {
|
|
27749
27909
|
logger12.warn("globalThis.fetch not available, cannot install bridge fetch auth");
|
|
@@ -27771,8 +27931,8 @@ function installBridgeFetchAuth(serverApiUrl, token) {
|
|
|
27771
27931
|
else url2 = input.url;
|
|
27772
27932
|
if (!shouldInject(url2)) return original(input, init);
|
|
27773
27933
|
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
27774
|
-
if (!headers.has(
|
|
27775
|
-
headers.set(
|
|
27934
|
+
if (!headers.has(BRIDGE_TOKEN_HEADER2)) {
|
|
27935
|
+
headers.set(BRIDGE_TOKEN_HEADER2, token);
|
|
27776
27936
|
}
|
|
27777
27937
|
return original(input, { ...init, headers });
|
|
27778
27938
|
});
|
|
@@ -27782,13 +27942,6 @@ function installBridgeFetchAuth(serverApiUrl, token) {
|
|
|
27782
27942
|
});
|
|
27783
27943
|
}
|
|
27784
27944
|
|
|
27785
|
-
// src/bridgeHttp.ts
|
|
27786
|
-
var BRIDGE_TOKEN_HEADER2 = "X-AHChat-Bridge-Token";
|
|
27787
|
-
function bridgeAuthHeaders(bridgeToken) {
|
|
27788
|
-
const token = bridgeToken?.trim();
|
|
27789
|
-
return token ? { [BRIDGE_TOKEN_HEADER2]: token } : {};
|
|
27790
|
-
}
|
|
27791
|
-
|
|
27792
27945
|
// src/agentRegistry.ts
|
|
27793
27946
|
var logger13 = createModuleLogger("agent.registry");
|
|
27794
27947
|
var HttpAgentRegistry = class {
|
|
@@ -27902,6 +28055,23 @@ var HttpSubscriptionRegistry = class {
|
|
|
27902
28055
|
const path24 = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
27903
28056
|
return `${base}${path24}`;
|
|
27904
28057
|
}
|
|
28058
|
+
primaryAliasFrom(sub) {
|
|
28059
|
+
return {
|
|
28060
|
+
...sub,
|
|
28061
|
+
id: PRIMARY_COMPANY_SUBSCRIPTION_ID,
|
|
28062
|
+
name: "\u516C\u53F8\u4E3B\u8BA2\u9605",
|
|
28063
|
+
resolvedSubscriptionId: sub.id,
|
|
28064
|
+
isVirtual: true
|
|
28065
|
+
};
|
|
28066
|
+
}
|
|
28067
|
+
rebuildPrimaryAlias() {
|
|
28068
|
+
this.subscriptions.delete(PRIMARY_COMPANY_SUBSCRIPTION_ID);
|
|
28069
|
+
const primary = Array.from(this.subscriptions.values()).find(
|
|
28070
|
+
(sub) => sub.billingMode === "company_billable" && sub.isPrimaryCompany === true
|
|
28071
|
+
);
|
|
28072
|
+
if (!primary) return;
|
|
28073
|
+
this.subscriptions.set(PRIMARY_COMPANY_SUBSCRIPTION_ID, this.primaryAliasFrom(primary));
|
|
28074
|
+
}
|
|
27905
28075
|
async refresh() {
|
|
27906
28076
|
const attempt = async () => {
|
|
27907
28077
|
try {
|
|
@@ -27929,6 +28099,7 @@ var HttpSubscriptionRegistry = class {
|
|
|
27929
28099
|
const s = item;
|
|
27930
28100
|
if (s && typeof s.id === "string") this.subscriptions.set(s.id, s);
|
|
27931
28101
|
}
|
|
28102
|
+
this.rebuildPrimaryAlias();
|
|
27932
28103
|
logger14.info("Subscription registry refreshed", { count: this.subscriptions.size });
|
|
27933
28104
|
} catch (e) {
|
|
27934
28105
|
logger14.warn("Subscription registry parse failed", { error: e });
|
|
@@ -27938,6 +28109,10 @@ var HttpSubscriptionRegistry = class {
|
|
|
27938
28109
|
return this.subscriptions.get(id) ?? null;
|
|
27939
28110
|
}
|
|
27940
28111
|
async fetchById(id) {
|
|
28112
|
+
if (isPrimaryCompanySubscriptionId(id)) {
|
|
28113
|
+
await this.refresh();
|
|
28114
|
+
return this.getById(id);
|
|
28115
|
+
}
|
|
27941
28116
|
try {
|
|
27942
28117
|
const res = await fetch(this.apiUrl(`/api/subscriptions/${encodeURIComponent(id)}`), {
|
|
27943
28118
|
headers: bridgeAuthHeaders(this.bridgeToken)
|
|
@@ -27953,9 +28128,11 @@ var HttpSubscriptionRegistry = class {
|
|
|
27953
28128
|
}
|
|
27954
28129
|
upsert(sub) {
|
|
27955
28130
|
this.subscriptions.set(sub.id, sub);
|
|
28131
|
+
this.rebuildPrimaryAlias();
|
|
27956
28132
|
}
|
|
27957
28133
|
remove(id) {
|
|
27958
28134
|
this.subscriptions.delete(id);
|
|
28135
|
+
this.rebuildPrimaryAlias();
|
|
27959
28136
|
}
|
|
27960
28137
|
};
|
|
27961
28138
|
|
|
@@ -28894,7 +29071,6 @@ import path14 from "path";
|
|
|
28894
29071
|
import os8 from "os";
|
|
28895
29072
|
import readline from "readline";
|
|
28896
29073
|
var logger19 = createModuleLogger("bridge.logScanner");
|
|
28897
|
-
var DEFAULT_LIMIT = 500;
|
|
28898
29074
|
var MAX_LIMIT = 2e3;
|
|
28899
29075
|
function listLogFiles(logsDir, baseName) {
|
|
28900
29076
|
let names;
|
|
@@ -28907,7 +29083,7 @@ function listLogFiles(logsDir, baseName) {
|
|
|
28907
29083
|
const pattern = new RegExp(`^${baseName.replace(".", "\\.")}(\\.\\d+)?$`);
|
|
28908
29084
|
return names.filter((n) => pattern.test(n)).map((n) => path14.join(logsDir, n));
|
|
28909
29085
|
}
|
|
28910
|
-
async function scanFile(filePath, source, filter,
|
|
29086
|
+
async function scanFile(filePath, source, filter, state) {
|
|
28911
29087
|
const file2 = path14.basename(filePath);
|
|
28912
29088
|
const stream = fs8.createReadStream(filePath, { encoding: "utf-8" });
|
|
28913
29089
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
@@ -28919,31 +29095,36 @@ async function scanFile(filePath, source, filter, limit, state) {
|
|
|
28919
29095
|
if (!parsed) continue;
|
|
28920
29096
|
if (parsed.source !== source) continue;
|
|
28921
29097
|
if (!matchesFilter(parsed, filter)) continue;
|
|
28922
|
-
state.hits.push({ ...parsed, file: file2, lineNum });
|
|
28923
|
-
if (state.hits.length > limit) {
|
|
28924
|
-
state.truncated = true;
|
|
28925
|
-
state.hits.length = limit;
|
|
28926
|
-
}
|
|
29098
|
+
state.hits.push({ ...parsed, raw: line, file: file2, lineNum });
|
|
28927
29099
|
}
|
|
28928
29100
|
}
|
|
28929
29101
|
async function scanLocalLogs(logsDir, baseName, filter) {
|
|
28930
29102
|
const source = filter.source;
|
|
28931
|
-
const limit = Math.min(Math.max(filter.limit
|
|
29103
|
+
const limit = filter.limit == null ? null : Math.min(Math.max(filter.limit, 1), MAX_LIMIT);
|
|
29104
|
+
const offset = Math.max(filter.offset ?? 0, 0);
|
|
28932
29105
|
const files = listLogFiles(logsDir, baseName);
|
|
28933
29106
|
const state = { hits: [], totalScanned: 0, truncated: false };
|
|
28934
29107
|
for (const filePath of files) {
|
|
28935
|
-
if (state.truncated) break;
|
|
28936
29108
|
try {
|
|
28937
|
-
await scanFile(filePath, source, filter,
|
|
29109
|
+
await scanFile(filePath, source, filter, state);
|
|
28938
29110
|
} catch (e) {
|
|
28939
29111
|
logger19.warn("scanLocalLogs: file read failed", { filePath, error: e });
|
|
28940
29112
|
}
|
|
28941
29113
|
}
|
|
28942
|
-
state.hits.sort((a, b) =>
|
|
29114
|
+
state.hits.sort((a, b) => b.ts.localeCompare(a.ts));
|
|
29115
|
+
const totalMatched = state.hits.length;
|
|
29116
|
+
const endOffset = limit === null ? totalMatched : offset + limit;
|
|
29117
|
+
const entries = state.hits.slice(offset, endOffset);
|
|
29118
|
+
const nextOffset = endOffset < totalMatched ? endOffset : void 0;
|
|
29119
|
+
if (nextOffset !== void 0) {
|
|
29120
|
+
state.truncated = true;
|
|
29121
|
+
}
|
|
28943
29122
|
return {
|
|
28944
|
-
entries
|
|
29123
|
+
entries,
|
|
28945
29124
|
truncated: state.truncated,
|
|
28946
|
-
totalScanned: state.totalScanned
|
|
29125
|
+
totalScanned: state.totalScanned,
|
|
29126
|
+
totalMatched,
|
|
29127
|
+
nextOffset
|
|
28947
29128
|
};
|
|
28948
29129
|
}
|
|
28949
29130
|
async function scanBridgeLogs(filter) {
|
|
@@ -28957,6 +29138,8 @@ async function scanBridgeLogs(filter) {
|
|
|
28957
29138
|
const result = await scanLocalLogs(logDir, "bridge.log", { ...filter, source: "bridge" });
|
|
28958
29139
|
logger19.info("scanBridgeLogs complete", {
|
|
28959
29140
|
hitCount: result.entries.length,
|
|
29141
|
+
totalMatched: result.totalMatched,
|
|
29142
|
+
nextOffset: result.nextOffset,
|
|
28960
29143
|
totalScanned: result.totalScanned,
|
|
28961
29144
|
truncated: result.truncated
|
|
28962
29145
|
});
|
|
@@ -29029,6 +29212,10 @@ function isProcessAlive(pid) {
|
|
|
29029
29212
|
} catch (e) {
|
|
29030
29213
|
const err = e;
|
|
29031
29214
|
if (err.code === "ESRCH") return false;
|
|
29215
|
+
if (err.code === "EPERM") {
|
|
29216
|
+
logger21.warn("Treating inaccessible lock PID as stale", { pid, error: e });
|
|
29217
|
+
return false;
|
|
29218
|
+
}
|
|
29032
29219
|
throw e;
|
|
29033
29220
|
}
|
|
29034
29221
|
}
|
|
@@ -29154,6 +29341,7 @@ function createTaskDispatchHandler(agentManager, agentRegistry, emit) {
|
|
|
29154
29341
|
conversationId: payload.conversationId,
|
|
29155
29342
|
content: payload.content,
|
|
29156
29343
|
attachments: payload.attachments ?? void 0,
|
|
29344
|
+
replyToMessage: payload.replyToMessage ?? void 0,
|
|
29157
29345
|
replyMessageId: payload.ackId,
|
|
29158
29346
|
traceId: payload.traceId,
|
|
29159
29347
|
planMode: payload.planMode ?? void 0
|
|
@@ -30225,6 +30413,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
30225
30413
|
onConnected: async () => {
|
|
30226
30414
|
await agentRegistry.refresh();
|
|
30227
30415
|
await groupRegistry.refresh();
|
|
30416
|
+
await subscriptionRegistry.refresh();
|
|
30228
30417
|
await agentManager.recoverFromRestart(agentRegistry.getAll());
|
|
30229
30418
|
},
|
|
30230
30419
|
onServerPush: async (msg) => {
|
|
@@ -30352,7 +30541,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
30352
30541
|
const entries = await listDirectoryEntries(resolved.path);
|
|
30353
30542
|
connector?.send({
|
|
30354
30543
|
type: "bridge:list_dir_response",
|
|
30355
|
-
payload: { requestId, entries }
|
|
30544
|
+
payload: { requestId, entries, localPath: resolved.path }
|
|
30356
30545
|
});
|
|
30357
30546
|
logger29.info("list_dir response sent", { requestId, count: entries.length });
|
|
30358
30547
|
} catch (e) {
|
|
@@ -30389,6 +30578,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
30389
30578
|
payload: {
|
|
30390
30579
|
requestId,
|
|
30391
30580
|
path: written.path,
|
|
30581
|
+
bridgePath: written.path,
|
|
30392
30582
|
relativePath: written.relativePath,
|
|
30393
30583
|
size: written.size
|
|
30394
30584
|
}
|
|
@@ -30483,7 +30673,9 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
30483
30673
|
endIso: filter.endIso,
|
|
30484
30674
|
traceId: filter.traceId,
|
|
30485
30675
|
module: filter.module,
|
|
30486
|
-
levelMin: filter.levelMin
|
|
30676
|
+
levelMin: filter.levelMin,
|
|
30677
|
+
limit: filter.limit,
|
|
30678
|
+
offset: filter.offset
|
|
30487
30679
|
});
|
|
30488
30680
|
try {
|
|
30489
30681
|
const result = await scanBridgeLogs({ ...filter, source: "bridge" });
|
|
@@ -30493,13 +30685,17 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
30493
30685
|
requestId,
|
|
30494
30686
|
entries: result.entries,
|
|
30495
30687
|
truncated: result.truncated,
|
|
30496
|
-
totalScanned: result.totalScanned
|
|
30688
|
+
totalScanned: result.totalScanned,
|
|
30689
|
+
totalMatched: result.totalMatched,
|
|
30690
|
+
nextOffset: result.nextOffset
|
|
30497
30691
|
}
|
|
30498
30692
|
});
|
|
30499
30693
|
logger29.info("fetch_logs response sent", {
|
|
30500
30694
|
requestId,
|
|
30501
30695
|
count: result.entries.length,
|
|
30502
|
-
truncated: result.truncated
|
|
30696
|
+
truncated: result.truncated,
|
|
30697
|
+
totalMatched: result.totalMatched,
|
|
30698
|
+
nextOffset: result.nextOffset
|
|
30503
30699
|
});
|
|
30504
30700
|
} catch (e) {
|
|
30505
30701
|
const err = e instanceof Error ? e.message : String(e);
|