@duetso/agent 0.1.34 → 0.1.36
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/package.json +2 -2
- package/dist/src/cli/env.d.ts +18 -0
- package/dist/src/cli/env.d.ts.map +1 -0
- package/dist/src/cli/env.js +114 -0
- package/dist/src/cli/env.js.map +1 -0
- package/dist/src/cli/help.d.ts +8 -0
- package/dist/src/cli/help.d.ts.map +1 -0
- package/dist/src/cli/help.js +178 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/login.d.ts +13 -0
- package/dist/src/cli/login.d.ts.map +1 -0
- package/dist/src/cli/login.js +61 -0
- package/dist/src/cli/login.js.map +1 -0
- package/dist/src/cli/memory-db.d.ts +24 -0
- package/dist/src/cli/memory-db.d.ts.map +1 -0
- package/dist/src/cli/memory-db.js +74 -0
- package/dist/src/cli/memory-db.js.map +1 -0
- package/dist/src/cli/memory-tui.d.ts +11 -0
- package/dist/src/cli/memory-tui.d.ts.map +1 -0
- package/dist/src/cli/memory-tui.js +266 -0
- package/dist/src/cli/memory-tui.js.map +1 -0
- package/dist/src/cli/memory.d.ts +9 -0
- package/dist/src/cli/memory.d.ts.map +1 -0
- package/dist/src/cli/memory.js +38 -0
- package/dist/src/cli/memory.js.map +1 -0
- package/dist/src/cli/package-manager.d.ts +38 -0
- package/dist/src/cli/package-manager.d.ts.map +1 -0
- package/dist/src/cli/package-manager.js +78 -0
- package/dist/src/cli/package-manager.js.map +1 -0
- package/dist/src/cli/resume-hint.d.ts +22 -0
- package/dist/src/cli/resume-hint.d.ts.map +1 -0
- package/dist/src/cli/resume-hint.js +61 -0
- package/dist/src/cli/resume-hint.js.map +1 -0
- package/dist/src/cli/run.d.ts +43 -0
- package/dist/src/cli/run.d.ts.map +1 -0
- package/dist/src/cli/run.js +273 -0
- package/dist/src/cli/run.js.map +1 -0
- package/dist/src/cli/shared.d.ts +55 -0
- package/dist/src/cli/shared.d.ts.map +1 -0
- package/dist/src/cli/shared.js +125 -0
- package/dist/src/cli/shared.js.map +1 -0
- package/dist/src/cli/skills.d.ts +10 -0
- package/dist/src/cli/skills.d.ts.map +1 -0
- package/dist/src/cli/skills.js +42 -0
- package/dist/src/cli/skills.js.map +1 -0
- package/dist/src/cli/upgrade.d.ts +9 -0
- package/dist/src/cli/upgrade.d.ts.map +1 -0
- package/dist/src/cli/upgrade.js +52 -0
- package/dist/src/cli/upgrade.js.map +1 -0
- package/dist/src/cli/version-check.d.ts +22 -0
- package/dist/src/cli/version-check.d.ts.map +1 -0
- package/dist/src/cli/version-check.js +78 -0
- package/dist/src/cli/version-check.js.map +1 -0
- package/dist/src/cli.d.ts +20 -63
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +38 -887
- package/dist/src/cli.js.map +1 -1
- package/dist/src/memory/observational-prompts.d.ts.map +1 -1
- package/dist/src/memory/observational-prompts.js +11 -7
- package/dist/src/memory/observational-prompts.js.map +1 -1
- package/dist/src/tui/app.d.ts +7 -47
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +204 -389
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/autocomplete.d.ts +91 -0
- package/dist/src/tui/autocomplete.d.ts.map +1 -0
- package/dist/src/tui/autocomplete.js +177 -0
- package/dist/src/tui/autocomplete.js.map +1 -0
- package/dist/src/tui/file-index.d.ts +11 -0
- package/dist/src/tui/file-index.d.ts.map +1 -0
- package/dist/src/tui/file-index.js +75 -0
- package/dist/src/tui/file-index.js.map +1 -0
- package/dist/src/tui/history.d.ts +50 -0
- package/dist/src/tui/history.d.ts.map +1 -0
- package/dist/src/tui/history.js +132 -0
- package/dist/src/tui/history.js.map +1 -0
- package/dist/src/tui/sidebar.d.ts +20 -0
- package/dist/src/tui/sidebar.d.ts.map +1 -0
- package/dist/src/tui/sidebar.js +118 -0
- package/dist/src/tui/sidebar.js.map +1 -0
- package/dist/src/tui/theme.d.ts +15 -0
- package/dist/src/tui/theme.d.ts.map +1 -0
- package/dist/src/tui/theme.js +18 -0
- package/dist/src/tui/theme.js.map +1 -0
- package/dist/src/turn-runner/prompts.d.ts.map +1 -1
- package/dist/src/turn-runner/prompts.js +10 -1
- package/dist/src/turn-runner/prompts.js.map +1 -1
- package/dist/src/turn-runner/tools.d.ts +15 -1
- package/dist/src/turn-runner/tools.d.ts.map +1 -1
- package/dist/src/turn-runner/tools.js +96 -11
- package/dist/src/turn-runner/tools.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { formatCompactJson } from "../lib/compact-json.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert a persisted agent transcript into transcript-ready blocks.
|
|
4
|
+
*
|
|
5
|
+
* Tool calls and their tool results are stitched back together by id so the
|
|
6
|
+
* resumed view matches what the live runner renders during a turn — running
|
|
7
|
+
* spinner first, then `✓`/`✗` plus result body once the result arrives.
|
|
8
|
+
*/
|
|
9
|
+
export function historyDisplayBlocks(history) {
|
|
10
|
+
const blocks = [];
|
|
11
|
+
const activeToolBlockIndexes = new Map();
|
|
12
|
+
for (const message of history) {
|
|
13
|
+
if (!("role" in message))
|
|
14
|
+
continue;
|
|
15
|
+
if (message.role === "user") {
|
|
16
|
+
const text = userMessageText(message.content);
|
|
17
|
+
if (text)
|
|
18
|
+
blocks.push({ kind: "user", content: `you:\n${text}` });
|
|
19
|
+
}
|
|
20
|
+
else if (message.role === "assistant") {
|
|
21
|
+
for (const block of message.content) {
|
|
22
|
+
if (block.type === "text") {
|
|
23
|
+
blocks.push({ kind: "agent", content: block.text });
|
|
24
|
+
}
|
|
25
|
+
else if (block.type === "thinking") {
|
|
26
|
+
const trimmed = block.thinking.trim();
|
|
27
|
+
if (trimmed)
|
|
28
|
+
blocks.push({ kind: "reasoning", content: `[reasoning]\n${trimmed}` });
|
|
29
|
+
}
|
|
30
|
+
else if (block.type === "toolCall") {
|
|
31
|
+
const input = block.arguments === undefined ? "" : `\n${formatCompactJson(block.arguments)}`;
|
|
32
|
+
activeToolBlockIndexes.set(block.id, blocks.length);
|
|
33
|
+
blocks.push({ kind: "tool", content: `[tool ${block.name}] ⏳${input}` });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (message.errorMessage) {
|
|
37
|
+
blocks.push({ kind: "error", content: `[error]\n${message.errorMessage}` });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (message.role === "toolResult") {
|
|
41
|
+
const text = textFromHistoryContent(message.content);
|
|
42
|
+
const existingIndex = activeToolBlockIndexes.get(message.toolCallId);
|
|
43
|
+
const marker = message.isError ? "✗" : "✓";
|
|
44
|
+
const label = message.isError ? "[error]" : "[result]";
|
|
45
|
+
if (existingIndex !== undefined) {
|
|
46
|
+
const existing = blocks[existingIndex];
|
|
47
|
+
const [, ...inputLines] = existing.content.split("\n");
|
|
48
|
+
const input = inputLines.length > 0 ? `\n${inputLines.join("\n")}` : "";
|
|
49
|
+
existing.kind = message.isError ? "error" : "tool";
|
|
50
|
+
existing.content = text
|
|
51
|
+
? `[tool ${message.toolName}] ${marker}${input}\n${label}\n${text}`
|
|
52
|
+
: `[tool ${message.toolName}] ${marker}${input}`;
|
|
53
|
+
activeToolBlockIndexes.delete(message.toolCallId);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const content = text
|
|
57
|
+
? `[tool ${message.toolName}] ${marker}\n${label}\n${text}`
|
|
58
|
+
: `[tool ${message.toolName}] ${marker}`;
|
|
59
|
+
blocks.push({ kind: message.isError ? "error" : "tool", content });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return blocks;
|
|
64
|
+
}
|
|
65
|
+
/** Compose the duet startup banner for the TUI header. */
|
|
66
|
+
export function startupHeaderLines(input) {
|
|
67
|
+
const lines = [
|
|
68
|
+
`[duet] v${input.packageVersion}`,
|
|
69
|
+
`[cwd] ${input.workDir}`,
|
|
70
|
+
`[session] ${input.sessionId}`,
|
|
71
|
+
input.modelSource
|
|
72
|
+
? `[model] ${input.modelName} — ${input.modelSource}`
|
|
73
|
+
: `[model] ${input.modelName}`,
|
|
74
|
+
input.memoryModelSource
|
|
75
|
+
? `[memory model] ${input.memoryModelName} — ${input.memoryModelSource}`
|
|
76
|
+
: `[memory model] ${input.memoryModelName}`,
|
|
77
|
+
];
|
|
78
|
+
if (input.newVersionNotice)
|
|
79
|
+
lines.push(input.newVersionNotice);
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Trim a sequence of display blocks to fit `maxLines` total rendered lines.
|
|
84
|
+
*
|
|
85
|
+
* Walks back-to-front so the most recent context is kept; when the budget
|
|
86
|
+
* lands mid-block, the trailing portion of that block is preserved and the
|
|
87
|
+
* dropped line count is reported so the caller can render a "showing last N"
|
|
88
|
+
* notice.
|
|
89
|
+
*/
|
|
90
|
+
export function limitHistoryDisplayBlocks(blocks, maxLines) {
|
|
91
|
+
if (maxLines <= 0)
|
|
92
|
+
return { blocks: [], omittedLines: countHistoryLines(blocks) };
|
|
93
|
+
const selected = [];
|
|
94
|
+
let remaining = maxLines;
|
|
95
|
+
let omittedLines = 0;
|
|
96
|
+
for (let index = blocks.length - 1; index >= 0; index--) {
|
|
97
|
+
const block = blocks[index];
|
|
98
|
+
const lines = block.content.split("\n");
|
|
99
|
+
if (lines.length <= remaining) {
|
|
100
|
+
selected.unshift(block);
|
|
101
|
+
remaining -= lines.length;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (remaining > 0) {
|
|
105
|
+
selected.unshift({ ...block, content: lines.slice(-remaining).join("\n") });
|
|
106
|
+
omittedLines += lines.length - remaining;
|
|
107
|
+
remaining = 0;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
omittedLines += lines.length;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { blocks: selected, omittedLines };
|
|
114
|
+
}
|
|
115
|
+
function countHistoryLines(blocks) {
|
|
116
|
+
return blocks.reduce((count, block) => count + block.content.split("\n").length, 0);
|
|
117
|
+
}
|
|
118
|
+
function userMessageText(content) {
|
|
119
|
+
if (typeof content === "string")
|
|
120
|
+
return content;
|
|
121
|
+
return content
|
|
122
|
+
.filter((block) => block.type === "text" && typeof block.text === "string")
|
|
123
|
+
.map((block) => block.text)
|
|
124
|
+
.join("");
|
|
125
|
+
}
|
|
126
|
+
function textFromHistoryContent(content) {
|
|
127
|
+
return content
|
|
128
|
+
.filter((block) => block.type === "text")
|
|
129
|
+
.map((block) => block.text)
|
|
130
|
+
.join("\n");
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../../src/tui/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BoxRenderable, type CliRenderer } from "@opentui/core";
|
|
2
|
+
import type { TurnContextUsageEvent, TurnTodo } from "../types/protocol.js";
|
|
3
|
+
import type { StateMachineSession } from "../types/state-machine.js";
|
|
4
|
+
/**
|
|
5
|
+
* Right-hand sidebar that surfaces the runner's todos, active state machine,
|
|
6
|
+
* and most recent context-window usage. Three stacked panels share the same
|
|
7
|
+
* width and bordering so the column has a consistent visual rhythm.
|
|
8
|
+
*/
|
|
9
|
+
export interface Sidebar {
|
|
10
|
+
/** Outer container; caller adds this to the root row. */
|
|
11
|
+
readonly view: BoxRenderable;
|
|
12
|
+
/** Replace the rendered todo list with the runner's current todos. */
|
|
13
|
+
setTodos(todos: readonly TurnTodo[]): void;
|
|
14
|
+
/** Mirror the active state-machine pipeline; pass undefined to clear. */
|
|
15
|
+
setStateMachine(session: StateMachineSession | undefined): void;
|
|
16
|
+
/** Render the latest context-usage progress bar; pass undefined to clear. */
|
|
17
|
+
setContextUsage(usage: TurnContextUsageEvent | undefined): void;
|
|
18
|
+
}
|
|
19
|
+
export declare function createSidebar(renderer: CliRenderer): Sidebar;
|
|
20
|
+
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/tui/sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAkB,MAAM,eAAe,CAAC;AAChF,OAAO,KAAK,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGrE;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC3C,yEAAyE;IACzE,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,GAAG,IAAI,CAAC;IAChE,6EAA6E;IAC7E,eAAe,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,GAAG,IAAI,CAAC;CACjE;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAoE5D"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { BoxRenderable, TextRenderable } from "@opentui/core";
|
|
2
|
+
import { COLORS } from "./theme.js";
|
|
3
|
+
export function createSidebar(renderer) {
|
|
4
|
+
// Fixed width keeps the sidebar legible on narrow terminals without
|
|
5
|
+
// squashing the transcript. The three panels stack vertically inside.
|
|
6
|
+
const view = new BoxRenderable(renderer, {
|
|
7
|
+
flexDirection: "column",
|
|
8
|
+
width: 36,
|
|
9
|
+
height: "100%",
|
|
10
|
+
flexShrink: 0,
|
|
11
|
+
});
|
|
12
|
+
const { panel: todoPanel, body: todoBody } = createPanel(renderer, "todos", "(none)");
|
|
13
|
+
const { panel: smPanel, body: smBody } = createPanel(renderer, "state machine", "(inactive)");
|
|
14
|
+
const { panel: contextPanel, body: contextBody } = createPanel(renderer, "context", "(waiting for usage)", { fixedHeight: 5, grow: false });
|
|
15
|
+
view.add(todoPanel);
|
|
16
|
+
view.add(smPanel);
|
|
17
|
+
view.add(contextPanel);
|
|
18
|
+
return {
|
|
19
|
+
view,
|
|
20
|
+
setTodos(todos) {
|
|
21
|
+
if (todos.length === 0) {
|
|
22
|
+
todoBody.content = "(none)";
|
|
23
|
+
todoBody.fg = COLORS.hint;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
todoBody.content = todos
|
|
27
|
+
.map((todo) => `${todoStatusGlyph(todo.status)} ${todo.content}`)
|
|
28
|
+
.join("\n");
|
|
29
|
+
todoBody.fg = COLORS.agent;
|
|
30
|
+
},
|
|
31
|
+
setStateMachine(session) {
|
|
32
|
+
if (!session) {
|
|
33
|
+
smBody.content = "(inactive)";
|
|
34
|
+
smBody.fg = COLORS.hint;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const current = session.currentState;
|
|
38
|
+
const lines = session.definition.states.map((state) => {
|
|
39
|
+
const marker = state.name === current ? "▶" : " ";
|
|
40
|
+
return `${marker} ${state.name}`;
|
|
41
|
+
});
|
|
42
|
+
if (session.terminal) {
|
|
43
|
+
lines.push("", `terminal: ${session.terminal.status}`);
|
|
44
|
+
}
|
|
45
|
+
smBody.content = lines.join("\n");
|
|
46
|
+
smBody.fg = COLORS.agent;
|
|
47
|
+
},
|
|
48
|
+
setContextUsage(usage) {
|
|
49
|
+
if (!usage) {
|
|
50
|
+
contextBody.content = "(waiting for usage)";
|
|
51
|
+
contextBody.fg = COLORS.hint;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const usedTokens = usage.usage.totalTokens;
|
|
55
|
+
const percent = Math.min(1, usedTokens / usage.contextWindow);
|
|
56
|
+
contextBody.content = [
|
|
57
|
+
progressBar(percent, 25),
|
|
58
|
+
`${formatTokenCount(usedTokens)} / ${formatTokenCount(usage.contextWindow)}`,
|
|
59
|
+
].join("\n");
|
|
60
|
+
contextBody.fg = usedTokens >= usage.contextWindow ? COLORS.error : COLORS.agent;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function createPanel(renderer, title, initialBody, options = {}) {
|
|
65
|
+
const grow = options.grow ?? true;
|
|
66
|
+
const panel = new BoxRenderable(renderer, {
|
|
67
|
+
flexDirection: "column",
|
|
68
|
+
border: true,
|
|
69
|
+
borderColor: COLORS.border,
|
|
70
|
+
paddingLeft: 1,
|
|
71
|
+
paddingRight: 1,
|
|
72
|
+
padding: options.fixedHeight ? undefined : 1,
|
|
73
|
+
...(options.fixedHeight ? { height: options.fixedHeight } : {}),
|
|
74
|
+
...(grow ? { flexGrow: 1, flexShrink: 1 } : { flexShrink: 0 }),
|
|
75
|
+
});
|
|
76
|
+
const titleNode = new TextRenderable(renderer, {
|
|
77
|
+
content: title,
|
|
78
|
+
fg: COLORS.status,
|
|
79
|
+
height: 1,
|
|
80
|
+
flexShrink: 0,
|
|
81
|
+
});
|
|
82
|
+
const body = new TextRenderable(renderer, {
|
|
83
|
+
content: initialBody,
|
|
84
|
+
fg: COLORS.hint,
|
|
85
|
+
flexGrow: grow ? 1 : 0,
|
|
86
|
+
flexShrink: 1,
|
|
87
|
+
});
|
|
88
|
+
panel.add(titleNode);
|
|
89
|
+
panel.add(body);
|
|
90
|
+
return { panel, body };
|
|
91
|
+
}
|
|
92
|
+
function todoStatusGlyph(status) {
|
|
93
|
+
if (status === "completed")
|
|
94
|
+
return "✓";
|
|
95
|
+
if (status === "in_progress")
|
|
96
|
+
return "●";
|
|
97
|
+
if (status === "failed")
|
|
98
|
+
return "✗";
|
|
99
|
+
return "○";
|
|
100
|
+
}
|
|
101
|
+
function progressBar(value, width) {
|
|
102
|
+
const clamped = Math.max(0, Math.min(1, value));
|
|
103
|
+
const filled = Math.round(clamped * width);
|
|
104
|
+
const empty = width - filled;
|
|
105
|
+
return `[${"█".repeat(filled)}${"░".repeat(empty)}] ${`${Math.round(clamped * 100)}%`.padStart(4)}`;
|
|
106
|
+
}
|
|
107
|
+
function formatTokenCount(tokens) {
|
|
108
|
+
if (tokens >= 1_000_000)
|
|
109
|
+
return `${formatCompactNumber(tokens / 1_000_000)}m`;
|
|
110
|
+
if (tokens >= 1_000)
|
|
111
|
+
return `${formatCompactNumber(tokens / 1_000)}k`;
|
|
112
|
+
return String(tokens);
|
|
113
|
+
}
|
|
114
|
+
function formatCompactNumber(value) {
|
|
115
|
+
const rounded = value >= 10 ? Math.round(value) : Math.round(value * 10) / 10;
|
|
116
|
+
return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.js","sourceRoot":"","sources":["../../../src/tui/sidebar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const COLORS: {
|
|
2
|
+
readonly user: "#7DD3FC";
|
|
3
|
+
readonly agent: "#FFFFFF";
|
|
4
|
+
readonly reasoning: "#9CA3AF";
|
|
5
|
+
readonly tool: "#A78BFA";
|
|
6
|
+
readonly system: "#FBBF24";
|
|
7
|
+
readonly error: "#F87171";
|
|
8
|
+
readonly hint: "#6B7280";
|
|
9
|
+
readonly memory: "#6B7280";
|
|
10
|
+
readonly status: "#34D399";
|
|
11
|
+
readonly border: "#374151";
|
|
12
|
+
};
|
|
13
|
+
export declare const HINT_IDLE = "Enter: send \u00B7 Esc: quit \u00B7 Ctrl+C: force quit";
|
|
14
|
+
export declare const HINT_RUNNING = "Enter: steer \u00B7 Shift+Enter: queue follow-up \u00B7 Esc: interrupt and quit \u00B7 Ctrl+C: force quit";
|
|
15
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../src/tui/theme.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM;;;;;;;;;;;CAWT,CAAC;AAEX,eAAO,MAAM,SAAS,2DAAiD,CAAC;AACxE,eAAO,MAAM,YAAY,8GACqE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Shared TUI palette and footer hints. Kept in one place so individual
|
|
2
|
+
// renderers stay focused on layout and the color story stays consistent
|
|
3
|
+
// across the transcript, sidebar, and autocomplete panels.
|
|
4
|
+
export const COLORS = {
|
|
5
|
+
user: "#7DD3FC",
|
|
6
|
+
agent: "#FFFFFF",
|
|
7
|
+
reasoning: "#9CA3AF",
|
|
8
|
+
tool: "#A78BFA",
|
|
9
|
+
system: "#FBBF24",
|
|
10
|
+
error: "#F87171",
|
|
11
|
+
hint: "#6B7280",
|
|
12
|
+
memory: "#6B7280",
|
|
13
|
+
status: "#34D399",
|
|
14
|
+
border: "#374151",
|
|
15
|
+
};
|
|
16
|
+
export const HINT_IDLE = "Enter: send · Esc: quit · Ctrl+C: force quit";
|
|
17
|
+
export const HINT_RUNNING = "Enter: steer · Shift+Enter: queue follow-up · Esc: interrupt and quit · Ctrl+C: force quit";
|
|
18
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../../src/tui/theme.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wEAAwE;AACxE,2DAA2D;AAC3D,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;CACT,CAAC;AAEX,MAAM,CAAC,MAAM,SAAS,GAAG,8CAA8C,CAAC;AACxE,MAAM,CAAC,MAAM,YAAY,GACvB,4FAA4F,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/turn-runner/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAG7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/turn-runner/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAG7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAyBhE,wBAAgB,oCAAoC,CAAC,KAAK,EAAE;IAC1D,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACnC,GAAG,MAAM,CAIT;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,GAAG,MAAM,CAsCT"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import dedent from "dedent";
|
|
2
2
|
import { toXML } from "../lib/xml.js";
|
|
3
|
+
import { DEFAULT_BASH_TIMEOUT_SECONDS } from "./tools.js";
|
|
3
4
|
function currentDateSystemPrompt() {
|
|
4
5
|
// Day-level resolution keeps the prompt stable for the whole UTC day so prompt
|
|
5
6
|
// caching is not invalidated on every turn. Agents that need finer-grained
|
|
@@ -15,6 +16,10 @@ const TOOL_EXECUTION_SYSTEM_PROMPT = dedent `
|
|
|
15
16
|
<use_parallel_tool_calls>
|
|
16
17
|
For maximum efficiency, whenever you perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially. Prioritize calling tools in parallel whenever possible. For example, when reading 3 files, run 3 tool calls in parallel to read all 3 files into context at the same time. When running multiple read-only commands like \`ls\` or \`list_dir\`, always run all of the commands in parallel. Err on the side of maximizing parallel tool calls rather than running too many tools sequentially.
|
|
17
18
|
</use_parallel_tool_calls>
|
|
19
|
+
|
|
20
|
+
<bash_timeout>
|
|
21
|
+
Bash commands run with a default timeout of ${DEFAULT_BASH_TIMEOUT_SECONDS} seconds (${Math.round(DEFAULT_BASH_TIMEOUT_SECONDS / 60)} minutes); commands that exceed it are killed and reported as timed out. Scope commands so they finish well under that — prefer narrow searches (e.g. \`rg\` inside the repo) over filesystem-wide walks like \`find /\`. When a command genuinely needs longer (long builds, test suites, package installs), pass an explicit \`timeout\` argument in seconds sized to the expected runtime.
|
|
22
|
+
</bash_timeout>
|
|
18
23
|
`;
|
|
19
24
|
export function createSystemPromptWithAppendedLayers(input) {
|
|
20
25
|
return [createBaseSystemPrompt(input.config, input.skills), ...input.append]
|
|
@@ -40,10 +45,14 @@ export function createStateMachineSystemPromptLayer(input) {
|
|
|
40
45
|
// state instead of relying on the parent transcript.
|
|
41
46
|
return [
|
|
42
47
|
"Route durable business-process work through state-machine tools whenever possible.",
|
|
48
|
+
'Also reach for a state machine whenever the work breaks down into well-scoped steps that a sub-agent or script can complete on its own ("do X with these inputs and return the result"). Each state runs outside this conversation: agent states get a fresh sub-agent context, and only a compact result returns to you. Their tool calls, file reads, and script output never enter this transcript, so using a state machine is the main way to keep the parent context clean on multi-step work. The definition and current progress are rendered to the user in real time, so it also serves as a visible plan. Prefer this over doing the steps yourself with todo_write whenever you do not need to keep reasoning over the intermediate output.',
|
|
49
|
+
'State-machine work also keeps the user unblocked. While states run in the background the user can still send messages and you (the parent) respond without waiting for the state machine to finish. State-machine progress continues regardless of what you do here — by default just answer the user. Only call select_state_machine_state if the user explicitly wants to redirect or change the running work; questions, status checks, and side conversations should be answered with plain replies. A "steer" message reaches you immediately as an interruption (right shape for redirects or anything time-sensitive); a "follow_up" message is queued and delivered when your current turn settles (right shape for context that does not need to interrupt). Doing the same multi-step work via todo_write would block the user behind your own tool calls instead.',
|
|
43
50
|
"If the request is simple or unrelated, answer normally without calling a turn-runner control tool.",
|
|
44
|
-
"After you select a state-machine state, the runner executes that state outside your current assistant message and may later sleep, wake, or continue in the background.",
|
|
51
|
+
"After you select a state-machine state, the runner executes that state outside your current assistant message and may later sleep, wake, or continue in the background. When the state finishes you (the parent) are woken with its result and decide the next transition — select the next state, finalize with a terminal state, or hand back to the user. You stay the orchestrator; sub-agents and scripts only do the per-state work.",
|
|
45
52
|
"State prompts and script commands may use template strings like {{ input.email }}. Add inputSchema to states that need template input, and pass matching input when selecting that state.",
|
|
46
53
|
'Poll states run recurring script checks and must set intervalMs. Timer states are separate: use kind "timer" with wakeAt to pause until one absolute Unix epoch millisecond timestamp. Poll states fail the state machine when timeoutMs is exceeded.',
|
|
54
|
+
"Poll intervalMs must be at least 15 minutes and timer wakeAt must be at least 15 minutes in the future. If the work needs anything shorter-term, run it directly in your turn instead of through a state machine — orchestration overhead is not worth it for sub-15-minute waits.",
|
|
55
|
+
'Every state-machine definition must include at least one terminal state with status "completed" for the happy-path exit. The runner auto-injects "failed" and "cancelled" terminal states when missing, so you always have escape hatches without writing boilerplate terminals.',
|
|
47
56
|
"Use allowedSkills on agent states only when that sub-agent should receive a restricted skill set.",
|
|
48
57
|
'When resuming after an interruption, an agent ask, or uncertainty about progress, call get_current_state_machine_state before selecting the next state. Also call it before answering user questions about current state-machine progress, background work, poll/wake status, what has already happened, or why the session is waiting. If currentState is "interrupted", use the history to identify the interrupted state and rerun it when appropriate.',
|
|
49
58
|
"When the user changes direction during state-machine work, select the same state again with updated input or select a different state. Selecting a state while another state is running replaces the active state work.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/turn-runner/prompts.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/turn-runner/prompts.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAE1D,SAAS,uBAAuB;IAC9B,+EAA+E;IAC/E,2EAA2E;IAC3E,gDAAgD;IAChD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpD,OAAO,MAAM,CAAA;;0BAEW,KAAK;;GAE5B,CAAC;AACJ,CAAC;AAED,MAAM,4BAA4B,GAAG,MAAM,CAAA;;;;;;gDAMK,4BAA4B,aAAa,IAAI,CAAC,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC;;CAErI,CAAC;AAEF,MAAM,UAAU,oCAAoC,CAAC,KAIpD;IACC,OAAO,CAAC,sBAAsB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;SACzE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,KAGnD;IACC,MAAM,UAAU,GACd,KAAK,CAAC,IAAI,KAAK,MAAM;QACnB,CAAC,CAAC,uFAAuF;QACzF,CAAC,CAAC,0FAA0F,CAAC;IACjG,MAAM,UAAU,GACd,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC;IACxF,MAAM,gBAAgB,GAAG,UAAU;QACjC,CAAC,CAAC,MAAM,CAAA;;;UAGF,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;;;OAGtC;QACH,CAAC,CAAC,SAAS,CAAC;IAEd,0EAA0E;IAC1E,2EAA2E;IAC3E,qDAAqD;IACrD,OAAO;QACL,oFAAoF;QACpF,ytBAAytB;QACztB,80BAA80B;QAC90B,oGAAoG;QACpG,4aAA4a;QAC5a,2LAA2L;QAC3L,uPAAuP;QACvP,oRAAoR;QACpR,kRAAkR;QAClR,mGAAmG;QACnG,4bAA4b;QAC5b,yNAAyN;QACzN,UAAU;QACV,gBAAgB;KACjB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,sBAAsB,CAAC,MAAwB,EAAE,MAAwB;IAChF,OAAO;QACL,MAAM,CAAC,kBAAkB;QACzB,uBAAuB,EAAE;QACzB,4BAA4B;QAC5B,wBAAwB,CAAC,MAAM,CAAC;KACjC;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAwB;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAA;;MAET,KAAK,CAAC;QACN,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7B,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;SACxE,CAAC,CAAC;KACJ,CAAC;GACH,CAAC;AACJ,CAAC"}
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import { type Skill } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type BashOperations, type Skill } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Type, type Static } from "typebox";
|
|
4
4
|
import type { TurnMode, TurnQuestion, TurnTodo } from "../types/protocol.js";
|
|
5
5
|
import type { StateMachineSession, StateMachineSessionEvent, StateMachineAgentState, StateMachineDefinition, StateMachinePollState, StateMachineProgress, StateMachineScriptState, StateMachineState, StateMachineTimerState, StateMachineTerminalResult } from "../types/state-machine.js";
|
|
6
6
|
import type { ActiveStateOutput } from "./state-machine-controller.js";
|
|
7
|
+
/**
|
|
8
|
+
* Default cap (in seconds) applied to bash tool invocations that omit an
|
|
9
|
+
* explicit timeout. Upstream's bash tool ships with no default timeout, so
|
|
10
|
+
* stray commands like `find /` could otherwise run for many minutes before
|
|
11
|
+
* anything intervenes. The model can still pass a larger `timeout` argument
|
|
12
|
+
* for legitimate long-running work.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_BASH_TIMEOUT_SECONDS = 300;
|
|
15
|
+
/**
|
|
16
|
+
* Wrap a `BashOperations` implementation so any `exec` call without an
|
|
17
|
+
* explicit `timeout` uses `defaultTimeoutSeconds`. Calls that already specify
|
|
18
|
+
* a timeout (the model passed one) are forwarded unchanged.
|
|
19
|
+
*/
|
|
20
|
+
export declare function withDefaultBashTimeout(base: BashOperations, defaultTimeoutSeconds?: number): BashOperations;
|
|
7
21
|
declare const askUserQuestionSchema: Type.TObject<{
|
|
8
22
|
questions: Type.TArray<Type.TObject<{
|
|
9
23
|
question: Type.TString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/turn-runner/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/turn-runner/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createCodingTools } from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import { createCodingTools, createLocalBashOperations, } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Ajv } from "ajv";
|
|
3
3
|
import dedent from "dedent";
|
|
4
4
|
import { Type } from "typebox";
|
|
@@ -6,6 +6,27 @@ import { Value } from "typebox/value";
|
|
|
6
6
|
import { INTERRUPTED_STATE_MACHINE_STATE } from "../types/state-machine.js";
|
|
7
7
|
import { readSkillInstructions } from "./skills.js";
|
|
8
8
|
const jsonSchemaValidator = new Ajv({ strictSchema: false });
|
|
9
|
+
/**
|
|
10
|
+
* Default cap (in seconds) applied to bash tool invocations that omit an
|
|
11
|
+
* explicit timeout. Upstream's bash tool ships with no default timeout, so
|
|
12
|
+
* stray commands like `find /` could otherwise run for many minutes before
|
|
13
|
+
* anything intervenes. The model can still pass a larger `timeout` argument
|
|
14
|
+
* for legitimate long-running work.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_BASH_TIMEOUT_SECONDS = 300;
|
|
17
|
+
/**
|
|
18
|
+
* Wrap a `BashOperations` implementation so any `exec` call without an
|
|
19
|
+
* explicit `timeout` uses `defaultTimeoutSeconds`. Calls that already specify
|
|
20
|
+
* a timeout (the model passed one) are forwarded unchanged.
|
|
21
|
+
*/
|
|
22
|
+
export function withDefaultBashTimeout(base, defaultTimeoutSeconds = DEFAULT_BASH_TIMEOUT_SECONDS) {
|
|
23
|
+
return {
|
|
24
|
+
exec: (command, cwd, options) => base.exec(command, cwd, {
|
|
25
|
+
...options,
|
|
26
|
+
timeout: options.timeout ?? defaultTimeoutSeconds,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
9
30
|
const questionOptionSchema = Type.Object({
|
|
10
31
|
label: Type.String({ description: "Answer text shown to the user." }),
|
|
11
32
|
description: Type.Optional(Type.String({ description: "Optional context explaining this choice." })),
|
|
@@ -216,7 +237,9 @@ export function isTurnRunnerControlResult(value) {
|
|
|
216
237
|
}
|
|
217
238
|
export function createDefaultTurnRunnerTools(cwd, todoStorage, skills = []) {
|
|
218
239
|
return [
|
|
219
|
-
...createCodingTools(cwd
|
|
240
|
+
...createCodingTools(cwd, {
|
|
241
|
+
bash: { operations: withDefaultBashTimeout(createLocalBashOperations()) },
|
|
242
|
+
}),
|
|
220
243
|
createTodoWriteTool(todoStorage),
|
|
221
244
|
createAskUserQuestionTool(),
|
|
222
245
|
createReadSkillTool(skills),
|
|
@@ -299,21 +322,23 @@ export function createTodoWriteTool(storage) {
|
|
|
299
322
|
name: "todo_write",
|
|
300
323
|
label: "Write todos",
|
|
301
324
|
description: dedent `
|
|
302
|
-
Track multi-step work as a structured, visible todo list. The list is shown to the user in real time — it is your shared scratchpad of "what we agreed to do" and "where we are."
|
|
325
|
+
Track multi-step work that you are doing yourself in this conversation, as a structured, visible todo list. The list is shown to the user in real time — it is your shared scratchpad of "what we agreed to do" and "where we are."
|
|
303
326
|
|
|
304
|
-
Reach for this tool whenever any of these are true:
|
|
305
|
-
- The user's message contains more than one independent task ("do X, also Y, and don't forget Z").
|
|
306
|
-
- The work needs three or more non-trivial steps to finish (research, edit, test, commit, etc.).
|
|
327
|
+
Reach for this tool when the steps require *your* ongoing reasoning and tool use in this transcript: edits you need to review, search results you need to keep referencing, or work where the user wants to see your moves as you make them. Use it whenever any of these are true:
|
|
328
|
+
- The user's message contains more than one independent task ("do X, also Y, and don't forget Z") and you will handle them yourself.
|
|
329
|
+
- The work needs three or more non-trivial steps to finish (research, edit, test, commit, etc.) that you will execute in this conversation.
|
|
307
330
|
- You are about to spend several tool calls on something — write the plan first so the user can see and correct it.
|
|
308
331
|
- You are resuming or interrupting work and want to make state explicit.
|
|
309
332
|
|
|
333
|
+
Prefer a state machine over this tool when the steps are well-scoped enough that a sub-agent or script could complete each one on its own ("do X with these inputs and return the result"). State-machine states run outside this transcript, so their intermediate output does not consume your context — using todo_write for that kind of work pollutes the parent context with tool output you do not actually need to keep.
|
|
334
|
+
|
|
310
335
|
How to use it well:
|
|
311
336
|
- Lay out the full plan up front with merge=false. Mark exactly one item in_progress at a time.
|
|
312
337
|
- As you finish each item, call again with merge=true and just that item flipped to completed; advance the next one to in_progress in the same call.
|
|
313
338
|
- If the plan changes (user redirects, you discover new work), update the list immediately so it stays honest.
|
|
314
|
-
- Skip the tool
|
|
339
|
+
- Skip the tool for genuinely single-step requests — a one-shot answer or a single file edit doesn't need a list.
|
|
315
340
|
|
|
316
|
-
Treat "the user gave me a list of asks" as an automatic cue to call this tool before doing anything else.
|
|
341
|
+
Treat "the user gave me a list of asks I will handle myself" as an automatic cue to call this tool before doing anything else.
|
|
317
342
|
`,
|
|
318
343
|
parameters: todoWriteSchema,
|
|
319
344
|
async execute(_toolCallId, params) {
|
|
@@ -357,15 +382,29 @@ function createStateMachineDefinitionTool() {
|
|
|
357
382
|
name: "create_state_machine_definition",
|
|
358
383
|
label: "Create state machine definition",
|
|
359
384
|
description: dedent `
|
|
360
|
-
Create a state-machine definition for durable business-process work
|
|
385
|
+
Create a state-machine definition for durable business-process work, or for any multi-step task whose steps are well-scoped enough that a sub-agent or script can complete each one on its own.
|
|
386
|
+
|
|
387
|
+
Reach for this tool — not todo_write — whenever a step can be described as "do X with these inputs and return the result." Each agent state runs in a fresh sub-agent context, and each script/poll/timer state runs without an agent at all. Only a compact result returns to you, so the sub-agent's tool calls, file reads, and script output never pollute this transcript. That makes a state machine the primary way to keep the parent context clean on multi-step work. The definition, current state, and progress are also rendered to the user in real time, so it doubles as a visible plan — they can see which state is running, what came before, and what is waiting.
|
|
388
|
+
|
|
389
|
+
You stay the orchestrator: when each state finishes, the runner wakes you with its result so you can inspect the output and decide the next transition (select the next state, finalize with a terminal state, or hand back to the user). Sub-agents and scripts only do the per-state work; they do not pick what comes next.
|
|
390
|
+
|
|
391
|
+
State-machine work also keeps the user unblocked. While states execute in the background the user can keep sending messages and you (the parent) will respond without waiting for the state machine to finish. State-machine progress continues regardless of what you do in that side reply — by default just answer the user. Only call select_state_machine_state if the user actually wants to redirect or change the running work; questions, status checks, and side conversations should be answered with plain replies. A "steer" message arrives immediately as an interruption (right shape for redirects or anything time-sensitive); a "follow_up" message is queued and delivered when your current turn settles (right shape for context that does not need to interrupt). Doing the same multi-step work via todo_write would block the user behind your own tool calls instead.
|
|
392
|
+
|
|
393
|
+
Use todo_write instead only when you need to do the steps yourself in this conversation because you will keep reasoning over the intermediate output.
|
|
394
|
+
|
|
395
|
+
State prompts and script commands may use template strings such as {{ input.email }}; define inputSchema on those states and pass matching input when selecting them. Agent states may set allowedSkills to restrict which skills are injected into that sub-agent.
|
|
361
396
|
|
|
362
397
|
Poll states always run script attempts on a recurring intervalMs and fail the state machine when timeoutMs is exceeded. Timer states are separate: set kind "timer" with wakeAt as an absolute Unix epoch millisecond timestamp, and the state completes at that time so the parent can choose the next state.
|
|
363
398
|
|
|
399
|
+
Poll intervalMs must be at least 15 minutes (900000 ms), and timer wakeAt must be at least 15 minutes in the future. State machines are for long-running lifecycle work that benefits from sleep/wake/background execution. Anything shorter-term should run directly in your turn rather than through a state machine — the orchestration overhead is not worth it for sub-15-minute waits.
|
|
400
|
+
|
|
401
|
+
Every definition must include at least one terminal state with status "completed" representing the happy-path exit (success). The runner automatically adds terminal states named "failed" (status "failed") and "cancelled" (status "cancelled") if you do not define them, so you always have escape hatches for unrecoverable failure and user cancellation without specifying boilerplate terminals. You may still define your own "failed" or "cancelled" states (with reasons or different names) to override or supplement the auto-injected ones.
|
|
402
|
+
|
|
364
403
|
Use this only when no state machine is active or the previous state machine has reached a terminal state; otherwise use select_state_machine_state.
|
|
365
404
|
`,
|
|
366
405
|
parameters: createDefinitionSchema,
|
|
367
406
|
async execute(_toolCallId, params) {
|
|
368
|
-
|
|
407
|
+
assertValidDefinition(params.definition);
|
|
369
408
|
const result = {
|
|
370
409
|
type: "create_state_machine_definition",
|
|
371
410
|
definition: params.definition,
|
|
@@ -475,13 +514,39 @@ function assertValidStateInput(state, input) {
|
|
|
475
514
|
const message = first?.message ?? "does not match schema";
|
|
476
515
|
throw new Error(`Invalid input for state "${state.name}" at ${path}: ${message}`);
|
|
477
516
|
}
|
|
478
|
-
|
|
517
|
+
// Minimum poll/timer cadence. State machines are for long-running lifecycle
|
|
518
|
+
// work that survives sleeps, wakes, and background execution; anything shorter
|
|
519
|
+
// than this should be performed directly in the parent turn rather than paid
|
|
520
|
+
// for with the orchestration overhead of a state machine.
|
|
521
|
+
const MINIMUM_STATE_MACHINE_DELAY_MS = 15 * 60 * 1000;
|
|
522
|
+
function assertValidDefinition(definition) {
|
|
479
523
|
for (const state of definition.states) {
|
|
480
524
|
if (state.name === INTERRUPTED_STATE_MACHINE_STATE) {
|
|
481
525
|
throw new Error(`State name "${INTERRUPTED_STATE_MACHINE_STATE}" is reserved.`);
|
|
482
526
|
}
|
|
483
527
|
assertValidStateInputSchema(state);
|
|
484
528
|
assertValidStateSchedule(state);
|
|
529
|
+
assertValidStateScheduleMinimum(state);
|
|
530
|
+
}
|
|
531
|
+
injectMissingTerminalEscapeHatches(definition);
|
|
532
|
+
assertHasCompletedTerminal(definition);
|
|
533
|
+
}
|
|
534
|
+
// The author defines the happy-path exit; failed/cancelled escape hatches are
|
|
535
|
+
// added automatically so every definition can always be aborted or finalized
|
|
536
|
+
// without forcing the caller to remember boilerplate terminal states.
|
|
537
|
+
function injectMissingTerminalEscapeHatches(definition) {
|
|
538
|
+
const existingNames = new Set(definition.states.map((state) => state.name));
|
|
539
|
+
if (!existingNames.has("failed")) {
|
|
540
|
+
definition.states.push({ kind: "terminal", name: "failed", status: "failed" });
|
|
541
|
+
}
|
|
542
|
+
if (!existingNames.has("cancelled")) {
|
|
543
|
+
definition.states.push({ kind: "terminal", name: "cancelled", status: "cancelled" });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function assertHasCompletedTerminal(definition) {
|
|
547
|
+
const hasCompletedTerminal = definition.states.some((state) => state.kind === "terminal" && state.status === "completed");
|
|
548
|
+
if (!hasCompletedTerminal) {
|
|
549
|
+
throw new Error('State-machine definition must include at least one terminal state with status "completed" representing successful completion of the lifecycle.');
|
|
485
550
|
}
|
|
486
551
|
}
|
|
487
552
|
function assertValidStateInputSchema(state) {
|
|
@@ -494,6 +559,9 @@ function assertValidStateInputSchema(state) {
|
|
|
494
559
|
});
|
|
495
560
|
throw new Error(`Invalid inputSchema for state "${state.name}": ${message}`);
|
|
496
561
|
}
|
|
562
|
+
// Shape validation: intervalMs / wakeAt must be present and finite. Runs at
|
|
563
|
+
// both definition creation and state selection so malformed overrides are
|
|
564
|
+
// rejected too.
|
|
497
565
|
function assertValidStateSchedule(state) {
|
|
498
566
|
if (state.kind === "poll" &&
|
|
499
567
|
(typeof state.intervalMs !== "number" ||
|
|
@@ -506,4 +574,21 @@ function assertValidStateSchedule(state) {
|
|
|
506
574
|
throw new Error(`Invalid timer schedule for state "${state.name}": wakeAt must be finite.`);
|
|
507
575
|
}
|
|
508
576
|
}
|
|
577
|
+
// Minimum-cadence guidance: enforced only when a new definition is being
|
|
578
|
+
// created. Existing definitions handed to the runner via `mode:` may legitimately
|
|
579
|
+
// have shorter cadences from configuration the agent did not author, and the
|
|
580
|
+
// runtime should run them as-is rather than re-litigating the boundary.
|
|
581
|
+
function assertValidStateScheduleMinimum(state) {
|
|
582
|
+
if (state.kind === "poll" && typeof state.intervalMs === "number") {
|
|
583
|
+
if (state.intervalMs < MINIMUM_STATE_MACHINE_DELAY_MS) {
|
|
584
|
+
throw new Error(`Invalid poll schedule for state "${state.name}": intervalMs must be at least 15 minutes (${MINIMUM_STATE_MACHINE_DELAY_MS} ms). Anything shorter should run directly in the parent turn instead of through a state machine.`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (state.kind === "timer" && typeof state.wakeAt === "number") {
|
|
588
|
+
const minWakeAt = Date.now() + MINIMUM_STATE_MACHINE_DELAY_MS;
|
|
589
|
+
if (state.wakeAt < minWakeAt) {
|
|
590
|
+
throw new Error(`Invalid timer schedule for state "${state.name}": wakeAt must be at least 15 minutes in the future. Anything shorter should run directly in the parent turn instead of through a state machine.`);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
509
594
|
//# sourceMappingURL=tools.js.map
|