@bolloon/bolloon-agent 0.2.11 → 0.2.13
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/README.md +495 -467
- package/bin/bolloon-cli.cjs +183 -183
- package/bin/bolloon-daemon.sh +207 -0
- package/bin/bolloon.cjs +0 -0
- package/bin/ipfs +0 -0
- package/dist/agents/agent-manifest-protocol.js +52 -0
- package/dist/agents/chat-segmenter.js +298 -0
- package/dist/agents/constraint-layer.js +19 -19
- package/dist/agents/judgment-protocol.js +479 -0
- package/dist/agents/parse-tool-call.js +304 -0
- package/dist/agents/peer-manifest-loader.js +210 -0
- package/dist/agents/pi-sdk-session-factory.js +110 -0
- package/dist/agents/pi-sdk-session-manager.js +297 -0
- package/dist/agents/pi-sdk-tools.js +1288 -0
- package/dist/agents/pi-sdk-types.js +13 -0
- package/dist/agents/pi-sdk.js +553 -1306
- package/dist/agents/react-loop.js +120 -0
- package/dist/agents/session-store.js +171 -0
- package/dist/agents/shell-guard.js +2 -2
- package/dist/agents/tool-registry.js +136 -0
- package/dist/agents/workflow-pivot-loop.js +200 -22
- package/dist/bollharness/src/scripts/context_router.js +7 -0
- package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
- package/dist/bollharness-integration/context-router-judgment.js +4 -4
- package/dist/bollharness-integration/context-router.js +292 -292
- package/dist/bollharness-integration/gate-state-machine.js +26 -13
- package/dist/bollharness-integration/integration.js +71 -0
- package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
- package/dist/bollharness-integration/skill-adapter.js +57 -127
- package/dist/bootstrap/chat-archiver.js +276 -0
- package/dist/bootstrap/context-collector.js +6 -3
- package/dist/bootstrap/event-log.js +160 -0
- package/dist/bootstrap/lifecycle-hooks.js +15 -1
- package/dist/bootstrap/memory-compressor.js +170 -0
- package/dist/bootstrap/persona-loader.js +94 -0
- package/dist/bootstrap/project-state.js +159 -0
- package/dist/bootstrap/remote-mirror.js +97 -0
- package/dist/bootstrap/session-window.js +121 -0
- package/dist/bootstrap/vector-index.js +248 -0
- package/dist/cli/loading-tui.js +40 -0
- package/dist/cli-entry.js +41 -37
- package/dist/context-compaction/auto-compact.js +7 -7
- package/dist/electron/config.js +21 -0
- package/dist/electron/config.js.map +1 -0
- package/dist/electron/dialogs.js +108 -0
- package/dist/electron/dialogs.js.map +1 -0
- package/dist/electron/first-run.js +170 -0
- package/dist/electron/first-run.js.map +1 -0
- package/dist/electron/ipc.js +20 -0
- package/dist/electron/ipc.js.map +1 -0
- package/dist/electron/logger.js +114 -0
- package/dist/electron/logger.js.map +1 -0
- package/dist/electron/main.js +63 -0
- package/dist/electron/main.js.map +1 -0
- package/dist/electron/menu.js +145 -0
- package/dist/electron/menu.js.map +1 -0
- package/dist/electron/paths.js +75 -0
- package/dist/electron/paths.js.map +1 -0
- package/dist/electron/server.js +119 -0
- package/dist/electron/server.js.map +1 -0
- package/dist/electron/tray.js +111 -0
- package/dist/electron/tray.js.map +1 -0
- package/dist/electron/window.js +111 -0
- package/dist/electron/window.js.map +1 -0
- package/dist/electron-preload.js +26 -6
- package/dist/electron-preload.js.map +1 -1
- package/dist/electron.js +6 -168
- package/dist/electron.js.map +1 -1
- package/dist/index.js +323 -266
- package/dist/llm/config-store.js +24 -8
- package/dist/llm/llm-judgment-client.js +102 -102
- package/dist/llm/pi-ai.js +137 -85
- package/dist/llm/system-prompt/layers/channel/local.md +14 -14
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
- package/dist/llm/system-prompt/layers/core/identity.md +37 -37
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
- package/dist/llm/system-prompt/layers/core/tone.md +31 -31
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
- package/dist/llm/system-prompt/layers/role/architect.md +20 -20
- package/dist/llm/system-prompt/layers/role/expert.md +19 -19
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
- package/dist/llm/system-prompt/layers/role/security.md +15 -15
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
- package/dist/llm/tool-manifest/ask_user_input.js +1 -1
- package/dist/llm/tool-manifest/bash.js +3 -3
- package/dist/llm/tool-manifest/create_file.js +4 -4
- package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
- package/dist/llm/tool-manifest/image_search.js +2 -2
- package/dist/llm/tool-manifest/mcp.js +2 -2
- package/dist/llm/tool-manifest/message_compose.js +3 -3
- package/dist/llm/tool-manifest/places.js +2 -2
- package/dist/llm/tool-manifest/present_files.js +1 -1
- package/dist/llm/tool-manifest/recipe.js +2 -2
- package/dist/llm/tool-manifest/str_replace.js +5 -5
- package/dist/llm/tool-manifest/view.js +3 -3
- package/dist/llm/tool-manifest/weather.js +4 -4
- package/dist/llm/tool-manifest/web.js +4 -4
- package/dist/network/local-inbox-bus.js +73 -0
- package/dist/network/p2p-outbox.js +161 -0
- package/dist/network/peer-fs.js +420 -0
- package/dist/network/peer-resource-bridge.js +216 -0
- package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
- package/dist/pi-ecosystem-judgment/cleanup.js +126 -0
- package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
- package/dist/pi-ecosystem-judgment/distillation.js +14 -14
- package/dist/pi-ecosystem-judgment/human-value-store.js +45 -11
- package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
- package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
- package/dist/security/context-router-tool.js +15 -15
- package/dist/security/tool-gate.js +11 -0
- package/dist/web/api-config.html +520 -520
- package/dist/web/client-loop-status.js +220 -0
- package/dist/web/client.js +1677 -244
- package/dist/web/client.js.map +7 -0
- package/dist/web/components/wallet-viem.mjs +118 -118
- package/dist/web/index.html +375 -374
- package/dist/web/input-validator.js +103 -0
- package/dist/web/manifest.json +20 -20
- package/dist/web/routes-judgments.js +738 -0
- package/dist/web/routes-llm-config.js +279 -0
- package/dist/web/routes-tasks.js +222 -0
- package/dist/web/server-sse.js +121 -0
- package/dist/web/server-storage.js +154 -0
- package/dist/web/server-types.js +15 -0
- package/dist/web/server-v3-p2p.js +224 -0
- package/dist/web/server.js +1070 -1307
- package/dist/web/style.css +4742 -4737
- package/dist/web/util/safe-name.js +32 -0
- package/package.json +162 -160
- package/scripts/build-cli.js +215 -215
- package/scripts/build-web.ts +130 -125
- package/scripts/postinstall.js +152 -152
- package/bin/bolloon.js +0 -157
- package/dist/constraint-runtime/src/_archive_helper.js +0 -9
- package/dist/constraint-runtime/src/agent/coordinator.js +0 -48
- package/dist/constraint-runtime/src/agent/index.js +0 -1
- package/dist/constraint-runtime/src/assistant/index.js +0 -12
- package/dist/constraint-runtime/src/bootstrap/index.js +0 -12
- package/dist/constraint-runtime/src/bootstrap_graph.js +0 -13
- package/dist/constraint-runtime/src/bridge/index.js +0 -12
- package/dist/constraint-runtime/src/buddy/index.js +0 -12
- package/dist/constraint-runtime/src/cli/index.js +0 -12
- package/dist/constraint-runtime/src/command_graph.js +0 -10
- package/dist/constraint-runtime/src/commands.js +0 -60
- package/dist/constraint-runtime/src/components/index.js +0 -12
- package/dist/constraint-runtime/src/constants/index.js +0 -12
- package/dist/constraint-runtime/src/constraint/budget.js +0 -22
- package/dist/constraint-runtime/src/constraint/index.js +0 -2
- package/dist/constraint-runtime/src/constraint/permission.js +0 -20
- package/dist/constraint-runtime/src/context.js +0 -30
- package/dist/constraint-runtime/src/coordinator/index.js +0 -12
- package/dist/constraint-runtime/src/cost_hook.js +0 -4
- package/dist/constraint-runtime/src/cost_tracker.js +0 -8
- package/dist/constraint-runtime/src/deferred_init.js +0 -10
- package/dist/constraint-runtime/src/direct_modes.js +0 -6
- package/dist/constraint-runtime/src/dynamic-tool-loader.js +0 -85
- package/dist/constraint-runtime/src/entrypoints/index.js +0 -12
- package/dist/constraint-runtime/src/execution_registry.js +0 -44
- package/dist/constraint-runtime/src/history.js +0 -9
- package/dist/constraint-runtime/src/hooks/index.js +0 -12
- package/dist/constraint-runtime/src/index.js +0 -26
- package/dist/constraint-runtime/src/ink.js +0 -4
- package/dist/constraint-runtime/src/keybindings/index.js +0 -12
- package/dist/constraint-runtime/src/memdir/index.js +0 -12
- package/dist/constraint-runtime/src/migrations/index.js +0 -12
- package/dist/constraint-runtime/src/models.js +0 -1
- package/dist/constraint-runtime/src/moreright/index.js +0 -12
- package/dist/constraint-runtime/src/native_ts/index.js +0 -12
- package/dist/constraint-runtime/src/output_styles/index.js +0 -12
- package/dist/constraint-runtime/src/parity_audit.js +0 -12
- package/dist/constraint-runtime/src/plugins/index.js +0 -12
- package/dist/constraint-runtime/src/port_manifest.js +0 -11
- package/dist/constraint-runtime/src/prefetch.js +0 -9
- package/dist/constraint-runtime/src/query.js +0 -1
- package/dist/constraint-runtime/src/remote/index.js +0 -12
- package/dist/constraint-runtime/src/remote_runtime.js +0 -9
- package/dist/constraint-runtime/src/runtime/index.js +0 -1
- package/dist/constraint-runtime/src/runtime/session.js +0 -35
- package/dist/constraint-runtime/src/schemas/index.js +0 -12
- package/dist/constraint-runtime/src/screens/index.js +0 -12
- package/dist/constraint-runtime/src/server/index.js +0 -12
- package/dist/constraint-runtime/src/services/index.js +0 -12
- package/dist/constraint-runtime/src/session_store.js +0 -22
- package/dist/constraint-runtime/src/setup.js +0 -30
- package/dist/constraint-runtime/src/skills/index.js +0 -1
- package/dist/constraint-runtime/src/skills/skill-registry.js +0 -28
- package/dist/constraint-runtime/src/state/index.js +0 -12
- package/dist/constraint-runtime/src/system_init.js +0 -20
- package/dist/constraint-runtime/src/thinking/engine.js +0 -42
- package/dist/constraint-runtime/src/thinking/index.js +0 -1
- package/dist/constraint-runtime/src/tool_pool.js +0 -8
- package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +0 -7
- package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +0 -7
- package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +0 -7
- package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +0 -8
- package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +0 -6
- package/dist/constraint-runtime/src/tools.js +0 -80
- package/dist/constraint-runtime/src/transcript.js +0 -19
- package/dist/constraint-runtime/src/types/index.js +0 -12
- package/dist/constraint-runtime/src/upstream_proxy/index.js +0 -12
- package/dist/constraint-runtime/src/utils/index.js +0 -12
- package/dist/constraint-runtime/src/vim/index.js +0 -12
- package/dist/constraint-runtime/src/voice/index.js +0 -12
- package/dist/constraint-runtime/tests/agent.test.js +0 -16
- package/dist/constraint-runtime/tests/constraint.test.js +0 -41
- package/dist/constraint-runtime/tests/skill.test.js +0 -19
- package/dist/constraint-runtime/tests/thinking.test.js +0 -22
- package/dist/pi-ecosystem-colony/index.js +0 -365
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
- package/dist/social/ant-colony/PheromoneEngine.js +0 -227
- package/dist/social/ant-colony/index.js +0 -6
- package/dist/social/ant-colony/types.js +0 -24
- package/dist/test/ai-judgment-test.js +0 -80
- package/dist/test/bollharness-integration.test.js +0 -318
- package/dist/test/channel-agent-multi-dialogue.js +0 -205
- package/dist/test/channel-heartbeat-agent-test.js +0 -201
- package/dist/test/constraint-layer.test.js +0 -164
- package/dist/test/diap-identity-test.js +0 -172
- package/dist/test/diap-quick-test.js +0 -62
- package/dist/test/global-shared-context.test.js +0 -315
- package/dist/test/harness-judgment-injection.test.js +0 -246
- package/dist/test/harness-workflow-integrator-test.js +0 -228
- package/dist/test/human-value-store.test.js +0 -243
- package/dist/test/hybrid-integration-test.js +0 -118
- package/dist/test/hybrid-messenger-verify.js +0 -55
- package/dist/test/iroh-bistream-debug.js +0 -38
- package/dist/test/iroh-communication.test.js +0 -66
- package/dist/test/iroh-debug-test.js +0 -57
- package/dist/test/iroh-diap-test.js +0 -71
- package/dist/test/iroh-direct-connect.js +0 -55
- package/dist/test/iroh-e2e-fixed.js +0 -89
- package/dist/test/iroh-e2e-same-process.js +0 -63
- package/dist/test/iroh-e2e.js +0 -66
- package/dist/test/iroh-final-e2e.js +0 -72
- package/dist/test/iroh-relay-test.js +0 -37
- package/dist/test/iroh-simple-test.js +0 -41
- package/dist/test/iroh-transport-verify.js +0 -54
- package/dist/test/iroh-transport.test.js +0 -37
- package/dist/test/iroh-two-nodes.js +0 -70
- package/dist/test/iroh-verify.js +0 -44
- package/dist/test/judgment-decision.test.js +0 -219
- package/dist/test/llm-judgment-integration.test.js +0 -220
- package/dist/test/p2p-agent-complex-dialogue.js +0 -385
- package/dist/test/p2p-agent-dialogue.js +0 -341
- package/dist/test/p2p-agent-full-bidirectional.js +0 -510
- package/dist/test/p2p-agent-harness-flow.js +0 -437
- package/dist/test/p2p-agent-harness-single.js +0 -143
- package/dist/test/p2p-ai-dialogue-test.js +0 -318
- package/dist/test/p2p-cid-connect-test.js +0 -195
- package/dist/test/p2p-connect-receiver.js +0 -69
- package/dist/test/p2p-doc-transfer.js +0 -110
- package/dist/test/p2p-identity-page-test.js +0 -77
- package/dist/test/p2p-iroh-test.js +0 -171
- package/dist/test/p2p-minimal-test.js +0 -241
- package/dist/test/p2p-node-1.js +0 -148
- package/dist/test/p2p-node-2.js +0 -148
- package/dist/test/p2p-server.js +0 -281
- package/dist/test/p2p-two-nodes-test.js +0 -438
- package/dist/test/pi-sdk.test.js +0 -44
- package/dist/test/set-persona.js +0 -40
- package/dist/test/simple.test.js +0 -9
- package/dist/test/storage-integration.test.js +0 -150
- package/dist/test/subagent-manager.test.js +0 -276
- package/dist/test/test-gate-flow.test.js +0 -81
- package/dist/test/workflow-engine.test.js +0 -87
- package/dist/test/workflow-pivot-loop.test.js +0 -246
|
@@ -77,14 +77,25 @@ export class WorkflowPivotLoop {
|
|
|
77
77
|
tools;
|
|
78
78
|
messageHistory;
|
|
79
79
|
streamCallback;
|
|
80
|
+
// 2026-07-06: pivot 想看内部明细设 BOLLOON_VERBOSE=1 — 默认只保留 status 事件给 UI
|
|
81
|
+
verbose = typeof process !== 'undefined' && process.env?.BOLLOON_VERBOSE === '1';
|
|
82
|
+
vlog(msg) { if (this.verbose)
|
|
83
|
+
console.log(msg); }
|
|
84
|
+
onApproachingTokenBudget;
|
|
85
|
+
compactedThisRun = false; // 防止 pivot 单次 execute 反复触发 compact
|
|
86
|
+
// 2026-07-06: iter ≥ 2 时用简短 systemHeader 替代完整 systemPrompt
|
|
87
|
+
// pivot 默认 moderate profile 是 30 iter, 每次调 llm 都重复装 11K persona+tools 装 + 25 layer
|
|
88
|
+
// (pi-ai.ts buildSystemPromptAsync 重复读 .md) — 真没必要. 第一轮装全, 后续用锚句占位.
|
|
89
|
+
// compactor 触发后 (旧 systemHeader 代表性弱化) 再重新装一次全量.
|
|
90
|
+
continuationSystemHeader = null;
|
|
80
91
|
constructor(config) {
|
|
81
92
|
this.tools = new Map();
|
|
82
93
|
// Default configuration based on task complexity if not provided
|
|
83
94
|
const defaults = {
|
|
84
|
-
maxIterations: config.maxIterations || 50
|
|
95
|
+
maxIterations: config.maxIterations || 1000, // 2026-07-06: 持久循环 (旧 50)
|
|
85
96
|
minIterations: config.minIterations || 2,
|
|
86
97
|
qualityThreshold: config.qualityThreshold || 0.7,
|
|
87
|
-
maxConsecutiveNoProgress: config.maxConsecutiveNoProgress ||
|
|
98
|
+
maxConsecutiveNoProgress: config.maxConsecutiveNoProgress || 8,
|
|
88
99
|
maxTokenBudget: config.maxTokenBudget || 50000,
|
|
89
100
|
complexity: config.complexity || 'moderate'
|
|
90
101
|
};
|
|
@@ -120,13 +131,33 @@ export class WorkflowPivotLoop {
|
|
|
120
131
|
/**
|
|
121
132
|
* Execute the pivot loop
|
|
122
133
|
*/
|
|
123
|
-
async execute(input, llm, systemPrompt, streamCallback
|
|
134
|
+
async execute(input, llm, systemPrompt, streamCallback, signal,
|
|
135
|
+
/**
|
|
136
|
+
* 2026-07-06: token 预算接近上限时回调 — 让上层 (PiAgentSession) 跑 compactor
|
|
137
|
+
* 否者单纯报 "Token 预算超支" 直接 break, 用户消息丢失.
|
|
138
|
+
* 回调同步返回值 (newMessageHistory) 时替换 this.messageHistory 后继续.
|
|
139
|
+
* 异步: PiAgent 触发 compactPipeline, 这里 await 等折叠完再继续.
|
|
140
|
+
*/
|
|
141
|
+
onApproachingTokenBudget) {
|
|
124
142
|
this.streamCallback = streamCallback;
|
|
125
143
|
this.state = this.createInitialState();
|
|
144
|
+
this.onApproachingTokenBudget = onApproachingTokenBudget;
|
|
145
|
+
// 2026-07-06: 准备短 systemHeader. iter ≥ 2 用它替代完整 systemPrompt
|
|
146
|
+
// LLM 已经在 messageHistory 里看到全部历史, 不需要每次重装. compact 触发后下次再装全量.
|
|
147
|
+
this.continuationSystemHeader = this.buildContinuationHeader(systemPrompt);
|
|
148
|
+
// 重置 compact 状态 — 这次 execute 第一次 iter 仍用全量
|
|
149
|
+
this.compactedThisRun = false;
|
|
150
|
+
this.vlog(`[pivot] execute: input chars=${input.length}, systemPrompt chars=${systemPrompt.length}, signal=${!!signal}, continuationHeader chars=${this.continuationSystemHeader?.length ?? 0}`);
|
|
126
151
|
this.messageHistory = [{ role: 'user', content: input }];
|
|
127
152
|
// Analyze task complexity and adapt config
|
|
128
153
|
const taskProfile = analyzeTaskComplexity(input);
|
|
129
154
|
const effectiveConfig = this.adaptConfigForTask(taskProfile);
|
|
155
|
+
// 2026-06-18 (supervisor): taskProfile 算的 tokenBudget 只看 input 长度, 但 systemPrompt 53K 时不够
|
|
156
|
+
// 把 effectiveConfig.maxTokenBudget 提到 systemPrompt * 1.2 留余量, 简单问题也走完
|
|
157
|
+
// 2026-07-06: 但累计 totalTokens = systemPrompt + sum(replies), 每 iter LLM 反 ~3-10K
|
|
158
|
+
// 旧公式 budget=11K*1.2=13K, 5 iter 累计 5 × 11K + replies = ~70K → 12-13K 处直接 break.
|
|
159
|
+
// 修法: budget = systemPrompt × 1.2 × maxIterations, 容纳 N 次 prompt + N-1 次 reply.
|
|
160
|
+
effectiveConfig.maxTokenBudget = Math.max(effectiveConfig.maxTokenBudget, Math.ceil(systemPrompt.length * 1.2 * effectiveConfig.maxIterations));
|
|
130
161
|
this.emit({
|
|
131
162
|
type: 'status',
|
|
132
163
|
content: `🔍 任务复杂度: ${taskProfile.complexity} (预估 ${taskProfile.estimatedSteps} 步)`,
|
|
@@ -139,6 +170,15 @@ export class WorkflowPivotLoop {
|
|
|
139
170
|
});
|
|
140
171
|
let response = '';
|
|
141
172
|
while (this.shouldContinue(effectiveConfig)) {
|
|
173
|
+
// 2026-07-04: signal abort 让 pivot 提前退出 (防止 LLM hang)
|
|
174
|
+
if (signal?.aborted) {
|
|
175
|
+
this.emit({
|
|
176
|
+
type: 'status',
|
|
177
|
+
content: `⏹️ pivot loop 被 abort (iter=${this.state.iteration})`,
|
|
178
|
+
tool: 'loop'
|
|
179
|
+
});
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
142
182
|
this.state.iteration++;
|
|
143
183
|
this.emit({
|
|
144
184
|
type: 'status',
|
|
@@ -148,13 +188,57 @@ export class WorkflowPivotLoop {
|
|
|
148
188
|
// Build context for LLM
|
|
149
189
|
const context = this.buildContext();
|
|
150
190
|
const fullPrompt = `${systemPrompt}\n\n${context}`;
|
|
191
|
+
// 2026-07-06: iter ≥ 2 改用 continuationHeader — messageHistory 已经载过全 persona/tools,
|
|
192
|
+
// 重装 11K + 25 layer 是浪费, 同时让 pi-ai.chat 走 < 2000 分支 (不重新装 system prompt).
|
|
193
|
+
// compact 触发 → 这次 iter 之后下一 iter 恢复用 full.
|
|
194
|
+
let headerForThisIter = systemPrompt;
|
|
195
|
+
let usingContinuation = false;
|
|
196
|
+
const shouldUseContinuation = this.state.iteration >= 2 && !this.compactedThisRun && this.continuationSystemHeader;
|
|
197
|
+
if (shouldUseContinuation) {
|
|
198
|
+
headerForThisIter = this.continuationSystemHeader;
|
|
199
|
+
usingContinuation = true;
|
|
200
|
+
}
|
|
201
|
+
this.vlog(`[pivot] iter=${this.state.iteration} ctx=${context.length} fullPrompt=${fullPrompt.length} budget=${effectiveConfig.maxTokenBudget} iterHeader=${usingContinuation ? 'short' : 'full'} (${headerForThisIter.length}B)`);
|
|
151
202
|
try {
|
|
152
203
|
// Call LLM
|
|
153
|
-
const
|
|
204
|
+
const t0 = Date.now();
|
|
205
|
+
const llmResponse = await llm.chat(context, headerForThisIter, signal);
|
|
154
206
|
const reply = llmResponse.reply.trim();
|
|
207
|
+
this.vlog(`[pivot] iter=${this.state.iteration} LLM took=${Date.now() - t0}ms reply=${reply.length} head=${reply.substring(0, 80).replace(/\n/g, ' ')}`);
|
|
155
208
|
this.emit({ type: 'token', content: reply.substring(0, 100) });
|
|
209
|
+
// 2026-07-06: 把完整 reply 推给前端 — 前端按需更新临时气泡
|
|
210
|
+
// 之前只 emit token(100B 截断), 前端拿到 100B 看不清. 现在 emit preview 带完整 content.
|
|
211
|
+
// 折叠 / 清洗交给前端的 message-renderer.addMessage (类型 ai 入口统一 strip).
|
|
212
|
+
this.emit({ type: 'reply-preview', content: reply, iteration: this.state.iteration });
|
|
156
213
|
// Estimate token usage
|
|
157
|
-
this.state.totalTokens += this.estimateTokens(
|
|
214
|
+
this.state.totalTokens += this.estimateTokens(headerForThisIter + '\n\n' + context) + this.estimateTokens(reply);
|
|
215
|
+
// 2026-07-06: token 接近预算时先尝试自动压缩, 而不是直接 break — 上层 PiAgentSession
|
|
216
|
+
// 通过 onApproachingTokenBudget 回调触发 compactPipeline (5 层短路)
|
|
217
|
+
const budgetRatio = this.state.totalTokens / effectiveConfig.maxTokenBudget;
|
|
218
|
+
if (budgetRatio > 0.7 && this.onApproachingTokenBudget && !this.compactedThisRun && this.messageHistory.length >= 6) {
|
|
219
|
+
this.compactedThisRun = true;
|
|
220
|
+
this.emit({
|
|
221
|
+
type: 'status',
|
|
222
|
+
content: `🗜️ token ${this.state.totalTokens} 接近预算 (${(budgetRatio * 100).toFixed(0)}%), 尝试自动压缩上下文`,
|
|
223
|
+
tool: 'compactor',
|
|
224
|
+
});
|
|
225
|
+
try {
|
|
226
|
+
await this.onApproachingTokenBudget();
|
|
227
|
+
// 重置 totalTokens 因为 compactor 折叠后本来就不准
|
|
228
|
+
this.state.totalTokens = Math.ceil(systemPrompt.length * 0.5); // 粗略剩余量
|
|
229
|
+
this.emit({
|
|
230
|
+
type: 'status',
|
|
231
|
+
content: `🗜️ 自动压缩完成, 继续循环 (剩余估算 ${this.state.totalTokens} chars)`,
|
|
232
|
+
tool: 'compactor',
|
|
233
|
+
});
|
|
234
|
+
// 继续 loop, 不 break
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
console.warn('[pivot] onApproachingTokenBudget failed (non-fatal, 继续走 token 阈值):', String(err?.message || err).slice(0, 100));
|
|
239
|
+
// compact 失败 → 回到原 check
|
|
240
|
+
}
|
|
241
|
+
}
|
|
158
242
|
// Check token budget
|
|
159
243
|
if (this.state.totalTokens > effectiveConfig.maxTokenBudget) {
|
|
160
244
|
this.emit({
|
|
@@ -166,6 +250,39 @@ export class WorkflowPivotLoop {
|
|
|
166
250
|
// Check if this is a final response (no tool calls)
|
|
167
251
|
const pendingTools = this.extractPendingToolUses(reply);
|
|
168
252
|
if (pendingTools.length === 0) {
|
|
253
|
+
// 2026-07-06: LLM 显式 <final gen> 标记 — pivot 立即退出, 不再走 quality/iter 流程
|
|
254
|
+
// 这个 marker 之前和 思考/ 同义被忽略, 害得 "你好" 类问题跑 11 iter 还不见停
|
|
255
|
+
// 加上之后 iter=1 收到 <final gen> 就 accept
|
|
256
|
+
if (/<final\s+gen\s*\/?>|<\/final\s+gen>/i.test(reply)) {
|
|
257
|
+
const cleaned = reply.replace(/<final\s+gen\s*\/?>|<\/final\s+gen>/gi, '').trim();
|
|
258
|
+
response = cleaned || reply;
|
|
259
|
+
this.emit({
|
|
260
|
+
type: 'status',
|
|
261
|
+
content: `✅ 检测到 <final gen> 结束标记, 立即退出 (iter=${this.state.iteration})`,
|
|
262
|
+
tool: 'system',
|
|
263
|
+
});
|
|
264
|
+
return this.createResult(true, response, 'final_gen_marker');
|
|
265
|
+
}
|
|
266
|
+
// Check if the reply contains tool call intent but couldn't be parsed
|
|
267
|
+
// 2026-07-06: 排除合法的 思考/<final gen> 这些 tag (它们是 sentinel 不是 tool call)
|
|
268
|
+
const cleanedForIntentCheck = reply
|
|
269
|
+
.replace(/<final\s+gen\s*\/?>|<\/final\s+gen>/gi, '')
|
|
270
|
+
.replace(/<\/?think(?:ing)?>/gi, ''); // 移除
|
|
271
|
+
const containsToolCallIntent = cleanedForIntentCheck.includes('调用工具') || cleanedForIntentCheck.includes('tool(') ||
|
|
272
|
+
cleanedForIntentCheck.includes('使用工具') || cleanedForIntentCheck.includes('需要获取') || cleanedForIntentCheck.includes('需要查看') ||
|
|
273
|
+
cleanedForIntentCheck.includes('tool =>') || cleanedForIntentCheck.includes('[TOOL_CALL]') ||
|
|
274
|
+
// 仅匹配真工具调用 tag (tool_use / function_calls / tool_call / invoke / tool_code)
|
|
275
|
+
/<\s*(tool_use|tool_call|function_calls?|tool_code|invoke)\s*>/i.test(cleanedForIntentCheck);
|
|
276
|
+
// If there's tool call intent but no parsed tools, continue the loop
|
|
277
|
+
if (containsToolCallIntent && this.state.iteration < effectiveConfig.maxIterations) {
|
|
278
|
+
this.emit({
|
|
279
|
+
type: 'status',
|
|
280
|
+
content: `🔄 检测到工具调用意图但格式无法解析,继续循环...`,
|
|
281
|
+
tool: 'system'
|
|
282
|
+
});
|
|
283
|
+
this.state.consecutiveNoProgress++;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
169
286
|
// No pending tool uses - this is a normal completion
|
|
170
287
|
this.state.pendingToolUses = [];
|
|
171
288
|
// Evaluate quality before accepting
|
|
@@ -377,6 +494,29 @@ export class WorkflowPivotLoop {
|
|
|
377
494
|
}
|
|
378
495
|
}
|
|
379
496
|
}
|
|
497
|
+
// 2026-06-18 (supervisor): Claude Code 风格 <tool_call><tool_name>...</tool_call>
|
|
498
|
+
// bolloon agent 之前一直被 model 教用这个格式, 但 pivot loop 只认 3 个旧 pattern.
|
|
499
|
+
// 现在加: <tool_call><invoke name="X"><parameter name="k">v</parameter></invoke></tool_call>
|
|
500
|
+
const toolCodeRe = /<tool_code>([\s\S]*?)<\/tool_code>/g;
|
|
501
|
+
while ((match = toolCodeRe.exec(content)) !== null) {
|
|
502
|
+
const block = match[1];
|
|
503
|
+
const invokeRe = /<invoke\s+name="(\w+)"\s*>([\s\S]*?)<\/invoke>/g;
|
|
504
|
+
let im;
|
|
505
|
+
while ((im = invokeRe.exec(block)) !== null) {
|
|
506
|
+
const name = im[1];
|
|
507
|
+
if (!this.tools.has(name))
|
|
508
|
+
continue;
|
|
509
|
+
const args = {};
|
|
510
|
+
const paramRe = /<parameter\s+name="(\w+)"\s*>([\s\S]*?)<\/parameter>/g;
|
|
511
|
+
let pm;
|
|
512
|
+
while ((pm = paramRe.exec(im[2])) !== null) {
|
|
513
|
+
args[pm[1]] = pm[2].trim().replace(/^["']|['"]$/g, '');
|
|
514
|
+
}
|
|
515
|
+
if (!pending.some(p => p.name === name)) {
|
|
516
|
+
pending.push({ name, args, description: '', parameters: {} });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
380
520
|
// Pattern 1: Chinese format "调用工具: tool_name(args)"
|
|
381
521
|
const pattern1 = /调用工具[::]\s*(\w+)\s*\(([^)]*)\)/g;
|
|
382
522
|
while ((match = pattern1.exec(content)) !== null) {
|
|
@@ -417,6 +557,31 @@ export class WorkflowPivotLoop {
|
|
|
417
557
|
catch {
|
|
418
558
|
// JSON parsing failed, ignore
|
|
419
559
|
}
|
|
560
|
+
// Pattern 4: Single JSON tool call format {"name": "tool_name", "arguments": {...}}
|
|
561
|
+
try {
|
|
562
|
+
const singleJsonRe = /\{\s*"name"\s*:\s*"(\w+)"\s*,\s*"arguments"\s*:\s*(\{[\s\S]*?\})\s*\}/g;
|
|
563
|
+
let singleMatch;
|
|
564
|
+
while ((singleMatch = singleJsonRe.exec(content)) !== null) {
|
|
565
|
+
const name = singleMatch[1];
|
|
566
|
+
if (pending.some(p => p.name === name))
|
|
567
|
+
continue;
|
|
568
|
+
if (!this.tools.has(name))
|
|
569
|
+
continue;
|
|
570
|
+
try {
|
|
571
|
+
const args = JSON.parse(singleMatch[2]);
|
|
572
|
+
if (args && typeof args === 'object') {
|
|
573
|
+
const normalizedArgs = this.normalizeArgs(args);
|
|
574
|
+
pending.push({ name, args: normalizedArgs, description: '', parameters: {} });
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
// JSON parsing failed, skip
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
catch {
|
|
583
|
+
// Pattern matching failed, ignore
|
|
584
|
+
}
|
|
420
585
|
return pending;
|
|
421
586
|
}
|
|
422
587
|
/**
|
|
@@ -493,25 +658,21 @@ export class WorkflowPivotLoop {
|
|
|
493
658
|
* Evaluate response quality
|
|
494
659
|
*/
|
|
495
660
|
evaluateQuality(response) {
|
|
496
|
-
let score = 0.
|
|
497
|
-
// Length
|
|
661
|
+
let score = 0.7; // 2026-07-06: 起点 0.7 — 短回复不应被当成低质量打回去重跑
|
|
662
|
+
// Length bonus
|
|
498
663
|
if (response.length > 100)
|
|
499
|
-
score += 0.
|
|
664
|
+
score += 0.05;
|
|
500
665
|
if (response.length > 500)
|
|
501
666
|
score += 0.1;
|
|
502
|
-
|
|
503
|
-
score -= 0.2;
|
|
504
|
-
// Structure indicators
|
|
667
|
+
// Structure
|
|
505
668
|
if (response.includes('\n'))
|
|
506
669
|
score += 0.05;
|
|
507
|
-
if (response.includes('-') || response.includes('•'))
|
|
508
|
-
score += 0.05;
|
|
509
670
|
if (response.includes('```'))
|
|
510
671
|
score += 0.1;
|
|
511
|
-
//
|
|
512
|
-
const conclusionWords = ['完成', '
|
|
672
|
+
// Conclusion language
|
|
673
|
+
const conclusionWords = ['完成', '总结', '所以', '因此', '答案', '推荐', '建议'];
|
|
513
674
|
if (conclusionWords.some(w => response.includes(w)))
|
|
514
|
-
score += 0.
|
|
675
|
+
score += 0.05;
|
|
515
676
|
// Negative indicators
|
|
516
677
|
if (response.includes('调用工具') || response.includes('tool('))
|
|
517
678
|
score -= 0.15;
|
|
@@ -546,6 +707,20 @@ export class WorkflowPivotLoop {
|
|
|
546
707
|
// Rough estimate: ~4 characters per token for Chinese/English mix
|
|
547
708
|
return Math.ceil(text.length / 4);
|
|
548
709
|
}
|
|
710
|
+
/**
|
|
711
|
+
* 2026-07-06: build continuation header — iter ≥ 2 的短 system 头部
|
|
712
|
+
* LLM 已在 messageHistory 里, 不需要每次 11K persona+tools 重装.
|
|
713
|
+
* 短头告诉 LLM: "你已经看过首轮; 继续 conversation, 详情见历史".
|
|
714
|
+
*/
|
|
715
|
+
buildContinuationHeader(fullSystemPrompt) {
|
|
716
|
+
// 从 fullSystemPrompt 提取关键锚句: identity persona 第 1 行 + 工作模式 head 段
|
|
717
|
+
// 完整重装只在 iter=1 和 compact 之后两次
|
|
718
|
+
const lines = fullSystemPrompt.split('\n');
|
|
719
|
+
const identityLine = lines.find((l) => l.includes('你是') && !l.includes('(续)')) ?? '';
|
|
720
|
+
return `[continuation] 你的 persona + tools + judgments 已在首轮 messageHistory 中.
|
|
721
|
+
${identityLine ? identityLine + '\n' : ''}当前 step 别再读 persona 全文, 继续推进任务即可.
|
|
722
|
+
> <final gen> 只在真完成时输出.`;
|
|
723
|
+
}
|
|
549
724
|
/**
|
|
550
725
|
* Create result object
|
|
551
726
|
*/
|
|
@@ -607,26 +782,29 @@ export class WorkflowPivotLoop {
|
|
|
607
782
|
* Factory to create a default pivot loop configuration
|
|
608
783
|
*/
|
|
609
784
|
export function createDefaultPivotConfig(complexity) {
|
|
785
|
+
// 2026-07-06: maxIterations 默认大幅上调 — LLM 自己约束结束时机, 持久循环.
|
|
786
|
+
// 真实停止由 LLM emit <final gen> / 质量达标 / 连续无进展 / user abort 触发.
|
|
787
|
+
// 旧 30/60 iter 在长任务 (eg. 大文档改写) 太短, 现在跑到 N 次也不报超时.
|
|
610
788
|
const profiles = {
|
|
611
789
|
simple: {
|
|
612
|
-
maxIterations:
|
|
790
|
+
maxIterations: 200,
|
|
613
791
|
minIterations: 1,
|
|
614
792
|
qualityThreshold: 0.6,
|
|
615
|
-
maxConsecutiveNoProgress:
|
|
793
|
+
maxConsecutiveNoProgress: 5,
|
|
616
794
|
maxTokenBudget: 10000
|
|
617
795
|
},
|
|
618
796
|
moderate: {
|
|
619
|
-
maxIterations:
|
|
797
|
+
maxIterations: 1000,
|
|
620
798
|
minIterations: 2,
|
|
621
799
|
qualityThreshold: 0.7,
|
|
622
|
-
maxConsecutiveNoProgress:
|
|
800
|
+
maxConsecutiveNoProgress: 8,
|
|
623
801
|
maxTokenBudget: 30000
|
|
624
802
|
},
|
|
625
803
|
complex: {
|
|
626
|
-
maxIterations:
|
|
804
|
+
maxIterations: 2000,
|
|
627
805
|
minIterations: 3,
|
|
628
806
|
qualityThreshold: 0.75,
|
|
629
|
-
maxConsecutiveNoProgress:
|
|
807
|
+
maxConsecutiveNoProgress: 12,
|
|
630
808
|
maxTokenBudget: 60000
|
|
631
809
|
}
|
|
632
810
|
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
// ESM compatibility: root package.json has "type": "module" so bare `__dirname`
|
|
5
|
+
// is undefined at module-eval time (this module is re-exported via
|
|
6
|
+
// dist/bollharness-integration/index.js which dist/index.js imports unconditionally,
|
|
7
|
+
// so the crash fires before --web/--cli even reaches parseArgs).
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
3
10
|
export const FRAGMENTS_DIR = path.join(__dirname, "..", "context-fragments");
|
|
4
11
|
export const CONTEXT_MAP = {
|
|
5
12
|
"bridge_agent/": ["bridge-constitution"],
|
|
@@ -104,17 +104,17 @@ function checkRsync(cmd) {
|
|
|
104
104
|
function block(reason, host = null) {
|
|
105
105
|
let guidance;
|
|
106
106
|
if (host === PROD_IP) {
|
|
107
|
-
guidance = `请使用标准部署流程:
|
|
108
|
-
后端: bash scripts/deploy.sh --yes
|
|
109
|
-
Demo 正式: bash scripts/deploy-demo.sh <name> --channel prod --yes
|
|
110
|
-
Demo 内测: bash scripts/deploy-demo.sh <name> --channel preview --yes
|
|
111
|
-
Edge/Nginx: bash scripts/deploy-edge.sh --yes
|
|
107
|
+
guidance = `请使用标准部署流程:
|
|
108
|
+
后端: bash scripts/deploy.sh --yes
|
|
109
|
+
Demo 正式: bash scripts/deploy-demo.sh <name> --channel prod --yes
|
|
110
|
+
Demo 内测: bash scripts/deploy-demo.sh <name> --channel preview --yes
|
|
111
|
+
Edge/Nginx: bash scripts/deploy-edge.sh --yes
|
|
112
112
|
详见 Bolloon.md Development Commands。`;
|
|
113
113
|
}
|
|
114
114
|
else if (BRIDGE_VPS_HOSTS.includes(host ?? "")) {
|
|
115
|
-
guidance = `Bridge VPS 必须走 git pull 更新路径:
|
|
116
|
-
ssh root@${host} 'sudo -u boll git -C /opt/boll pull --ff-only'
|
|
117
|
-
scp/rsync 直传会重新制造 orphan worktree。
|
|
115
|
+
guidance = `Bridge VPS 必须走 git pull 更新路径:
|
|
116
|
+
ssh root@${host} 'sudo -u boll git -C /opt/boll pull --ff-only'
|
|
117
|
+
scp/rsync 直传会重新制造 orphan worktree。
|
|
118
118
|
详见 docs/issues/guard-20260408-0445-bridge-vps-orphan-worktree.md。`;
|
|
119
119
|
}
|
|
120
120
|
else {
|
|
@@ -253,9 +253,9 @@ export async function generateJudgmentInjection(filePath, gate, options = {}) {
|
|
|
253
253
|
const header = gate === 3
|
|
254
254
|
? '# Plan Freeze - Decision Principles'
|
|
255
255
|
: `# Gate ${gate} - Active Judgments`;
|
|
256
|
-
return `${header}
|
|
257
|
-
# Path: ${filePath}
|
|
258
|
-
# Confidence: ${(result.confidence * 100).toFixed(0)}%
|
|
259
|
-
|
|
256
|
+
return `${header}
|
|
257
|
+
# Path: ${filePath}
|
|
258
|
+
# Confidence: ${(result.confidence * 100).toFixed(0)}%
|
|
259
|
+
|
|
260
260
|
${result.contextYaml}`;
|
|
261
261
|
}
|