@qlingzzy/qling 1.0.0 → 1.1.1
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/CHANGELOG.md +158 -0
- package/README.en.md +83 -18
- package/README.md +19 -9
- package/dist/agent/main-loop.d.ts +120 -0
- package/dist/agent/main-loop.d.ts.map +1 -0
- package/dist/agent/main-loop.js +279 -0
- package/dist/agent/subtask-parallel.d.ts +29 -0
- package/dist/agent/subtask-parallel.d.ts.map +1 -0
- package/dist/agent/subtask-parallel.js +107 -0
- package/dist/agent/subtask.d.ts +13 -0
- package/dist/agent/subtask.d.ts.map +1 -1
- package/dist/agent/subtask.js +79 -24
- package/dist/agent/system-prompt.d.ts +39 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +89 -0
- package/dist/agent/tool-orchestrator.d.ts +66 -0
- package/dist/agent/tool-orchestrator.d.ts.map +1 -0
- package/dist/agent/tool-orchestrator.js +355 -0
- package/dist/agent-loop.d.ts +29 -16
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +262 -807
- package/dist/agents/roles.d.ts +57 -0
- package/dist/agents/roles.d.ts.map +1 -0
- package/dist/agents/roles.js +198 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +17 -3
- package/dist/commands/claude-style.d.ts.map +1 -1
- package/dist/commands/claude-style.js +19 -10
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +3 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/mode.d.ts +16 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +67 -0
- package/dist/commands/recover.d.ts +3 -0
- package/dist/commands/recover.d.ts.map +1 -0
- package/dist/commands/recover.js +69 -0
- package/dist/commands/runtime.d.ts +2 -0
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +2 -0
- package/dist/commands/trace.d.ts +3 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +45 -0
- package/dist/commands/verify.js +2 -2
- package/dist/config-report.d.ts +0 -1
- package/dist/config-report.d.ts.map +1 -1
- package/dist/config-report.js +1 -2
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -1
- package/dist/context-report.d.ts +13 -7
- package/dist/context-report.d.ts.map +1 -1
- package/dist/context-report.js +64 -61
- package/dist/context-tool-hygiene.d.ts +36 -0
- package/dist/context-tool-hygiene.d.ts.map +1 -0
- package/dist/context-tool-hygiene.js +125 -0
- package/dist/dashboard/client.d.ts +2 -0
- package/dist/dashboard/client.d.ts.map +1 -0
- package/dist/dashboard/client.js +305 -0
- package/dist/dashboard/model.d.ts +13 -0
- package/dist/dashboard/model.d.ts.map +1 -0
- package/dist/dashboard/model.js +112 -0
- package/dist/dashboard/page.d.ts +3 -0
- package/dist/dashboard/page.d.ts.map +1 -0
- package/dist/dashboard/page.js +204 -0
- package/dist/dashboard/types.d.ts +63 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/types.js +1 -0
- package/dist/dashboard-server.d.ts +24 -4
- package/dist/dashboard-server.d.ts.map +1 -1
- package/dist/dashboard-server.js +397 -302
- package/dist/discovery-registry.d.ts +17 -3
- package/dist/discovery-registry.d.ts.map +1 -1
- package/dist/discovery-registry.js +78 -3
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +116 -0
- package/dist/eval/llm-tasks.d.ts +5 -0
- package/dist/eval/llm-tasks.d.ts.map +1 -0
- package/dist/eval/llm-tasks.js +125 -0
- package/dist/eval/repo-tasks.d.ts +12 -0
- package/dist/eval/repo-tasks.d.ts.map +1 -0
- package/dist/eval/repo-tasks.js +220 -0
- package/dist/eval/runner.d.ts +3 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +23 -4
- package/dist/eval/tasks.d.ts.map +1 -1
- package/dist/eval/tasks.js +186 -0
- package/dist/eval/types.d.ts +8 -5
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/execution/event-bus.d.ts +44 -0
- package/dist/execution/event-bus.d.ts.map +1 -0
- package/dist/execution/event-bus.js +76 -0
- package/dist/execution/failure-classifier.d.ts +11 -0
- package/dist/execution/failure-classifier.d.ts.map +1 -0
- package/dist/execution/failure-classifier.js +66 -0
- package/dist/execution/progress-detector.d.ts +3 -0
- package/dist/execution/progress-detector.d.ts.map +1 -0
- package/dist/execution/progress-detector.js +23 -0
- package/dist/execution/recovery-controller.d.ts +24 -0
- package/dist/execution/recovery-controller.d.ts.map +1 -0
- package/dist/execution/recovery-controller.js +114 -0
- package/dist/execution/recovery-messages.d.ts +24 -0
- package/dist/execution/recovery-messages.d.ts.map +1 -0
- package/dist/execution/recovery-messages.js +48 -0
- package/dist/execution/recovery-metrics.d.ts +16 -0
- package/dist/execution/recovery-metrics.d.ts.map +1 -0
- package/dist/execution/recovery-metrics.js +73 -0
- package/dist/execution/recovery-strategy-planner.d.ts +6 -0
- package/dist/execution/recovery-strategy-planner.d.ts.map +1 -0
- package/dist/execution/recovery-strategy-planner.js +24 -0
- package/dist/execution/run-trace-store.d.ts +29 -0
- package/dist/execution/run-trace-store.d.ts.map +1 -0
- package/dist/execution/run-trace-store.js +140 -0
- package/dist/execution/staged-verifier.d.ts +33 -0
- package/dist/execution/staged-verifier.d.ts.map +1 -0
- package/dist/execution/staged-verifier.js +39 -0
- package/dist/execution/types.d.ts +58 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +1 -0
- package/dist/execution/verification-loop.d.ts +58 -0
- package/dist/execution/verification-loop.d.ts.map +1 -0
- package/dist/execution/verification-loop.js +195 -0
- package/dist/execution/verification-stages.d.ts +17 -0
- package/dist/execution/verification-stages.d.ts.map +1 -0
- package/dist/execution/verification-stages.js +102 -0
- package/dist/help-topics.d.ts.map +1 -1
- package/dist/help-topics.js +11 -0
- package/dist/index.js +0 -8
- package/dist/lsp/ts-service.d.ts +36 -0
- package/dist/lsp/ts-service.d.ts.map +1 -0
- package/dist/lsp/ts-service.js +291 -0
- package/dist/memory/lifecycle.d.ts +19 -0
- package/dist/memory/lifecycle.d.ts.map +1 -0
- package/dist/memory/lifecycle.js +53 -0
- package/dist/memory.d.ts +0 -16
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +0 -36
- package/dist/metrics/collector.d.ts +7 -0
- package/dist/metrics/collector.d.ts.map +1 -1
- package/dist/metrics/collector.js +60 -0
- package/dist/mission/manager.d.ts +1 -0
- package/dist/mission/manager.d.ts.map +1 -1
- package/dist/mission/manager.js +9 -0
- package/dist/mission/progress-notify.d.ts +39 -0
- package/dist/mission/progress-notify.d.ts.map +1 -0
- package/dist/mission/progress-notify.js +386 -0
- package/dist/pipeline/hooks.d.ts +1 -1
- package/dist/pipeline/hooks.d.ts.map +1 -1
- package/dist/pipeline/hooks.js +1 -0
- package/dist/pipeline/sections.d.ts +8 -4
- package/dist/pipeline/sections.d.ts.map +1 -1
- package/dist/pipeline/sections.js +70 -27
- package/dist/pipeline/verification.d.ts +1 -0
- package/dist/pipeline/verification.d.ts.map +1 -1
- package/dist/pipeline/verification.js +10 -7
- package/dist/providers/llm-client.d.ts +38 -0
- package/dist/providers/llm-client.d.ts.map +1 -0
- package/dist/providers/llm-client.js +105 -0
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +1 -0
- package/dist/session/durable-session-supervisor.d.ts.map +1 -1
- package/dist/session/durable-session-supervisor.js +13 -6
- package/dist/session/session-persistence.d.ts +29 -0
- package/dist/session/session-persistence.d.ts.map +1 -0
- package/dist/session/session-persistence.js +45 -0
- package/dist/session/session-scheduler.d.ts +8 -1
- package/dist/session/session-scheduler.d.ts.map +1 -1
- package/dist/session/session-scheduler.js +33 -4
- package/dist/session-task-report.d.ts +1 -0
- package/dist/session-task-report.d.ts.map +1 -1
- package/dist/session-task-report.js +2 -1
- package/dist/shortcuts.d.ts.map +1 -1
- package/dist/shortcuts.js +1 -0
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +10 -0
- package/dist/skills/security-scan.d.ts +15 -0
- package/dist/skills/security-scan.d.ts.map +1 -0
- package/dist/skills/security-scan.js +95 -0
- package/dist/skills/types.d.ts +2 -0
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/statusline.d.ts +3 -3
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +9 -17
- package/dist/token-usage.d.ts +27 -0
- package/dist/token-usage.d.ts.map +1 -0
- package/dist/token-usage.js +107 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +5 -3
- package/dist/tools/browser-act-session.d.ts +48 -0
- package/dist/tools/browser-act-session.d.ts.map +1 -0
- package/dist/tools/browser-act-session.js +168 -0
- package/dist/tools/browser-act.d.ts +14 -0
- package/dist/tools/browser-act.d.ts.map +1 -0
- package/dist/tools/browser-act.js +297 -0
- package/dist/tools/code-symbols.d.ts +35 -0
- package/dist/tools/code-symbols.d.ts.map +1 -0
- package/dist/tools/code-symbols.js +257 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +22 -2
- package/dist/tools/lsp.d.ts +13 -0
- package/dist/tools/lsp.d.ts.map +1 -0
- package/dist/tools/lsp.js +136 -0
- package/dist/tools/patch.d.ts +5 -0
- package/dist/tools/patch.d.ts.map +1 -1
- package/dist/tools/patch.js +25 -4
- package/dist/tools/search.d.ts +7 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +20 -3
- package/dist/tools/skill.d.ts +2 -0
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +47 -14
- package/dist/tools/subtask.d.ts +3 -1
- package/dist/tools/subtask.d.ts.map +1 -1
- package/dist/tools/subtask.js +151 -56
- package/dist/tui/shell.d.ts +12 -0
- package/dist/tui/shell.d.ts.map +1 -1
- package/dist/tui/shell.js +36 -3
- package/dist/tui/streaming-repl.d.ts +1 -0
- package/dist/tui/streaming-repl.d.ts.map +1 -1
- package/dist/tui/streaming-repl.js +27 -4
- package/dist/tui/streaming-tui.d.ts +10 -0
- package/dist/tui/streaming-tui.d.ts.map +1 -1
- package/dist/tui/streaming-tui.js +70 -12
- package/dist/types.d.ts +0 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-runtime.d.ts.map +1 -1
- package/dist/workflow-runtime.js +10 -2
- package/dist/workflow-types.d.ts +2 -0
- package/dist/workflow-types.d.ts.map +1 -1
- package/docs/install.md +46 -12
- package/docs/skills.md +56 -7
- package/docs/web-routing.md +83 -0
- package/package.json +18 -4
- package/scripts/dep-layers.mjs +275 -0
- package/scripts/eval-llm.mjs +27 -0
- package/scripts/eval-recovery.mjs +101 -0
- package/scripts/eval-tasks.mjs +20 -0
- package/scripts/validate-packaging.mjs +57 -0
- package/skills/examples/README.md +23 -0
- package/skills/examples/add-function/SKILL.md +31 -0
- package/skills/examples/fix-failing-test/SKILL.md +32 -0
- package/skills/examples/pr-summary/SKILL.md +34 -0
- package/skills/lifecycle-build/SKILL.md +22 -0
- package/skills/lifecycle-plan/SKILL.md +32 -0
- package/skills/lifecycle-review/SKILL.md +25 -0
- package/skills/lifecycle-ship/SKILL.md +22 -0
- package/skills/lifecycle-spec/SKILL.md +24 -0
- package/skills/lifecycle-test/SKILL.md +21 -0
- package/skills/opencli/SKILL.md +222 -0
- package/skills/qling.md +14 -3
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Agent 主循环:外层 transport 恢复 + 内层 turn 迭代(从 AgentLoop 抽出)
|
|
3
|
+
// ============================================================
|
|
4
|
+
import { resolveRoundTokenUsage, } from "../token-usage.js";
|
|
5
|
+
import { classifyFailure } from "../execution/failure-classifier.js";
|
|
6
|
+
import { executePreparedTools, prepareToolCalls, } from "./tool-orchestrator.js";
|
|
7
|
+
import { runWriteToolVerification } from "../execution/verification-loop.js";
|
|
8
|
+
import { findLastUserMessageContent } from "./system-prompt.js";
|
|
9
|
+
export function applyProviderUsage(counters, usage) {
|
|
10
|
+
const tokenUsage = resolveRoundTokenUsage(usage);
|
|
11
|
+
if (tokenUsage.source !== "provider")
|
|
12
|
+
return counters;
|
|
13
|
+
return {
|
|
14
|
+
sessionTokens: counters.sessionTokens + tokenUsage.tokens,
|
|
15
|
+
sessionPromptTokens: counters.sessionPromptTokens + tokenUsage.promptTokens,
|
|
16
|
+
sessionCompletionTokens: counters.sessionCompletionTokens + tokenUsage.completionTokens,
|
|
17
|
+
tokenUsageSource: "provider",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function logTurnTelemetry(metrics, totals) {
|
|
21
|
+
const toolCallTotal = totals.toolCallTotal + metrics.toolCalls;
|
|
22
|
+
const toolFailureTotal = totals.toolFailureTotal + metrics.toolFailures;
|
|
23
|
+
const turnFailureRate = metrics.toolCalls === 0 ? 0 : Math.round((metrics.toolFailures / metrics.toolCalls) * 100);
|
|
24
|
+
const totalFailureRate = toolCallTotal === 0 ? 0 : Math.round((toolFailureTotal / toolCallTotal) * 100);
|
|
25
|
+
if (totals.format === "json") {
|
|
26
|
+
console.error(JSON.stringify({
|
|
27
|
+
type: "observability",
|
|
28
|
+
turn: metrics.turn,
|
|
29
|
+
toolCalls: metrics.toolCalls,
|
|
30
|
+
turnFailureRate,
|
|
31
|
+
totalFailureRate,
|
|
32
|
+
compactions: totals.compactionCount,
|
|
33
|
+
retries: totals.retryCountTotal,
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error("📊 [Obs] turn=" +
|
|
38
|
+
metrics.turn +
|
|
39
|
+
" tools=" +
|
|
40
|
+
metrics.toolCalls +
|
|
41
|
+
" turnFailRate=" +
|
|
42
|
+
turnFailureRate +
|
|
43
|
+
"% totalFailRate=" +
|
|
44
|
+
totalFailureRate +
|
|
45
|
+
"% compactions=" +
|
|
46
|
+
totals.compactionCount +
|
|
47
|
+
" retries=" +
|
|
48
|
+
totals.retryCountTotal);
|
|
49
|
+
}
|
|
50
|
+
return { toolCallTotal, toolFailureTotal };
|
|
51
|
+
}
|
|
52
|
+
function toolMessageIsError(messages, toolCallId) {
|
|
53
|
+
for (const m of messages) {
|
|
54
|
+
if (m.tool_call_id !== toolCallId || m.role !== "tool")
|
|
55
|
+
continue;
|
|
56
|
+
try {
|
|
57
|
+
return Boolean(JSON.parse(m.content).is_error);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
export function distillSuccessfulBashPractices(preparedCalls, messages, memoryStore) {
|
|
66
|
+
const hasError = preparedCalls.some((p) => Boolean(p.immediateResult?.is_error) ||
|
|
67
|
+
(p.call.id ? toolMessageIsError(messages, p.call.id) : false));
|
|
68
|
+
if (hasError)
|
|
69
|
+
return;
|
|
70
|
+
const successfulCmds = preparedCalls
|
|
71
|
+
.filter((p) => p.call.name === "bash")
|
|
72
|
+
.map((p) => {
|
|
73
|
+
const args = p.call.arguments;
|
|
74
|
+
return args.cmd || args.command;
|
|
75
|
+
})
|
|
76
|
+
.filter((cmd) => Boolean(cmd));
|
|
77
|
+
if (successfulCmds.length === 0)
|
|
78
|
+
return;
|
|
79
|
+
const lastUserMsg = findLastUserMessageContent(messages);
|
|
80
|
+
const files = preparedCalls
|
|
81
|
+
.map((p) => {
|
|
82
|
+
const args = p.call.arguments;
|
|
83
|
+
return args.path || args.file;
|
|
84
|
+
})
|
|
85
|
+
.filter((f) => Boolean(f));
|
|
86
|
+
memoryStore.addPractice(lastUserMsg.slice(0, 100), successfulCmds, files);
|
|
87
|
+
console.error(`✨ [认知] 已将 ${successfulCmds.length} 条成功指令蒸馏为最佳实践`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Inner maxIterations loop: compact → prompt → chat → tools → verify.
|
|
91
|
+
* Mutates host.messages / counters / turnCount in place.
|
|
92
|
+
*/
|
|
93
|
+
export async function runInnerIterationLoop(host) {
|
|
94
|
+
const toolSignatureCounts = new Map();
|
|
95
|
+
for (let i = 0; i < host.maxIterations; i++) {
|
|
96
|
+
host.turnCount++;
|
|
97
|
+
const runId = host.activeRunId ?? `run_untracked_${host.turnCount}`;
|
|
98
|
+
const attemptId = `attempt_${runId}_${host.turnCount}`;
|
|
99
|
+
host.executionEventBus.startAttempt({ runId, sessionId: host.sessionId, attemptId });
|
|
100
|
+
const lastUserMsg = findLastUserMessageContent(host.messages);
|
|
101
|
+
if (host.compactor.needsCompaction(host.messages)) {
|
|
102
|
+
console.error("\n📦 上下文压缩中...(" + host.messages.length + " 条消息)");
|
|
103
|
+
const compacted = await host.compactor.compact(host.messages);
|
|
104
|
+
host.messages.splice(0, host.messages.length, ...compacted);
|
|
105
|
+
host.compactionCount++;
|
|
106
|
+
console.error("📦 压缩完成 → " + host.messages.length + " 条消息\n");
|
|
107
|
+
}
|
|
108
|
+
const conflicts = host.compactor.scanConflicts(host.messages);
|
|
109
|
+
if (conflicts.length > 0) {
|
|
110
|
+
console.error("⚠️ 检测到 " + conflicts.length + " 处指令冲突");
|
|
111
|
+
}
|
|
112
|
+
const poison = host.compactor.scanPoison(host.messages);
|
|
113
|
+
if (poison.length > 0) {
|
|
114
|
+
console.error("🚨 检测到 " + poison.length + " 处可能的提示注入");
|
|
115
|
+
}
|
|
116
|
+
const systemPrompt = await host.buildSystemPrompt();
|
|
117
|
+
if (process.env.QLING_FEATURES_WORKFLOW_RUNTIME === "true") {
|
|
118
|
+
await host.workflowRuntime.updateContext(host.messages);
|
|
119
|
+
}
|
|
120
|
+
const { content, tool_calls, usage } = await host.chat(systemPrompt);
|
|
121
|
+
host.counters = applyProviderUsage(host.counters, usage);
|
|
122
|
+
host.messages.push({ role: "assistant", content, tool_calls });
|
|
123
|
+
host.emit("thinking", content || "正在思考...");
|
|
124
|
+
if (!tool_calls || tool_calls.length === 0) {
|
|
125
|
+
host.knowledgeAdapter.onAssistantMessage(content);
|
|
126
|
+
await host.checkAutoDream();
|
|
127
|
+
await host.knowledgeAdapter.onTurnEnd(host.turnCount);
|
|
128
|
+
const totals = logTurnTelemetry({ turn: host.turnCount, toolCalls: 0, toolFailures: 0 }, {
|
|
129
|
+
toolCallTotal: host.toolCallTotal,
|
|
130
|
+
toolFailureTotal: host.toolFailureTotal,
|
|
131
|
+
compactionCount: host.compactionCount,
|
|
132
|
+
retryCountTotal: host.retryCountTotal,
|
|
133
|
+
format: host.loggingFormat,
|
|
134
|
+
});
|
|
135
|
+
host.toolCallTotal = totals.toolCallTotal;
|
|
136
|
+
host.toolFailureTotal = totals.toolFailureTotal;
|
|
137
|
+
host.executionEventBus.completeAttempt(runId, "succeeded");
|
|
138
|
+
return content;
|
|
139
|
+
}
|
|
140
|
+
console.error("\n🔧 执行 " + tool_calls.length + " 个工具...\n");
|
|
141
|
+
const preparedCalls = prepareToolCalls(tool_calls, {
|
|
142
|
+
parseRetries: host.parseRetries,
|
|
143
|
+
toolRepeatLimit: host.toolRepeatLimit,
|
|
144
|
+
signatureCounts: toolSignatureCounts,
|
|
145
|
+
});
|
|
146
|
+
const { turnToolCalls, turnToolFailures } = await executePreparedTools({
|
|
147
|
+
pipeline: host.pipeline,
|
|
148
|
+
tools: host.tools,
|
|
149
|
+
guardConfig: host.guardConfig,
|
|
150
|
+
channel: host.channel,
|
|
151
|
+
approvalGate: host.approvalGate,
|
|
152
|
+
knowledgeAdapter: host.knowledgeAdapter,
|
|
153
|
+
memoryStore: host.memoryStore,
|
|
154
|
+
workspaceDir: host.workspaceDir,
|
|
155
|
+
workflowRuntime: host.workflowRuntime,
|
|
156
|
+
executionEventBus: host.executionEventBus,
|
|
157
|
+
emit: host.emit,
|
|
158
|
+
reflectiveThink: host.reflectiveThink,
|
|
159
|
+
}, {
|
|
160
|
+
preparedCalls,
|
|
161
|
+
messages: host.messages,
|
|
162
|
+
runId,
|
|
163
|
+
attemptId,
|
|
164
|
+
});
|
|
165
|
+
const verifyOutcome = await runWriteToolVerification(preparedCalls, {
|
|
166
|
+
verificationCommand: host.verificationCommand,
|
|
167
|
+
runCommand: host.runVerificationCommand,
|
|
168
|
+
recoveryController: host.recoveryController,
|
|
169
|
+
executionEventBus: host.executionEventBus,
|
|
170
|
+
emit: host.emit,
|
|
171
|
+
getRecoveryState: host.getRecoveryState,
|
|
172
|
+
verifier: host.verifier,
|
|
173
|
+
messages: host.messages,
|
|
174
|
+
runId,
|
|
175
|
+
});
|
|
176
|
+
if (verifyOutcome.kind === "pause") {
|
|
177
|
+
return verifyOutcome.text;
|
|
178
|
+
}
|
|
179
|
+
if (verifyOutcome.kind === "recover") {
|
|
180
|
+
host.messages.push({ role: "user", content: verifyOutcome.userMessage });
|
|
181
|
+
host.emit("repair", verifyOutcome.failureMessage, verifyOutcome.strategy, verifyOutcome.strategyAttempts);
|
|
182
|
+
host.executionEventBus.completeAttempt(runId, "recovering");
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
await host.checkAutoDream();
|
|
186
|
+
if (host.turnCount > 0) {
|
|
187
|
+
distillSuccessfulBashPractices(preparedCalls, host.messages, host.memoryStore);
|
|
188
|
+
}
|
|
189
|
+
host.memoryStore.addConversationTurn("user", lastUserMsg);
|
|
190
|
+
host.memoryStore.addConversationTurn("assistant", content);
|
|
191
|
+
host.knowledgeAdapter.onAssistantMessage(content);
|
|
192
|
+
await host.knowledgeAdapter.onTurnEnd(host.turnCount);
|
|
193
|
+
const totals = logTurnTelemetry({ turn: host.turnCount, toolCalls: turnToolCalls, toolFailures: turnToolFailures }, {
|
|
194
|
+
toolCallTotal: host.toolCallTotal,
|
|
195
|
+
toolFailureTotal: host.toolFailureTotal,
|
|
196
|
+
compactionCount: host.compactionCount,
|
|
197
|
+
retryCountTotal: host.retryCountTotal,
|
|
198
|
+
format: host.loggingFormat,
|
|
199
|
+
});
|
|
200
|
+
host.toolCallTotal = totals.toolCallTotal;
|
|
201
|
+
host.toolFailureTotal = totals.toolFailureTotal;
|
|
202
|
+
host.executionEventBus.completeAttempt(runId, "succeeded");
|
|
203
|
+
}
|
|
204
|
+
return "⚠️ 达到最大迭代次数,任务未完成。";
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Outer loop: start run, handle provider transport retries + recovery strategy.
|
|
208
|
+
*/
|
|
209
|
+
export async function runOuterAgentLoop(host) {
|
|
210
|
+
const recoveryState = host.getRecoveryState();
|
|
211
|
+
const resumable = host.activeRun && recoveryState?.status === "recovering";
|
|
212
|
+
const originalTask = resumable
|
|
213
|
+
? host.activeRun.originalTask
|
|
214
|
+
: findLastUserMessageContent(host.messages);
|
|
215
|
+
const runId = resumable
|
|
216
|
+
? host.activeRun.runId
|
|
217
|
+
: `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;
|
|
218
|
+
if (!resumable) {
|
|
219
|
+
host.setActiveRun({
|
|
220
|
+
runId,
|
|
221
|
+
sessionId: host.sessionId,
|
|
222
|
+
originalTask,
|
|
223
|
+
startedAt: Date.now(),
|
|
224
|
+
});
|
|
225
|
+
host.recoveryController.startRun({ runId, sessionId: host.sessionId, originalTask });
|
|
226
|
+
host.executionEventBus.startRun({ runId, sessionId: host.sessionId });
|
|
227
|
+
}
|
|
228
|
+
let transportAttempts = 0;
|
|
229
|
+
while (true) {
|
|
230
|
+
try {
|
|
231
|
+
const response = await host.executeInner();
|
|
232
|
+
if (host.getRecoveryState()?.status === "paused")
|
|
233
|
+
return response;
|
|
234
|
+
host.executionEventBus.completeRun(runId, "succeeded");
|
|
235
|
+
host.setActiveRun(null);
|
|
236
|
+
return response;
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
host.executionEventBus.completeAttempt(runId, "failed");
|
|
240
|
+
const failure = classifyFailure(error, { provider: true });
|
|
241
|
+
if (failure.category === "provider_transient" && transportAttempts < 3) {
|
|
242
|
+
transportAttempts++;
|
|
243
|
+
const delay = Math.min(4_000, 250 * 2 ** (transportAttempts - 1)) + Math.floor(Math.random() * 100);
|
|
244
|
+
host.executionEventBus.emit({
|
|
245
|
+
runId,
|
|
246
|
+
sessionId: host.sessionId,
|
|
247
|
+
type: "recovery_started",
|
|
248
|
+
status: "recovering",
|
|
249
|
+
stage: "provider",
|
|
250
|
+
category: failure.category,
|
|
251
|
+
fingerprint: failure.fingerprint,
|
|
252
|
+
recoveryAction: "transport_retry",
|
|
253
|
+
});
|
|
254
|
+
host.emit("repair", failure.message, "provider transport retry", transportAttempts);
|
|
255
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const decision = host.recoveryController.recordFailure(failure, {});
|
|
259
|
+
const state = host.recoveryController.getRecoveryState();
|
|
260
|
+
host.executionEventBus.emit({
|
|
261
|
+
runId,
|
|
262
|
+
sessionId: host.sessionId,
|
|
263
|
+
type: "failure",
|
|
264
|
+
status: decision.action === "pause" ? "paused" : "recovering",
|
|
265
|
+
stage: "agent",
|
|
266
|
+
category: decision.category,
|
|
267
|
+
fingerprint: failure.fingerprint,
|
|
268
|
+
recoveryAction: decision.recommendedStrategy ?? decision.action,
|
|
269
|
+
});
|
|
270
|
+
host.emit("recovery_paused", state, decision);
|
|
271
|
+
if (decision.action === "pause") {
|
|
272
|
+
return host.formatRecoveryPause(failure.message, decision.reason);
|
|
273
|
+
}
|
|
274
|
+
await host.applyRecoveryStrategy(failure, decision.recommendedStrategy);
|
|
275
|
+
host.emit("repair", failure.message, decision.recommendedStrategy ?? decision.reason, state.strategyAttempts);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SubtaskResult } from "./subtask.js";
|
|
2
|
+
import { type SubAgentRole } from "../agents/roles.js";
|
|
3
|
+
export declare function isSubtaskParallelEnabled(env?: NodeJS.ProcessEnv | Record<string, string | undefined>): boolean;
|
|
4
|
+
export declare function resolveParallelMax(env?: NodeJS.ProcessEnv | Record<string, string | undefined>): number;
|
|
5
|
+
/**
|
|
6
|
+
* 解析并行任务列表:优先 tasks 数组,否则空。
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseParallelTasks(raw: unknown): string[];
|
|
9
|
+
export interface ParallelExploreGate {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
errorCode?: string;
|
|
12
|
+
errorMessage?: string;
|
|
13
|
+
tasks: string[];
|
|
14
|
+
role: SubAgentRole;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 校验是否允许并行:仅 explore/review 只读角色;须显式开启。
|
|
18
|
+
*/
|
|
19
|
+
export declare function gateParallelExplore(options: {
|
|
20
|
+
tasks: string[];
|
|
21
|
+
role?: unknown;
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
max?: number;
|
|
24
|
+
}): ParallelExploreGate;
|
|
25
|
+
export declare function formatParallelExploreReport(results: Array<{
|
|
26
|
+
task: string;
|
|
27
|
+
result: SubtaskResult;
|
|
28
|
+
}>): string;
|
|
29
|
+
//# sourceMappingURL=subtask-parallel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subtask-parallel.d.ts","sourceRoot":"","sources":["../../src/agent/subtask-parallel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAI9E,wBAAgB,wBAAwB,CACtC,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxE,OAAO,CAGT;AAED,wBAAgB,kBAAkB,CAChC,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxE,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAsBzD;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,mBAAmB,CAiDtB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,GACtD,MAAM,CAeR"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Phase 3.2+ — 只读 explore 并行(默认关闭)
|
|
3
|
+
// 启用:QLING_SUBTASK_PARALLEL=1
|
|
4
|
+
// ============================================================
|
|
5
|
+
import { normalizeSubAgentRole } from "../agents/roles.js";
|
|
6
|
+
const ENABLED = new Set(["1", "true", "on", "yes"]);
|
|
7
|
+
export function isSubtaskParallelEnabled(env = process.env) {
|
|
8
|
+
const raw = String(env.QLING_SUBTASK_PARALLEL ?? "").trim().toLowerCase();
|
|
9
|
+
return ENABLED.has(raw);
|
|
10
|
+
}
|
|
11
|
+
export function resolveParallelMax(env = process.env) {
|
|
12
|
+
const n = Number(env.QLING_SUBTASK_PARALLEL_MAX ?? 3);
|
|
13
|
+
if (!Number.isFinite(n) || n < 1)
|
|
14
|
+
return 3;
|
|
15
|
+
return Math.min(5, Math.floor(n));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 解析并行任务列表:优先 tasks 数组,否则空。
|
|
19
|
+
*/
|
|
20
|
+
export function parseParallelTasks(raw) {
|
|
21
|
+
if (!raw)
|
|
22
|
+
return [];
|
|
23
|
+
if (Array.isArray(raw)) {
|
|
24
|
+
return raw.map((t) => String(t ?? "").trim()).filter(Boolean);
|
|
25
|
+
}
|
|
26
|
+
if (typeof raw === "string") {
|
|
27
|
+
const s = raw.trim();
|
|
28
|
+
if (!s)
|
|
29
|
+
return [];
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(s);
|
|
32
|
+
if (Array.isArray(parsed)) {
|
|
33
|
+
return parsed.map((t) => String(t ?? "").trim()).filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// 按换行或 || 分割
|
|
38
|
+
return s
|
|
39
|
+
.split(/\n+|\|\|/)
|
|
40
|
+
.map((t) => t.trim())
|
|
41
|
+
.filter(Boolean);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 校验是否允许并行:仅 explore/review 只读角色;须显式开启。
|
|
48
|
+
*/
|
|
49
|
+
export function gateParallelExplore(options) {
|
|
50
|
+
const enabled = options.enabled ?? isSubtaskParallelEnabled();
|
|
51
|
+
const max = options.max ?? resolveParallelMax();
|
|
52
|
+
const tasks = options.tasks.filter(Boolean);
|
|
53
|
+
const role = normalizeSubAgentRole(options.role ?? "explore");
|
|
54
|
+
if (tasks.length === 0) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
errorCode: "SUBTASK_PARALLEL_EMPTY",
|
|
58
|
+
errorMessage: "tasks 为空",
|
|
59
|
+
tasks: [],
|
|
60
|
+
role,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (!enabled) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
errorCode: "SUBTASK_PARALLEL_DISABLED",
|
|
67
|
+
errorMessage: "并行 subtask 默认关闭。启用: QLING_SUBTASK_PARALLEL=1(仅 explore/review 只读角色)",
|
|
68
|
+
tasks,
|
|
69
|
+
role,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (role === "implement") {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
errorCode: "SUBTASK_PARALLEL_ROLE",
|
|
76
|
+
errorMessage: "并行仅允许 role=explore 或 review(只读)。写操作必须串行 implement。",
|
|
77
|
+
tasks,
|
|
78
|
+
role,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (tasks.length > max) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
errorCode: "SUBTASK_PARALLEL_TOO_MANY",
|
|
85
|
+
errorMessage: `并行任务过多: ${tasks.length} > max ${max}(QLING_SUBTASK_PARALLEL_MAX)`,
|
|
86
|
+
tasks,
|
|
87
|
+
role,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return { ok: true, tasks, role };
|
|
91
|
+
}
|
|
92
|
+
export function formatParallelExploreReport(results) {
|
|
93
|
+
const lines = [
|
|
94
|
+
"【并行探索回传】",
|
|
95
|
+
`count: ${results.length}`,
|
|
96
|
+
`ok: ${results.filter((r) => r.result.success).length}`,
|
|
97
|
+
`fail: ${results.filter((r) => !r.result.success).length}`,
|
|
98
|
+
"",
|
|
99
|
+
];
|
|
100
|
+
results.forEach((item, i) => {
|
|
101
|
+
lines.push(`--- task[${i + 1}] ${item.result.success ? "OK" : "FAIL"} ---`);
|
|
102
|
+
lines.push(`goal: ${item.task.slice(0, 200)}`);
|
|
103
|
+
lines.push(item.result.contractText || item.result.output);
|
|
104
|
+
lines.push("");
|
|
105
|
+
});
|
|
106
|
+
return lines.join("\n").trim();
|
|
107
|
+
}
|
package/dist/agent/subtask.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentConfig } from "../types.js";
|
|
2
|
+
import { type SubAgentRole } from "../agents/roles.js";
|
|
2
3
|
export interface SubtaskConfig {
|
|
3
4
|
task: string;
|
|
4
5
|
parentContext?: string;
|
|
@@ -6,16 +7,28 @@ export interface SubtaskConfig {
|
|
|
6
7
|
depth?: number;
|
|
7
8
|
tools?: AgentConfig["tools"];
|
|
8
9
|
timeoutMs?: number;
|
|
10
|
+
/** explore | implement | review */
|
|
11
|
+
role?: SubAgentRole | string;
|
|
9
12
|
}
|
|
10
13
|
export interface SubtaskResult {
|
|
11
14
|
success: boolean;
|
|
12
15
|
output: string;
|
|
13
16
|
iterations: number;
|
|
14
17
|
durationMs: number;
|
|
18
|
+
role: SubAgentRole;
|
|
19
|
+
filesTouched: string[];
|
|
20
|
+
/** 已格式化的回传契约(父代理应优先使用) */
|
|
21
|
+
contractText: string;
|
|
15
22
|
}
|
|
23
|
+
interface TimeoutController {
|
|
24
|
+
setTimeout(callback: () => void, timeoutMs: number): unknown;
|
|
25
|
+
clearTimeout(handle: unknown): void;
|
|
26
|
+
}
|
|
27
|
+
export declare function runWithTimeout<T>(operation: Promise<T>, timeoutMs: number, timers?: TimeoutController): Promise<T>;
|
|
16
28
|
export declare class SubtaskRunner {
|
|
17
29
|
private parentConfig;
|
|
18
30
|
constructor(parentConfig: Partial<AgentConfig>);
|
|
19
31
|
run(config: SubtaskConfig): Promise<SubtaskResult>;
|
|
20
32
|
}
|
|
33
|
+
export {};
|
|
21
34
|
//# sourceMappingURL=subtask.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtask.d.ts","sourceRoot":"","sources":["../../src/agent/subtask.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"subtask.d.ts","sourceRoot":"","sources":["../../src/agent/subtask.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EACL,KAAK,YAAY,EAOlB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,iBAAiB;IACzB,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7D,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;CACrC;AAOD,wBAAsB,cAAc,CAAC,CAAC,EACpC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EACrB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,iBAA4C,GACnD,OAAO,CAAC,CAAC,CAAC,CAcZ;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAuB;gBAE/B,YAAY,EAAE,OAAO,CAAC,WAAW,CAAC;IAIxC,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CA2EzD"}
|
package/dist/agent/subtask.js
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
// ============================================================
|
|
2
2
|
// 轻灵 - Subtask 隔离执行器
|
|
3
|
-
// 在同进程内创建独立 AgentLoop
|
|
3
|
+
// 在同进程内创建独立 AgentLoop 实例;Phase 3.2 支持角色与回传契约
|
|
4
4
|
// ============================================================
|
|
5
5
|
import { AgentLoop } from "../agent-loop.js";
|
|
6
|
+
import { buildRoleSystemPreamble, extractEvidenceHints, extractFilesTouchedFromMessages, filterToolsForRole, formatSubAgentReturnContract, normalizeSubAgentRole, } from "../agents/roles.js";
|
|
7
|
+
const defaultTimeoutController = {
|
|
8
|
+
setTimeout: (callback, timeoutMs) => setTimeout(callback, timeoutMs),
|
|
9
|
+
clearTimeout: (handle) => clearTimeout(handle),
|
|
10
|
+
};
|
|
11
|
+
export async function runWithTimeout(operation, timeoutMs, timers = defaultTimeoutController) {
|
|
12
|
+
let handle;
|
|
13
|
+
const timeout = new Promise((_, reject) => {
|
|
14
|
+
handle = timers.setTimeout(() => reject(new Error(`Subtask timeout after ${timeoutMs}ms`)), timeoutMs);
|
|
15
|
+
});
|
|
16
|
+
try {
|
|
17
|
+
return await Promise.race([operation, timeout]);
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
if (handle !== undefined)
|
|
21
|
+
timers.clearTimeout(handle);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
6
24
|
export class SubtaskRunner {
|
|
7
25
|
parentConfig;
|
|
8
26
|
constructor(parentConfig) {
|
|
@@ -12,9 +30,11 @@ export class SubtaskRunner {
|
|
|
12
30
|
const start = Date.now();
|
|
13
31
|
const maxIter = config.maxIterations ?? 10;
|
|
14
32
|
const timeout = config.timeoutMs ?? 120_000;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
33
|
+
const role = normalizeSubAgentRole(config.role);
|
|
34
|
+
const baseTools = config.tools ??
|
|
35
|
+
this.parentConfig.tools?.filter((t) => t.name !== "subtask") ??
|
|
36
|
+
[];
|
|
37
|
+
const tools = filterToolsForRole(baseTools, role);
|
|
18
38
|
const subtaskConfig = {
|
|
19
39
|
...this.parentConfig,
|
|
20
40
|
tools,
|
|
@@ -22,34 +42,69 @@ export class SubtaskRunner {
|
|
|
22
42
|
};
|
|
23
43
|
const subAgent = new AgentLoop(subtaskConfig);
|
|
24
44
|
await subAgent.waitForInit();
|
|
25
|
-
|
|
26
|
-
let prompt = config.task
|
|
45
|
+
const preamble = buildRoleSystemPreamble(role);
|
|
46
|
+
let prompt = `${preamble}\n\n[子任务]\n${config.task}`;
|
|
27
47
|
if (config.parentContext) {
|
|
28
|
-
prompt =
|
|
48
|
+
prompt =
|
|
49
|
+
`${preamble}\n\n[父任务上下文]\n${config.parentContext}\n\n[子任务]\n${config.task}`;
|
|
29
50
|
}
|
|
30
51
|
subAgent.addUserMessage(prompt);
|
|
52
|
+
let rawOutput = "";
|
|
53
|
+
let success = false;
|
|
31
54
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("Subtask timeout")), timeout)),
|
|
35
|
-
]);
|
|
36
|
-
return {
|
|
37
|
-
success: true,
|
|
38
|
-
output,
|
|
39
|
-
iterations: maxIter,
|
|
40
|
-
durationMs: Date.now() - start,
|
|
41
|
-
};
|
|
55
|
+
rawOutput = await runWithTimeout(subAgent.run(), timeout);
|
|
56
|
+
success = true;
|
|
42
57
|
}
|
|
43
58
|
catch (err) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
output: err.message,
|
|
47
|
-
iterations: maxIter,
|
|
48
|
-
durationMs: Date.now() - start,
|
|
49
|
-
};
|
|
59
|
+
rawOutput = err.message;
|
|
60
|
+
success = false;
|
|
50
61
|
}
|
|
51
62
|
finally {
|
|
52
|
-
|
|
63
|
+
try {
|
|
64
|
+
await subAgent.shutdown();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// ignore shutdown errors
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const messages = subAgent.getMessagesSnapshot?.() ?? [];
|
|
71
|
+
const filesTouched = extractFilesTouchedFromMessages(messages);
|
|
72
|
+
const summary = buildSummary(rawOutput, success, role, filesTouched);
|
|
73
|
+
const evidence = extractEvidenceHints(rawOutput);
|
|
74
|
+
if (!success) {
|
|
75
|
+
evidence.unshift(`失败: ${rawOutput.slice(0, 200)}`);
|
|
53
76
|
}
|
|
77
|
+
const durationMs = Date.now() - start;
|
|
78
|
+
const contractText = formatSubAgentReturnContract({
|
|
79
|
+
role,
|
|
80
|
+
success,
|
|
81
|
+
durationMs,
|
|
82
|
+
iterations: maxIter,
|
|
83
|
+
summary,
|
|
84
|
+
filesTouched,
|
|
85
|
+
evidence,
|
|
86
|
+
rawOutput,
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
success,
|
|
90
|
+
output: contractText,
|
|
91
|
+
iterations: maxIter,
|
|
92
|
+
durationMs,
|
|
93
|
+
role,
|
|
94
|
+
filesTouched,
|
|
95
|
+
contractText,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function buildSummary(raw, success, role, files) {
|
|
100
|
+
const firstLine = raw
|
|
101
|
+
.split("\n")
|
|
102
|
+
.map((l) => l.trim())
|
|
103
|
+
.find((l) => l.length > 0 && !l.startsWith("【")) ?? "";
|
|
104
|
+
const fileHint = files.length > 0 ? ` 触及 ${files.length} 个文件` : "";
|
|
105
|
+
if (!success) {
|
|
106
|
+
return `角色 ${role} 未完成${fileHint}: ${firstLine.slice(0, 120) || "见 evidence"}`;
|
|
54
107
|
}
|
|
108
|
+
return (firstLine.slice(0, 200) ||
|
|
109
|
+
`角色 ${role} 已完成${fileHint}`);
|
|
55
110
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PromptSectionRegistry } from "../types.js";
|
|
2
|
+
import type { Message, ToolCall } from "../types.js";
|
|
3
|
+
import type { MemoryStore } from "../memory.js";
|
|
4
|
+
import type { LlmChatResponse } from "../providers/llm-client.js";
|
|
5
|
+
export declare function findLastUserMessageContent(messages: Message[]): string;
|
|
6
|
+
export declare function buildRuntimeMetaSection(options: {
|
|
7
|
+
provider?: string;
|
|
8
|
+
endpoint?: string;
|
|
9
|
+
workspaceDir?: string | null;
|
|
10
|
+
fileCacheDir?: string;
|
|
11
|
+
fileStateDir?: string;
|
|
12
|
+
runtimeRootDir: string;
|
|
13
|
+
}): string;
|
|
14
|
+
export declare function assembleSystemPrompt(options: {
|
|
15
|
+
baseSystemPrompt: string;
|
|
16
|
+
sectionRegistry: PromptSectionRegistry;
|
|
17
|
+
memoryStore: MemoryStore;
|
|
18
|
+
messages: Message[];
|
|
19
|
+
provider?: string;
|
|
20
|
+
endpoint?: string;
|
|
21
|
+
workspaceDir?: string | null;
|
|
22
|
+
fileCacheDir?: string;
|
|
23
|
+
fileStateDir?: string;
|
|
24
|
+
runtimeRootDir: string;
|
|
25
|
+
}): Promise<string>;
|
|
26
|
+
export type ReflectionDecision = "proceed" | "ask" | "block" | "warn";
|
|
27
|
+
export declare function heuristicReflect(tc: ToolCall): {
|
|
28
|
+
decision: ReflectionDecision;
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Self-reflective pre-check for high-risk tools.
|
|
33
|
+
* Uses optional chat callback; falls back to heuristics on failure.
|
|
34
|
+
*/
|
|
35
|
+
export declare function reflectiveThink(tc: ToolCall, chat: (systemPrompt: string, overrides?: Record<string, unknown>) => Promise<LlmChatResponse>): Promise<{
|
|
36
|
+
decision: ReflectionDecision;
|
|
37
|
+
reason: string;
|
|
38
|
+
}>;
|
|
39
|
+
//# sourceMappingURL=system-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/agent/system-prompt.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAKtE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,MAAM,CAYT;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClB;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;AAEtE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,QAAQ,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAO/F;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,eAAe,CAAC,GAC5F,OAAO,CAAC;IAAE,QAAQ,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAa3D"}
|