@bolloon/bolloon-agent 0.5.0 → 0.5.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/dist/agents/execution-supervisor.js +87 -5
- package/dist/agents/model-policy.js +651 -0
- package/dist/agents/pi-sdk-tools.js +84 -33
- package/dist/agents/pi-sdk.js +83 -23
- package/dist/agents/run-store.js +53 -0
- package/dist/agents/task/task-runner.js +8 -1
- package/dist/agents/workflow-pivot-loop.js +19 -12
- package/dist/cli/clipboard.js +65 -0
- package/dist/cli/ink-app.js +145 -17
- package/dist/cli/log-gate.js +386 -0
- package/dist/cli/mention-data.js +2 -0
- package/dist/cli/model-selector.js +538 -0
- package/dist/cli/reply-hygiene.js +54 -0
- package/dist/cli/setup-wizard.js +686 -69
- package/dist/cli/startup-notice.js +160 -0
- package/dist/cli/stores.js +22 -1
- package/dist/cli/theme.js +49 -0
- package/dist/cli/tui-select.js +970 -0
- package/dist/cli-entry.js +125 -18
- package/dist/electron-build/agents/execution-supervisor.js +86 -4
- package/dist/electron-build/agents/execution-supervisor.js.map +1 -1
- package/dist/electron-build/agents/goal-store.js.map +1 -1
- package/dist/electron-build/agents/model-policy.js +706 -0
- package/dist/electron-build/agents/model-policy.js.map +1 -0
- package/dist/electron-build/agents/pi-sdk-tools.js +84 -33
- package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk-types.js.map +1 -1
- package/dist/electron-build/agents/pi-sdk.js +83 -23
- package/dist/electron-build/agents/pi-sdk.js.map +1 -1
- package/dist/electron-build/agents/run-store.js +55 -1
- package/dist/electron-build/agents/run-store.js.map +1 -1
- package/dist/electron-build/agents/task/task-runner.js +8 -1
- package/dist/electron-build/agents/task/task-runner.js.map +1 -1
- package/dist/electron-build/agents/workflow-pivot-loop.js +19 -12
- package/dist/electron-build/agents/workflow-pivot-loop.js.map +1 -1
- package/dist/electron-build/llm/config-store.js +146 -6
- package/dist/electron-build/llm/config-store.js.map +1 -1
- package/dist/electron-build/llm/connection-probe.js +764 -0
- package/dist/electron-build/llm/connection-probe.js.map +1 -0
- package/dist/electron-build/llm/custom-provider-store.js +272 -0
- package/dist/electron-build/llm/custom-provider-store.js.map +1 -0
- package/dist/electron-build/llm/data/provider-catalog-baked.js +23 -0
- package/dist/electron-build/llm/data/provider-catalog-baked.js.map +1 -0
- package/dist/electron-build/llm/model-catalog.js +778 -0
- package/dist/electron-build/llm/model-catalog.js.map +1 -0
- package/dist/electron-build/llm/model-discovery.js +1202 -0
- package/dist/electron-build/llm/model-discovery.js.map +1 -0
- package/dist/electron-build/llm/model-selection.js +1315 -0
- package/dist/electron-build/llm/model-selection.js.map +1 -0
- package/dist/electron-build/llm/pi-ai.js +70 -11
- package/dist/electron-build/llm/pi-ai.js.map +1 -1
- package/dist/electron-build/llm/provider-catalog.js +969 -0
- package/dist/electron-build/llm/provider-catalog.js.map +1 -0
- package/dist/electron-build/llm/provider-registry.js +950 -0
- package/dist/electron-build/llm/provider-registry.js.map +1 -0
- package/dist/electron-build/llm/tool-name.js +266 -0
- package/dist/electron-build/llm/tool-name.js.map +1 -0
- package/dist/electron-build/utils/dual-source-facts.js +236 -0
- package/dist/electron-build/utils/dual-source-facts.js.map +1 -0
- package/dist/electron-build/utils/dual-source.js +32 -156
- package/dist/electron-build/utils/dual-source.js.map +1 -1
- package/dist/electron-build/utils/update-manager.js +22 -72
- package/dist/electron-build/utils/update-manager.js.map +1 -1
- package/dist/electron-build/utils/update-state.js +2 -19
- package/dist/electron-build/utils/update-state.js.map +1 -1
- package/dist/electron-build/utils/version-identity.js +193 -0
- package/dist/electron-build/utils/version-identity.js.map +1 -0
- package/dist/electron-build/utils/version-info.js +47 -101
- package/dist/electron-build/utils/version-info.js.map +1 -1
- package/dist/index.js +282 -96
- package/dist/ios/bolloon-web.json +10 -0
- package/dist/ios/mobile-contacts.js +44 -11
- package/dist/ios/mobile-core.js +1723 -84
- package/dist/ios/mobile-tasks.js +339 -0
- package/dist/ios/mobile-update.js +1442 -0
- package/dist/ios/mobile.js +308 -35
- package/dist/ios/routes-llm-config.js +344 -52
- package/dist/ios/routes-mobile-tasks.js +353 -0
- package/dist/ios/server.js +163 -4
- package/dist/ios/sw.js +1 -1
- package/dist/llm/config-store.js +146 -6
- package/dist/llm/connection-probe.js +744 -0
- package/dist/llm/custom-provider-store.js +224 -0
- package/dist/llm/data/provider-catalog-baked.js +19 -0
- package/dist/llm/model-catalog.js +717 -0
- package/dist/llm/model-discovery.js +1137 -0
- package/dist/llm/model-selection.js +1241 -0
- package/dist/llm/pi-ai.js +70 -11
- package/dist/llm/provider-catalog.js +898 -0
- package/dist/llm/provider-registry.js +917 -0
- package/dist/llm/tool-name.js +220 -0
- package/dist/setup/onboard.js +34 -8
- package/dist/utils/dual-source-facts.js +223 -0
- package/dist/utils/dual-source.js +12 -141
- package/dist/utils/update-manager.js +16 -59
- package/dist/utils/update-state.js +6 -18
- package/dist/utils/version-identity.js +176 -0
- package/dist/utils/version-info.js +9 -78
- package/dist/web/bolloon-web.json +10 -0
- package/dist/web/mobile-core.js +1721 -84
- package/dist/web/mobile-update.js +1442 -0
- package/dist/web/mobile.js +308 -35
- package/dist/web/routes-llm-config.js +344 -52
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/scripts/build-web.ts +36 -0
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import * as os from 'os';
|
|
15
15
|
import { listRunnableGoals, claimGoal, heartbeatGoal, releaseGoal, readGoal, setContinuation, bumpContinuationAttempts, evaluateGoalCompletion, addEvidence, } from './goal-store.js';
|
|
16
|
-
|
|
16
|
+
// 2026-09-26 (P7 接线): 长期任务的模型策略 —— 「下一个 Run 用哪一份模型」的唯一决定函数,
|
|
17
|
+
// 以及「这次失败换模型能解决吗」的唯一判定函数 (Supervisor 不再自己看失败类别猜)。
|
|
18
|
+
import { resolveNextRunModel, supervisorMaySwitchModel, parseGoalModelPolicy, formatModelDecision, isTerminalRunStatus, } from './model-policy.js';
|
|
19
|
+
import { readRun, reconcileOrphans, superviseRuns, buildContinuationPlan, recordModelSwitch, RESUMABLE_STATUSES, } from './run-store.js';
|
|
17
20
|
// 2026-09-25 (飞轮接线): P0–P4 的七个模块经**唯一**适配层接进真实执行路径
|
|
18
21
|
// (节奏由进展决定 · Run 收尾必过 closeRun · 子 Agent 走工作合同 · 阻塞监控 · 变更注入 · 用户可见态)
|
|
19
22
|
// 2026-09-25 (串行收口): 四条线各自报"只有主线能加"的钩子在这里补齐 ——
|
|
@@ -96,13 +99,19 @@ export function decideGoalOutcome(goal, run, opts = {}) {
|
|
|
96
99
|
case 'failed':
|
|
97
100
|
case 'needs_human': {
|
|
98
101
|
const cls = run.errorClass || 'unknown';
|
|
102
|
+
// ★ 2026-09-26 (P7 接线): 这次失败"换一个模型能不能解决"由**唯一判定函数**回答, 不再由
|
|
103
|
+
// Supervisor 这边看类别自己猜。结论照实写进 reason (含策略模式与理由), 但**不改写**任何
|
|
104
|
+
// 在跑的 Run —— 真正换模型发生在下一个 Run 的决定里 (`resolveNextRunModel`, 见 runGoal)。
|
|
105
|
+
const policyMode = parseGoalModelPolicy(goal.modelPolicy).policy.mode;
|
|
106
|
+
const modelVerdict = supervisorMaySwitchModel({ mode: policyMode, errorClass: run.errorClass });
|
|
107
|
+
const modelHint = `; 模型: 策略=${policyMode} · ${modelVerdict.reason}`;
|
|
99
108
|
const needsHuman = ['auth', 'persist_failed', 'corrupt_state', 'policy_denied', 'repeat_failure', 'bad_args', 'no_such_tool'].includes(cls)
|
|
100
109
|
|| attempts >= maxAttempts;
|
|
101
110
|
if (needsHuman) {
|
|
102
111
|
return {
|
|
103
112
|
goalStatus: 'needs_human',
|
|
104
113
|
continuation: { ...base, autoContinue: false, wakeReason: 'needs_human', attempts },
|
|
105
|
-
reason: `${cls} 需要人工介入${attempts >= maxAttempts ? ` (自动继续已试 ${attempts} 次)` : ''}`,
|
|
114
|
+
reason: `${cls} 需要人工介入${attempts >= maxAttempts ? ` (自动继续已试 ${attempts} 次)` : ''}${modelHint}`,
|
|
106
115
|
};
|
|
107
116
|
}
|
|
108
117
|
const wait = continuationBackoffMs(attempts);
|
|
@@ -114,7 +123,7 @@ export function decideGoalOutcome(goal, run, opts = {}) {
|
|
|
114
123
|
wakeAt: new Date(now + wait).toISOString(),
|
|
115
124
|
attempts: attempts + 1,
|
|
116
125
|
},
|
|
117
|
-
reason: `可恢复错误 ${cls}: 第 ${attempts + 1} 次自动继续, ${Math.round(wait / 1000)}s
|
|
126
|
+
reason: `可恢复错误 ${cls}: 第 ${attempts + 1} 次自动继续, ${Math.round(wait / 1000)}s 后唤醒${modelHint}`,
|
|
118
127
|
};
|
|
119
128
|
}
|
|
120
129
|
case 'recovering':
|
|
@@ -500,6 +509,55 @@ export class ExecutionSupervisor {
|
|
|
500
509
|
const prevRun = prevRunId ? await readRun(prevRunId) : null;
|
|
501
510
|
const plan = prevRunId ? await buildContinuationPlan(prevRunId).catch(() => null) : null;
|
|
502
511
|
const guards = plan?.replayGuards || [];
|
|
512
|
+
// ★ 2026-09-26 (P7 接线): 下一个 Run 该用**哪一份**模型配置 —— 唯一决定函数 `resolveNextRunModel`。
|
|
513
|
+
// 它自己走完四步: ① 读 Goal 策略 (记录上的 modelPolicy 优先, 没有才读 sidecar);
|
|
514
|
+
// ② 定稿配置 (auto → 最新 Global 默认; pinned → 固定三元组; session → 会话绑定);
|
|
515
|
+
// ③ 按**失败类别**判定能不能挑备用模型 (内部就是 `supervisorMaySwitchModel`);
|
|
516
|
+
// ④ 跨 Run 非幂等守卫照带 (模型换了也不重做副作用), 并把这次决定写成 Run 事件。
|
|
517
|
+
// 它算的是**下一条** Run: 在跑的那条 Run 的快照一个字都不动 (旧 Run 可追溯)。
|
|
518
|
+
//
|
|
519
|
+
// ⚠ **事件落点** (接线时真跑逼出来的, 不是设计洁癖): P7 自己文档里的事实边界是
|
|
520
|
+
// 「本层算出来的只用于①下一个 Run 的启动快照 ②切换事件 —— **它不回头改老 Run**」,
|
|
521
|
+
// 飞轮规则 ⑦ (`goal-flywheel-wiring.test.ts`) 更是**逐字节**钉住「已发生的 Run 记录不被改写」。
|
|
522
|
+
// 而决定函数的事件缺省落点是 `prevRunId` —— 上一条 Run **已经收尾**时, 那条写入等于
|
|
523
|
+
// 往历史记录上追加一格 (真跑实测: `updatedAt`/`modelSwitches`/`harness` 全变 ⇒ 判红)。
|
|
524
|
+
// 所以分两种, 都说清: 上一条 Run **还活着** → 事件就写它 (它是当事 Run, 也是缺省);
|
|
525
|
+
// **已收尾** → 它是历史, 决定"只算不写", 等新 Run 起来后把同一条决定记到**新 Run 自己**的
|
|
526
|
+
// 账本上 (`RunModelSwitchEvent.to` 的语义本来就是"这个 Run **或下一个 Run** 该用的那一份")。
|
|
527
|
+
const prevIsHistory = prevRun ? isTerminalRunStatus(prevRun.status) : true;
|
|
528
|
+
let modelResolution = null;
|
|
529
|
+
try {
|
|
530
|
+
// 备用候选: 只有上一个 Run 是**模型相关失败**时才值得去凑 (凑法在切换入口里, 只挑现在真能用的)
|
|
531
|
+
const fallbackCandidates = prevRun?.errorClass
|
|
532
|
+
? await (async () => {
|
|
533
|
+
const ms = await import('../llm/model-selection.js');
|
|
534
|
+
return await ms.usableFallbackCandidates(prevRun.modelConfig ?? null);
|
|
535
|
+
})().catch(() => [])
|
|
536
|
+
: [];
|
|
537
|
+
modelResolution = await resolveNextRunModel({
|
|
538
|
+
goalId: goal.goalId,
|
|
539
|
+
// 上一条 Run 已收尾 = 历史 → 不给事件落点 (P7 契约里"只算不写"的那一档), 免得往历史追加
|
|
540
|
+
...(prevIsHistory ? {} : { prevRunId: prevRunId || undefined }),
|
|
541
|
+
policy: goal.modelPolicy,
|
|
542
|
+
errorClass: prevRun?.errorClass,
|
|
543
|
+
...(fallbackCandidates.length ? { fallbackCandidates } : {}),
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
catch (err) {
|
|
547
|
+
// 算不出来**不猜**: 下一句日志说清, 执行器按自己的默认启动 (Run 记录里因此没有模型快照)
|
|
548
|
+
this.log(`[supervisor] goal=${goal.goalId} 下一个 Run 的模型决定算不出来 (按无快照启动): ${String(err?.message || err).slice(0, 160)}`);
|
|
549
|
+
}
|
|
550
|
+
const nextModelConfig = modelResolution?.startRunModelConfig;
|
|
551
|
+
if (modelResolution) {
|
|
552
|
+
this.log(`[supervisor] goal=${goal.goalId} 下一个 Run 模型: ${formatModelDecision(modelResolution.decision)}`
|
|
553
|
+
+ `; 策略来源=${modelResolution.policyOrigin}`
|
|
554
|
+
+ `${modelResolution.startRunModelConfig ? `; 启动快照 hash=${modelResolution.startRunModelConfig.configHash}` : '; 没有可信快照 → 不写快照'}`
|
|
555
|
+
+ `; 事件=${modelResolution.event.ok
|
|
556
|
+
? `已写(Run ${modelResolution.event.onRunId || '-'})`
|
|
557
|
+
: prevIsHistory && modelResolution.startRunModelConfig
|
|
558
|
+
? '等新 Run 起来后写在它自己的账本上 (上一条 Run 已收尾 = 历史, 不许改写)'
|
|
559
|
+
: `未写(${modelResolution.event.reason || '原因未明'})`}`);
|
|
560
|
+
}
|
|
503
561
|
// 2026-09-25 (飞轮接线 P4 / P2): 下一个 Run 必须真的读到**同一份**事实 ——
|
|
504
562
|
// ① 权威 continuation 的 nextAction (飞轮收尾写下的"下一步是什么");
|
|
505
563
|
// ② 已生效的新要求 (变更注入: 只影响后续 Run, 不改写历史);
|
|
@@ -525,7 +583,7 @@ export class ExecutionSupervisor {
|
|
|
525
583
|
if (!runner && this.resolver) {
|
|
526
584
|
let res;
|
|
527
585
|
try {
|
|
528
|
-
res = await this.resolver({ goal, kind, prevRunId, instruction, guards });
|
|
586
|
+
res = await this.resolver({ goal, kind, prevRunId, instruction, guards, ...(nextModelConfig ? { modelConfig: nextModelConfig } : {}) });
|
|
529
587
|
}
|
|
530
588
|
catch (err) {
|
|
531
589
|
res = { ok: false, kind: 'none', reason: `resolver 抛错: ${String(err?.message || err).slice(0, 140)}` };
|
|
@@ -600,7 +658,7 @@ export class ExecutionSupervisor {
|
|
|
600
658
|
let result;
|
|
601
659
|
const t0 = Date.now();
|
|
602
660
|
try {
|
|
603
|
-
result = await runner({ goal, kind, prevRunId, instruction, guards });
|
|
661
|
+
result = await runner({ goal, kind, prevRunId, instruction, guards, ...(nextModelConfig ? { modelConfig: nextModelConfig } : {}) });
|
|
604
662
|
}
|
|
605
663
|
catch (err) {
|
|
606
664
|
result = { error: err?.message || String(err) };
|
|
@@ -608,6 +666,30 @@ export class ExecutionSupervisor {
|
|
|
608
666
|
finally {
|
|
609
667
|
clearInterval(hb);
|
|
610
668
|
}
|
|
669
|
+
// ★ 2026-09-26 (P7 接线): 决定"只算不写"的那一档, 把同一条决定**补写进它真正生效的那条 Run**。
|
|
670
|
+
// 为什么不写在算决定的那一刻: 那时新 Run 还没有 id, 而唯一的现成落点是已经收尾的上一条 Run
|
|
671
|
+
// —— 那是历史 (`prevIsHistory` 分支就是为了不碰它)。落点等执行器报回 runId 再定, 事实不丢。
|
|
672
|
+
const runIdOfThisRun = result.runId && result.runId !== prevRunId ? result.runId : null;
|
|
673
|
+
if (modelResolution && nextModelConfig && runIdOfThisRun && !modelResolution.event.ok
|
|
674
|
+
&& prevIsHistory && (await readRun(runIdOfThisRun).catch(() => null))) {
|
|
675
|
+
const d = modelResolution.decision;
|
|
676
|
+
const from = prevRun?.modelConfig ?? null;
|
|
677
|
+
// 同口径 = 同一份 `configHash` 就是同一份 (P7 的 configHash 契约), 别自己另立一套
|
|
678
|
+
const outcome = (d.conflict && d.conflict.length) ? 'conflict'
|
|
679
|
+
: (from && from.configHash === nextModelConfig.configHash) ? 'frozen' : 'switched';
|
|
680
|
+
const w = await recordModelSwitch(runIdOfThisRun, {
|
|
681
|
+
to: nextModelConfig,
|
|
682
|
+
from,
|
|
683
|
+
outcome,
|
|
684
|
+
mode: (d.mode === 'auto' || d.mode === 'pinned' || d.mode === 'session' ? d.mode : 'unknown'),
|
|
685
|
+
source: d.source,
|
|
686
|
+
reason: `${d.reason}; 事件落在新 Run (上一条 Run 已收尾 = 历史, 不许改写)`.slice(0, 400),
|
|
687
|
+
guardsCarried: guards.length,
|
|
688
|
+
goalId: goal.goalId,
|
|
689
|
+
});
|
|
690
|
+
this.log(`[supervisor] goal=${goal.goalId} 模型决定补写在新 Run ${runIdOfThisRun} 的账本上: `
|
|
691
|
+
+ `${w.ok ? `outcome=${outcome}` : `写不进去 (${w.reason || '原因未明'})`}`);
|
|
692
|
+
}
|
|
611
693
|
// Run 结束 → Goal 决策 (确定性 reducer, 落盘)
|
|
612
694
|
const finalRunId = result.runId || prevRunId;
|
|
613
695
|
const finalRun = finalRunId ? await readRun(finalRunId) : null;
|