@osolmaz/pi-workflows 0.1.0 → 0.2.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 +36 -21
- package/dist/extension/executor.d.ts +14 -1
- package/dist/extension/executor.js +11 -1
- package/dist/extension/executor.js.map +1 -1
- package/dist/extension/index.js +79 -7
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/recorder.d.ts +85 -0
- package/dist/extension/recorder.js +525 -0
- package/dist/extension/recorder.js.map +1 -0
- package/dist/extension/session-events.d.ts +134 -0
- package/dist/extension/session-events.js +60 -0
- package/dist/extension/session-events.js.map +1 -0
- package/dist/extension/widget.js +25 -24
- package/dist/extension/widget.js.map +1 -1
- package/dist/render/canvas.d.ts +1 -1
- package/dist/render/canvas.js +5 -0
- package/dist/render/canvas.js.map +1 -1
- package/dist/render/graph-render.d.ts +5 -0
- package/dist/render/graph-render.js +211 -48
- package/dist/render/graph-render.js.map +1 -1
- package/dist/viewer/render.js +19 -3
- package/dist/viewer/render.js.map +1 -1
- package/dist/viewer/session-reducer.d.ts +45 -0
- package/dist/viewer/session-reducer.js +266 -0
- package/dist/viewer/session-reducer.js.map +1 -0
- package/dist/workflows/artifacts.d.ts +40 -0
- package/dist/workflows/artifacts.js +155 -0
- package/dist/workflows/artifacts.js.map +1 -0
- package/dist/workflows/engine.d.ts +2 -0
- package/dist/workflows/engine.js +38 -7
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/index.d.ts +3 -2
- package/dist/workflows/index.js +2 -1
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/store.d.ts +53 -9
- package/dist/workflows/store.js +523 -43
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +126 -3
- package/docs/development.md +43 -19
- package/docs/live-replay-protocol.md +155 -0
- package/docs/plans/piw-viewer-experience-implementation-plan.md +674 -0
- package/docs/plans/replayable-run-bundles-implementation-plan.md +65 -0
- package/docs/plans/session-event-replay-implementation-plan.md +494 -0
- package/docs/plans/tui-viewer-implementation-plan.md +64 -0
- package/docs/run-bundles.md +320 -55
- package/docs/session-event-journal.md +470 -0
- package/docs/tui-viewer.md +218 -0
- package/package.json +2 -1
- package/src/extension/executor.ts +28 -1
- package/src/extension/index.ts +87 -7
- package/src/extension/recorder.ts +633 -0
- package/src/extension/session-events.ts +119 -0
- package/src/extension/widget.ts +26 -24
- package/src/render/canvas.ts +19 -1
- package/src/render/graph-render.ts +277 -44
- package/src/viewer/render.ts +21 -3
- package/src/viewer/session-reducer.ts +347 -0
- package/src/workflows/artifacts.ts +188 -0
- package/src/workflows/engine.ts +39 -7
- package/src/workflows/index.ts +15 -0
- package/src/workflows/store.ts +649 -49
- package/src/workflows/types.ts +141 -3
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export type PublicAssistantMessageEvent =
|
|
2
|
+
| { type: "start"; partial: unknown }
|
|
3
|
+
| { type: "text_start"; contentIndex: number; partial: unknown }
|
|
4
|
+
| { type: "text_delta"; contentIndex: number; delta: string; partial: unknown }
|
|
5
|
+
| { type: "text_end"; contentIndex: number; content: string; partial: unknown }
|
|
6
|
+
| { type: "thinking_start"; contentIndex: number; partial: unknown }
|
|
7
|
+
| { type: "thinking_delta"; contentIndex: number; delta: string; partial: unknown }
|
|
8
|
+
| { type: "thinking_end"; contentIndex: number; content: string; partial: unknown }
|
|
9
|
+
| { type: "toolcall_start"; contentIndex: number; partial: unknown }
|
|
10
|
+
| { type: "toolcall_delta"; contentIndex: number; delta: string; partial: unknown }
|
|
11
|
+
| { type: "toolcall_end"; contentIndex: number; toolCall: unknown; partial: unknown }
|
|
12
|
+
| { type: "done"; reason: "stop" | "length" | "toolUse"; message: unknown }
|
|
13
|
+
| { type: "error"; reason: "aborted" | "error"; error: unknown };
|
|
14
|
+
|
|
15
|
+
export type TurnStartEventLike = { turnIndex: number };
|
|
16
|
+
export type TurnEndEventLike = { turnIndex: number; message: unknown };
|
|
17
|
+
export type MessageStartEventLike = { message: unknown };
|
|
18
|
+
export type MessageUpdateEventLike = {
|
|
19
|
+
message: unknown;
|
|
20
|
+
assistantMessageEvent: PublicAssistantMessageEvent;
|
|
21
|
+
};
|
|
22
|
+
export type MessageEndEventLike = { message: unknown };
|
|
23
|
+
export type ToolExecutionStartEventLike = {
|
|
24
|
+
toolCallId: string;
|
|
25
|
+
toolName: string;
|
|
26
|
+
args: unknown;
|
|
27
|
+
};
|
|
28
|
+
export type ToolExecutionUpdateEventLike = { toolCallId: string };
|
|
29
|
+
export type ToolExecutionEndEventLike = {
|
|
30
|
+
toolCallId: string;
|
|
31
|
+
toolName: string;
|
|
32
|
+
result: unknown;
|
|
33
|
+
isError: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type NormalizedAssistantEvent =
|
|
37
|
+
| { type: "start" }
|
|
38
|
+
| { type: "text_start"; contentIndex: number }
|
|
39
|
+
| { type: "text_delta"; contentIndex: number; delta: string }
|
|
40
|
+
| { type: "text_end"; contentIndex: number; content: string }
|
|
41
|
+
| { type: "thinking_start"; contentIndex: number }
|
|
42
|
+
| { type: "thinking_delta"; contentIndex: number; delta: string }
|
|
43
|
+
| { type: "thinking_end"; contentIndex: number; content: string }
|
|
44
|
+
| { type: "toolcall_start"; contentIndex: number }
|
|
45
|
+
| { type: "toolcall_delta"; contentIndex: number; delta: string }
|
|
46
|
+
| { type: "toolcall_end"; contentIndex: number; toolCall: unknown }
|
|
47
|
+
| { type: "done"; reason: "stop" | "length" | "toolUse" }
|
|
48
|
+
| { type: "error"; reason: "aborted" | "error" };
|
|
49
|
+
|
|
50
|
+
/** Remove cumulative snapshots while preserving every semantic stream event. */
|
|
51
|
+
export function normalizeAssistantEvent(
|
|
52
|
+
event: PublicAssistantMessageEvent,
|
|
53
|
+
): NormalizedAssistantEvent {
|
|
54
|
+
switch (event.type) {
|
|
55
|
+
case "start":
|
|
56
|
+
return { type: event.type };
|
|
57
|
+
case "text_start":
|
|
58
|
+
case "thinking_start":
|
|
59
|
+
case "toolcall_start":
|
|
60
|
+
return { type: event.type, contentIndex: event.contentIndex };
|
|
61
|
+
case "text_delta":
|
|
62
|
+
case "thinking_delta":
|
|
63
|
+
case "toolcall_delta":
|
|
64
|
+
return { type: event.type, contentIndex: event.contentIndex, delta: event.delta };
|
|
65
|
+
case "text_end":
|
|
66
|
+
case "thinking_end":
|
|
67
|
+
return { type: event.type, contentIndex: event.contentIndex, content: event.content };
|
|
68
|
+
case "toolcall_end":
|
|
69
|
+
return {
|
|
70
|
+
type: event.type,
|
|
71
|
+
contentIndex: event.contentIndex,
|
|
72
|
+
toolCall: event.toolCall,
|
|
73
|
+
};
|
|
74
|
+
case "done":
|
|
75
|
+
return { type: event.type, reason: event.reason };
|
|
76
|
+
case "error":
|
|
77
|
+
return { type: event.type, reason: event.reason };
|
|
78
|
+
default: {
|
|
79
|
+
const exhaustive: never = event;
|
|
80
|
+
return exhaustive;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function messageRole(message: unknown): string {
|
|
86
|
+
if (typeof message !== "object" || message === null || !("role" in message)) {
|
|
87
|
+
return "unknown";
|
|
88
|
+
}
|
|
89
|
+
const role = (message as { role?: unknown }).role;
|
|
90
|
+
return typeof role === "string" && role.length > 0 ? role : "unknown";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function toolCallIdFromAssistantEvent(event: NormalizedAssistantEvent): string | null {
|
|
94
|
+
if (event.type !== "toolcall_end" || typeof event.toolCall !== "object" || !event.toolCall) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const id = (event.toolCall as { id?: unknown }).id;
|
|
98
|
+
return typeof id === "string" && id.length > 0 ? id : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function toolStartedPayload(event: ToolExecutionStartEventLike): Record<string, unknown> {
|
|
102
|
+
return { toolName: event.toolName, args: event.args };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function toolFinishedPayload(event: ToolExecutionEndEventLike): Record<string, unknown> {
|
|
106
|
+
return { toolName: event.toolName, isError: event.isError, result: event.result };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function turnFinishedPayload(
|
|
110
|
+
event: TurnEndEventLike,
|
|
111
|
+
messageId: string | undefined,
|
|
112
|
+
toolCallIds: string[],
|
|
113
|
+
): Record<string, unknown> {
|
|
114
|
+
return {
|
|
115
|
+
turnIndex: event.turnIndex,
|
|
116
|
+
...(messageId === undefined ? {} : { messageId }),
|
|
117
|
+
toolCallIds,
|
|
118
|
+
};
|
|
119
|
+
}
|
package/src/extension/widget.ts
CHANGED
|
@@ -113,16 +113,24 @@ export function buildWidgetLines(
|
|
|
113
113
|
/** The graph row the window should center on: the active or waiting node. */
|
|
114
114
|
function focusLine(graph: string[], state: WorkflowRunState): number {
|
|
115
115
|
const active = graph.findIndex((line) => stripAnsi(line).includes("◐"));
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
const focus =
|
|
117
|
+
active !== -1
|
|
118
|
+
? active
|
|
119
|
+
: state.waitingOn
|
|
120
|
+
? graph.findIndex((line) => stripAnsi(line).includes(state.waitingOn as string))
|
|
121
|
+
: -1;
|
|
122
|
+
if (focus === -1) {
|
|
123
|
+
return graph.length - 1;
|
|
118
124
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return waiting;
|
|
123
|
-
}
|
|
125
|
+
let top = focus;
|
|
126
|
+
while (top > 0 && !/[┌┏]/u.test(stripAnsi(graph[top] ?? ""))) {
|
|
127
|
+
top -= 1;
|
|
124
128
|
}
|
|
125
|
-
|
|
129
|
+
let bottom = focus;
|
|
130
|
+
while (bottom + 1 < graph.length && !/[└┗]/u.test(stripAnsi(graph[bottom] ?? ""))) {
|
|
131
|
+
bottom += 1;
|
|
132
|
+
}
|
|
133
|
+
return Math.floor((top + bottom) / 2);
|
|
126
134
|
}
|
|
127
135
|
|
|
128
136
|
/**
|
|
@@ -139,24 +147,18 @@ function windowLines(
|
|
|
139
147
|
if (lines.length <= budget) {
|
|
140
148
|
return { lines, scroll: 0, maxScroll: 0 };
|
|
141
149
|
}
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
let inner = budget;
|
|
146
|
-
for (let pass = 0; pass < 2; pass += 1) {
|
|
147
|
-
const start = clampStart(anchor, inner, lines.length, anchorIsStart);
|
|
148
|
-
inner = budget - (start > 0 ? 1 : 0) - (start + inner < lines.length ? 1 : 0);
|
|
149
|
-
}
|
|
150
|
+
// Reserve one combined overflow row, leaving seven rows for a complete
|
|
151
|
+
// full card even when the widget also has an error footer.
|
|
152
|
+
const inner = Math.max(1, budget - 1);
|
|
150
153
|
const start = clampStart(anchor, inner, lines.length, anchorIsStart);
|
|
151
154
|
const end = start + inner;
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
155
|
+
const above = start;
|
|
156
|
+
const below = Math.max(0, lines.length - end);
|
|
157
|
+
const out = lines.slice(start, end);
|
|
158
|
+
const directions = [above > 0 ? `↑ ${above}` : "", below > 0 ? `↓ ${below}` : ""]
|
|
159
|
+
.filter(Boolean)
|
|
160
|
+
.join(" · ");
|
|
161
|
+
out.push(ansi.dim(`${directions} more · shift+↑/↓ scroll`));
|
|
160
162
|
return { lines: out, scroll: start, maxScroll: Math.max(0, lines.length - inner) };
|
|
161
163
|
}
|
|
162
164
|
|
package/src/render/canvas.ts
CHANGED
|
@@ -4,7 +4,20 @@
|
|
|
4
4
|
* edge polylines join instead of overwriting each other.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export type CanvasStyle =
|
|
7
|
+
export type CanvasStyle =
|
|
8
|
+
| "plain"
|
|
9
|
+
| "dim"
|
|
10
|
+
| "taken"
|
|
11
|
+
| "active"
|
|
12
|
+
| "back"
|
|
13
|
+
| "ok"
|
|
14
|
+
| "fail"
|
|
15
|
+
| "warn"
|
|
16
|
+
| "branch"
|
|
17
|
+
| "agent"
|
|
18
|
+
| "compute"
|
|
19
|
+
| "action"
|
|
20
|
+
| "checkpoint";
|
|
8
21
|
|
|
9
22
|
type CanvasChar = { char: string; style: CanvasStyle };
|
|
10
23
|
|
|
@@ -40,6 +53,11 @@ const STYLE_PRIORITY: CanvasStyle[] = [
|
|
|
40
53
|
"warn",
|
|
41
54
|
"ok",
|
|
42
55
|
"fail",
|
|
56
|
+
"branch",
|
|
57
|
+
"agent",
|
|
58
|
+
"compute",
|
|
59
|
+
"action",
|
|
60
|
+
"checkpoint",
|
|
43
61
|
"taken",
|
|
44
62
|
"active",
|
|
45
63
|
];
|