@fragno-dev/pi-fragment 0.0.1 → 0.0.3
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 +39 -3
- package/dist/browser/client/react.d.ts +44 -36
- package/dist/browser/client/react.d.ts.map +1 -1
- package/dist/browser/client/react.js +105 -22
- package/dist/browser/client/react.js.map +1 -1
- package/dist/browser/client/solid.d.ts +42 -36
- package/dist/browser/client/solid.d.ts.map +1 -1
- package/dist/browser/client/solid.js +27 -13
- package/dist/browser/client/solid.js.map +1 -1
- package/dist/browser/client/svelte.d.ts +42 -36
- package/dist/browser/client/svelte.d.ts.map +1 -1
- package/dist/browser/client/svelte.js +14 -6
- package/dist/browser/client/svelte.js.map +1 -1
- package/dist/browser/client/vanilla.d.ts +99 -39
- package/dist/browser/client/vanilla.d.ts.map +1 -1
- package/dist/browser/client/vanilla.js +151 -3
- package/dist/browser/client/vanilla.js.map +1 -1
- package/dist/browser/client/vue.d.ts +54 -38
- package/dist/browser/client/vue.d.ts.map +1 -1
- package/dist/browser/client/vue.js +25 -17
- package/dist/browser/client/vue.js.map +1 -1
- package/dist/browser/{factory-DKoO_lRA.js → clients-BscY_HVe.js} +1051 -799
- package/dist/browser/clients-BscY_HVe.js.map +1 -0
- package/dist/browser/index.d.ts +3 -776
- package/dist/browser/index.js +801 -2
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/routes-CpL_YGWK.d.ts +1560 -0
- package/dist/browser/routes-CpL_YGWK.d.ts.map +1 -0
- package/dist/cli/mod.d.ts.map +1 -1
- package/dist/cli/mod.js +245 -7
- package/dist/cli/mod.js.map +1 -1
- package/dist/node/{pi → client}/clients.d.ts +46 -36
- package/dist/node/client/clients.d.ts.map +1 -0
- package/dist/node/client/clients.js +54 -0
- package/dist/node/client/clients.js.map +1 -0
- package/dist/node/client/session-controller.d.ts +31 -0
- package/dist/node/client/session-controller.d.ts.map +1 -0
- package/dist/node/client/session-controller.js +33 -0
- package/dist/node/client/session-controller.js.map +1 -0
- package/dist/node/client/session-store.d.ts +71 -0
- package/dist/node/client/session-store.d.ts.map +1 -0
- package/dist/node/client/session-store.js +637 -0
- package/dist/node/client/session-store.js.map +1 -0
- package/dist/node/debug-log.d.ts +9 -0
- package/dist/node/debug-log.d.ts.map +1 -0
- package/dist/node/debug-log.js +58 -0
- package/dist/node/debug-log.js.map +1 -0
- package/dist/node/index.d.ts +5 -4
- package/dist/node/index.js +5 -3
- package/dist/node/pi/definition.d.ts +1 -1
- package/dist/node/pi/definition.d.ts.map +1 -1
- package/dist/node/pi/dsl.d.ts +5 -2
- package/dist/node/pi/dsl.d.ts.map +1 -1
- package/dist/node/pi/dsl.js +22 -3
- package/dist/node/pi/dsl.js.map +1 -1
- package/dist/node/pi/factory.d.ts +37 -34
- package/dist/node/pi/factory.d.ts.map +1 -1
- package/dist/node/pi/factory.js.map +1 -1
- package/dist/node/pi/mappers.js +0 -1
- package/dist/node/pi/mappers.js.map +1 -1
- package/dist/node/pi/route-schemas.js +42 -10
- package/dist/node/pi/route-schemas.js.map +1 -1
- package/dist/node/pi/types.d.ts +155 -7
- package/dist/node/pi/types.d.ts.map +1 -1
- package/dist/node/pi/types.js +6 -0
- package/dist/node/pi/types.js.map +1 -0
- package/dist/node/pi/workflow/active-session.d.ts +2 -0
- package/dist/node/pi/workflow/active-session.js +107 -0
- package/dist/node/pi/workflow/active-session.js.map +1 -0
- package/dist/node/pi/workflow/agent-runner.d.ts +13 -0
- package/dist/node/pi/workflow/agent-runner.d.ts.map +1 -0
- package/dist/node/pi/workflow/agent-runner.js +228 -0
- package/dist/node/pi/workflow/agent-runner.js.map +1 -0
- package/dist/node/pi/workflow/tool-journal.js +157 -0
- package/dist/node/pi/workflow/tool-journal.js.map +1 -0
- package/dist/node/pi/workflow/workflow.d.ts +29 -0
- package/dist/node/pi/workflow/workflow.d.ts.map +1 -0
- package/dist/node/pi/workflow/workflow.js +219 -0
- package/dist/node/pi/workflow/workflow.js.map +1 -0
- package/dist/node/routes.d.ts +38 -35
- package/dist/node/routes.d.ts.map +1 -1
- package/dist/node/routes.js +203 -132
- package/dist/node/routes.js.map +1 -1
- package/dist/node/schema.js +1 -1
- package/dist/node/schema.js.map +1 -1
- package/package.json +30 -29
- package/dist/browser/client-Bk-J98pf.d.ts +0 -679
- package/dist/browser/client-Bk-J98pf.d.ts.map +0 -1
- package/dist/browser/factory-DKoO_lRA.js.map +0 -1
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/node/pi/clients.d.ts.map +0 -1
- package/dist/node/pi/clients.js +0 -18
- package/dist/node/pi/clients.js.map +0 -1
- package/dist/node/pi/workflow.d.ts +0 -31
- package/dist/node/pi/workflow.d.ts.map +0 -1
- package/dist/node/pi/workflow.js +0 -242
- package/dist/node/pi/workflow.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/browser/index.js
CHANGED
|
@@ -1,3 +1,802 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as STEERING_MODES, c as piFragmentDefinition, i as SESSION_STATUSES, n as createPiSessionStore, o as THINKING_LEVELS, r as piRoutesFactory, s as PiLogger, t as createPiFragmentClients } from "./clients-BscY_HVe.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { NonRetryableError, defineWorkflow } from "@fragno-dev/workflows";
|
|
4
|
+
import { column, idColumn, schema } from "@fragno-dev/db/schema";
|
|
5
|
+
import { Agent } from "@mariozechner/pi-agent-core";
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
//#region src/schema.ts
|
|
8
|
+
const piSchema = schema("pi-fragment", (s) => {
|
|
9
|
+
return s.addTable("session", (t) => {
|
|
10
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string").nullable()).addColumn("agent", column("string")).addColumn("status", column("string")).addColumn("steeringMode", column("string")).addColumn("metadata", column("json").nullable()).addColumn("tags", column("json").nullable()).addColumn("createdAt", column("timestamp").defaultTo((b) => b.now())).addColumn("updatedAt", column("timestamp").defaultTo((b) => b.now())).createIndex("idx_session_status", ["status"]).createIndex("idx_session_created", ["createdAt"]);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/pi/mappers.ts
|
|
16
|
+
const normalizeSteeringMode = (value) => {
|
|
17
|
+
return STEERING_MODES.includes(value) ? value : "one-at-a-time";
|
|
18
|
+
};
|
|
19
|
+
const extractAssistantText = (messages) => {
|
|
20
|
+
const lastAssistant = [...messages].reverse().find((message) => {
|
|
21
|
+
return typeof message === "object" && message !== null && "role" in message && message.role === "assistant";
|
|
22
|
+
});
|
|
23
|
+
if (!lastAssistant || typeof lastAssistant !== "object") return "";
|
|
24
|
+
const content = lastAssistant.content;
|
|
25
|
+
if (!Array.isArray(content)) return "";
|
|
26
|
+
return content.filter((block) => typeof block === "object" && block !== null && block.type === "text").map((block) => block.text ?? "").join("").trim();
|
|
27
|
+
};
|
|
28
|
+
const extractAssistantTextFromMessage = (message) => {
|
|
29
|
+
if (!message) return "";
|
|
30
|
+
return extractAssistantText([message]);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/pi/workflow/active-session.ts
|
|
35
|
+
const WAIT_FOR_USER_TIMEOUT_MS$1 = 3600 * 1e3;
|
|
36
|
+
const buildWaitingForUser$1 = (turn) => ({
|
|
37
|
+
type: "user_message",
|
|
38
|
+
turn,
|
|
39
|
+
stepKey: `waitForEvent:wait-user-${turn}`,
|
|
40
|
+
timeoutMs: WAIT_FOR_USER_TIMEOUT_MS$1
|
|
41
|
+
});
|
|
42
|
+
const getActiveSessionReplayBuffer = (state) => {
|
|
43
|
+
const replayBuffer = state.activeSessionUpdatesByTurn;
|
|
44
|
+
return Array.isArray(replayBuffer) ? structuredClone(replayBuffer) : [];
|
|
45
|
+
};
|
|
46
|
+
const createPiActiveSessionState = (options) => {
|
|
47
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
48
|
+
const updatesByTurn = /* @__PURE__ */ new Map();
|
|
49
|
+
const trimPreviousTurns = (turn) => {
|
|
50
|
+
for (const previousTurn of updatesByTurn.keys()) if (previousTurn < turn - 1) updatesByTurn.delete(previousTurn);
|
|
51
|
+
};
|
|
52
|
+
const appendUpdate = (turn, update) => {
|
|
53
|
+
const existing = updatesByTurn.get(turn) ?? [];
|
|
54
|
+
updatesByTurn.set(turn, [...existing, structuredClone(update)]);
|
|
55
|
+
trimPreviousTurns(turn);
|
|
56
|
+
};
|
|
57
|
+
const exportReplayBuffer = () => structuredClone([...updatesByTurn.entries()].sort(([leftTurn], [rightTurn]) => leftTurn - rightTurn).map(([turn, updates]) => ({
|
|
58
|
+
turn,
|
|
59
|
+
updates
|
|
60
|
+
})));
|
|
61
|
+
const syncReplayBuffer = () => {
|
|
62
|
+
options?.onReplayBufferChange?.(exportReplayBuffer());
|
|
63
|
+
};
|
|
64
|
+
const importReplayBuffer = (buffer) => {
|
|
65
|
+
updatesByTurn.clear();
|
|
66
|
+
for (const entry of structuredClone(buffer)) for (const update of entry.updates) appendUpdate(entry.turn, update);
|
|
67
|
+
syncReplayBuffer();
|
|
68
|
+
};
|
|
69
|
+
if (options?.replayBuffer) importReplayBuffer(options.replayBuffer);
|
|
70
|
+
const notify = (update) => {
|
|
71
|
+
for (const listener of Array.from(listeners)) try {
|
|
72
|
+
listener(update);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.warn("Pi active-session listener failed.", {
|
|
75
|
+
error,
|
|
76
|
+
updateType: update.type
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
subscribe(listener) {
|
|
82
|
+
listeners.add(listener);
|
|
83
|
+
return () => {
|
|
84
|
+
listeners.delete(listener);
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
publishEvent(turn, event) {
|
|
88
|
+
const update = {
|
|
89
|
+
type: "event",
|
|
90
|
+
turn,
|
|
91
|
+
event
|
|
92
|
+
};
|
|
93
|
+
appendUpdate(turn, update);
|
|
94
|
+
syncReplayBuffer();
|
|
95
|
+
notify(update);
|
|
96
|
+
},
|
|
97
|
+
settleTurn(turn, status) {
|
|
98
|
+
const update = {
|
|
99
|
+
type: "settled",
|
|
100
|
+
turn,
|
|
101
|
+
status
|
|
102
|
+
};
|
|
103
|
+
appendUpdate(turn, update);
|
|
104
|
+
syncReplayBuffer();
|
|
105
|
+
notify(update);
|
|
106
|
+
},
|
|
107
|
+
replayTurn(turn) {
|
|
108
|
+
return structuredClone(updatesByTurn.get(turn) ?? []);
|
|
109
|
+
},
|
|
110
|
+
exportReplayBuffer,
|
|
111
|
+
importReplayBuffer,
|
|
112
|
+
listenerCount: () => listeners.size
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
const createInitialPiAgentLoopState = (messages = []) => ({
|
|
116
|
+
messages,
|
|
117
|
+
events: [],
|
|
118
|
+
trace: [],
|
|
119
|
+
summaries: [],
|
|
120
|
+
turn: 0,
|
|
121
|
+
phase: "waiting-for-user",
|
|
122
|
+
waitingFor: buildWaitingForUser$1(0),
|
|
123
|
+
activeSessionUpdatesByTurn: []
|
|
124
|
+
});
|
|
125
|
+
const ensurePiActiveSessionState = (state) => {
|
|
126
|
+
if (state.activeSession) return state.activeSession;
|
|
127
|
+
const activeSession = createPiActiveSessionState({
|
|
128
|
+
replayBuffer: getActiveSessionReplayBuffer(state),
|
|
129
|
+
onReplayBufferChange: (replayBuffer) => {
|
|
130
|
+
state.activeSessionUpdatesByTurn = replayBuffer;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
state.activeSessionUpdatesByTurn = activeSession.exportReplayBuffer();
|
|
134
|
+
state.activeSession = activeSession;
|
|
135
|
+
return activeSession;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/pi/types.ts
|
|
140
|
+
const PI_TOOL_JOURNAL_VERSION = 1;
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/pi/workflow/tool-journal.ts
|
|
144
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
145
|
+
const TOOL_JOURNAL_FIELD = "toolJournal";
|
|
146
|
+
const persistedToolResultContentSchema = z.union([z.object({
|
|
147
|
+
type: z.literal("text"),
|
|
148
|
+
text: z.string(),
|
|
149
|
+
textSignature: z.string().optional()
|
|
150
|
+
}), z.object({
|
|
151
|
+
type: z.literal("image"),
|
|
152
|
+
data: z.string(),
|
|
153
|
+
mimeType: z.string()
|
|
154
|
+
})]);
|
|
155
|
+
const persistedToolResultSchema = z.object({
|
|
156
|
+
content: z.array(persistedToolResultContentSchema),
|
|
157
|
+
details: z.unknown()
|
|
158
|
+
});
|
|
159
|
+
const persistedToolCallSchema = z.object({
|
|
160
|
+
version: z.literal(PI_TOOL_JOURNAL_VERSION),
|
|
161
|
+
key: z.string(),
|
|
162
|
+
sessionId: z.string(),
|
|
163
|
+
turnId: z.string(),
|
|
164
|
+
toolCallId: z.string(),
|
|
165
|
+
toolName: z.string(),
|
|
166
|
+
args: z.record(z.string(), z.unknown()),
|
|
167
|
+
result: persistedToolResultSchema,
|
|
168
|
+
isError: z.boolean(),
|
|
169
|
+
source: z.enum(["executed", "replay"]),
|
|
170
|
+
capturedAt: z.number().finite(),
|
|
171
|
+
seq: z.number().int().nonnegative()
|
|
172
|
+
});
|
|
173
|
+
const formatToolJournalIssueLocation = (location, issue) => {
|
|
174
|
+
if (issue.path.length === 0) return location;
|
|
175
|
+
return `${location}.${issue.path.join(".")}`;
|
|
176
|
+
};
|
|
177
|
+
const buildStableToolCallKey = (sessionId, turnId, toolCallId) => `${sessionId}:${turnId}:${toolCallId}`;
|
|
178
|
+
const compareToolJournalEntries = (a, b) => a.seq !== b.seq ? a.seq - b.seq : a.capturedAt - b.capturedAt;
|
|
179
|
+
const clonePersistedToolCall = (entry) => structuredClone(entry);
|
|
180
|
+
const buildToolErrorResult = (error) => ({
|
|
181
|
+
content: [{
|
|
182
|
+
type: "text",
|
|
183
|
+
text: error instanceof Error ? error.message : String(error)
|
|
184
|
+
}],
|
|
185
|
+
details: {}
|
|
186
|
+
});
|
|
187
|
+
const extractToolErrorMessage = (result) => {
|
|
188
|
+
for (const block of result.content) if (block.type === "text") return block.text;
|
|
189
|
+
return "Tool execution failed";
|
|
190
|
+
};
|
|
191
|
+
const createPersistedToolCall = (options) => ({
|
|
192
|
+
version: PI_TOOL_JOURNAL_VERSION,
|
|
193
|
+
key: buildStableToolCallKey(options.sessionId, options.turnId, options.toolCallId),
|
|
194
|
+
sessionId: options.sessionId,
|
|
195
|
+
turnId: options.turnId,
|
|
196
|
+
toolCallId: options.toolCallId,
|
|
197
|
+
toolName: options.toolName,
|
|
198
|
+
args: options.args,
|
|
199
|
+
result: options.result,
|
|
200
|
+
isError: options.isError,
|
|
201
|
+
source: options.source,
|
|
202
|
+
capturedAt: Date.now(),
|
|
203
|
+
seq: options.seq
|
|
204
|
+
});
|
|
205
|
+
const parsePersistedToolCall = (value, location) => {
|
|
206
|
+
if (!isRecord(value) || Array.isArray(value)) throw new NonRetryableError(`Invalid tool journal entry at ${location}.`);
|
|
207
|
+
if (value["version"] !== PI_TOOL_JOURNAL_VERSION) throw new NonRetryableError(`Unsupported tool journal version at ${location}: ${String(value["version"])}`);
|
|
208
|
+
const parsed = persistedToolCallSchema.safeParse(value);
|
|
209
|
+
if (!parsed.success) {
|
|
210
|
+
const issue = parsed.error.issues[0];
|
|
211
|
+
throw new NonRetryableError(`Invalid tool journal entry at ${formatToolJournalIssueLocation(location, issue)}: ${issue.message}`);
|
|
212
|
+
}
|
|
213
|
+
return parsed.data;
|
|
214
|
+
};
|
|
215
|
+
const parsePersistedToolJournal = (assistantResult, stepName) => {
|
|
216
|
+
if (!isRecord(assistantResult) || Array.isArray(assistantResult)) throw new NonRetryableError(`Assistant step ${stepName} returned an invalid result object.`);
|
|
217
|
+
if (!(TOOL_JOURNAL_FIELD in assistantResult)) return [];
|
|
218
|
+
const raw = assistantResult[TOOL_JOURNAL_FIELD];
|
|
219
|
+
if (!Array.isArray(raw)) throw new NonRetryableError(`Assistant step ${stepName} contains an invalid tool journal.`);
|
|
220
|
+
return raw.map((entry, index) => parsePersistedToolCall(entry, `${stepName}[${index}]`));
|
|
221
|
+
};
|
|
222
|
+
const hydrateReplayCache = (cache, entries) => {
|
|
223
|
+
const sorted = [...entries].sort(compareToolJournalEntries);
|
|
224
|
+
for (const entry of sorted) {
|
|
225
|
+
if (entry.source === "replay" && cache.has(entry.key)) continue;
|
|
226
|
+
cache.set(entry.key, clonePersistedToolCall(entry));
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const reduceBashSideEffects = (state, entry) => {
|
|
230
|
+
const details = isRecord(entry.result.details) ? entry.result.details : {};
|
|
231
|
+
const base = isRecord(state) ? state : {};
|
|
232
|
+
const next = {
|
|
233
|
+
cwd: typeof details.cwd === "string" ? details.cwd : typeof base.cwd === "string" ? base.cwd : "/",
|
|
234
|
+
files: isRecord(base.files) && !Array.isArray(base.files) ? { ...base.files } : {}
|
|
235
|
+
};
|
|
236
|
+
const detailsFiles = isRecord(details.files) && !Array.isArray(details.files) ? details.files : null;
|
|
237
|
+
if (detailsFiles) for (const [path, value] of Object.entries(detailsFiles)) next.files[path] = value;
|
|
238
|
+
if (Array.isArray(details.writes)) for (const item of details.writes) {
|
|
239
|
+
if (!isRecord(item)) continue;
|
|
240
|
+
const writeEntry = item;
|
|
241
|
+
const path = typeof writeEntry.path === "string" ? writeEntry.path : null;
|
|
242
|
+
if (!path) continue;
|
|
243
|
+
next.files[path] = typeof writeEntry.content === "string" ? writeEntry.content : "";
|
|
244
|
+
}
|
|
245
|
+
const deletes = Array.isArray(details.deletes) ? details.deletes : Array.isArray(details.deletedPaths) ? details.deletedPaths : [];
|
|
246
|
+
for (const path of deletes) if (typeof path === "string") delete next.files[path];
|
|
247
|
+
return next;
|
|
248
|
+
};
|
|
249
|
+
const buildSideEffectState = (options) => {
|
|
250
|
+
const reducers = {
|
|
251
|
+
bash: reduceBashSideEffects,
|
|
252
|
+
...options.reducers
|
|
253
|
+
};
|
|
254
|
+
const state = {};
|
|
255
|
+
const journal = [...options.cache.values()].sort(compareToolJournalEntries);
|
|
256
|
+
for (const entry of journal) {
|
|
257
|
+
const reducer = reducers[entry.toolName];
|
|
258
|
+
if (!reducer) continue;
|
|
259
|
+
try {
|
|
260
|
+
state[entry.toolName] = reducer(state[entry.toolName], entry, {
|
|
261
|
+
key: entry.key,
|
|
262
|
+
sessionId: entry.sessionId,
|
|
263
|
+
turnId: entry.turnId
|
|
264
|
+
});
|
|
265
|
+
} catch (error) {
|
|
266
|
+
throw new NonRetryableError(`Tool side-effect reducer failed for ${entry.toolName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return state;
|
|
270
|
+
};
|
|
271
|
+
const replaySequenceByContext = /* @__PURE__ */ new WeakMap();
|
|
272
|
+
const takeNextReplaySequence = (replayContext) => {
|
|
273
|
+
const current = replaySequenceByContext.get(replayContext) ?? 0;
|
|
274
|
+
replaySequenceByContext.set(replayContext, current + 1);
|
|
275
|
+
return current;
|
|
276
|
+
};
|
|
277
|
+
const createReplayContext = (options) => {
|
|
278
|
+
const localCache = /* @__PURE__ */ new Map();
|
|
279
|
+
for (const [key, entry] of options.cache.entries()) localCache.set(key, clonePersistedToolCall(entry));
|
|
280
|
+
const replayContext = {
|
|
281
|
+
cache: localCache,
|
|
282
|
+
journal: [],
|
|
283
|
+
sideEffects: buildSideEffectState({
|
|
284
|
+
cache: localCache,
|
|
285
|
+
reducers: options.reducers
|
|
286
|
+
})
|
|
287
|
+
};
|
|
288
|
+
const maxSeq = [...localCache.values()].reduce((max, entry) => entry.seq > max ? entry.seq : max, -1);
|
|
289
|
+
replaySequenceByContext.set(replayContext, maxSeq + 1);
|
|
290
|
+
return replayContext;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/pi/workflow/agent-runner.ts
|
|
295
|
+
const isAssistantLikeMessage = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && value.role === "assistant" && Array.isArray(value.content) && typeof value.stopReason === "string";
|
|
296
|
+
const buildStreamErrorAssistantMessage = (model, error) => ({
|
|
297
|
+
role: "assistant",
|
|
298
|
+
content: [{
|
|
299
|
+
type: "text",
|
|
300
|
+
text: ""
|
|
301
|
+
}],
|
|
302
|
+
api: model.api,
|
|
303
|
+
provider: model.provider,
|
|
304
|
+
model: model.id,
|
|
305
|
+
usage: {
|
|
306
|
+
input: 0,
|
|
307
|
+
output: 0,
|
|
308
|
+
cacheRead: 0,
|
|
309
|
+
cacheWrite: 0,
|
|
310
|
+
totalTokens: 0,
|
|
311
|
+
cost: {
|
|
312
|
+
input: 0,
|
|
313
|
+
output: 0,
|
|
314
|
+
cacheRead: 0,
|
|
315
|
+
cacheWrite: 0,
|
|
316
|
+
total: 0
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
stopReason: "error",
|
|
320
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
321
|
+
timestamp: Date.now()
|
|
322
|
+
});
|
|
323
|
+
const wrapStreamFn = (streamFn) => streamFn ? async (...args) => {
|
|
324
|
+
const [model] = args;
|
|
325
|
+
const stream = await streamFn(...args);
|
|
326
|
+
if (typeof stream !== "object" || stream === null || Array.isArray(stream)) return stream;
|
|
327
|
+
const response = stream;
|
|
328
|
+
if (typeof response.result !== "function") return stream;
|
|
329
|
+
const originalResult = response.result.bind(stream);
|
|
330
|
+
let streamResultError;
|
|
331
|
+
response.result = async () => {
|
|
332
|
+
if (streamResultError) throw streamResultError;
|
|
333
|
+
try {
|
|
334
|
+
const result = await originalResult();
|
|
335
|
+
if (isAssistantLikeMessage(result)) return result;
|
|
336
|
+
streamResultError = /* @__PURE__ */ new Error("Stream result is not a valid assistant message.");
|
|
337
|
+
} catch (error) {
|
|
338
|
+
streamResultError = error;
|
|
339
|
+
}
|
|
340
|
+
const errorMessage = buildStreamErrorAssistantMessage(model, streamResultError);
|
|
341
|
+
if ("push" in stream && typeof stream.push === "function") stream.push({
|
|
342
|
+
type: "error",
|
|
343
|
+
reason: "error",
|
|
344
|
+
error: errorMessage
|
|
345
|
+
});
|
|
346
|
+
return errorMessage;
|
|
347
|
+
};
|
|
348
|
+
return stream;
|
|
349
|
+
} : void 0;
|
|
350
|
+
const resolveTool = async (name, factory, context) => {
|
|
351
|
+
if (!factory) throw new NonRetryableError(`Tool ${name} not found.`);
|
|
352
|
+
if (typeof factory === "function") {
|
|
353
|
+
const tool = await factory(context);
|
|
354
|
+
if (!tool) throw new NonRetryableError(`Tool ${name} returned no definition.`);
|
|
355
|
+
return tool;
|
|
356
|
+
}
|
|
357
|
+
return factory;
|
|
358
|
+
};
|
|
359
|
+
const wrapToolWithReplay = (options) => ({
|
|
360
|
+
...options.tool,
|
|
361
|
+
execute: async (toolCallId, params, signal, onUpdate) => {
|
|
362
|
+
const sessionId = options.context.session.id;
|
|
363
|
+
const toolCallIdValue = String(toolCallId);
|
|
364
|
+
const key = buildStableToolCallKey(sessionId, options.context.turnId, toolCallIdValue);
|
|
365
|
+
const replayEntry = options.context.replay.cache.get(key);
|
|
366
|
+
if (replayEntry) {
|
|
367
|
+
options.context.replay.journal.push(clonePersistedToolCall({
|
|
368
|
+
...replayEntry,
|
|
369
|
+
source: "replay",
|
|
370
|
+
seq: takeNextReplaySequence(options.context.replay)
|
|
371
|
+
}));
|
|
372
|
+
PiLogger.debug("tool replay hit", {
|
|
373
|
+
sessionId,
|
|
374
|
+
turnId: options.context.turnId,
|
|
375
|
+
toolName: replayEntry.toolName,
|
|
376
|
+
key
|
|
377
|
+
});
|
|
378
|
+
if (replayEntry.isError) throw new Error(extractToolErrorMessage(replayEntry.result));
|
|
379
|
+
return structuredClone(replayEntry.result);
|
|
380
|
+
}
|
|
381
|
+
const argsSnapshot = structuredClone(params);
|
|
382
|
+
const recordResult = (result, isError) => {
|
|
383
|
+
const entry = createPersistedToolCall({
|
|
384
|
+
sessionId,
|
|
385
|
+
turnId: options.context.turnId,
|
|
386
|
+
toolCallId: toolCallIdValue,
|
|
387
|
+
toolName: options.toolName,
|
|
388
|
+
args: argsSnapshot,
|
|
389
|
+
result,
|
|
390
|
+
isError,
|
|
391
|
+
source: "executed",
|
|
392
|
+
seq: takeNextReplaySequence(options.context.replay)
|
|
393
|
+
});
|
|
394
|
+
options.context.replay.cache.set(entry.key, clonePersistedToolCall(entry));
|
|
395
|
+
options.context.replay.journal.push(clonePersistedToolCall(entry));
|
|
396
|
+
return entry;
|
|
397
|
+
};
|
|
398
|
+
try {
|
|
399
|
+
const result = await options.tool.execute(toolCallId, params, signal, onUpdate);
|
|
400
|
+
recordResult(structuredClone(result), false);
|
|
401
|
+
return result;
|
|
402
|
+
} catch (error) {
|
|
403
|
+
recordResult(buildToolErrorResult(error), true);
|
|
404
|
+
throw error;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
const resolveTools = async (options) => {
|
|
409
|
+
const toolNames = options.agent.tools ?? [];
|
|
410
|
+
if (toolNames.length === 0) return [];
|
|
411
|
+
const context = {
|
|
412
|
+
session: options.session,
|
|
413
|
+
turnId: options.turnId,
|
|
414
|
+
toolConfig: options.agent.toolConfig ?? null,
|
|
415
|
+
messages: options.messages,
|
|
416
|
+
replay: options.replay
|
|
417
|
+
};
|
|
418
|
+
const resolved = [];
|
|
419
|
+
for (const name of toolNames) {
|
|
420
|
+
const tool = await resolveTool(name, options.tools[name], context);
|
|
421
|
+
resolved.push(wrapToolWithReplay({
|
|
422
|
+
toolName: name,
|
|
423
|
+
tool,
|
|
424
|
+
context
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
return resolved;
|
|
428
|
+
};
|
|
429
|
+
const findLastAssistantMessage = (messages) => messages.findLast((m) => m.role === "assistant") ?? null;
|
|
430
|
+
const createAgent = async (options) => {
|
|
431
|
+
const now = /* @__PURE__ */ new Date();
|
|
432
|
+
const session = {
|
|
433
|
+
id: options.params.sessionId,
|
|
434
|
+
name: null,
|
|
435
|
+
status: "active",
|
|
436
|
+
agent: options.params.agentName,
|
|
437
|
+
steeringMode: options.steeringMode,
|
|
438
|
+
metadata: null,
|
|
439
|
+
tags: [],
|
|
440
|
+
createdAt: now,
|
|
441
|
+
updatedAt: now
|
|
442
|
+
};
|
|
443
|
+
const agentTools = await resolveTools({
|
|
444
|
+
agent: options.agent,
|
|
445
|
+
tools: options.tools,
|
|
446
|
+
session,
|
|
447
|
+
turnId: options.turnId,
|
|
448
|
+
messages: options.messages,
|
|
449
|
+
replay: options.replay
|
|
450
|
+
});
|
|
451
|
+
const initialState = {
|
|
452
|
+
systemPrompt: options.params.systemPrompt ?? options.agent.systemPrompt,
|
|
453
|
+
model: options.agent.model,
|
|
454
|
+
tools: agentTools,
|
|
455
|
+
messages: options.messages
|
|
456
|
+
};
|
|
457
|
+
if (options.agent.thinkingLevel) initialState.thinkingLevel = options.agent.thinkingLevel;
|
|
458
|
+
const agent = new Agent({
|
|
459
|
+
initialState,
|
|
460
|
+
streamFn: wrapStreamFn(options.agent.streamFn),
|
|
461
|
+
convertToLlm: options.agent.convertToLlm,
|
|
462
|
+
transformContext: options.agent.transformContext,
|
|
463
|
+
getApiKey: options.agent.getApiKey,
|
|
464
|
+
thinkingBudgets: options.agent.thinkingBudgets,
|
|
465
|
+
maxRetryDelayMs: options.agent.maxRetryDelayMs,
|
|
466
|
+
sessionId: options.params.sessionId
|
|
467
|
+
});
|
|
468
|
+
agent.setSteeringMode(options.steeringMode);
|
|
469
|
+
const trace = [];
|
|
470
|
+
const unsubscribe = agent.subscribe((event) => {
|
|
471
|
+
trace.push(event);
|
|
472
|
+
options.onEvent?.(event);
|
|
473
|
+
if (!options.agent.onEvent) return;
|
|
474
|
+
try {
|
|
475
|
+
options.agent.onEvent(event, {
|
|
476
|
+
sessionId: options.params.sessionId,
|
|
477
|
+
turnId: options.turnId
|
|
478
|
+
});
|
|
479
|
+
} catch (error) {
|
|
480
|
+
console.warn("Agent onEvent hook failed.", {
|
|
481
|
+
error,
|
|
482
|
+
sessionId: options.params.sessionId,
|
|
483
|
+
turnId: options.turnId,
|
|
484
|
+
agent: options.agent.name
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
try {
|
|
489
|
+
await agent.continue();
|
|
490
|
+
} finally {
|
|
491
|
+
unsubscribe();
|
|
492
|
+
}
|
|
493
|
+
const assistant = findLastAssistantMessage(agent.state.messages);
|
|
494
|
+
const stateError = agent.state.error;
|
|
495
|
+
if (stateError) throw stateError instanceof Error ? stateError : new Error(String(stateError));
|
|
496
|
+
if (assistant && "errorMessage" in assistant && typeof assistant.errorMessage === "string") throw new Error(assistant.errorMessage);
|
|
497
|
+
return {
|
|
498
|
+
agent,
|
|
499
|
+
trace,
|
|
500
|
+
assistant,
|
|
501
|
+
toolJournal: options.replay.journal.map(clonePersistedToolCall)
|
|
502
|
+
};
|
|
503
|
+
};
|
|
504
|
+
const runAgentTurn = async (options) => {
|
|
505
|
+
const result = await createAgent(options);
|
|
506
|
+
return {
|
|
507
|
+
messages: result.agent.state.messages,
|
|
508
|
+
trace: result.trace,
|
|
509
|
+
assistant: result.assistant,
|
|
510
|
+
toolJournal: result.toolJournal
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region src/pi/workflow/workflow.ts
|
|
516
|
+
const PI_WORKFLOW_NAME = "agent-loop-workflow";
|
|
517
|
+
const WAIT_FOR_USER_TIMEOUT = "1 hour";
|
|
518
|
+
const WAIT_FOR_USER_TIMEOUT_MS = 3600 * 1e3;
|
|
519
|
+
const agentLoopParamsSchema = z.object({
|
|
520
|
+
sessionId: z.string(),
|
|
521
|
+
agentName: z.string(),
|
|
522
|
+
systemPrompt: z.string().optional(),
|
|
523
|
+
initialMessages: z.array(z.custom()).optional()
|
|
524
|
+
});
|
|
525
|
+
const userMessageSchema = z.object({
|
|
526
|
+
text: z.string().optional(),
|
|
527
|
+
done: z.boolean().optional(),
|
|
528
|
+
steeringMode: z.enum(["all", "one-at-a-time"]).optional()
|
|
529
|
+
});
|
|
530
|
+
const buildWaitingForUser = (turn) => ({
|
|
531
|
+
type: "user_message",
|
|
532
|
+
turn,
|
|
533
|
+
stepKey: `waitForEvent:wait-user-${turn}`,
|
|
534
|
+
timeoutMs: WAIT_FOR_USER_TIMEOUT_MS
|
|
535
|
+
});
|
|
536
|
+
const initLoopState = (params, existingState) => {
|
|
537
|
+
const activeSession = existingState ? ensurePiActiveSessionState(existingState) : createPiActiveSessionState();
|
|
538
|
+
return {
|
|
539
|
+
messages: Array.isArray(params.initialMessages) ? params.initialMessages : [],
|
|
540
|
+
events: [],
|
|
541
|
+
trace: [],
|
|
542
|
+
summaries: [],
|
|
543
|
+
turn: 0,
|
|
544
|
+
phase: "waiting-for-user",
|
|
545
|
+
waitingFor: buildWaitingForUser(0),
|
|
546
|
+
replayCache: /* @__PURE__ */ new Map(),
|
|
547
|
+
activeSession
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
const setPhase = (loop, phase) => {
|
|
551
|
+
loop.phase = phase;
|
|
552
|
+
switch (phase) {
|
|
553
|
+
case "waiting-for-user":
|
|
554
|
+
loop.waitingFor = buildWaitingForUser(loop.turn);
|
|
555
|
+
break;
|
|
556
|
+
case "running-agent":
|
|
557
|
+
loop.waitingFor = {
|
|
558
|
+
type: "assistant",
|
|
559
|
+
turn: loop.turn,
|
|
560
|
+
stepKey: `do:assistant-${loop.turn}`
|
|
561
|
+
};
|
|
562
|
+
break;
|
|
563
|
+
case "complete":
|
|
564
|
+
loop.waitingFor = null;
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const emitState = (ctx, loop) => {
|
|
569
|
+
ctx?.setState({
|
|
570
|
+
messages: loop.messages,
|
|
571
|
+
events: loop.events,
|
|
572
|
+
trace: loop.trace,
|
|
573
|
+
summaries: loop.summaries,
|
|
574
|
+
turn: loop.turn,
|
|
575
|
+
phase: loop.phase,
|
|
576
|
+
waitingFor: loop.waitingFor,
|
|
577
|
+
activeSession: loop.activeSession,
|
|
578
|
+
activeSessionUpdatesByTurn: loop.activeSession.exportReplayBuffer()
|
|
579
|
+
});
|
|
580
|
+
};
|
|
581
|
+
const mutateSessionStatus = (forSchema, sessionId, status) => {
|
|
582
|
+
try {
|
|
583
|
+
forSchema(piSchema).update("session", sessionId, (builder) => builder.set({ status }));
|
|
584
|
+
} catch {}
|
|
585
|
+
};
|
|
586
|
+
const projectSessionStatus = (tx, sessionId, status) => {
|
|
587
|
+
tx.mutate(({ forSchema }) => {
|
|
588
|
+
mutateSessionStatus(forSchema, sessionId, status);
|
|
589
|
+
});
|
|
590
|
+
};
|
|
591
|
+
const buildDetailEvent = (turn, event) => {
|
|
592
|
+
const timestamp = event.timestamp instanceof Date ? event.timestamp : new Date(event.timestamp);
|
|
593
|
+
return {
|
|
594
|
+
id: `${event.type}:${turn}:${timestamp.getTime()}`,
|
|
595
|
+
type: event.type,
|
|
596
|
+
payload: event.payload ?? null,
|
|
597
|
+
createdAt: timestamp,
|
|
598
|
+
deliveredAt: timestamp,
|
|
599
|
+
consumedByStepKey: `waitForEvent:wait-user-${turn}`
|
|
600
|
+
};
|
|
601
|
+
};
|
|
602
|
+
const buildTurnSummary = (turn, assistant) => {
|
|
603
|
+
if (!assistant) return null;
|
|
604
|
+
return {
|
|
605
|
+
turn,
|
|
606
|
+
assistant,
|
|
607
|
+
summary: extractAssistantTextFromMessage(assistant) || null
|
|
608
|
+
};
|
|
609
|
+
};
|
|
610
|
+
const parseAssistantStepResult = (value, stepName) => {
|
|
611
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new NonRetryableError(`Assistant step ${stepName} returned an invalid result.`);
|
|
612
|
+
const result = value;
|
|
613
|
+
if (!Array.isArray(result.messages)) throw new NonRetryableError(`Assistant step ${stepName} is missing messages.`);
|
|
614
|
+
const messages = result.messages;
|
|
615
|
+
return {
|
|
616
|
+
messages,
|
|
617
|
+
trace: Array.isArray(result.trace) ? result.trace : [],
|
|
618
|
+
assistant: (result.assistant && typeof result.assistant === "object" ? result.assistant : null) ?? messages.findLast((m) => m.role === "assistant") ?? null,
|
|
619
|
+
toolJournal: parsePersistedToolJournal(value, stepName)
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
const createPiAgentLoopWorkflow = (options) => defineWorkflow({
|
|
623
|
+
name: PI_WORKFLOW_NAME,
|
|
624
|
+
schema: agentLoopParamsSchema,
|
|
625
|
+
initialState: createInitialPiAgentLoopState()
|
|
626
|
+
}, async function(event, step) {
|
|
627
|
+
const params = agentLoopParamsSchema.parse(event.payload ?? {});
|
|
628
|
+
const agentDefinition = options.agents[params.agentName];
|
|
629
|
+
if (!agentDefinition) throw new NonRetryableError(`Agent ${params.agentName} not found.`);
|
|
630
|
+
const loop = initLoopState(params, this?.getState());
|
|
631
|
+
emitState(this, loop);
|
|
632
|
+
while (true) {
|
|
633
|
+
setPhase(loop, "waiting-for-user");
|
|
634
|
+
emitState(this, loop);
|
|
635
|
+
const userEvent = await step.waitForEvent(`wait-user-${loop.turn}`, {
|
|
636
|
+
type: "user_message",
|
|
637
|
+
timeout: WAIT_FOR_USER_TIMEOUT
|
|
638
|
+
});
|
|
639
|
+
const userPayload = userMessageSchema.parse(userEvent.payload ?? {});
|
|
640
|
+
const userText = userPayload.text ?? "";
|
|
641
|
+
const isDone = userPayload.done ?? false;
|
|
642
|
+
const steeringMode = normalizeSteeringMode(userPayload.steeringMode);
|
|
643
|
+
loop.events = [...loop.events, buildDetailEvent(loop.turn, userEvent)];
|
|
644
|
+
loop.messages = (await step.do(`user-${loop.turn}`, async (tx) => {
|
|
645
|
+
projectSessionStatus(tx, event.instanceId, "active");
|
|
646
|
+
const userMessage = {
|
|
647
|
+
role: "user",
|
|
648
|
+
content: [{
|
|
649
|
+
type: "text",
|
|
650
|
+
text: userText
|
|
651
|
+
}],
|
|
652
|
+
timestamp: Date.now()
|
|
653
|
+
};
|
|
654
|
+
return { messages: [...loop.messages, userMessage] };
|
|
655
|
+
})).messages;
|
|
656
|
+
setPhase(loop, "running-agent");
|
|
657
|
+
emitState(this, loop);
|
|
658
|
+
const replay = createReplayContext({
|
|
659
|
+
cache: loop.replayCache,
|
|
660
|
+
reducers: options.toolSideEffectReducers
|
|
661
|
+
});
|
|
662
|
+
const assistantStepName = `assistant-${loop.turn}`;
|
|
663
|
+
const traceLengthBeforeTurn = loop.trace.length;
|
|
664
|
+
const turnId = `${event.instanceId}:${loop.turn}`;
|
|
665
|
+
let assistantResult;
|
|
666
|
+
try {
|
|
667
|
+
assistantResult = await step.do(assistantStepName, { retries: {
|
|
668
|
+
limit: 1,
|
|
669
|
+
delay: "0 ms",
|
|
670
|
+
backoff: "constant"
|
|
671
|
+
} }, async (tx) => {
|
|
672
|
+
tx.onTerminalError.mutate(({ forSchema }) => {
|
|
673
|
+
mutateSessionStatus(forSchema, event.instanceId, "errored");
|
|
674
|
+
});
|
|
675
|
+
const result = await runAgentTurn({
|
|
676
|
+
params,
|
|
677
|
+
agent: agentDefinition,
|
|
678
|
+
tools: options.tools,
|
|
679
|
+
messages: loop.messages,
|
|
680
|
+
steeringMode,
|
|
681
|
+
turnId,
|
|
682
|
+
replay,
|
|
683
|
+
onEvent: (agentEvent) => {
|
|
684
|
+
loop.trace = [...loop.trace, agentEvent];
|
|
685
|
+
loop.activeSession.publishEvent(loop.turn, agentEvent);
|
|
686
|
+
emitState(this, loop);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
projectSessionStatus(tx, event.instanceId, isDone ? "complete" : "waiting");
|
|
690
|
+
return result;
|
|
691
|
+
});
|
|
692
|
+
} catch (error) {
|
|
693
|
+
if (!(error instanceof Error && error.name === "RunnerStepSuspended")) {
|
|
694
|
+
loop.activeSession.settleTurn(loop.turn, "errored");
|
|
695
|
+
emitState(this, loop);
|
|
696
|
+
}
|
|
697
|
+
throw error;
|
|
698
|
+
}
|
|
699
|
+
const parsed = parseAssistantStepResult(assistantResult, assistantStepName);
|
|
700
|
+
loop.messages = parsed.messages;
|
|
701
|
+
loop.trace = [...loop.trace.slice(0, traceLengthBeforeTurn), ...parsed.trace];
|
|
702
|
+
const summary = buildTurnSummary(loop.turn, parsed.assistant);
|
|
703
|
+
if (summary) loop.summaries = [...loop.summaries, summary];
|
|
704
|
+
hydrateReplayCache(loop.replayCache, parsed.toolJournal);
|
|
705
|
+
if (isDone) {
|
|
706
|
+
setPhase(loop, "complete");
|
|
707
|
+
loop.activeSession.settleTurn(loop.turn, "complete");
|
|
708
|
+
emitState(this, loop);
|
|
709
|
+
return { messages: loop.messages };
|
|
710
|
+
}
|
|
711
|
+
loop.activeSession.settleTurn(loop.turn, "waiting-for-user");
|
|
712
|
+
loop.turn += 1;
|
|
713
|
+
emitState(this, loop);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
const createPiWorkflows = (options) => {
|
|
717
|
+
PiLogger.reset();
|
|
718
|
+
if (options.logging) PiLogger.configure(options.logging);
|
|
719
|
+
return { agentLoop: createPiAgentLoopWorkflow(options) };
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/pi/dsl.ts
|
|
724
|
+
const defineAgent = (name, definition) => {
|
|
725
|
+
if (definition.name && definition.name !== name) throw new Error(`defineAgent name mismatch: expected ${name}, got ${definition.name}`);
|
|
726
|
+
return {
|
|
727
|
+
...definition,
|
|
728
|
+
name
|
|
729
|
+
};
|
|
730
|
+
};
|
|
731
|
+
const createPi = () => {
|
|
732
|
+
const agents = {};
|
|
733
|
+
const tools = {};
|
|
734
|
+
const toolSideEffectReducers = {};
|
|
735
|
+
let defaultSteeringMode;
|
|
736
|
+
let logging;
|
|
737
|
+
const builder = {
|
|
738
|
+
agent(definition) {
|
|
739
|
+
agents[definition.name] = definition;
|
|
740
|
+
return builder;
|
|
741
|
+
},
|
|
742
|
+
agents(registry) {
|
|
743
|
+
Object.assign(agents, registry);
|
|
744
|
+
return builder;
|
|
745
|
+
},
|
|
746
|
+
tool(name, tool) {
|
|
747
|
+
tools[name] = tool;
|
|
748
|
+
return builder;
|
|
749
|
+
},
|
|
750
|
+
tools(registry) {
|
|
751
|
+
Object.assign(tools, registry);
|
|
752
|
+
return builder;
|
|
753
|
+
},
|
|
754
|
+
toolSideEffectReducer(toolName, reducer) {
|
|
755
|
+
toolSideEffectReducers[toolName] = reducer;
|
|
756
|
+
return builder;
|
|
757
|
+
},
|
|
758
|
+
toolSideEffectReducers(registry) {
|
|
759
|
+
Object.assign(toolSideEffectReducers, registry);
|
|
760
|
+
return builder;
|
|
761
|
+
},
|
|
762
|
+
defaultSteeringMode(mode) {
|
|
763
|
+
defaultSteeringMode = mode;
|
|
764
|
+
return builder;
|
|
765
|
+
},
|
|
766
|
+
logging(config) {
|
|
767
|
+
logging = config;
|
|
768
|
+
return builder;
|
|
769
|
+
},
|
|
770
|
+
build() {
|
|
771
|
+
const agentsSnapshot = { ...agents };
|
|
772
|
+
const toolsSnapshot = { ...tools };
|
|
773
|
+
const reducersSnapshot = { ...toolSideEffectReducers };
|
|
774
|
+
return {
|
|
775
|
+
config: {
|
|
776
|
+
agents: agentsSnapshot,
|
|
777
|
+
tools: toolsSnapshot,
|
|
778
|
+
defaultSteeringMode,
|
|
779
|
+
toolSideEffectReducers: reducersSnapshot,
|
|
780
|
+
logging
|
|
781
|
+
},
|
|
782
|
+
workflows: createPiWorkflows({
|
|
783
|
+
agents: agentsSnapshot,
|
|
784
|
+
tools: toolsSnapshot,
|
|
785
|
+
toolSideEffectReducers: reducersSnapshot,
|
|
786
|
+
logging
|
|
787
|
+
})
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
return builder;
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
//#endregion
|
|
795
|
+
//#region src/pi/factory.ts
|
|
796
|
+
function createPiFragment(config, options, services) {
|
|
797
|
+
return {};
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
//#endregion
|
|
801
|
+
export { PI_TOOL_JOURNAL_VERSION, PI_WORKFLOW_NAME, SESSION_STATUSES, STEERING_MODES, THINKING_LEVELS, createPi, createPiFragment, createPiFragmentClients, createPiSessionStore, createPiWorkflows, defineAgent, piFragmentDefinition, piRoutesFactory };
|
|
802
|
+
//# sourceMappingURL=index.js.map
|