@fangyb/ahchat-bridge 0.1.39 → 0.1.41
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 +362 -107
- package/dist/feedbackWorkerCli.cjs +30 -0
- package/dist/index.js +362 -107
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -94678,6 +94678,25 @@ Transform tasks into verifiable goals:
|
|
|
94678
94678
|
- "Refactor X" \u2192 ensure tests pass before and after.
|
|
94679
94679
|
For multi-step tasks, state a brief plan with verification checks.
|
|
94680
94680
|
`.trim();
|
|
94681
|
+
var GROUP_ONLY_SECTION_HEADERS = [
|
|
94682
|
+
"# \u7FA4\u804A\u516C\u7406\uFF08Group Chat Axiom \u2014 \u6700\u9AD8\u4F18\u5148\u7EA7\uFF09",
|
|
94683
|
+
"# Runtime payload \u2014 how to read unread messages",
|
|
94684
|
+
"# Group chat \u2014 when to speak",
|
|
94685
|
+
"# Group chat \u2014 recency & commitment",
|
|
94686
|
+
"# Length & conciseness in group chat",
|
|
94687
|
+
"# Group chat \u2014 shared task board",
|
|
94688
|
+
"# Group chat \u2014 batched inbox handling",
|
|
94689
|
+
"# \u7FA4\u804A\u4EA7\u7269\u7EAA\u5F8B\uFF08What to capture in group chats\uFF09",
|
|
94690
|
+
"# When a user joins or leaves your group"
|
|
94691
|
+
];
|
|
94692
|
+
function stripGroupOnlySections(full, headers) {
|
|
94693
|
+
const headerSet = new Set(headers);
|
|
94694
|
+
return full.split(/\n(?=# )/).filter((section) => !headerSet.has(section.split("\n", 1)[0].trim())).join("\n").trim();
|
|
94695
|
+
}
|
|
94696
|
+
var PLATFORM_AGENT_RULES_SINGLE = stripGroupOnlySections(
|
|
94697
|
+
PLATFORM_AGENT_RULES,
|
|
94698
|
+
GROUP_ONLY_SECTION_HEADERS
|
|
94699
|
+
);
|
|
94681
94700
|
var FAN_OUT_TRACE_TTL_MS = 10 * 6e4;
|
|
94682
94701
|
var MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
94683
94702
|
var MAX_IMAGE_SIZE = 10 * 1024 * 1024;
|
|
@@ -94849,6 +94868,14 @@ function assertArrayPayloadField(type, payload, field) {
|
|
|
94849
94868
|
throw invalidWsMessage(type, field);
|
|
94850
94869
|
}
|
|
94851
94870
|
}
|
|
94871
|
+
function assertWorkdirSignalsPayloadField(type, payload, field) {
|
|
94872
|
+
assertArrayPayloadField(type, payload, field);
|
|
94873
|
+
for (const [index, item] of payload[field].entries()) {
|
|
94874
|
+
if (!isPlainRecord(item) || typeof item.toolName !== "string") {
|
|
94875
|
+
throw invalidWsMessage(type, `${field}[${index}].toolName`);
|
|
94876
|
+
}
|
|
94877
|
+
}
|
|
94878
|
+
}
|
|
94852
94879
|
function assertRecordPayloadField(type, payload, field) {
|
|
94853
94880
|
if (!isPlainRecord(payload[field])) {
|
|
94854
94881
|
throw invalidWsMessage(type, field);
|
|
@@ -94929,6 +94956,9 @@ function validateWSMessageShape(msg) {
|
|
|
94929
94956
|
"traceId"
|
|
94930
94957
|
]);
|
|
94931
94958
|
assertArrayPayloadField(type, payload, "contentBlocks");
|
|
94959
|
+
if ("workdirSignals" in payload && payload.workdirSignals !== void 0) {
|
|
94960
|
+
assertWorkdirSignalsPayloadField(type, payload, "workdirSignals");
|
|
94961
|
+
}
|
|
94932
94962
|
return;
|
|
94933
94963
|
}
|
|
94934
94964
|
case "agent:turn_complete": {
|
|
@@ -115629,7 +115659,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
|
|
|
115629
115659
|
system_prompt: external_exports.string().describe("\u8BE5 Agent \u7684 system prompt\uFF0C\u5B9A\u4E49\u4EBA\u683C\u3001\u4E13\u957F\u3001\u884C\u4E3A\u51C6\u5219\u3002\u4E0D\u80FD\u4E3A\u7A7A\u3002"),
|
|
115630
115660
|
tier: external_exports.enum(["smart", "balanced", "fast"]).describe("\u80FD\u529B\u6863\u4F4D\uFF1Asmart\uFF08\u65D7\u8230\uFF0C\u590D\u6742\u4EFB\u52A1\uFF09\u3001balanced\uFF08\u6807\u51C6\uFF0C\u5E38\u89C4\u4EFB\u52A1\uFF09\u3001fast\uFF08\u8F7B\u91CF\uFF0C\u7B80\u5355\u4EFB\u52A1\uFF09\u3002"),
|
|
115631
115661
|
avatar: external_exports.string().optional().describe(
|
|
115632
|
-
"\u5934\u50CF key\
|
|
115662
|
+
"\u53EF\u9009\u5934\u50CF key\u3002\u901A\u5E38\u7559\u7A7A\uFF0C\u7531\u7CFB\u7EDF\u6839\u636E Agent \u540D\u5B57\u3001\u89D2\u8272\u548C\u63D0\u793A\u8BCD\u81EA\u52A8\u5206\u914D\u673A\u5668\u4EBA\u5934\u50CF\u5E76\u5F02\u6B65\u751F\u6210\u6700\u7EC8\u5934\u50CF\u3002\u4E0D\u8981\u7ED9 Agent \u4F7F\u7528 avatar_human_*\uFF0C\u8FD9\u4E9B\u53EA\u7ED9\u771F\u5B9E\u4EBA\u7C7B\u7528\u6237\u4F7F\u7528\u3002"
|
|
115633
115663
|
),
|
|
115634
115664
|
initial_instruction: external_exports.string().optional().describe(
|
|
115635
115665
|
'\u53EF\u9009\u3002\u521B\u5EFA\u540E\u7ACB\u5373\u4E0B\u53D1\u7ED9\u65B0 Agent \u7684\u4E00\u53E5\u8BDD\u6307\u4EE4\u3002\u5178\u578B\uFF1A"\u8BF7\u7528 1-2 \u53E5\u8BDD\u5411\u7528\u6237\u505A\u81EA\u6211\u4ECB\u7ECD\uFF0C\u8BF4\u660E\u4F60\u7684\u4E13\u957F"\u3002\u53EA\u5728\u7528\u6237\u660E\u786E\u8981"\u521B\u5EFA\u4E00\u4E2A\u5355 Agent"\u4E14\u5E0C\u671B\u8BE5 Agent \u7ACB\u5373\u9732\u9762\u65F6\u4F20\u3002\u56E2\u961F\u573A\u666F\u8BF7\u52FF\u4F20\u2014\u2014\u7531 Leader \u5728\u7FA4\u91CC\u6253\u62DB\u547C\u3002'
|
|
@@ -115972,7 +116002,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
|
|
|
115972
116002
|
system_prompt: external_exports.string().optional().describe("\u65B0\u7684 system prompt\uFF08\u5B9A\u4E49\u4EBA\u683C\u3001\u4E13\u957F\u3001\u884C\u4E3A\u51C6\u5219\uFF09\u3002"),
|
|
115973
116003
|
tier: external_exports.enum(["smart", "balanced", "fast"]).optional().describe("\u80FD\u529B\u6863\u4F4D\u3002\u4F20\u6B64\u53C2\u6570\u4F1A\u66F4\u65B0\u8BE5 Agent \u4F7F\u7528\u7684\u6A21\u578B\u3002"),
|
|
115974
116004
|
avatar: external_exports.string().optional().describe(
|
|
115975
|
-
"\u5934\u50CF key\uFF08\u5982 avatar_dev / avatar_pm /
|
|
116005
|
+
"\u5934\u50CF key\uFF08\u5982 avatar_dev / avatar_pm / avatar_default \u7B49\uFF09\u3002\u4E0D\u8981\u7ED9 Agent \u4F7F\u7528 avatar_human_*\uFF0C\u8FD9\u4E9B\u53EA\u7ED9\u771F\u5B9E\u4EBA\u7C7B\u7528\u6237\u4F7F\u7528\u3002"
|
|
115976
116006
|
),
|
|
115977
116007
|
machine_bridge_key: external_exports.string().optional().describe(
|
|
115978
116008
|
'\u53EF\u9009\u3002\u65B0\u7684\u8FD0\u884C\u673A\u5668 bridgeKey\uFF0C\u6765\u81EA list_contacts \u7684"\u53EF\u7528\u673A\u5668"\u3002\u7701\u7565\u8868\u793A\u4E0D\u6539\uFF1B\u4F20 auto \u6216\u7A7A\u5B57\u7B26\u4E32\u6E05\u9664\u673A\u5668\u504F\u597D\u3002'
|
|
@@ -116974,9 +117004,11 @@ function buildGroupInboxPrompt(entries, opts = {}) {
|
|
|
116974
117004
|
// src/sdkEventMapper.ts
|
|
116975
117005
|
init_cjs_shims();
|
|
116976
117006
|
var logger12 = createModuleLogger("sdk.mapper");
|
|
117007
|
+
var DEBUG_ONLY_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set(["status", "thinking_tokens"]);
|
|
116977
117008
|
var HIGH_WATERMARK_INPUT_TOKENS = 12e4;
|
|
116978
117009
|
var WARN_THRESHOLD_INPUT_TOKENS = 1e5;
|
|
116979
117010
|
var LIVE_INPUT_PREVIEW_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit"]);
|
|
117011
|
+
var WORKDIR_MUTATION_TOOL_NAMES = /* @__PURE__ */ new Set(["write", "edit", "multiedit", "notebookedit", "bash"]);
|
|
116980
117012
|
var CONTEXT_OVERFLOW_LOCK_MS = 6e4;
|
|
116981
117013
|
function parseJsonRecord(text) {
|
|
116982
117014
|
try {
|
|
@@ -116998,6 +117030,17 @@ function isSuccessfulOfficialMediaOutput(toolName, output) {
|
|
|
116998
117030
|
if (!["succeeded", "success", "completed", "done"].includes(state)) return false;
|
|
116999
117031
|
return Array.isArray(parsed.images) && parsed.images.length > 0 || typeof parsed.video_url === "string" || typeof parsed.videoUrl === "string";
|
|
117000
117032
|
}
|
|
117033
|
+
function isWorkdirMutationToolName(toolName) {
|
|
117034
|
+
return WORKDIR_MUTATION_TOOL_NAMES.has(toolName.trim().toLowerCase());
|
|
117035
|
+
}
|
|
117036
|
+
function recordWorkdirSignal(proc, toolName, isError) {
|
|
117037
|
+
if (isError || !isGroupTask(proc) || !isWorkdirMutationToolName(toolName)) return;
|
|
117038
|
+
const signals = proc.workdirSignals ?? [];
|
|
117039
|
+
if (!signals.some((signal) => signal.toolName === toolName)) {
|
|
117040
|
+
signals.push({ toolName });
|
|
117041
|
+
}
|
|
117042
|
+
proc.workdirSignals = signals;
|
|
117043
|
+
}
|
|
117001
117044
|
function isContextOverflowText(text) {
|
|
117002
117045
|
const trimmed = text.trim();
|
|
117003
117046
|
return /^prompt is too long\b/i.test(trimmed) || /context length .* exceed/i.test(trimmed);
|
|
@@ -117502,6 +117545,7 @@ function countByStatus(todos) {
|
|
|
117502
117545
|
function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = false) {
|
|
117503
117546
|
const groupId = proc.currentTask?.groupId;
|
|
117504
117547
|
if (!groupId) return;
|
|
117548
|
+
const workdirSignals = proc.workdirSignals?.length ? [...proc.workdirSignals] : void 0;
|
|
117505
117549
|
proc.segmentCount += 1;
|
|
117506
117550
|
logger12.info("Group segment emitted", {
|
|
117507
117551
|
agentId: base.agentId,
|
|
@@ -117511,6 +117555,7 @@ function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = f
|
|
|
117511
117555
|
contentLen: content.length,
|
|
117512
117556
|
blockCount: contentBlocks.length,
|
|
117513
117557
|
blockTypes: contentBlocks.map((b) => b.type),
|
|
117558
|
+
workdirSignalCount: workdirSignals?.length ?? 0,
|
|
117514
117559
|
traceId: base.traceId,
|
|
117515
117560
|
isAuditOnly: content.length === 0,
|
|
117516
117561
|
isSilent
|
|
@@ -117523,9 +117568,11 @@ function emitGroupSegment(proc, emit, base, content, contentBlocks, isSilent = f
|
|
|
117523
117568
|
groupId,
|
|
117524
117569
|
content,
|
|
117525
117570
|
contentBlocks: [...contentBlocks],
|
|
117571
|
+
...workdirSignals ? { workdirSignals } : {},
|
|
117526
117572
|
...isSilent ? { isSilent: true } : {}
|
|
117527
117573
|
}
|
|
117528
117574
|
});
|
|
117575
|
+
proc.workdirSignals = [];
|
|
117529
117576
|
}
|
|
117530
117577
|
function flushTextSegmentOnBlockStop(proc, emit, base) {
|
|
117531
117578
|
const trimmed = proc.segmentBuffer.trim();
|
|
@@ -117544,7 +117591,7 @@ function flushTextSegmentOnBlockStop(proc, emit, base) {
|
|
|
117544
117591
|
traceId: base.traceId
|
|
117545
117592
|
});
|
|
117546
117593
|
}
|
|
117547
|
-
} else if (proc.contentBlocks.length > 0) {
|
|
117594
|
+
} else if (proc.contentBlocks.length > 0 || (proc.workdirSignals?.length ?? 0) > 0) {
|
|
117548
117595
|
const blockCount = proc.contentBlocks.length;
|
|
117549
117596
|
emitGroupSegment(proc, emit, base, "", proc.contentBlocks, true);
|
|
117550
117597
|
proc.contentBlocks = [];
|
|
@@ -117634,7 +117681,8 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117634
117681
|
proc.activeSubagentTaskIds?.delete(subagentTaskId);
|
|
117635
117682
|
}
|
|
117636
117683
|
}
|
|
117637
|
-
|
|
117684
|
+
const logUnhandledSystemSubtype = DEBUG_ONLY_SYSTEM_SUBTYPES.has(String(sysMsg.subtype ?? "")) ? logger12.debug.bind(logger12) : logger12.info.bind(logger12);
|
|
117685
|
+
logUnhandledSystemSubtype("SDK system subtype unhandled", {
|
|
117638
117686
|
agentId: proc.agentId,
|
|
117639
117687
|
scope: proc.scope.kind === "single" ? "single" : proc.scope.groupId,
|
|
117640
117688
|
subtype: sysMsg.subtype ?? "(none)",
|
|
@@ -117680,6 +117728,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117680
117728
|
const isMcpTool = parseMcpRuntimeToolName(toolName) != null;
|
|
117681
117729
|
proc.currentMcpInvocationId = isMcpTool ? createMcpToolInvocationId() : null;
|
|
117682
117730
|
proc.currentMcpInvocationStartedAt = isMcpTool ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
117731
|
+
proc.currentMcpInvocationToolUseId = isMcpTool ? toolUseId ?? null : null;
|
|
117683
117732
|
if (shouldStreamInternals(proc) && !proc.suppressCurrentToolUse && toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
117684
117733
|
emit({
|
|
117685
117734
|
type: "agent:tool_use",
|
|
@@ -117690,6 +117739,8 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117690
117739
|
input: {}
|
|
117691
117740
|
}
|
|
117692
117741
|
});
|
|
117742
|
+
}
|
|
117743
|
+
if (shouldStreamInternals(proc) && !proc.suppressCurrentToolUse && toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
117693
117744
|
proc.contentBlocks.push({
|
|
117694
117745
|
type: "tool_use",
|
|
117695
117746
|
...toolUseId ? { toolUseId } : {},
|
|
@@ -117866,6 +117917,14 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117866
117917
|
}
|
|
117867
117918
|
if (proc.currentToolName && !proc.suppressCurrentToolUse && proc.currentMcpInvocationId && proc.currentMcpInvocationStartedAt && parseMcpRuntimeToolName(proc.currentToolName)) {
|
|
117868
117919
|
try {
|
|
117920
|
+
logger12.info("MCP audit start paired with tool_use", {
|
|
117921
|
+
agentId: proc.agentId,
|
|
117922
|
+
replyMessageId: base.replyMessageId,
|
|
117923
|
+
traceId: base.traceId,
|
|
117924
|
+
toolUseId: proc.currentMcpInvocationToolUseId ?? null,
|
|
117925
|
+
runtimeToolName: proc.currentToolName,
|
|
117926
|
+
mcpInvocationId: proc.currentMcpInvocationId
|
|
117927
|
+
});
|
|
117869
117928
|
proc.mcpAuditRecorder?.recordStart({
|
|
117870
117929
|
id: proc.currentMcpInvocationId,
|
|
117871
117930
|
runtimeToolName: proc.currentToolName,
|
|
@@ -117946,6 +118005,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117946
118005
|
});
|
|
117947
118006
|
proc.currentMcpInvocationId = null;
|
|
117948
118007
|
proc.currentMcpInvocationStartedAt = null;
|
|
118008
|
+
proc.currentMcpInvocationToolUseId = null;
|
|
117949
118009
|
proc.activeToolUseStartedAt = void 0;
|
|
117950
118010
|
proc.currentToolName = null;
|
|
117951
118011
|
proc.currentToolUseId = null;
|
|
@@ -117962,6 +118022,16 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117962
118022
|
}
|
|
117963
118023
|
if (proc.currentMcpInvocationId && parseMcpRuntimeToolName(toolName)) {
|
|
117964
118024
|
try {
|
|
118025
|
+
logger12.info("MCP audit result paired with tool_result", {
|
|
118026
|
+
agentId: proc.agentId,
|
|
118027
|
+
replyMessageId: base.replyMessageId,
|
|
118028
|
+
traceId: base.traceId,
|
|
118029
|
+
toolUseId,
|
|
118030
|
+
startedToolUseId: proc.currentMcpInvocationToolUseId ?? null,
|
|
118031
|
+
runtimeToolName: toolName,
|
|
118032
|
+
mcpInvocationId: proc.currentMcpInvocationId,
|
|
118033
|
+
isError
|
|
118034
|
+
});
|
|
117965
118035
|
proc.mcpAuditRecorder?.recordResult({
|
|
117966
118036
|
id: proc.currentMcpInvocationId,
|
|
117967
118037
|
runtimeToolName: toolName,
|
|
@@ -117983,6 +118053,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
117983
118053
|
}
|
|
117984
118054
|
proc.currentMcpInvocationId = null;
|
|
117985
118055
|
proc.currentMcpInvocationStartedAt = null;
|
|
118056
|
+
proc.currentMcpInvocationToolUseId = null;
|
|
117986
118057
|
}
|
|
117987
118058
|
if (shouldStreamInternals(proc)) {
|
|
117988
118059
|
emit({
|
|
@@ -118010,6 +118081,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118010
118081
|
}
|
|
118011
118082
|
}
|
|
118012
118083
|
}
|
|
118084
|
+
recordWorkdirSignal(proc, toolName, isError);
|
|
118013
118085
|
proc.activeToolUseStartedAt = void 0;
|
|
118014
118086
|
proc.currentToolUseId = null;
|
|
118015
118087
|
}
|
|
@@ -118071,7 +118143,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118071
118143
|
if (isNoReplyText(trimmed, { allowSdkSyntheticNoResponse: groupMode })) {
|
|
118072
118144
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
118073
118145
|
emitUsageReported(proc, emit, base, usage);
|
|
118074
|
-
if (groupMode && proc.contentBlocks.length > 0) {
|
|
118146
|
+
if (groupMode && (proc.contentBlocks.length > 0 || (proc.workdirSignals?.length ?? 0) > 0)) {
|
|
118075
118147
|
emitGroupSegment(
|
|
118076
118148
|
proc,
|
|
118077
118149
|
emit,
|
|
@@ -118116,11 +118188,12 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118116
118188
|
proc.segmentBuffer = proc.accumulatedText;
|
|
118117
118189
|
flushTextSegmentOnBlockStop(proc, emit, base);
|
|
118118
118190
|
}
|
|
118119
|
-
if (proc.contentBlocks.length > 0) {
|
|
118191
|
+
if (proc.contentBlocks.length > 0 || (proc.workdirSignals?.length ?? 0) > 0) {
|
|
118120
118192
|
logger12.info("Group turn trailing audit segment", {
|
|
118121
118193
|
agentId: proc.agentId,
|
|
118122
118194
|
replyMessageId: base.replyMessageId,
|
|
118123
118195
|
blockCount: proc.contentBlocks.length,
|
|
118196
|
+
workdirSignalCount: proc.workdirSignals?.length ?? 0,
|
|
118124
118197
|
traceId: base.traceId
|
|
118125
118198
|
});
|
|
118126
118199
|
emitGroupSegment(proc, emit, base, "", proc.contentBlocks, true);
|
|
@@ -118265,6 +118338,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118265
118338
|
payload: { ...wireBase(base), error: errorText }
|
|
118266
118339
|
});
|
|
118267
118340
|
proc.contentBlocks = [];
|
|
118341
|
+
proc.workdirSignals = [];
|
|
118268
118342
|
proc.accumulatedText = "";
|
|
118269
118343
|
proc.accumulatedThinking = "";
|
|
118270
118344
|
proc.segmentBuffer = "";
|
|
@@ -118297,6 +118371,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118297
118371
|
proc.apiErrorEmitted = true;
|
|
118298
118372
|
}
|
|
118299
118373
|
proc.contentBlocks = [];
|
|
118374
|
+
proc.workdirSignals = [];
|
|
118300
118375
|
proc.accumulatedText = "";
|
|
118301
118376
|
proc.accumulatedThinking = "";
|
|
118302
118377
|
proc.segmentBuffer = "";
|
|
@@ -118323,6 +118398,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118323
118398
|
proc.apiErrorEmitted = true;
|
|
118324
118399
|
}
|
|
118325
118400
|
proc.contentBlocks = [];
|
|
118401
|
+
proc.workdirSignals = [];
|
|
118326
118402
|
proc.accumulatedText = "";
|
|
118327
118403
|
proc.accumulatedThinking = "";
|
|
118328
118404
|
proc.segmentBuffer = "";
|
|
@@ -118359,6 +118435,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted, onPost
|
|
|
118359
118435
|
});
|
|
118360
118436
|
}
|
|
118361
118437
|
proc.contentBlocks = [];
|
|
118438
|
+
proc.workdirSignals = [];
|
|
118362
118439
|
proc.accumulatedText = "";
|
|
118363
118440
|
proc.accumulatedThinking = "";
|
|
118364
118441
|
proc.segmentBuffer = "";
|
|
@@ -118396,9 +118473,11 @@ function resetAccumulators(proc) {
|
|
|
118396
118473
|
proc.currentToolUseId = null;
|
|
118397
118474
|
proc.currentMcpInvocationId = null;
|
|
118398
118475
|
proc.currentMcpInvocationStartedAt = null;
|
|
118476
|
+
proc.currentMcpInvocationToolUseId = null;
|
|
118399
118477
|
proc.activeToolUseStartedAt = void 0;
|
|
118400
118478
|
proc.segmentBuffer = "";
|
|
118401
118479
|
proc.segmentCount = 0;
|
|
118480
|
+
proc.workdirSignals = [];
|
|
118402
118481
|
proc.accumulatedToolInput = "";
|
|
118403
118482
|
proc.apiErrorEmitted = false;
|
|
118404
118483
|
proc.peakContextUsage = void 0;
|
|
@@ -118598,7 +118677,7 @@ function missingSubscriptionMessage(subscriptionId) {
|
|
|
118598
118677
|
}
|
|
118599
118678
|
var NODE_USER_UID = 1e3;
|
|
118600
118679
|
var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
|
|
118601
|
-
var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-mcp-abi-prompt-
|
|
118680
|
+
var SCOPE_PROMPT_FINGERPRINT_REVISION = "workdir-scope-mcp-abi-prompt-v6";
|
|
118602
118681
|
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;
|
|
118603
118682
|
var IMAGE_READ_EXT_RE = /\.(?:bmp|gif|jpeg|jpg|png|webp)$/i;
|
|
118604
118683
|
var DOCUMENT_READING_RULES = `DOCUMENT READING:
|
|
@@ -118614,6 +118693,31 @@ var MEDIA_GENERATION_RULES = `MEDIA GENERATION:
|
|
|
118614
118693
|
- 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.
|
|
118615
118694
|
- 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.
|
|
118616
118695
|
- 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.`;
|
|
118696
|
+
var SMITH_ALLOWED_TOOLS = [
|
|
118697
|
+
// creation / configuration (Smith-only)
|
|
118698
|
+
"mcp__neural__create_agent",
|
|
118699
|
+
"mcp__neural__update_agent_profile",
|
|
118700
|
+
"mcp__neural__recommend_agent_skills",
|
|
118701
|
+
"mcp__neural__read_skill",
|
|
118702
|
+
// diagnostics (log detective)
|
|
118703
|
+
"mcp__neural__fetch_logs",
|
|
118704
|
+
// friend approval (Smith-only)
|
|
118705
|
+
"mcp__neural__list_friends",
|
|
118706
|
+
"mcp__neural__accept_friend",
|
|
118707
|
+
"mcp__neural__add_friend",
|
|
118708
|
+
// team assembly
|
|
118709
|
+
"mcp__neural__list_contacts",
|
|
118710
|
+
"mcp__neural__create_group",
|
|
118711
|
+
"mcp__neural__add_to_group",
|
|
118712
|
+
"mcp__neural__transfer_group_owner",
|
|
118713
|
+
"mcp__neural__leave_group",
|
|
118714
|
+
// neural bridge — cross-scope coordination when Smith is pulled into a group
|
|
118715
|
+
"mcp__neural__neural_send",
|
|
118716
|
+
"mcp__neural__neural_list_scopes",
|
|
118717
|
+
// interaction / planning
|
|
118718
|
+
"AskUserQuestion",
|
|
118719
|
+
"Write"
|
|
118720
|
+
];
|
|
118617
118721
|
function resolveVisionMcpToolHints(externalMcp) {
|
|
118618
118722
|
let describe3 = null;
|
|
118619
118723
|
let ocr = null;
|
|
@@ -119878,7 +119982,7 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119878
119982
|
} catch (error51) {
|
|
119879
119983
|
logger15.error("Failed to read existing API-key agent settings; starting fresh", {
|
|
119880
119984
|
agentId: agentConfig.id,
|
|
119881
|
-
|
|
119985
|
+
settingsFile: "settings.json",
|
|
119882
119986
|
error: error51
|
|
119883
119987
|
});
|
|
119884
119988
|
}
|
|
@@ -119891,7 +119995,7 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119891
119995
|
await import_promises3.default.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
|
|
119892
119996
|
logger15.info("API-key agent using isolated config dir", {
|
|
119893
119997
|
agentId: agentConfig.id,
|
|
119894
|
-
|
|
119998
|
+
configDirKind: "api-key-agent",
|
|
119895
119999
|
isNew,
|
|
119896
120000
|
hasBaseUrl: !!cfg.apiBaseUrl,
|
|
119897
120001
|
settingsWritten: Object.keys(envEntries)
|
|
@@ -119985,12 +120089,21 @@ ${cfg.instructions.trim()}` : "";
|
|
|
119985
120089
|
});
|
|
119986
120090
|
}
|
|
119987
120091
|
}
|
|
119988
|
-
const
|
|
120092
|
+
const resolvedExternalMcp = this.mcpRegistry?.buildForAgent({
|
|
119989
120093
|
agentId: agentConfig.id,
|
|
119990
120094
|
capabilityTier: cfg.capabilityTier,
|
|
119991
120095
|
isSmith: smithAgent,
|
|
119992
120096
|
cwd: agentCwd
|
|
119993
120097
|
}) ?? { mcpServers: {}, allowedTools: [], toolAbi: [] };
|
|
120098
|
+
const externalMcp = smithAgent ? { mcpServers: {}, allowedTools: [], toolAbi: [] } : resolvedExternalMcp;
|
|
120099
|
+
if (smithAgent && (Object.keys(resolvedExternalMcp.mcpServers).length > 0 || resolvedExternalMcp.allowedTools.length > 0 || (resolvedExternalMcp.toolAbi?.length ?? 0) > 0)) {
|
|
120100
|
+
logger15.info("Smith external MCP ignored by fixed tool whitelist", {
|
|
120101
|
+
agentId: agentConfig.id,
|
|
120102
|
+
scope: scopeKey(scope),
|
|
120103
|
+
serverNames: Object.keys(resolvedExternalMcp.mcpServers),
|
|
120104
|
+
allowedToolCount: resolvedExternalMcp.allowedTools.length
|
|
120105
|
+
});
|
|
120106
|
+
}
|
|
119994
120107
|
const visionMcpTools = resolveVisionMcpToolHints(externalMcp);
|
|
119995
120108
|
logger15.info("External MCP resolved for runtime", {
|
|
119996
120109
|
agentId: agentConfig.id,
|
|
@@ -120063,6 +120176,7 @@ ${cfg.instructions.trim()}` : "";
|
|
|
120063
120176
|
logger15.info("Creating Agent query", {
|
|
120064
120177
|
agentId: agentConfig.id,
|
|
120065
120178
|
scope: scopeKey(scope),
|
|
120179
|
+
systemPromptMode: smithAgent ? "string" : "preset",
|
|
120066
120180
|
cwd: agentCwd,
|
|
120067
120181
|
resume: !!savedSessionId,
|
|
120068
120182
|
sessionId: savedSessionId,
|
|
@@ -120083,71 +120197,63 @@ ${cfg.instructions.trim()}` : "";
|
|
|
120083
120197
|
});
|
|
120084
120198
|
const planModeRef = { active: false, denyCount: 0 };
|
|
120085
120199
|
const mediaGenerationTurnGuard = createOfficialMediaGenerationTurnGuard();
|
|
120200
|
+
const platformRules = scope.kind === "group" ? PLATFORM_AGENT_RULES : PLATFORM_AGENT_RULES_SINGLE;
|
|
120201
|
+
const appendText = [
|
|
120202
|
+
platformRules,
|
|
120203
|
+
nativeReadToolDisabled ? buildNativeReadDisabledRules(visionMcpTools) : "",
|
|
120204
|
+
DOCUMENT_READING_RULES,
|
|
120205
|
+
MEDIA_GENERATION_RULES,
|
|
120206
|
+
agentConfig.systemPrompt,
|
|
120207
|
+
scopedInstructions,
|
|
120208
|
+
notebookSection,
|
|
120209
|
+
forkHistorySection,
|
|
120210
|
+
scopesSection
|
|
120211
|
+
].filter((s) => typeof s === "string" && s.trim().length > 0).join("\n\n");
|
|
120212
|
+
const systemPrompt = smithAgent ? appendText : { type: "preset", preset: "claude_code", append: appendText };
|
|
120213
|
+
const universalAllowedTools = [
|
|
120214
|
+
...nativeReadToolDisabled ? [] : ["Read"],
|
|
120215
|
+
"Edit",
|
|
120216
|
+
"Write",
|
|
120217
|
+
"Bash",
|
|
120218
|
+
"Glob",
|
|
120219
|
+
"Grep",
|
|
120220
|
+
...builtinWebSearchAllowed ? ["WebSearch"] : [],
|
|
120221
|
+
"WebFetch",
|
|
120222
|
+
"TodoWrite",
|
|
120223
|
+
"TaskCreate",
|
|
120224
|
+
"TaskUpdate",
|
|
120225
|
+
"AskUserQuestion",
|
|
120226
|
+
"mcp__neural__neural_send",
|
|
120227
|
+
"mcp__neural__neural_list_scopes",
|
|
120228
|
+
"mcp__neural__self_note",
|
|
120229
|
+
"mcp__neural__list_contacts",
|
|
120230
|
+
"mcp__neural__create_group",
|
|
120231
|
+
"mcp__neural__add_to_group",
|
|
120232
|
+
"mcp__neural__leave_group",
|
|
120233
|
+
"mcp__neural__remove_from_group",
|
|
120234
|
+
"mcp__neural__create_group_issue",
|
|
120235
|
+
"mcp__neural__resolve_group_issue",
|
|
120236
|
+
"mcp__neural__list_group_tasks",
|
|
120237
|
+
"mcp__neural__update_group_task",
|
|
120238
|
+
"mcp__neural__transfer_group_owner",
|
|
120239
|
+
"mcp__neural__post_to_moments",
|
|
120240
|
+
"mcp__neural__post_to_forum",
|
|
120241
|
+
"mcp__neural__read_moments",
|
|
120242
|
+
"mcp__neural__read_chat_history",
|
|
120243
|
+
"mcp__neural__read_document",
|
|
120244
|
+
"mcp__neural__list_available_skills",
|
|
120245
|
+
"mcp__neural__list_skill_index"
|
|
120246
|
+
];
|
|
120086
120247
|
const options = {
|
|
120087
120248
|
cwd: agentCwd,
|
|
120088
|
-
systemPrompt
|
|
120089
|
-
type: "preset",
|
|
120090
|
-
preset: "claude_code",
|
|
120091
|
-
append: [
|
|
120092
|
-
PLATFORM_AGENT_RULES,
|
|
120093
|
-
nativeReadToolDisabled ? buildNativeReadDisabledRules(visionMcpTools) : "",
|
|
120094
|
-
DOCUMENT_READING_RULES,
|
|
120095
|
-
MEDIA_GENERATION_RULES,
|
|
120096
|
-
agentConfig.systemPrompt,
|
|
120097
|
-
scopedInstructions,
|
|
120098
|
-
notebookSection,
|
|
120099
|
-
forkHistorySection,
|
|
120100
|
-
scopesSection
|
|
120101
|
-
].filter((s) => typeof s === "string" && s.trim().length > 0).join("\n\n")
|
|
120102
|
-
},
|
|
120249
|
+
systemPrompt,
|
|
120103
120250
|
permissionMode: "bypassPermissions",
|
|
120104
120251
|
allowDangerouslySkipPermissions: true,
|
|
120105
120252
|
// allowedTools is the visibility whitelist passed to Claude Code. MCP tools
|
|
120106
120253
|
// with always_ask must still be included here so the model can request them;
|
|
120107
120254
|
// the MCP server policy/permission layer decides whether execution asks.
|
|
120108
120255
|
allowedTools: [
|
|
120109
|
-
...
|
|
120110
|
-
"Edit",
|
|
120111
|
-
"Write",
|
|
120112
|
-
"Bash",
|
|
120113
|
-
"Glob",
|
|
120114
|
-
"Grep",
|
|
120115
|
-
...builtinWebSearchAllowed ? ["WebSearch"] : [],
|
|
120116
|
-
"WebFetch",
|
|
120117
|
-
"TodoWrite",
|
|
120118
|
-
"TaskCreate",
|
|
120119
|
-
"TaskUpdate",
|
|
120120
|
-
"AskUserQuestion",
|
|
120121
|
-
"mcp__neural__neural_send",
|
|
120122
|
-
"mcp__neural__neural_list_scopes",
|
|
120123
|
-
"mcp__neural__self_note",
|
|
120124
|
-
"mcp__neural__list_contacts",
|
|
120125
|
-
"mcp__neural__create_group",
|
|
120126
|
-
"mcp__neural__add_to_group",
|
|
120127
|
-
"mcp__neural__leave_group",
|
|
120128
|
-
"mcp__neural__remove_from_group",
|
|
120129
|
-
"mcp__neural__create_group_issue",
|
|
120130
|
-
"mcp__neural__resolve_group_issue",
|
|
120131
|
-
"mcp__neural__list_group_tasks",
|
|
120132
|
-
"mcp__neural__update_group_task",
|
|
120133
|
-
"mcp__neural__transfer_group_owner",
|
|
120134
|
-
"mcp__neural__post_to_moments",
|
|
120135
|
-
"mcp__neural__post_to_forum",
|
|
120136
|
-
"mcp__neural__read_moments",
|
|
120137
|
-
"mcp__neural__read_chat_history",
|
|
120138
|
-
"mcp__neural__read_document",
|
|
120139
|
-
"mcp__neural__list_available_skills",
|
|
120140
|
-
"mcp__neural__list_skill_index",
|
|
120141
|
-
...isSmithAgent2(agentConfig) ? [
|
|
120142
|
-
"mcp__neural__create_agent",
|
|
120143
|
-
"mcp__neural__update_agent_profile",
|
|
120144
|
-
"mcp__neural__recommend_agent_skills",
|
|
120145
|
-
"mcp__neural__read_skill",
|
|
120146
|
-
"mcp__neural__list_friends",
|
|
120147
|
-
"mcp__neural__accept_friend",
|
|
120148
|
-
"mcp__neural__add_friend",
|
|
120149
|
-
"mcp__neural__fetch_logs"
|
|
120150
|
-
] : [],
|
|
120256
|
+
...smithAgent ? SMITH_ALLOWED_TOOLS : universalAllowedTools,
|
|
120151
120257
|
...externalMcp.allowedTools
|
|
120152
120258
|
],
|
|
120153
120259
|
// Server-side WebSearch bypasses canUseTool; disallowedTools removes it from model context.
|
|
@@ -120159,7 +120265,7 @@ ${cfg.instructions.trim()}` : "";
|
|
|
120159
120265
|
// instructions as the workflow body (replacing the default code-implementation
|
|
120160
120266
|
// phases). The SDK wraps it with read-only enforcement + ExitPlanMode protocol.
|
|
120161
120267
|
planModeInstructions: (() => {
|
|
120162
|
-
const planTools = [
|
|
120268
|
+
const planTools = (smithAgent ? ["AskUserQuestion", "Write (plan file only)"] : [
|
|
120163
120269
|
...nativeReadToolDisabled ? [] : ["Read"],
|
|
120164
120270
|
"Glob",
|
|
120165
120271
|
"Grep",
|
|
@@ -120167,19 +120273,19 @@ ${cfg.instructions.trim()}` : "";
|
|
|
120167
120273
|
"WebFetch",
|
|
120168
120274
|
"AskUserQuestion",
|
|
120169
120275
|
"Write (plan file only)"
|
|
120170
|
-
].join(", ");
|
|
120171
|
-
const researchTools = [
|
|
120276
|
+
]).join(", ");
|
|
120277
|
+
const researchTools = (smithAgent ? ["AskUserQuestion"] : [
|
|
120172
120278
|
...nativeReadToolDisabled ? [] : ["Read"],
|
|
120173
120279
|
"Grep",
|
|
120174
120280
|
...builtinWebSearchAllowed ? ["WebSearch"] : []
|
|
120175
|
-
].join(", ");
|
|
120176
|
-
const unavailableTools = [
|
|
120281
|
+
]).join(", ");
|
|
120282
|
+
const unavailableTools = (smithAgent ? ["Read", "Edit", "Bash", "Glob", "Grep", "WebFetch", "TodoWrite", "ExitPlanMode"] : [
|
|
120177
120283
|
"Edit",
|
|
120178
120284
|
"Bash",
|
|
120179
120285
|
"TodoWrite",
|
|
120180
120286
|
"ExitPlanMode",
|
|
120181
120287
|
...nativeReadToolDisabled ? ["Read"] : []
|
|
120182
|
-
].join(", ");
|
|
120288
|
+
]).join(", ");
|
|
120183
120289
|
const smithTools = smithAgent ? "\nSMITH-SPECIFIC TOOLS (available in plan mode): mcp__neural__recommend_agent_skills, mcp__neural__read_skill, mcp__neural__fetch_logs, mcp__neural__create_agent, mcp__neural__update_agent_profile \u2014 use these to recommend initial skill sets, research existing skills, check logs, plan agent creation, and adjust Agent profiles." : "";
|
|
120184
120290
|
return `You are a PLANNER, NOT an executor. The user will execute your plan later.
|
|
120185
120291
|
|
|
@@ -120409,17 +120515,17 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
120409
120515
|
}
|
|
120410
120516
|
};
|
|
120411
120517
|
const userPromptTrimmed = (agentConfig.systemPrompt ?? "").trim();
|
|
120412
|
-
const appendStr = options.systemPrompt.append;
|
|
120413
120518
|
logger15.info("Platform rules attached", {
|
|
120414
120519
|
agentId: agentConfig.id,
|
|
120415
120520
|
scope: scopeKey(scope),
|
|
120416
|
-
|
|
120521
|
+
systemPromptMode: smithAgent ? "string" : "preset",
|
|
120522
|
+
platformRulesLen: platformRules.length,
|
|
120417
120523
|
userPromptLen: userPromptTrimmed.length,
|
|
120418
120524
|
hasUserPrompt: userPromptTrimmed.length > 0,
|
|
120419
120525
|
notebookLen: notebookSection.length,
|
|
120420
120526
|
forkHistoryLen: forkHistorySection.length,
|
|
120421
120527
|
scopesLen: scopesSection.length,
|
|
120422
|
-
appendLen:
|
|
120528
|
+
appendLen: appendText.length,
|
|
120423
120529
|
hasCreateAgentTool: smithAgent,
|
|
120424
120530
|
hasLogDetectiveTools: smithAgent && this.skillStore !== null
|
|
120425
120531
|
});
|
|
@@ -120489,6 +120595,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
|
|
|
120489
120595
|
mcpAuditRecorder: this.mcpAuditRecorder,
|
|
120490
120596
|
segmentBuffer: "",
|
|
120491
120597
|
segmentCount: 0,
|
|
120598
|
+
workdirSignals: [],
|
|
120492
120599
|
accumulatedToolInput: "",
|
|
120493
120600
|
planModeRef,
|
|
120494
120601
|
mediaGenerationTurnGuard,
|
|
@@ -121522,6 +121629,7 @@ ${lines.join("\n")}`;
|
|
|
121522
121629
|
proc.currentToolName = null;
|
|
121523
121630
|
proc.segmentBuffer = "";
|
|
121524
121631
|
proc.segmentCount = 0;
|
|
121632
|
+
proc.workdirSignals = [];
|
|
121525
121633
|
}
|
|
121526
121634
|
clearPostMergeContinuationTimer(runtime) {
|
|
121527
121635
|
if (runtime.postMergeContinuationTimer) {
|
|
@@ -124297,6 +124405,7 @@ var HttpMcpRegistry = class {
|
|
|
124297
124405
|
localStore;
|
|
124298
124406
|
serverConnections = /* @__PURE__ */ new Map();
|
|
124299
124407
|
localConnections = /* @__PURE__ */ new Map();
|
|
124408
|
+
missingSecretWarnedKeys = /* @__PURE__ */ new Set();
|
|
124300
124409
|
lastRefreshCount = null;
|
|
124301
124410
|
apiUrl(suffix) {
|
|
124302
124411
|
const base = this.serverApiUrl.replace(/\/$/, "");
|
|
@@ -124397,13 +124506,19 @@ var HttpMcpRegistry = class {
|
|
|
124397
124506
|
return false;
|
|
124398
124507
|
});
|
|
124399
124508
|
}
|
|
124509
|
+
warnMissingSecretOnce(connection) {
|
|
124510
|
+
const key = `${connection.id}:${connection.providerId}:${connection.serverName}`;
|
|
124511
|
+
if (this.missingSecretWarnedKeys.has(key)) return;
|
|
124512
|
+
this.missingSecretWarnedKeys.add(key);
|
|
124513
|
+
logger20.warn("Skipping MCP connection without required secret", {
|
|
124514
|
+
id: connection.id,
|
|
124515
|
+
providerId: connection.providerId,
|
|
124516
|
+
serverName: connection.serverName
|
|
124517
|
+
});
|
|
124518
|
+
}
|
|
124400
124519
|
toSdkServerConfig(connection, ctx) {
|
|
124401
124520
|
if (mcpConnectionRequiresSecret(connection) && !connection.hasAuthSecret) {
|
|
124402
|
-
|
|
124403
|
-
id: connection.id,
|
|
124404
|
-
providerId: connection.providerId,
|
|
124405
|
-
serverName: connection.serverName
|
|
124406
|
-
});
|
|
124521
|
+
this.warnMissingSecretOnce(connection);
|
|
124407
124522
|
return null;
|
|
124408
124523
|
}
|
|
124409
124524
|
const policies = toolPolicies(connection);
|
|
@@ -126600,8 +126715,47 @@ var import_node_fs11 = __toESM(require("fs"), 1);
|
|
|
126600
126715
|
var import_promises7 = __toESM(require("fs/promises"), 1);
|
|
126601
126716
|
var import_node_path21 = __toESM(require("path"), 1);
|
|
126602
126717
|
var logger29 = createModuleLogger("bridge.logUploader");
|
|
126718
|
+
var STALE_RATE_LIMIT_SKIP_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
126603
126719
|
var DEFAULT_LOG_UPLOAD_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
126604
126720
|
var DEFAULT_BATCH_SIZE = 200;
|
|
126721
|
+
var MAX_UPLOAD_CHUNK_BODY_BYTES = 448 * 1024;
|
|
126722
|
+
var MAX_UPLOAD_RETRY_AFTER_MS = 24 * 60 * 60 * 1e3;
|
|
126723
|
+
var LogUploadHttpError = class extends Error {
|
|
126724
|
+
status;
|
|
126725
|
+
scope;
|
|
126726
|
+
retryAfterMs;
|
|
126727
|
+
constructor(status, bodyText) {
|
|
126728
|
+
const parsed = parseUploadErrorBody(bodyText);
|
|
126729
|
+
const summary = parsed.error ?? bodyText;
|
|
126730
|
+
super(`upload failed HTTP ${status}: ${summary.slice(0, 160)}`);
|
|
126731
|
+
this.name = "LogUploadHttpError";
|
|
126732
|
+
this.status = status;
|
|
126733
|
+
if (parsed.scope) this.scope = parsed.scope;
|
|
126734
|
+
if (parsed.retryAfterMs !== void 0) this.retryAfterMs = parsed.retryAfterMs;
|
|
126735
|
+
}
|
|
126736
|
+
};
|
|
126737
|
+
function normalizeRetryAfterMs(value) {
|
|
126738
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
|
|
126739
|
+
return Math.min(Math.ceil(value), MAX_UPLOAD_RETRY_AFTER_MS);
|
|
126740
|
+
}
|
|
126741
|
+
function parseUploadErrorBody(bodyText) {
|
|
126742
|
+
try {
|
|
126743
|
+
const parsed = JSON.parse(bodyText);
|
|
126744
|
+
if (typeof parsed !== "object" || parsed === null) return {};
|
|
126745
|
+
const body = parsed;
|
|
126746
|
+
return {
|
|
126747
|
+
...typeof body.error === "string" && body.error.length > 0 ? { error: body.error } : {},
|
|
126748
|
+
...typeof body.scope === "string" && body.scope.length > 0 ? { scope: body.scope } : {},
|
|
126749
|
+
...(() => {
|
|
126750
|
+
const retryAfterMs = normalizeRetryAfterMs(body.retryAfterMs);
|
|
126751
|
+
return retryAfterMs === void 0 ? {} : { retryAfterMs };
|
|
126752
|
+
})()
|
|
126753
|
+
};
|
|
126754
|
+
} catch (e) {
|
|
126755
|
+
logger29.debug("Failed to parse log upload error body", { error: e });
|
|
126756
|
+
return {};
|
|
126757
|
+
}
|
|
126758
|
+
}
|
|
126605
126759
|
function defaultLogFile(dataDir) {
|
|
126606
126760
|
return import_node_path21.default.join(dataDir, "logs", "bridge.log");
|
|
126607
126761
|
}
|
|
@@ -126691,26 +126845,38 @@ function parseProcessedLines(raw, cursor, fileName, fingerprint) {
|
|
|
126691
126845
|
return { entries: [], nextCursor: cursor, advanced: false, reason: "partial_line" };
|
|
126692
126846
|
}
|
|
126693
126847
|
const processed = raw.slice(0, lastNewline + 1);
|
|
126694
|
-
const
|
|
126848
|
+
const linePattern = /.*?\n/g;
|
|
126695
126849
|
const entries = [];
|
|
126696
126850
|
let lineNum = cursor.lineNum;
|
|
126697
|
-
|
|
126698
|
-
|
|
126851
|
+
let offset = cursor.offset;
|
|
126852
|
+
let match;
|
|
126853
|
+
while ((match = linePattern.exec(processed)) !== null) {
|
|
126854
|
+
const rawLine = match[0];
|
|
126855
|
+
const line = rawLine.endsWith("\r\n") ? rawLine.slice(0, -2) : rawLine.slice(0, -1);
|
|
126699
126856
|
lineNum += 1;
|
|
126857
|
+
offset += Buffer.byteLength(rawLine, "utf8");
|
|
126858
|
+
const cursorAfter = {
|
|
126859
|
+
offset,
|
|
126860
|
+
lineNum,
|
|
126861
|
+
...fingerprint ? { fingerprint } : {}
|
|
126862
|
+
};
|
|
126700
126863
|
if (line.length === 0) continue;
|
|
126701
126864
|
const parsed = parseLogLine(line);
|
|
126702
126865
|
if (!parsed) continue;
|
|
126703
126866
|
entries.push({
|
|
126704
|
-
|
|
126705
|
-
|
|
126706
|
-
|
|
126707
|
-
|
|
126867
|
+
entry: {
|
|
126868
|
+
...parsed,
|
|
126869
|
+
raw: line,
|
|
126870
|
+
file: fileName,
|
|
126871
|
+
lineNum
|
|
126872
|
+
},
|
|
126873
|
+
cursorAfter
|
|
126708
126874
|
});
|
|
126709
126875
|
}
|
|
126710
126876
|
return {
|
|
126711
126877
|
entries,
|
|
126712
126878
|
nextCursor: {
|
|
126713
|
-
offset
|
|
126879
|
+
offset,
|
|
126714
126880
|
lineNum,
|
|
126715
126881
|
...fingerprint ? { fingerprint } : {}
|
|
126716
126882
|
},
|
|
@@ -126718,15 +126884,35 @@ function parseProcessedLines(raw, cursor, fileName, fingerprint) {
|
|
|
126718
126884
|
reason: "advanced"
|
|
126719
126885
|
};
|
|
126720
126886
|
}
|
|
126721
|
-
function
|
|
126722
|
-
|
|
126723
|
-
|
|
126724
|
-
|
|
126887
|
+
function logEntryTimeRange(entries) {
|
|
126888
|
+
let minTime = Number.POSITIVE_INFINITY;
|
|
126889
|
+
let maxTime = Number.NEGATIVE_INFINITY;
|
|
126890
|
+
let minTs = "";
|
|
126891
|
+
let maxTs = "";
|
|
126892
|
+
for (const entry of entries) {
|
|
126893
|
+
const parsed = Date.parse(entry.ts);
|
|
126894
|
+
if (!Number.isFinite(parsed)) return null;
|
|
126895
|
+
if (parsed < minTime) {
|
|
126896
|
+
minTime = parsed;
|
|
126897
|
+
minTs = entry.ts;
|
|
126898
|
+
}
|
|
126899
|
+
if (parsed > maxTime) {
|
|
126900
|
+
maxTime = parsed;
|
|
126901
|
+
maxTs = entry.ts;
|
|
126902
|
+
}
|
|
126725
126903
|
}
|
|
126726
|
-
return
|
|
126904
|
+
if (!minTs || !maxTs) return null;
|
|
126905
|
+
return { minTs, maxTs, maxTime };
|
|
126906
|
+
}
|
|
126907
|
+
function isStaleRateLimitedChunk(entries, nowMs) {
|
|
126908
|
+
const range = logEntryTimeRange(entries);
|
|
126909
|
+
if (!range) return null;
|
|
126910
|
+
if (nowMs - range.maxTime <= STALE_RATE_LIMIT_SKIP_AGE_MS) return null;
|
|
126911
|
+
return { minTs: range.minTs, maxTs: range.maxTs };
|
|
126727
126912
|
}
|
|
126728
126913
|
var BridgeLogUploader = class {
|
|
126729
126914
|
options;
|
|
126915
|
+
retryAfterByTarget = /* @__PURE__ */ new Map();
|
|
126730
126916
|
timer = null;
|
|
126731
126917
|
running = false;
|
|
126732
126918
|
stopped = false;
|
|
@@ -126743,7 +126929,7 @@ var BridgeLogUploader = class {
|
|
|
126743
126929
|
bridgeId: options.bridgeId,
|
|
126744
126930
|
hostname: options.hostname,
|
|
126745
126931
|
intervalMs: options.intervalMs ?? DEFAULT_LOG_UPLOAD_INTERVAL_MS,
|
|
126746
|
-
batchSize: options.batchSize ?? DEFAULT_BATCH_SIZE,
|
|
126932
|
+
batchSize: Math.max(1, Math.floor(options.batchSize ?? DEFAULT_BATCH_SIZE)),
|
|
126747
126933
|
primaryTarget,
|
|
126748
126934
|
extraTargets: (options.extraLogFiles ?? []).map((file2) => normalizeTarget(file2, options.dataDir)),
|
|
126749
126935
|
includeRotatedBridgeLogs: options.includeRotatedBridgeLogs ?? true
|
|
@@ -126785,13 +126971,26 @@ var BridgeLogUploader = class {
|
|
|
126785
126971
|
bridgeEntryCount: 0,
|
|
126786
126972
|
uploadedChunkCount: 0,
|
|
126787
126973
|
accepted: 0,
|
|
126788
|
-
skipped: 0
|
|
126974
|
+
skipped: 0,
|
|
126975
|
+
dropped: 0
|
|
126789
126976
|
};
|
|
126790
126977
|
try {
|
|
126791
126978
|
const targets = await this.resolveTargets();
|
|
126792
126979
|
summary.targetCount = targets.length;
|
|
126793
126980
|
for (const target of targets) {
|
|
126981
|
+
const targetKey = this.targetKey(target);
|
|
126794
126982
|
try {
|
|
126983
|
+
const retryUntil = this.retryAfterByTarget.get(targetKey);
|
|
126984
|
+
const now = Date.now();
|
|
126985
|
+
if (retryUntil && retryUntil > now) {
|
|
126986
|
+
summary.idleTargetCount += 1;
|
|
126987
|
+
logger29.debug("Bridge log upload target backoff active", {
|
|
126988
|
+
logFile: target.logFile,
|
|
126989
|
+
retryAfterMs: retryUntil - now
|
|
126990
|
+
});
|
|
126991
|
+
continue;
|
|
126992
|
+
}
|
|
126993
|
+
if (retryUntil) this.retryAfterByTarget.delete(targetKey);
|
|
126795
126994
|
const cursor = await readCursor(target.cursorFile);
|
|
126796
126995
|
const batch = await this.readNewEntries(target, cursor);
|
|
126797
126996
|
if (!batch.advanced) {
|
|
@@ -126803,28 +127002,45 @@ var BridgeLogUploader = class {
|
|
|
126803
127002
|
summary.advancedTargetCount += 1;
|
|
126804
127003
|
summary.parsedEntryCount += batch.entries.length;
|
|
126805
127004
|
if (batch.entries.length > 0) {
|
|
126806
|
-
const result = await this.uploadEntries(batch.entries);
|
|
127005
|
+
const result = await this.uploadEntries(batch.entries, target.cursorFile, batch.nextCursor);
|
|
126807
127006
|
summary.bridgeEntryCount += result.bridgeEntryCount;
|
|
126808
127007
|
summary.uploadedChunkCount += result.uploadedChunkCount;
|
|
126809
127008
|
summary.accepted += result.accepted;
|
|
126810
127009
|
summary.skipped += result.skipped;
|
|
127010
|
+
summary.dropped += result.dropped;
|
|
127011
|
+
} else {
|
|
127012
|
+
await writeCursor(target.cursorFile, batch.nextCursor);
|
|
126811
127013
|
}
|
|
126812
|
-
|
|
127014
|
+
this.retryAfterByTarget.delete(targetKey);
|
|
126813
127015
|
} catch (e) {
|
|
126814
127016
|
summary.failedTargetCount += 1;
|
|
126815
|
-
|
|
127017
|
+
if (e instanceof LogUploadHttpError && e.retryAfterMs !== void 0) {
|
|
127018
|
+
this.retryAfterByTarget.set(targetKey, Date.now() + e.retryAfterMs);
|
|
127019
|
+
logger29.warn("Bridge log upload target failed", {
|
|
127020
|
+
error: e,
|
|
127021
|
+
logFile: target.logFile,
|
|
127022
|
+
status: e.status,
|
|
127023
|
+
quotaScope: e.scope,
|
|
127024
|
+
retryAfterMs: e.retryAfterMs
|
|
127025
|
+
});
|
|
127026
|
+
} else {
|
|
127027
|
+
logger29.warn("Bridge log upload target failed", { error: e, logFile: target.logFile });
|
|
127028
|
+
}
|
|
126816
127029
|
}
|
|
126817
127030
|
}
|
|
126818
127031
|
} catch (e) {
|
|
126819
127032
|
logger29.warn("Bridge log upload cycle failed", { error: e });
|
|
126820
127033
|
} finally {
|
|
126821
|
-
logger29.
|
|
127034
|
+
logger29.debug("Bridge log upload cycle summary", {
|
|
126822
127035
|
...summary,
|
|
126823
127036
|
durationMs: Date.now() - startedAt
|
|
126824
127037
|
});
|
|
126825
127038
|
this.running = false;
|
|
126826
127039
|
}
|
|
126827
127040
|
}
|
|
127041
|
+
targetKey(target) {
|
|
127042
|
+
return `${target.logFile}\0${target.cursorFile}`;
|
|
127043
|
+
}
|
|
126828
127044
|
async resolveTargets() {
|
|
126829
127045
|
const bridgeTargets = this.options.includeRotatedBridgeLogs ? await listRotatedBridgeTargets(this.options.primaryTarget, this.options.dataDir) : [this.options.primaryTarget];
|
|
126830
127046
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -126857,15 +127073,40 @@ var BridgeLogUploader = class {
|
|
|
126857
127073
|
const raw = await readStreamText(target.logFile, normalizedCursor.offset);
|
|
126858
127074
|
return parseProcessedLines(raw, normalizedCursor, target.uploadedFileName, fingerprint);
|
|
126859
127075
|
}
|
|
126860
|
-
|
|
126861
|
-
|
|
127076
|
+
uploadBodyBytes(entries) {
|
|
127077
|
+
return Buffer.byteLength(JSON.stringify({
|
|
127078
|
+
bridgeId: this.options.bridgeId,
|
|
127079
|
+
hostname: this.options.hostname,
|
|
127080
|
+
entries
|
|
127081
|
+
}), "utf8");
|
|
127082
|
+
}
|
|
127083
|
+
chunkUploadEntries(entries) {
|
|
127084
|
+
const chunks = [];
|
|
127085
|
+
let current = [];
|
|
127086
|
+
for (const entry of entries) {
|
|
127087
|
+
const next = [...current, entry];
|
|
127088
|
+
const nextBodyBytes = this.uploadBodyBytes(next.map((item) => item.entry));
|
|
127089
|
+
if (current.length > 0 && (current.length >= this.options.batchSize || nextBodyBytes > MAX_UPLOAD_CHUNK_BODY_BYTES)) {
|
|
127090
|
+
chunks.push(current);
|
|
127091
|
+
current = [entry];
|
|
127092
|
+
} else {
|
|
127093
|
+
current = next;
|
|
127094
|
+
}
|
|
127095
|
+
}
|
|
127096
|
+
if (current.length > 0) chunks.push(current);
|
|
127097
|
+
return chunks;
|
|
127098
|
+
}
|
|
127099
|
+
async uploadEntries(entries, cursorFile, finalCursor) {
|
|
127100
|
+
const bridgeEntries = entries.filter((item) => item.entry.source === "bridge");
|
|
126862
127101
|
const result = {
|
|
126863
127102
|
bridgeEntryCount: bridgeEntries.length,
|
|
126864
127103
|
uploadedChunkCount: 0,
|
|
126865
127104
|
accepted: 0,
|
|
126866
|
-
skipped: 0
|
|
127105
|
+
skipped: 0,
|
|
127106
|
+
dropped: 0
|
|
126867
127107
|
};
|
|
126868
|
-
for (const chunk of
|
|
127108
|
+
for (const chunk of this.chunkUploadEntries(bridgeEntries)) {
|
|
127109
|
+
const payloadEntries = chunk.map((item) => item.entry);
|
|
126869
127110
|
const res = await fetch(`${this.options.serverApiUrl}/api/logs/upload`, {
|
|
126870
127111
|
method: "POST",
|
|
126871
127112
|
headers: {
|
|
@@ -126875,7 +127116,7 @@ var BridgeLogUploader = class {
|
|
|
126875
127116
|
body: JSON.stringify({
|
|
126876
127117
|
bridgeId: this.options.bridgeId,
|
|
126877
127118
|
hostname: this.options.hostname,
|
|
126878
|
-
entries:
|
|
127119
|
+
entries: payloadEntries
|
|
126879
127120
|
})
|
|
126880
127121
|
});
|
|
126881
127122
|
if (!res.ok) {
|
|
@@ -126883,13 +127124,27 @@ var BridgeLogUploader = class {
|
|
|
126883
127124
|
logger29.debug("Failed to read log upload error body", { error: e });
|
|
126884
127125
|
return "";
|
|
126885
127126
|
});
|
|
126886
|
-
|
|
127127
|
+
const staleChunk = res.status === 429 ? isStaleRateLimitedChunk(payloadEntries, Date.now()) : null;
|
|
127128
|
+
if (staleChunk) {
|
|
127129
|
+
result.dropped += chunk.length;
|
|
127130
|
+
logger29.warn("Skipping stale bridge log upload chunk after rate limit", {
|
|
127131
|
+
status: res.status,
|
|
127132
|
+
entryCount: chunk.length,
|
|
127133
|
+
minEntryTs: staleChunk.minTs,
|
|
127134
|
+
maxEntryTs: staleChunk.maxTs
|
|
127135
|
+
});
|
|
127136
|
+
continue;
|
|
127137
|
+
}
|
|
127138
|
+
throw new LogUploadHttpError(res.status, body2);
|
|
126887
127139
|
}
|
|
126888
127140
|
const body = await res.json();
|
|
126889
127141
|
result.uploadedChunkCount += 1;
|
|
126890
127142
|
result.accepted += typeof body.accepted === "number" ? body.accepted : 0;
|
|
126891
127143
|
result.skipped += typeof body.skipped === "number" ? body.skipped : 0;
|
|
127144
|
+
const last = chunk[chunk.length - 1];
|
|
127145
|
+
if (last) await writeCursor(cursorFile, last.cursorAfter);
|
|
126892
127146
|
}
|
|
127147
|
+
await writeCursor(cursorFile, finalCursor);
|
|
126893
127148
|
return result;
|
|
126894
127149
|
}
|
|
126895
127150
|
};
|
|
@@ -126973,7 +127228,7 @@ var SkillStore = class {
|
|
|
126973
127228
|
if (!isNotFoundError(e)) logger30.warn("Skill seed existing read failed", { name, filePath, error: e });
|
|
126974
127229
|
}
|
|
126975
127230
|
if (existing === content) {
|
|
126976
|
-
logger30.
|
|
127231
|
+
logger30.debug("Skill already in sync", { name, bytes: content.length });
|
|
126977
127232
|
return;
|
|
126978
127233
|
}
|
|
126979
127234
|
import_node_fs12.default.writeFileSync(tmpPath, content, "utf-8");
|