@zhushanwen/pi-subagent-workflow 9.4.0 → 9.5.0
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 +19 -5
- package/package.json +10 -10
- package/src/host/pi-host.ts +9 -6
- package/src/index.ts +9 -2
- package/src/injectors/__tests__/workflow-list-injector.test.ts +11 -4
- package/src/injectors/resource-list-injector.ts +17 -7
- package/src/injectors/subagent-list-injector.ts +27 -2
- package/src/injectors/workflow-list-injector.ts +1 -1
- package/src/interface/command/commands.ts +126 -66
- package/src/interface/gui/subagent-actions.ts +4 -2
- package/src/interface/tool/__tests__/capture-tool.ts +34 -13
- package/src/interface/tool/__tests__/subagent-tool-actions.test.ts +105 -41
- package/src/interface/tool/__tests__/subagent-tool-path-guard.test.ts +16 -12
- package/src/interface/tool/__tests__/tool-prompt-contract.test.ts +359 -175
- package/src/interface/tool/__tests__/tool-subagents.test.ts +28 -13
- package/src/interface/tool/__tests__/tool-workflow.test.ts +80 -59
- package/src/interface/tool/subagent-tool-schema.ts +79 -70
- package/src/interface/tool/subagent-tool.ts +205 -136
- package/src/interface/tool/tool-render.ts +7 -5
- package/src/interface/tool/tool-result.ts +3 -2
- package/src/interface/tool/tool-subagents.ts +39 -40
- package/src/interface/tool/tool-workflow-script.ts +7 -5
- package/src/interface/tool/tool-workflow.ts +164 -116
- package/src/jsonl-run-store.ts +126 -48
- package/src/session-lifecycle.ts +11 -7
package/src/jsonl-run-store.ts
CHANGED
|
@@ -67,13 +67,17 @@ import {
|
|
|
67
67
|
noteRebuiltSettlement,
|
|
68
68
|
settlementRecordOfRunSettledFrame,
|
|
69
69
|
type AgentResult,
|
|
70
|
+
type Budget,
|
|
70
71
|
type ExecutionTraceNode,
|
|
71
72
|
type RunEventLineIssue,
|
|
72
73
|
type RunOutcome,
|
|
74
|
+
type RunSpec,
|
|
73
75
|
type RunStore,
|
|
76
|
+
type WorkflowModelOverride,
|
|
74
77
|
type WorkflowRecordRegisteredEntryData,
|
|
75
78
|
type WorkflowRecordSettledEntryData,
|
|
76
79
|
type WorkflowRunEvent,
|
|
80
|
+
type WorkerLogEntry,
|
|
77
81
|
} from "@zhushanwen/subagent-core";
|
|
78
82
|
import { WorkflowRun } from "@zhushanwen/subagent-core";
|
|
79
83
|
import { errorLogsFromEvents, latestModelOverride, rebuildBudget, runAccountingFromEvents } from "@zhushanwen/subagent-core";
|
|
@@ -478,26 +482,32 @@ function rebuildRunSpecFromEntries(
|
|
|
478
482
|
};
|
|
479
483
|
}
|
|
480
484
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
485
|
+
/**
|
|
486
|
+
* [foldRecordStreamToRun 拆分] 两分支 reconstruct 共用的 fold 产物(spec 之外的
|
|
487
|
+
* 快照/元数据公共字段)。
|
|
488
|
+
*/
|
|
489
|
+
interface FoldCommonParts {
|
|
490
|
+
budget: Budget;
|
|
491
|
+
errorLogs: WorkerLogEntry[];
|
|
492
|
+
startedAt: string;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* [foldRecordStreamToRun 拆分] 两分支 reconstruct 共用的聚合重建块(trace + calls +
|
|
497
|
+
* 覆盖记账——原 fold 主干的公共块提取)。
|
|
498
|
+
*/
|
|
499
|
+
interface RebuiltRunAggregate {
|
|
500
|
+
calls: Map<number, AgentCall>;
|
|
501
|
+
trace: Trace;
|
|
502
|
+
/** 生效模型覆盖记账(无覆盖 undefined 不造键——语义见 rebuildRunAggregate 内注释)。 */
|
|
503
|
+
modelOverride: WorkflowModelOverride | undefined;
|
|
504
|
+
}
|
|
500
505
|
|
|
506
|
+
/**
|
|
507
|
+
* 聚合重建块:drafts → trace 节点 → Trace 副本 → call 集合(D-10 引用共享链)+
|
|
508
|
+
* 覆盖记账折叠。纯函数,零 IO。
|
|
509
|
+
*/
|
|
510
|
+
function rebuildRunAggregate(events: readonly WorkflowRunEvent[]): RebuiltRunAggregate {
|
|
501
511
|
const drafts = collectRunCallDrafts(events);
|
|
502
512
|
|
|
503
513
|
// Trace 先重建:call 的 traceNode 回链到 Trace 副本(D-10 引用共享;匹配不到
|
|
@@ -508,55 +518,123 @@ function foldRecordStreamToRun(
|
|
|
508
518
|
|
|
509
519
|
const calls = draftsToAgentCalls(drafts, sharedNodes, nodes);
|
|
510
520
|
|
|
511
|
-
const settledEvent = lastRunSettledEvent(events);
|
|
512
521
|
// [subagent-model-switch §6.6①/§7.4] 覆盖记账折叠(派生视图半边):生效覆盖值 =
|
|
513
522
|
// 最新一条(latestModelOverride core 单点——覆盖旧覆盖值不叠加,不变量 2);
|
|
514
523
|
// 无覆盖 undefined 不造键。fold 未跟时本行缺失 = 覆盖状态静默丢行——
|
|
515
524
|
// jsonl-run-store-loadall 的 fold 消费用例是此丢行风险的机器防线(P8 第五道)。
|
|
516
525
|
const modelOverride = latestModelOverride(events);
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
526
|
+
return { calls, trace, modelOverride };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* 非终局分支 reconstruct:无 run-settled 帧 = running(交恢复链收编)+ 中断标记
|
|
531
|
+
* 投影([D2])。
|
|
532
|
+
*/
|
|
533
|
+
function reconstructUnsettledRun(
|
|
534
|
+
runId: string,
|
|
535
|
+
spec: RunSpec,
|
|
536
|
+
aggregate: RebuiltRunAggregate,
|
|
537
|
+
parts: FoldCommonParts,
|
|
538
|
+
events: readonly WorkflowRunEvent[],
|
|
539
|
+
): WorkflowRun {
|
|
540
|
+
const interruptedAt = lastInterruptedAt(events);
|
|
541
|
+
return WorkflowRun.reconstruct(
|
|
542
|
+
runId,
|
|
543
|
+
spec,
|
|
544
|
+
{
|
|
545
|
+
budget: parts.budget,
|
|
546
|
+
calls: aggregate.calls,
|
|
547
|
+
trace: aggregate.trace,
|
|
548
|
+
errorLogs: parts.errorLogs,
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
startedAt: parts.startedAt,
|
|
552
|
+
// 中断标记([D2] 中断态经 meta 投影表达):末次 run-interrupted 后无
|
|
553
|
+
// run-resumed 复活 → meta.interruptedAt 置位,runSummary 投影 'interrupted'
|
|
554
|
+
//(CLI/TUI 不显示僵尸「运行中」;resume 资格判据在 core fold lifecycle,
|
|
555
|
+
// 不受本投影影响)。
|
|
556
|
+
...(interruptedAt !== undefined ? { interruptedAt } : {}),
|
|
557
|
+
...(aggregate.modelOverride !== undefined ? { modelOverride: aggregate.modelOverride } : {}),
|
|
558
|
+
},
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* 终局分支 reconstruct:run-settled 帧派生 DoneReason + completedAt;失败终局带
|
|
564
|
+
* 帧 reason 文本(不落 generic 恢复文案)。
|
|
565
|
+
*/
|
|
566
|
+
function reconstructSettledRun(
|
|
567
|
+
runId: string,
|
|
568
|
+
spec: RunSpec,
|
|
569
|
+
aggregate: RebuiltRunAggregate,
|
|
570
|
+
parts: FoldCommonParts,
|
|
571
|
+
settledEvent: RunSettledFrame,
|
|
572
|
+
): WorkflowRun {
|
|
539
573
|
const reason = runSettledOutcomeToDoneReason(settledEvent.outcome, settledEvent.errorCode);
|
|
540
574
|
return WorkflowRun.reconstruct(
|
|
541
575
|
runId,
|
|
542
576
|
spec,
|
|
543
577
|
{
|
|
544
578
|
reason,
|
|
545
|
-
budget,
|
|
546
|
-
calls,
|
|
547
|
-
trace,
|
|
548
|
-
errorLogs,
|
|
579
|
+
budget: parts.budget,
|
|
580
|
+
calls: aggregate.calls,
|
|
581
|
+
trace: aggregate.trace,
|
|
582
|
+
errorLogs: parts.errorLogs,
|
|
549
583
|
// 成功终局无 error;失败终局带帧 reason 文本(不落 generic 恢复文案)
|
|
550
584
|
...(reason !== "completed" && settledEvent.reason !== undefined ? { error: settledEvent.reason } : {}),
|
|
551
585
|
},
|
|
552
586
|
{
|
|
553
|
-
startedAt:
|
|
587
|
+
startedAt: parts.startedAt,
|
|
554
588
|
completedAt: new Date(settledEvent.ts).toISOString(),
|
|
555
|
-
...(modelOverride !== undefined ? { modelOverride } : {}),
|
|
589
|
+
...(aggregate.modelOverride !== undefined ? { modelOverride: aggregate.modelOverride } : {}),
|
|
556
590
|
},
|
|
557
591
|
);
|
|
558
592
|
}
|
|
559
593
|
|
|
594
|
+
/**
|
|
595
|
+
* startedAt 毫秒锚:run-created 帧 ts 优先,回落注册条目 startedAt(非有限数值 =
|
|
596
|
+
* 兜底当前时刻,保 startedAt 恒有值)。
|
|
597
|
+
*/
|
|
598
|
+
function resolveStartedAtMs(
|
|
599
|
+
created: Extract<WorkflowRunEvent, { type: "run-created" }> | undefined,
|
|
600
|
+
reg: WorkflowRecordRegisteredEntryData,
|
|
601
|
+
): number {
|
|
602
|
+
return created?.ts ?? (Number.isFinite(reg.startedAt) ? reg.startedAt : Date.now());
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* record 事件流 → WorkflowRun 聚合(纯函数,零 IO;fold 语义词表说明见文件头
|
|
607
|
+
* 「record 流 fold 重建」节)。主干只做产物编排:公共 fold 产物(budget/errorLogs/
|
|
608
|
+
* startedAt/spec)+ 聚合重建块(rebuildRunAggregate)+ 按终局帧有无分流到
|
|
609
|
+
* reconstructUnsettledRun / reconstructSettledRun。
|
|
610
|
+
*/
|
|
611
|
+
function foldRecordStreamToRun(
|
|
612
|
+
runId: string,
|
|
613
|
+
reg: WorkflowRecordRegisteredEntryData,
|
|
614
|
+
events: readonly WorkflowRunEvent[],
|
|
615
|
+
settled?: WorkflowRecordSettledEntryData,
|
|
616
|
+
): WorkflowRun {
|
|
617
|
+
const created = events.find(
|
|
618
|
+
(e): e is Extract<WorkflowRunEvent, { type: "run-created" }> => e.type === "run-created",
|
|
619
|
+
);
|
|
620
|
+
const spec = rebuildRunSpecFromEntries(created, reg, resolveSpecBudget(created, events));
|
|
621
|
+
// [§2.1b] 会计重建:v2 终态条目带活体口径 usedTokens/callCount → 真值优先;条目缺席
|
|
622
|
+
// 回落 agent-settled.result.usage 的同一加权口径(下界近似,含 usedCost)。
|
|
623
|
+
// [§2.1 errorLogs 持久化 / ADR-0093] 诊断日志重建:worker-log 帧 → errorLogs(与活体
|
|
624
|
+
// 写入同语义:按序 + 尾部上限裁剪)。此前无持久面、重启即空。
|
|
625
|
+
const parts: FoldCommonParts = {
|
|
626
|
+
budget: rebuildBudget(settled, events),
|
|
627
|
+
errorLogs: errorLogsFromEvents(events),
|
|
628
|
+
startedAt: new Date(resolveStartedAtMs(created, reg)).toISOString(),
|
|
629
|
+
};
|
|
630
|
+
const aggregate = rebuildRunAggregate(events);
|
|
631
|
+
const settledEvent = lastRunSettledEvent(events);
|
|
632
|
+
if (settledEvent === undefined) {
|
|
633
|
+
return reconstructUnsettledRun(runId, spec, aggregate, parts, events);
|
|
634
|
+
}
|
|
635
|
+
return reconstructSettledRun(runId, spec, aggregate, parts, settledEvent);
|
|
636
|
+
}
|
|
637
|
+
|
|
560
638
|
// ── JsonlRunStore ────────────────────────────────────────────
|
|
561
639
|
|
|
562
640
|
const logger = getLogger("subagents");
|
package/src/session-lifecycle.ts
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
import { bindNotifyLedgerHost, type NotifyLedgerHost } from "@zhushanwen/subagent-core";
|
|
43
43
|
import { IDENTITY_CUSTOM_TYPE, type SubagentIdentityData } from "@zhushanwen/subagent-core";
|
|
44
44
|
import type { ExecutionMode } from "@zhushanwen/subagent-core";
|
|
45
|
-
import {
|
|
45
|
+
import { startEngineJournalGcTimer } from "@zhushanwen/subagent-core";
|
|
46
46
|
import { resolvePiSessionScopedDir } from "@zhushanwen/subagent-core";
|
|
47
47
|
// [W1 / D5] session_start 兜底触发点的统一保留维护轮:入口 + record 域目录锚
|
|
48
48
|
// (getSubagentRecordsDir 布局 + ENV_ROOT_CWD 贯穿 env 名单源)+ state 目录分量
|
|
@@ -557,7 +557,7 @@ export function bindLedgerHostAndRecover(pi: ExtensionAPI, ctx: ExtensionContext
|
|
|
557
557
|
|
|
558
558
|
/**
|
|
559
559
|
* 随迁块 4 的进程级维护三连(各 try-catch「失败记日志不阻断」,设计 §3.4):
|
|
560
|
-
*
|
|
560
|
+
* 引擎 journal TTL 回收 / ADR-035 manifest tmp 恢复 / ADR-035 worktree reaper 扫描。
|
|
561
561
|
* ([modeless 波5] 原 [E1] sync 批崩溃恢复接线已摘除;[collect 退役] core 侧
|
|
562
562
|
* recoverSyncCollectBatch 方法本体已删——sync 批机制不存在,无恢复面可接线。)
|
|
563
563
|
*/
|
|
@@ -568,12 +568,16 @@ async function runProcessLevelMaintenance(
|
|
|
568
568
|
deps: SessionLifecycleDeps,
|
|
569
569
|
): Promise<void> {
|
|
570
570
|
try {
|
|
571
|
-
//
|
|
572
|
-
//
|
|
573
|
-
oncePerProcess
|
|
574
|
-
|
|
571
|
+
// 引擎 journal TTL 回收(30 天 mtime)+ worktree .patch 孤儿清扫(同 TTL,仅
|
|
572
|
+
// *.patch 两层枚举——按 branch 命名无会话锚,级联引用并集无锚可达,唯一 mtime
|
|
573
|
+
// 兜底通道)属进程级维护——oncePerProcess 守卫防双跑(u-audit-fix)。接线即扫
|
|
574
|
+
// 一次 + 24h 定时复扫(unref 不 hold 进程退出,对齐 main 侧 log-retention 形态)。
|
|
575
|
+
// 子代理会话文件(*.jsonl / sidecar / manifest / *.events)不在本维护面——回收归
|
|
576
|
+
// 删主会话级联(runtime session-content-cascade,2026-10-12 裁决)。
|
|
577
|
+
oncePerProcess("subagent-workflow:engine-journal-gc", () =>
|
|
578
|
+
startEngineJournalGcTimer(agentDir));
|
|
575
579
|
} catch (err) {
|
|
576
|
-
logger.warn("[subagents]
|
|
580
|
+
logger.warn("[subagents] engine journal gc failed", {
|
|
577
581
|
reason: toErrorMessage(err),
|
|
578
582
|
});
|
|
579
583
|
}
|