pi-agent-flow 2.0.2 → 2.0.6
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 +1 -1
- package/agents/audit.md +24 -17
- package/agents/build.md +1 -1
- package/agents/craft.md +1 -1
- package/agents/debug.md +1 -1
- package/agents/ideas.md +1 -1
- package/agents/scout.md +8 -8
- package/agents/trace.md +23 -0
- package/dist/batch/batch-bash.d.ts +10 -0
- package/dist/batch/batch-bash.d.ts.map +1 -1
- package/dist/batch/batch-bash.js +35 -2
- package/dist/batch/batch-bash.js.map +1 -1
- package/dist/batch/constants.d.ts +6 -3
- package/dist/batch/constants.d.ts.map +1 -1
- package/dist/batch/execute.js +2 -2
- package/dist/batch/execute.js.map +1 -1
- package/dist/batch/index.d.ts +9 -11
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +88 -58
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/render.d.ts +22 -5
- package/dist/batch/render.d.ts.map +1 -1
- package/dist/batch/render.js +332 -17
- package/dist/batch/render.js.map +1 -1
- package/dist/batch/summary.d.ts.map +1 -1
- package/dist/batch/summary.js +22 -4
- package/dist/batch/summary.js.map +1 -1
- package/dist/config/config.d.ts +5 -4
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +15 -5
- package/dist/config/config.js.map +1 -1
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +7 -1
- package/dist/config/models.js.map +1 -1
- package/dist/config/settings-resolver.d.ts +5 -4
- package/dist/config/settings-resolver.d.ts.map +1 -1
- package/dist/config/settings-resolver.js +50 -21
- package/dist/config/settings-resolver.js.map +1 -1
- package/dist/core2/snapshot.d.ts +21 -0
- package/dist/core2/snapshot.d.ts.map +1 -0
- package/dist/core2/snapshot.js +214 -0
- package/dist/core2/snapshot.js.map +1 -0
- package/dist/{core → flow}/agents.d.ts.map +1 -1
- package/dist/{core → flow}/agents.js +5 -2
- package/dist/{core → flow}/agents.js.map +1 -1
- package/dist/flow/command.d.ts +1 -1
- package/dist/flow/command.d.ts.map +1 -1
- package/dist/flow/complexity.d.ts +20 -0
- package/dist/flow/complexity.d.ts.map +1 -0
- package/dist/flow/complexity.js +34 -0
- package/dist/flow/complexity.js.map +1 -0
- package/dist/flow/continuation.d.ts +1 -1
- package/dist/flow/continuation.d.ts.map +1 -1
- package/dist/flow/continuation.js +2 -1
- package/dist/flow/continuation.js.map +1 -1
- package/dist/{core → flow}/depth.d.ts +1 -1
- package/dist/{core → flow}/depth.d.ts.map +1 -1
- package/dist/{core → flow}/depth.js.map +1 -1
- package/dist/{core → flow}/executor.d.ts +39 -19
- package/dist/flow/executor.d.ts.map +1 -0
- package/dist/flow/executor.js +727 -0
- package/dist/flow/executor.js.map +1 -0
- package/dist/flow/index.d.ts +2 -2
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +1 -1
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/loop-command.d.ts +1 -1
- package/dist/flow/loop-command.d.ts.map +1 -1
- package/dist/{core/flow.d.ts → flow/runner.d.ts} +10 -13
- package/dist/flow/runner.d.ts.map +1 -0
- package/dist/{core/flow.js → flow/runner.js} +35 -34
- package/dist/flow/runner.js.map +1 -0
- package/dist/{core → flow}/session-registry.d.ts.map +1 -1
- package/dist/{core → flow}/session-registry.js.map +1 -1
- package/dist/flow/settings-command.d.ts +3 -3
- package/dist/flow/settings-command.d.ts.map +1 -1
- package/dist/flow/settings-command.js +39 -21
- package/dist/flow/settings-command.js.map +1 -1
- package/dist/{core → flow}/transition.d.ts.map +1 -1
- package/dist/{core → flow}/transition.js.map +1 -1
- package/dist/flow/types.d.ts +4 -0
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/flow/warp.d.ts +1 -1
- package/dist/flow/warp.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +190 -189
- package/dist/index.js.map +1 -1
- package/dist/notify/notify.d.ts +1 -1
- package/dist/notify/notify.d.ts.map +1 -1
- package/dist/notify/notify.js +1 -1
- package/dist/snapshot/cli-args.d.ts +2 -2
- package/dist/snapshot/cli-args.d.ts.map +1 -1
- package/dist/snapshot/cli-args.js +21 -5
- package/dist/snapshot/cli-args.js.map +1 -1
- package/dist/snapshot/runner-events.d.ts +2 -2
- package/dist/snapshot/runner-events.d.ts.map +1 -1
- package/dist/snapshot/runner-events.js +48 -4
- package/dist/snapshot/runner-events.js.map +1 -1
- package/dist/snapshot/structured-output.d.ts +1 -1
- package/dist/snapshot/structured-output.d.ts.map +1 -1
- package/dist/snapshot/structured-output.js +20 -2
- package/dist/snapshot/structured-output.js.map +1 -1
- package/dist/steering/flow-prompt.d.ts +1 -3
- package/dist/steering/flow-prompt.d.ts.map +1 -1
- package/dist/steering/flow-prompt.js +7 -63
- package/dist/steering/flow-prompt.js.map +1 -1
- package/dist/steering/sliding-prompt.js +10 -10
- package/dist/steering/sliding-prompt.js.map +1 -1
- package/dist/tools/ask-user.d.ts +2 -2
- package/dist/tools/ask-user.d.ts.map +1 -1
- package/dist/tools/ask-user.js +1 -1
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/timed-bash.js +1 -1
- package/dist/tools/timed-bash.js.map +1 -1
- package/dist/tools/trace.d.ts +34 -0
- package/dist/tools/trace.d.ts.map +1 -0
- package/dist/tools/trace.js +180 -0
- package/dist/tools/trace.js.map +1 -0
- package/dist/tools/web-ops.d.ts +85 -0
- package/dist/tools/web-ops.d.ts.map +1 -0
- package/dist/tools/{web-tool.js → web-ops.js} +51 -125
- package/dist/tools/web-ops.js.map +1 -0
- package/dist/tui/flow-colors.d.ts +1 -0
- package/dist/tui/flow-colors.d.ts.map +1 -1
- package/dist/tui/flow-colors.js +2 -2
- package/dist/tui/flow-colors.js.map +1 -1
- package/dist/tui/render-utils.js +1 -1
- package/dist/tui/render-utils.js.map +1 -1
- package/dist/tui/render.d.ts +32 -1
- package/dist/tui/render.d.ts.map +1 -1
- package/dist/tui/render.js +666 -170
- package/dist/tui/render.js.map +1 -1
- package/dist/tui/scramble/algorithm.d.ts +4 -2
- package/dist/tui/scramble/algorithm.d.ts.map +1 -1
- package/dist/tui/scramble/algorithm.js +44 -12
- package/dist/tui/scramble/algorithm.js.map +1 -1
- package/dist/tui/scramble/constants.d.ts +3 -0
- package/dist/tui/scramble/constants.d.ts.map +1 -1
- package/dist/tui/scramble/constants.js +4 -1
- package/dist/tui/scramble/constants.js.map +1 -1
- package/dist/tui/scramble/index.d.ts +2 -1
- package/dist/tui/scramble/index.d.ts.map +1 -1
- package/dist/tui/scramble/index.js +1 -1
- package/dist/tui/scramble/index.js.map +1 -1
- package/dist/tui/scramble/manager.d.ts +1 -1
- package/dist/tui/scramble/manager.d.ts.map +1 -1
- package/dist/tui/scramble/manager.js +24 -19
- package/dist/tui/scramble/manager.js.map +1 -1
- package/dist/types/flow.d.ts +17 -1
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/flow.js.map +1 -1
- package/dist/types/output.d.ts +11 -36
- package/dist/types/output.d.ts.map +1 -1
- package/dist/types/output.js +1 -1
- package/dist/types/ui.d.ts +1 -1
- package/dist/types/ui.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/core/executor.d.ts.map +0 -1
- package/dist/core/executor.js +0 -378
- package/dist/core/executor.js.map +0 -1
- package/dist/core/flow.d.ts.map +0 -1
- package/dist/core/flow.js.map +0 -1
- package/dist/core/session-mode.d.ts +0 -11
- package/dist/core/session-mode.d.ts.map +0 -1
- package/dist/core/session-mode.js +0 -26
- package/dist/core/session-mode.js.map +0 -1
- package/dist/core/transitions.d.ts +0 -39
- package/dist/core/transitions.d.ts.map +0 -1
- package/dist/core/transitions.js +0 -59
- package/dist/core/transitions.js.map +0 -1
- package/dist/snapshot/index.d.ts +0 -2
- package/dist/snapshot/index.d.ts.map +0 -1
- package/dist/snapshot/index.js +0 -2
- package/dist/snapshot/index.js.map +0 -1
- package/dist/snapshot/reasoning-strip.d.ts +0 -22
- package/dist/snapshot/reasoning-strip.d.ts.map +0 -1
- package/dist/snapshot/reasoning-strip.js +0 -58
- package/dist/snapshot/reasoning-strip.js.map +0 -1
- package/dist/snapshot/snapshot.d.ts +0 -77
- package/dist/snapshot/snapshot.d.ts.map +0 -1
- package/dist/snapshot/snapshot.js +0 -1824
- package/dist/snapshot/snapshot.js.map +0 -1
- package/dist/tools/web-tool.d.ts +0 -46
- package/dist/tools/web-tool.d.ts.map +0 -1
- package/dist/tools/web-tool.js.map +0 -1
- /package/dist/{core → flow}/agents.d.ts +0 -0
- /package/dist/{core → flow}/depth.js +0 -0
- /package/dist/{core → flow}/session-registry.d.ts +0 -0
- /package/dist/{core → flow}/session-registry.js +0 -0
- /package/dist/{core → flow}/transition.d.ts +0 -0
- /package/dist/{core → flow}/transition.js +0 -0
package/dist/index.js
CHANGED
|
@@ -6,185 +6,164 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Type } from "@sinclair/typebox";
|
|
8
8
|
import { setupNotify } from "./notify/notify.js";
|
|
9
|
-
import { discoverFlows, getFlowTier } from "./
|
|
9
|
+
import { discoverFlows, getFlowTier } from "./flow/agents.js";
|
|
10
10
|
import { getInheritedCliArgs } from "./snapshot/cli-args.js";
|
|
11
11
|
import { renderFlowCall, renderFlowResult } from "./tui/render.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { DEFAULT_FLOW_COLORS } from "./tui/flow-colors.js";
|
|
13
|
+
import { terminateAllChildGroups } from "./flow/runner.js";
|
|
14
|
+
import { executeFlows } from "./flow/executor.js";
|
|
14
15
|
import { appendDirectiveOnce, resetDirectiveTracker, configureDirective, stripDirectivesFromMessages } from "./steering/tool-utils.js";
|
|
15
|
-
import { createBatchTool, createBatchReadTool, BashProcessTracker, createBatchBashPollTool, } from "./batch/index.js";
|
|
16
|
-
import { createWebTool } from "./tools/web-tool.js";
|
|
16
|
+
import { createBatchTool, createBatchReadTool, BashProcessTracker, createBatchBashPollTool, runBashWithLimits, } from "./batch/index.js";
|
|
17
17
|
import { createAskUserTool } from "./tools/ask-user.js";
|
|
18
18
|
import { stripSteeringHintText, stripSteeringHintsFromMessages, makeSteeringHintMessage, configureSteering, } from "./steering/sliding-prompt.js";
|
|
19
19
|
import { registerFlow, getGoal, getGoalForSession, recordFlowCompletion, addTokens, shutdownWakeup } from "./flow/index.js";
|
|
20
|
-
import * as sessionRegistry from "./
|
|
20
|
+
import * as sessionRegistry from "./flow/session-registry.js";
|
|
21
21
|
import { createTimedBashToolDefinition } from "./tools/timed-bash.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { createTraceTool } from "./tools/trace.js";
|
|
23
|
+
import { executeOperations } from "./batch/execute.js";
|
|
24
|
+
import { runWebOps } from "./tools/web-ops.js";
|
|
25
|
+
import { resolveFlowDepthConfig, } from "./flow/depth.js";
|
|
26
|
+
import { buildCore2Snapshot } from "./core2/snapshot.js";
|
|
24
27
|
import { resolveSettings, } from "./config/settings-resolver.js";
|
|
25
28
|
import { scrambleManager } from "./tui/scramble/index.js";
|
|
26
29
|
import { logWarn, logError } from "./config/log.js";
|
|
27
30
|
export { logWarn, logError };
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// Persistent flow result cache — shared across execute() calls so historical
|
|
30
|
-
// flow results are compressed properly in fork snapshots.
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
const flowResultCache = new Map();
|
|
33
|
-
/**
|
|
34
|
-
* Reconstruct flowResultCache from an existing session branch after restart.
|
|
35
|
-
* Scans tool results for the "flow" tool and rebuilds CompressedFlowResult
|
|
36
|
-
* entries so child-fork compression works immediately without waiting for
|
|
37
|
-
* new flows to complete.
|
|
38
|
-
*/
|
|
39
|
-
function reconstructFlowResultCache(sessionManager, cache) {
|
|
40
|
-
const branch = sessionManager.getBranch();
|
|
41
|
-
if (!Array.isArray(branch) || branch.length === 0)
|
|
42
|
-
return;
|
|
43
|
-
// Pass 1: map toolCallId -> "flow" from assistant messages
|
|
44
|
-
const toolCallIdToName = new Map();
|
|
45
|
-
for (const entry of branch) {
|
|
46
|
-
if (!entry || typeof entry !== "object")
|
|
47
|
-
continue;
|
|
48
|
-
const e = entry;
|
|
49
|
-
if (e.type !== "message")
|
|
50
|
-
continue;
|
|
51
|
-
const msg = e.message;
|
|
52
|
-
if (!msg || msg.role !== "assistant")
|
|
53
|
-
continue;
|
|
54
|
-
const content = msg.content;
|
|
55
|
-
if (!Array.isArray(content))
|
|
56
|
-
continue;
|
|
57
|
-
for (const part of content) {
|
|
58
|
-
if (!part || typeof part !== "object")
|
|
59
|
-
continue;
|
|
60
|
-
const p = part;
|
|
61
|
-
if (p.type === "toolCall" && p.name === "flow") {
|
|
62
|
-
const tcId = (p.id ?? p.toolCallId);
|
|
63
|
-
if (tcId)
|
|
64
|
-
toolCallIdToName.set(tcId, "flow");
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// Pass 2: scan tool/toolResult messages and rebuild cache
|
|
69
|
-
for (const entry of branch) {
|
|
70
|
-
if (!entry || typeof entry !== "object")
|
|
71
|
-
continue;
|
|
72
|
-
const e = entry;
|
|
73
|
-
if (e.type !== "message")
|
|
74
|
-
continue;
|
|
75
|
-
const msg = e.message;
|
|
76
|
-
if (!msg || (msg.role !== "tool" && msg.role !== "toolResult"))
|
|
77
|
-
continue;
|
|
78
|
-
let toolCallId;
|
|
79
|
-
if (typeof msg.toolCallId === "string" && msg.toolCallId.trim()) {
|
|
80
|
-
toolCallId = msg.toolCallId;
|
|
81
|
-
}
|
|
82
|
-
else if (Array.isArray(msg.content)) {
|
|
83
|
-
for (const part of msg.content) {
|
|
84
|
-
if (!part || typeof part !== "object")
|
|
85
|
-
continue;
|
|
86
|
-
const p = part;
|
|
87
|
-
if (p.type === "toolResult" && typeof p.toolCallId === "string" && p.toolCallId.trim()) {
|
|
88
|
-
toolCallId = p.toolCallId;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (!toolCallId || toolCallIdToName.get(toolCallId) !== "flow")
|
|
94
|
-
continue;
|
|
95
|
-
const details = msg.details;
|
|
96
|
-
if (!details || !Array.isArray(details.results))
|
|
97
|
-
continue;
|
|
98
|
-
const results = details.results;
|
|
99
|
-
const compressed = [];
|
|
100
|
-
for (const r of results) {
|
|
101
|
-
const so = r.structuredOutput;
|
|
102
|
-
if (!so)
|
|
103
|
-
continue;
|
|
104
|
-
const c = {
|
|
105
|
-
type: typeof r.type === "string" ? r.type : "unknown",
|
|
106
|
-
status: typeof r.exitCode === "number" && r.exitCode === 0 ? "accomplished" : "failed",
|
|
107
|
-
};
|
|
108
|
-
if (typeof r.intent === "string")
|
|
109
|
-
c.intent = r.intent;
|
|
110
|
-
if (typeof r.aim === "string")
|
|
111
|
-
c.aim = r.aim;
|
|
112
|
-
if (typeof so.summary === "string")
|
|
113
|
-
c.summary = so.summary;
|
|
114
|
-
if (Array.isArray(so.files))
|
|
115
|
-
c.files = so.files;
|
|
116
|
-
if (Array.isArray(so.actions))
|
|
117
|
-
c.actions = so.actions;
|
|
118
|
-
if (Array.isArray(so.commands))
|
|
119
|
-
c.commands = so.commands;
|
|
120
|
-
if (Array.isArray(so.notDone))
|
|
121
|
-
c.notDone = so.notDone;
|
|
122
|
-
if (Array.isArray(so.nextSteps))
|
|
123
|
-
c.nextSteps = so.nextSteps;
|
|
124
|
-
if (Array.isArray(so.reasoning))
|
|
125
|
-
c.reasoning = so.reasoning;
|
|
126
|
-
if (Array.isArray(so.notes))
|
|
127
|
-
c.notes = so.notes;
|
|
128
|
-
if (typeof r.errorMessage === "string")
|
|
129
|
-
c.error = r.errorMessage;
|
|
130
|
-
compressed.push(c);
|
|
131
|
-
}
|
|
132
|
-
if (compressed.length > 0) {
|
|
133
|
-
const existing = cache.get(toolCallId) ?? [];
|
|
134
|
-
existing.push(...compressed);
|
|
135
|
-
cache.set(toolCallId, existing);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
evictCacheOverflow(cache);
|
|
139
|
-
}
|
|
140
31
|
import { computeActiveTools, buildBeforeAgentStartPrompt, } from "./steering/flow-prompt.js";
|
|
141
32
|
// ---------------------------------------------------------------------------
|
|
142
33
|
// Tool parameter schema
|
|
143
34
|
// ---------------------------------------------------------------------------
|
|
35
|
+
const BatchDispatchOp = Type.Object({
|
|
36
|
+
tool: Type.Literal("batch"),
|
|
37
|
+
ops: Type.Array(Type.Object({
|
|
38
|
+
o: Type.String(),
|
|
39
|
+
p: Type.String(),
|
|
40
|
+
c: Type.Optional(Type.String()),
|
|
41
|
+
e: Type.Optional(Type.Array(Type.Object({ f: Type.String(), r: Type.String() }))),
|
|
42
|
+
s: Type.Optional(Type.Number()),
|
|
43
|
+
l: Type.Optional(Type.Union([Type.Number(), Type.Boolean()])),
|
|
44
|
+
i: Type.Optional(Type.Union([Type.String(), Type.Boolean()])),
|
|
45
|
+
t: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
|
46
|
+
h: Type.Optional(Type.String()),
|
|
47
|
+
q: Type.Optional(Type.String()),
|
|
48
|
+
n: Type.Optional(Type.Number()),
|
|
49
|
+
u: Type.Optional(Type.Number()),
|
|
50
|
+
}), { description: "File/batch operations matching the batch tool schema." }),
|
|
51
|
+
});
|
|
52
|
+
const BashDispatchOp = Type.Object({
|
|
53
|
+
tool: Type.Literal("bash"),
|
|
54
|
+
ops: Type.Array(Type.Object({
|
|
55
|
+
c: Type.String({ description: "Shell command" }),
|
|
56
|
+
h: Type.Optional(Type.String({ description: "Working directory override" })),
|
|
57
|
+
t: Type.Optional(Type.Number({ description: "Timeout in ms" })),
|
|
58
|
+
}), { description: "Bash command objects." }),
|
|
59
|
+
});
|
|
60
|
+
const WebDispatchOp = Type.Object({
|
|
61
|
+
tool: Type.Literal("web"),
|
|
62
|
+
ops: Type.Array(Type.Object({
|
|
63
|
+
o: Type.Union([Type.Literal("search"), Type.Literal("fetch")]),
|
|
64
|
+
q: Type.Optional(Type.String()),
|
|
65
|
+
u: Type.Optional(Type.String()),
|
|
66
|
+
f: Type.Optional(Type.String()),
|
|
67
|
+
}), { description: "Web operations matching the web tool schema." }),
|
|
68
|
+
});
|
|
69
|
+
const DispatchOpSchema = Type.Union([BatchDispatchOp, BashDispatchOp, WebDispatchOp], {
|
|
70
|
+
description: "Pre-dispatch tool call with discriminated tool type and typed ops array.",
|
|
71
|
+
});
|
|
144
72
|
const FlowItem = Type.Object({
|
|
145
73
|
type: Type.String({
|
|
146
|
-
description: "Flow type
|
|
74
|
+
description: "Flow type (scout, debug, build, craft, audit, ideas).",
|
|
147
75
|
}),
|
|
148
76
|
intent: Type.String({
|
|
149
|
-
description: "
|
|
77
|
+
description: "Detailed mission for this flow.",
|
|
150
78
|
}),
|
|
151
79
|
aim: Type.String({
|
|
152
|
-
description: "
|
|
80
|
+
description: "Short (5-7 words) headline summary.",
|
|
153
81
|
}),
|
|
154
|
-
acceptance: Type.Optional(Type.String({ description: "
|
|
155
|
-
cwd: Type.Optional(Type.String({ description: "Working directory override
|
|
156
|
-
|
|
82
|
+
acceptance: Type.Optional(Type.String({ description: "Success criteria for the task." })),
|
|
83
|
+
cwd: Type.Optional(Type.String({ description: "Working directory override." })),
|
|
84
|
+
complexity: Type.Union([
|
|
157
85
|
Type.Literal("snap"),
|
|
158
|
-
Type.Literal("
|
|
159
|
-
Type.Literal("
|
|
160
|
-
Type.Literal("
|
|
161
|
-
Type.Literal("
|
|
86
|
+
Type.Literal("simple"),
|
|
87
|
+
Type.Literal("moderate"),
|
|
88
|
+
Type.Literal("complex"),
|
|
89
|
+
Type.Literal("intricate"),
|
|
162
90
|
], {
|
|
163
|
-
description: "
|
|
91
|
+
description: "Budget/Audit level: snap (120s), simple (300s), moderate (600s), complex (900s), intricate (1200s).",
|
|
92
|
+
}),
|
|
93
|
+
dispatch: Type.Optional(Type.Array(DispatchOpSchema, {
|
|
94
|
+
description: "Tools to run before the flow starts (results are injected into the prompt).",
|
|
164
95
|
})),
|
|
165
96
|
}, {
|
|
166
97
|
title: "FlowTask",
|
|
167
|
-
description: "A single flow task
|
|
98
|
+
description: "A single flow task object.",
|
|
168
99
|
});
|
|
169
100
|
const FlowParams = Type.Object({
|
|
170
101
|
flow: Type.Array(FlowItem, {
|
|
171
|
-
description: "
|
|
172
|
-
"Optional sessionMode selects the flow state budget: fast=300s, default=600s, long=900s, extreme_long=1200s.",
|
|
173
|
-
examples: [
|
|
174
|
-
{ type: "scout", intent: "Map auth module files and trace JWT validation path", aim: "Map auth and trace JWT" },
|
|
175
|
-
{ type: "audit", intent: "Audit input validation and SQL injection risks in user routes", aim: "Audit user route security" },
|
|
176
|
-
],
|
|
102
|
+
description: "Specialized flow tasks to dive into.",
|
|
177
103
|
minItems: 1,
|
|
178
104
|
}),
|
|
179
105
|
confirmProjectFlows: Type.Optional(Type.Boolean({
|
|
180
|
-
description: "
|
|
106
|
+
description: "Prompt before running local flows. Default: true.",
|
|
181
107
|
default: true,
|
|
182
108
|
})),
|
|
109
|
+
auditLoop: Type.Optional(Type.Number({
|
|
110
|
+
description: "Override audit cycles (0-3).",
|
|
111
|
+
default: 0,
|
|
112
|
+
minimum: 0,
|
|
113
|
+
maximum: 3,
|
|
114
|
+
})),
|
|
115
|
+
}, {
|
|
116
|
+
title: "FlowToolParams",
|
|
117
|
+
description: "The root object MUST contain a 'flow' array. Never flatten fields to the root.",
|
|
118
|
+
examples: [{
|
|
119
|
+
flow: [{ type: "scout", intent: "Map auth module files", aim: "Map auth module", complexity: "moderate" }],
|
|
120
|
+
}],
|
|
183
121
|
});
|
|
184
122
|
const inheritedCliArgs = getInheritedCliArgs();
|
|
185
123
|
// ---------------------------------------------------------------------------
|
|
186
124
|
// Helpers
|
|
187
125
|
// ---------------------------------------------------------------------------
|
|
126
|
+
async function executeDispatchOps(dispatch, cwd, ctx, signal) {
|
|
127
|
+
const parts = [];
|
|
128
|
+
let toolCallIndex = 0;
|
|
129
|
+
for (const group of dispatch) {
|
|
130
|
+
if (signal?.aborted)
|
|
131
|
+
break;
|
|
132
|
+
const toolCallId = `pre_dispatch_${group.tool}_${toolCallIndex++}`;
|
|
133
|
+
try {
|
|
134
|
+
if (group.tool === "batch") {
|
|
135
|
+
// Separate file ops from bash ops
|
|
136
|
+
const fileOps = group.ops.filter((op) => op.o !== "bash");
|
|
137
|
+
const bashOps = group.ops.filter((op) => op.o === "bash");
|
|
138
|
+
if (fileOps.length > 0) {
|
|
139
|
+
const fileOutput = await executeOperations(fileOps, cwd, signal, { includeLimitWarnings: true });
|
|
140
|
+
parts.push(`### batch (file ops)\n\ntool_call_id: ${toolCallId}\n\n${fileOutput.contentText}`);
|
|
141
|
+
}
|
|
142
|
+
if (bashOps.length > 0) {
|
|
143
|
+
for (const op of bashOps) {
|
|
144
|
+
const { stdout, stderr, exitCode } = await runBashWithLimits(op.c ?? "", op.h ?? cwd, op.t ?? 30000, signal);
|
|
145
|
+
parts.push(`### bash [${op.i ?? "auto"}] exit ${exitCode}\n\ntool_call_id: ${toolCallId}\n\n${stdout}${stderr ? `\n[stderr]\n${stderr}` : ""}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else if (group.tool === "bash") {
|
|
150
|
+
for (const cmd of group.ops) {
|
|
151
|
+
const { stdout, stderr, exitCode } = await runBashWithLimits(cmd.c, cmd.h ?? cwd, cmd.t ?? 30000, signal);
|
|
152
|
+
parts.push(`### bash\n\ntool_call_id: ${toolCallId}\n\n--- bash exit ${exitCode} ---\n${stdout}${stderr ? `\n[stderr]\n${stderr}` : ""}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (group.tool === "web") {
|
|
156
|
+
const webOutput = await runWebOps({ op: group.ops }, ctx, signal);
|
|
157
|
+
parts.push(`### web\n\ntool_call_id: ${toolCallId}\n\n${webOutput.content[0].text}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
162
|
+
parts.push(`### ${group.tool} (error)\n\ntool_call_id: ${toolCallId}\n\nPre-dispatch failed: ${message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return parts.join("\n\n---\n\n");
|
|
166
|
+
}
|
|
188
167
|
function makeFlowDetailsFactory(projectFlowsDir) {
|
|
189
168
|
return (results) => ({
|
|
190
169
|
mode: "flow",
|
|
@@ -193,8 +172,6 @@ function makeFlowDetailsFactory(projectFlowsDir) {
|
|
|
193
172
|
results,
|
|
194
173
|
});
|
|
195
174
|
}
|
|
196
|
-
// Re-export compressToolResults and stripBatchReadToolCalls for tests
|
|
197
|
-
export { compressToolResults, stripBatchReadToolCalls } from "./snapshot/snapshot.js";
|
|
198
175
|
// ---------------------------------------------------------------------------
|
|
199
176
|
// Extension entry point
|
|
200
177
|
// ---------------------------------------------------------------------------
|
|
@@ -231,8 +208,8 @@ export default function (pi) {
|
|
|
231
208
|
description: "Maximum number of flows to execute in parallel (default: 4).",
|
|
232
209
|
type: "string",
|
|
233
210
|
});
|
|
234
|
-
pi.registerFlag("flow-
|
|
235
|
-
description: "Default child-flow
|
|
211
|
+
pi.registerFlag("flow-complexity", {
|
|
212
|
+
description: "Default child-flow complexity: snap (120s no review), simple (300s no review), moderate (600s 1x audit), complex (900s 2x audit), or intricate (1200s 3x audit).",
|
|
236
213
|
type: "string",
|
|
237
214
|
});
|
|
238
215
|
pi.registerFlag("tool-optimize", {
|
|
@@ -259,6 +236,14 @@ export default function (pi) {
|
|
|
259
236
|
description: "Disable glitch/scramble effect.",
|
|
260
237
|
type: "boolean",
|
|
261
238
|
});
|
|
239
|
+
pi.registerFlag("body-lite", {
|
|
240
|
+
description: "Use lite collapsed body mode (aim + cmd only).",
|
|
241
|
+
type: "boolean",
|
|
242
|
+
});
|
|
243
|
+
pi.registerFlag("body-full", {
|
|
244
|
+
description: "Use full collapsed body mode (aim + cmd + msg).",
|
|
245
|
+
type: "boolean",
|
|
246
|
+
});
|
|
262
247
|
// Wire up bundled notification channel
|
|
263
248
|
setupNotify(pi);
|
|
264
249
|
// Wire up /flow command and continuation hooks
|
|
@@ -273,11 +258,6 @@ export default function (pi) {
|
|
|
273
258
|
sessionRegistry.register(ctx.cwd, ctx.sessionManager.getSessionId());
|
|
274
259
|
_sessionCtx = ctx;
|
|
275
260
|
resolved = resolveSettings(pi, ctx.cwd);
|
|
276
|
-
// Reconstruct historical flow result cache so fork snapshots can compress
|
|
277
|
-
// past flow results immediately (instead of showing placeholder text until
|
|
278
|
-
// new flows complete). bashTracker is created fresh below — pending OS
|
|
279
|
-
// processes are inherently lost across restarts, which is expected.
|
|
280
|
-
reconstructFlowResultCache(ctx.sessionManager, flowResultCache);
|
|
281
261
|
// Wire resolved settings to modules
|
|
282
262
|
configureSteering({ enabled: resolved.steeringEnabled, customPrompt: resolved.steeringCustomPrompt });
|
|
283
263
|
configureDirective(resolved.steeringStrategicHint);
|
|
@@ -289,17 +269,14 @@ export default function (pi) {
|
|
|
289
269
|
pi.setActiveTools(computeActiveTools(resolved.toolOptimize));
|
|
290
270
|
}
|
|
291
271
|
// Register tools based on depth.
|
|
292
|
-
// Depth 0 (main root state):
|
|
272
|
+
// Depth 0 (main root state): batch_read + no bash ops.
|
|
293
273
|
// Depth > 0 (child flows): batch (with bash), batch_bash_poll — they need bash ops.
|
|
294
|
-
//
|
|
295
|
-
// registered for depth > 0 to avoid confusion and keep the tool set minimal.
|
|
274
|
+
// batch_read is registered at all depths for trace and read-only child operations.
|
|
296
275
|
// The bashProcessTracker is shared between the batch tool (launches bash ops)
|
|
297
276
|
// and the batch_bash_poll tool (checks on pending bash ops).
|
|
298
277
|
if (resolved.toolOptimize) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
278
|
+
pi.registerTool(createBatchReadTool());
|
|
279
|
+
if (currentDepth > 0) {
|
|
303
280
|
bashTracker = new BashProcessTracker();
|
|
304
281
|
pi.registerTool(createBatchTool(bashTracker, resolved.toolOptimize));
|
|
305
282
|
pi.registerTool(createBatchBashPollTool(bashTracker));
|
|
@@ -316,7 +293,6 @@ export default function (pi) {
|
|
|
316
293
|
});
|
|
317
294
|
// Clean up global mutable state on session shutdown
|
|
318
295
|
pi.on("session_shutdown", () => {
|
|
319
|
-
flowResultCache.clear();
|
|
320
296
|
_sessionCtx = undefined;
|
|
321
297
|
// bashTracker and its pending OS processes are discarded on restart.
|
|
322
298
|
// This is expected — child process state is not serializable.
|
|
@@ -342,11 +318,34 @@ export default function (pi) {
|
|
|
342
318
|
pi.on("before_agent_start", async (event) => {
|
|
343
319
|
if (currentDepth > 0 || !resolved)
|
|
344
320
|
return undefined;
|
|
345
|
-
const augmented = buildBeforeAgentStartPrompt(event, resolved.toolOptimize
|
|
321
|
+
const augmented = buildBeforeAgentStartPrompt(event, resolved.toolOptimize);
|
|
346
322
|
if (augmented === undefined)
|
|
347
323
|
return undefined;
|
|
348
324
|
return { systemPrompt: augmented };
|
|
349
325
|
});
|
|
326
|
+
// Compaction: inject flow context into the summarization prompt.
|
|
327
|
+
pi.on("session_before_compact", async (event, ctx) => {
|
|
328
|
+
const goal = getGoal(ctx.cwd);
|
|
329
|
+
if (!goal)
|
|
330
|
+
return undefined;
|
|
331
|
+
const completed = goal.completedFlows.slice(-3);
|
|
332
|
+
const flowSummary = completed.length > 0
|
|
333
|
+
? `\nRecently completed flows:\n${completed.map(f => `- [${f.type}] ${f.aim}`).join("\n")}`
|
|
334
|
+
: "";
|
|
335
|
+
const injection = `\n\n[Flow Context]\nCurrent Goal: ${goal.objective}${goal.acceptance ? `\nAcceptance: ${goal.acceptance}` : ""}${flowSummary}\nMaintain this goal and status in the summary.`;
|
|
336
|
+
return { prompt: (event.prompt || "") + injection };
|
|
337
|
+
});
|
|
338
|
+
// Compaction: re-anchor flow context after summarization.
|
|
339
|
+
pi.on("session_compact", async (_event, ctx) => {
|
|
340
|
+
const goal = getGoal(ctx.cwd);
|
|
341
|
+
if (!goal)
|
|
342
|
+
return;
|
|
343
|
+
// Send a non-displaying message to re-anchor the agent to its goal.
|
|
344
|
+
pi.sendMessage({
|
|
345
|
+
content: `[Flow Re-anchor] Compaction completed. Current Goal: ${goal.objective}. Continue execution.`,
|
|
346
|
+
display: false,
|
|
347
|
+
}, { triggerTurn: false });
|
|
348
|
+
});
|
|
350
349
|
// Steering hint: insert as a separate system message immediately
|
|
351
350
|
// before the latest user message each turn. The steering hint is never
|
|
352
351
|
// part of the static systemPrompt — it is injected dynamically here only.
|
|
@@ -413,31 +412,25 @@ export default function (pi) {
|
|
|
413
412
|
}
|
|
414
413
|
return result;
|
|
415
414
|
});
|
|
416
|
-
// Register the web tool
|
|
417
|
-
pi.registerTool(createWebTool());
|
|
418
415
|
// Register the ask_user tool
|
|
419
416
|
pi.registerTool(createAskUserTool());
|
|
417
|
+
// Register the trace tool (available at all depths — spawns a lightweight child reflection flow)
|
|
418
|
+
pi.registerTool(createTraceTool({
|
|
419
|
+
getSettings: () => resolved ? { toolOptimize: resolved.toolOptimize, structuredOutput: resolved.structuredOutput, bodyVerbosity: resolved.bodyVerbosity } : undefined,
|
|
420
|
+
getDepthConfig: () => depthConfig,
|
|
421
|
+
}));
|
|
420
422
|
// Register the flow tool
|
|
421
423
|
if (canTransition) {
|
|
422
424
|
pi.registerTool({
|
|
423
425
|
name: "flow",
|
|
424
426
|
label: "Flow",
|
|
425
|
-
promptSnippet: "
|
|
427
|
+
promptSnippet: "Dive into specialized flows (scout, debug, build, craft, audit, ideas) via a `flow` array.",
|
|
426
428
|
promptGuidelines: [
|
|
427
|
-
"
|
|
428
|
-
"
|
|
429
|
-
"
|
|
429
|
+
"Combine multiple tasks into a single `flow` array call.",
|
|
430
|
+
"Each task requires `type`, `intent`, `aim`, and `complexity`.",
|
|
431
|
+
"All tasks MUST be nested inside the `flow` array.",
|
|
430
432
|
],
|
|
431
|
-
description:
|
|
432
|
-
"If you cannot answer from your current context, you are forbidden from guessing.",
|
|
433
|
-
"You MUST enter to the following flow states, with tool call method.",
|
|
434
|
-
"",
|
|
435
|
-
"Flow states are isolated π processes with forked session snapshots. They run in parallel.",
|
|
436
|
-
'Invoke: { "flow": [{ "type": "scout", "intent": "...", "aim": "...", "sessionMode": "default" }, ...] }',
|
|
437
|
-
"Session modes: fast=300s, default=600s, long=900s, extreme_long=1200s. Use long or extreme_long only when the work genuinely needs the larger budget.",
|
|
438
|
-
"States: scout, debug, build, craft, audit, ideas.",
|
|
439
|
-
"Custom states configs in (create if not exists): .md files in .pi/agents/ or ~/.pi/agent/agents/.",
|
|
440
|
-
].join("\n"),
|
|
433
|
+
description: "Dives into specialized flow states. Requires a `flow` array of tasks with specific `complexity` (snap, simple, moderate, complex, intricate).",
|
|
441
434
|
parameters: FlowParams,
|
|
442
435
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
443
436
|
if (!resolved) {
|
|
@@ -446,16 +439,10 @@ export default function (pi) {
|
|
|
446
439
|
const discovery = discoverFlows(ctx.cwd, "all");
|
|
447
440
|
const { flows } = discovery;
|
|
448
441
|
const makeDetails = makeFlowDetailsFactory(discovery.projectFlowsDir);
|
|
449
|
-
// Build the
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
const { result: forkSessionSnapshotJsonl, stats: forkSessionSnapshotStats } = sanitizeForkSnapshot(buildForkSessionSnapshotJsonl(ctx.sessionManager), flowResultCache, {
|
|
454
|
-
forkedFrom: ctx.sessionManager.getSessionId(),
|
|
455
|
-
forkedAt: new Date().toISOString(),
|
|
456
|
-
depth: currentDepth + 1,
|
|
457
|
-
...(ancestorFlowStack.length > 0 ? { parentFlow: ancestorFlowStack[ancestorFlowStack.length - 1] } : {}),
|
|
458
|
-
});
|
|
442
|
+
// Build the fork session snapshot. Core-2 preserves all conversation
|
|
443
|
+
// verbatim in chronological order, stripping only batch read/write/edit
|
|
444
|
+
// bodies (keeping first 3 + last 3 lines as orientation).
|
|
445
|
+
const forkSessionSnapshotJsonl = buildCore2Snapshot(ctx.sessionManager);
|
|
459
446
|
const getTierOverride = (tier) => {
|
|
460
447
|
const flagName = tier === "lite"
|
|
461
448
|
? "flow-lite-model"
|
|
@@ -481,7 +468,13 @@ export default function (pi) {
|
|
|
481
468
|
acceptance: activeGoal.acceptance,
|
|
482
469
|
flowCount: activeGoal.completedFlows.length,
|
|
483
470
|
maxFlows: activeGoal.maxFlows,
|
|
471
|
+
completedFlows: activeGoal.completedFlows.map(f => ({ type: f.type, aim: f.aim })),
|
|
484
472
|
} : undefined;
|
|
473
|
+
const preDispatchResults = await Promise.all(params.flow.map(async (f) => {
|
|
474
|
+
if (!f.dispatch || f.dispatch.length === 0)
|
|
475
|
+
return undefined;
|
|
476
|
+
return executeDispatchOps(f.dispatch, f.cwd ?? ctx.cwd, ctx, signal);
|
|
477
|
+
}));
|
|
485
478
|
const result = await executeFlows({
|
|
486
479
|
flows,
|
|
487
480
|
currentDepth,
|
|
@@ -493,7 +486,7 @@ export default function (pi) {
|
|
|
493
486
|
cwd: ctx.cwd,
|
|
494
487
|
loadedFlowModelConfigs: resolved.loadedFlowModelConfigs,
|
|
495
488
|
maxConcurrency: resolved.maxConcurrency,
|
|
496
|
-
|
|
489
|
+
defaultComplexity: resolved.defaultComplexity,
|
|
497
490
|
signal,
|
|
498
491
|
onUpdate,
|
|
499
492
|
makeDetails,
|
|
@@ -501,8 +494,6 @@ export default function (pi) {
|
|
|
501
494
|
tierOverrideResolver: getTierOverride,
|
|
502
495
|
fallbackModel: inheritedCliArgs.fallbackModel,
|
|
503
496
|
forkSessionSnapshotJsonl,
|
|
504
|
-
forkSessionSnapshotStats,
|
|
505
|
-
flowResultCache,
|
|
506
497
|
projectFlowsDir: discovery.projectFlowsDir,
|
|
507
498
|
sessionManager: ctx.sessionManager,
|
|
508
499
|
hasUI: ctx.hasUI,
|
|
@@ -520,7 +511,15 @@ export default function (pi) {
|
|
|
520
511
|
addTokens(ctx.cwd, r.usage.input + r.usage.output);
|
|
521
512
|
}
|
|
522
513
|
},
|
|
523
|
-
}, params.flow.map((f) => ({
|
|
514
|
+
}, params.flow.map((f, i) => ({
|
|
515
|
+
type: f.type,
|
|
516
|
+
intent: f.intent,
|
|
517
|
+
aim: f.aim,
|
|
518
|
+
acceptance: f.acceptance,
|
|
519
|
+
cwd: f.cwd,
|
|
520
|
+
complexity: f.complexity,
|
|
521
|
+
preDispatchResults: preDispatchResults[i],
|
|
522
|
+
})), toolCallId, params.auditLoop ?? 0);
|
|
524
523
|
if (result.failed) {
|
|
525
524
|
const text = result.content?.[0]?.text ?? "Flow execution failed";
|
|
526
525
|
throw new Error(text);
|
|
@@ -546,8 +545,8 @@ export default function (pi) {
|
|
|
546
545
|
appendDirectiveOnce(flowToolResult, hintContext);
|
|
547
546
|
return flowToolResult;
|
|
548
547
|
},
|
|
549
|
-
renderCall: (args, theme) => renderFlowCall(args, theme),
|
|
550
|
-
renderResult: (result, { expanded }, theme, args) => renderFlowResult(result, expanded, theme, args),
|
|
548
|
+
renderCall: (args, theme) => renderFlowCall(args, theme, { ...DEFAULT_FLOW_COLORS, bodyVerbosity: resolved?.bodyVerbosity }),
|
|
549
|
+
renderResult: (result, { expanded }, theme, args) => renderFlowResult(result, expanded, theme, args, { ...DEFAULT_FLOW_COLORS, bodyVerbosity: resolved?.bodyVerbosity }),
|
|
551
550
|
});
|
|
552
551
|
}
|
|
553
552
|
// -------------------------------------------------------------------------
|
|
@@ -567,6 +566,7 @@ export default function (pi) {
|
|
|
567
566
|
steeringStrategicHint: resolved.steeringStrategicHint,
|
|
568
567
|
animationEnabled: resolved.animationEnabled,
|
|
569
568
|
animationGlitch: resolved.animationGlitch,
|
|
569
|
+
bodyVerbosity: resolved.bodyVerbosity,
|
|
570
570
|
}
|
|
571
571
|
: {
|
|
572
572
|
toolOptimize: true,
|
|
@@ -577,6 +577,7 @@ export default function (pi) {
|
|
|
577
577
|
steeringStrategicHint: true,
|
|
578
578
|
animationEnabled: true,
|
|
579
579
|
animationGlitch: true,
|
|
580
|
+
bodyVerbosity: "lite",
|
|
580
581
|
},
|
|
581
582
|
};
|
|
582
583
|
if (typeof pi.emit === "function") {
|