@fragno-dev/pi-harness 0.0.0-stage → 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/LICENSE.md +16 -0
- package/README.md +181 -2
- package/dist/browser/agent-harness-event-protocol-CuKubox1.js +666 -0
- package/dist/browser/agent-harness-event-protocol-CuKubox1.js.map +1 -0
- package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts +261 -0
- package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts.map +1 -0
- package/dist/browser/client/clients.d.ts +2 -0
- package/dist/browser/client/clients.js +2 -0
- package/dist/browser/client/pi-workflow-emission-stream.d.ts +13 -0
- package/dist/browser/client/pi-workflow-emission-stream.d.ts.map +1 -0
- package/dist/browser/client/pi-workflow-emission-stream.js +29 -0
- package/dist/browser/client/pi-workflow-emission-stream.js.map +1 -0
- package/dist/browser/client/react.d.ts +147 -0
- package/dist/browser/client/react.d.ts.map +1 -0
- package/dist/browser/client/react.js +187 -0
- package/dist/browser/client/react.js.map +1 -0
- package/dist/browser/client/solid.d.ts +150 -0
- package/dist/browser/client/solid.d.ts.map +1 -0
- package/dist/browser/client/solid.js +130 -0
- package/dist/browser/client/solid.js.map +1 -0
- package/dist/browser/client/svelte.d.ts +150 -0
- package/dist/browser/client/svelte.d.ts.map +1 -0
- package/dist/browser/client/svelte.js +132 -0
- package/dist/browser/client/svelte.js.map +1 -0
- package/dist/browser/client/vanilla.d.ts +177 -0
- package/dist/browser/client/vanilla.d.ts.map +1 -0
- package/dist/browser/client/vanilla.js +159 -0
- package/dist/browser/client/vanilla.js.map +1 -0
- package/dist/browser/client/vue.d.ts +150 -0
- package/dist/browser/client/vue.d.ts.map +1 -0
- package/dist/browser/client/vue.js +128 -0
- package/dist/browser/client/vue.js.map +1 -0
- package/dist/browser/client/workflow-lofi-session-projection.d.ts +17 -0
- package/dist/browser/client/workflow-lofi-session-projection.d.ts.map +1 -0
- package/dist/browser/client/workflow-lofi-session-projection.js +107 -0
- package/dist/browser/client/workflow-lofi-session-projection.js.map +1 -0
- package/dist/browser/clients-DYXj19je.d.ts +247 -0
- package/dist/browser/clients-DYXj19je.d.ts.map +1 -0
- package/dist/browser/clients-pIAk6ClP.js +1853 -0
- package/dist/browser/clients-pIAk6ClP.js.map +1 -0
- package/dist/browser/pi/context-usage.d.ts +20 -0
- package/dist/browser/pi/context-usage.d.ts.map +1 -0
- package/dist/browser/pi/context-usage.js +84 -0
- package/dist/browser/pi/context-usage.js.map +1 -0
- package/dist/browser/pi/harness/agent-harness-event-protocol.d.ts +2 -0
- package/dist/browser/pi/harness/agent-harness-event-protocol.js +2 -0
- package/dist/browser/pi/route-schemas.d.ts +2 -0
- package/dist/browser/pi/route-schemas.js +130 -0
- package/dist/browser/pi/route-schemas.js.map +1 -0
- package/dist/browser/pi/workflow-session-projection.d.ts +2 -0
- package/dist/browser/pi/workflow-session-projection.js +2 -0
- package/dist/browser/route-schemas-DQB5ZR1E.d.ts +109 -0
- package/dist/browser/route-schemas-DQB5ZR1E.d.ts.map +1 -0
- package/dist/browser/types-8q4RWFXT.js +23 -0
- package/dist/browser/types-8q4RWFXT.js.map +1 -0
- package/dist/browser/types-Dk856kV1.d.ts +527 -0
- package/dist/browser/types-Dk856kV1.d.ts.map +1 -0
- package/dist/browser/workflow-session-projection-CJ4MUkpJ.js +443 -0
- package/dist/browser/workflow-session-projection-CJ4MUkpJ.js.map +1 -0
- package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts +93 -0
- package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts.map +1 -0
- package/dist/node/pi/compact-command-outcome-projection.js +41 -0
- package/dist/node/pi/compact-command-outcome-projection.js.map +1 -0
- package/dist/node/pi/context-usage.d.ts +20 -0
- package/dist/node/pi/context-usage.d.ts.map +1 -0
- package/dist/node/pi/context-usage.js +84 -0
- package/dist/node/pi/context-usage.js.map +1 -0
- package/dist/node/pi/definition.d.ts +535 -0
- package/dist/node/pi/definition.d.ts.map +1 -0
- package/dist/node/pi/definition.js +71 -0
- package/dist/node/pi/definition.js.map +1 -0
- package/dist/node/pi/factory.d.ts +142 -0
- package/dist/node/pi/factory.d.ts.map +1 -0
- package/dist/node/pi/factory.js +22 -0
- package/dist/node/pi/factory.js.map +1 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.d.ts +261 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.d.ts.map +1 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.js +588 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.js.map +1 -0
- package/dist/node/pi/harness/json-value.js +82 -0
- package/dist/node/pi/harness/json-value.js.map +1 -0
- package/dist/node/pi/harness/pi-operation-completed.d.ts +16 -0
- package/dist/node/pi/harness/pi-operation-completed.d.ts.map +1 -0
- package/dist/node/pi/harness/pi-operation-completed.js +71 -0
- package/dist/node/pi/harness/pi-operation-completed.js.map +1 -0
- package/dist/node/pi/harness/session-storage.d.ts +62 -0
- package/dist/node/pi/harness/session-storage.d.ts.map +1 -0
- package/dist/node/pi/harness/session-storage.js +174 -0
- package/dist/node/pi/harness/session-storage.js.map +1 -0
- package/dist/node/pi/pi-jsonl-export.d.ts +11 -0
- package/dist/node/pi/pi-jsonl-export.d.ts.map +1 -0
- package/dist/node/pi/pi-jsonl-export.js +31 -0
- package/dist/node/pi/pi-jsonl-export.js.map +1 -0
- package/dist/node/pi/route-schemas.d.ts +109 -0
- package/dist/node/pi/route-schemas.d.ts.map +1 -0
- package/dist/node/pi/route-schemas.js +130 -0
- package/dist/node/pi/route-schemas.js.map +1 -0
- package/dist/node/pi/session-command-protocol.d.ts +14 -0
- package/dist/node/pi/session-command-protocol.d.ts.map +1 -0
- package/dist/node/pi/session-command-protocol.js +25 -0
- package/dist/node/pi/session-command-protocol.js.map +1 -0
- package/dist/node/pi/session-entry-projection.js +79 -0
- package/dist/node/pi/session-entry-projection.js.map +1 -0
- package/dist/node/pi/skills.d.ts +70 -0
- package/dist/node/pi/skills.d.ts.map +1 -0
- package/dist/node/pi/skills.js +150 -0
- package/dist/node/pi/skills.js.map +1 -0
- package/dist/node/pi/tools.d.ts +12 -0
- package/dist/node/pi/tools.d.ts.map +1 -0
- package/dist/node/pi/tools.js +8 -0
- package/dist/node/pi/tools.js.map +1 -0
- package/dist/node/pi/types.d.ts +165 -0
- package/dist/node/pi/types.d.ts.map +1 -0
- package/dist/node/pi/types.js +49 -0
- package/dist/node/pi/types.js.map +1 -0
- package/dist/node/pi/wait-for-command-step.js +46 -0
- package/dist/node/pi/wait-for-command-step.js.map +1 -0
- package/dist/node/pi/workflow-session-live-projection.js +220 -0
- package/dist/node/pi/workflow-session-live-projection.js.map +1 -0
- package/dist/node/pi/workflow-session-projection.d.ts +84 -0
- package/dist/node/pi/workflow-session-projection.d.ts.map +1 -0
- package/dist/node/pi/workflow-session-projection.js +100 -0
- package/dist/node/pi/workflow-session-projection.js.map +1 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.d.ts +37 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.d.ts.map +1 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.js +219 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.js.map +1 -0
- package/dist/node/pi/workflows/workflow-agent-harness.d.ts +142 -0
- package/dist/node/pi/workflows/workflow-agent-harness.d.ts.map +1 -0
- package/dist/node/pi/workflows/workflow-agent-harness.js +450 -0
- package/dist/node/pi/workflows/workflow-agent-harness.js.map +1 -0
- package/dist/node/routes.d.ts +631 -0
- package/dist/node/routes.d.ts.map +1 -0
- package/dist/node/routes.js +355 -0
- package/dist/node/routes.js.map +1 -0
- package/dist/node/schema.d.ts +5 -0
- package/dist/node/schema.d.ts.map +1 -0
- package/dist/node/schema.js +7 -0
- package/dist/node/schema.js.map +1 -0
- package/package.json +175 -3
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { PiSessionDataIntegrityError, PiSessionDataUnavailableError, projectPiSessionFromWorkflowInstance } from "./pi/types.js";
|
|
2
|
+
import { piHarnessDefinition } from "./pi/definition.js";
|
|
3
|
+
import { WorkflowBackedSessionStorage, createWorkflowBackedSessionEntryIdAllocator } from "./pi/harness/session-storage.js";
|
|
4
|
+
import { PI_JSONL_EXPORT_CWD, exportSessionStorageToJsonl } from "./pi/pi-jsonl-export.js";
|
|
5
|
+
import { commandAckSchema, commandInputSchema, sessionBaseSchema, sessionDetailSchema } from "./pi/route-schemas.js";
|
|
6
|
+
import { createPiSessionCommandId, piSessionCommandWaitability } from "./pi/session-command-protocol.js";
|
|
7
|
+
import { CommandStepFailedError, CommandStepWaitTimeoutError, CommandWorkflowTerminatedError, waitForCommandStep } from "./pi/wait-for-command-step.js";
|
|
8
|
+
import { defineRoutes } from "@fragno-dev/core";
|
|
9
|
+
import { serviceCalls } from "@fragno-dev/db";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { WorkflowsLogger } from "@fragno-dev/workflows/debug-log";
|
|
12
|
+
import { createId } from "@fragno-dev/db/id";
|
|
13
|
+
import { WorkflowInstanceNotFoundError, WorkflowNotFoundError, WorkflowParamsInvalidError } from "@fragno-dev/workflows/workflow";
|
|
14
|
+
import { validateWorkflowParams } from "@fragno-dev/workflows";
|
|
15
|
+
//#region src/routes.ts
|
|
16
|
+
const DEFAULT_PAGE_SIZE = 50;
|
|
17
|
+
const MAX_PAGE_SIZE = 200;
|
|
18
|
+
const DEFAULT_COMMAND_STEP_WAIT_TIMEOUT_MS = 12e4;
|
|
19
|
+
const createCommandPayload = (commandId, command) => {
|
|
20
|
+
switch (command.kind) {
|
|
21
|
+
case "prompt": return {
|
|
22
|
+
commandId,
|
|
23
|
+
kind: command.kind,
|
|
24
|
+
input: command.input
|
|
25
|
+
};
|
|
26
|
+
case "skill": return {
|
|
27
|
+
commandId,
|
|
28
|
+
kind: command.kind,
|
|
29
|
+
input: command.input
|
|
30
|
+
};
|
|
31
|
+
case "promptFromTemplate": return {
|
|
32
|
+
commandId,
|
|
33
|
+
kind: command.kind,
|
|
34
|
+
input: command.input
|
|
35
|
+
};
|
|
36
|
+
case "compact": return {
|
|
37
|
+
commandId,
|
|
38
|
+
kind: command.kind,
|
|
39
|
+
input: command.input
|
|
40
|
+
};
|
|
41
|
+
case "steer": return {
|
|
42
|
+
commandId,
|
|
43
|
+
kind: command.kind,
|
|
44
|
+
input: command.input
|
|
45
|
+
};
|
|
46
|
+
case "followUp": return {
|
|
47
|
+
commandId,
|
|
48
|
+
kind: command.kind,
|
|
49
|
+
input: command.input
|
|
50
|
+
};
|
|
51
|
+
case "abort": return command.reason ? {
|
|
52
|
+
commandId,
|
|
53
|
+
kind: command.kind,
|
|
54
|
+
reason: command.reason
|
|
55
|
+
} : {
|
|
56
|
+
commandId,
|
|
57
|
+
kind: command.kind
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
throw new Error("Unsupported Pi session command kind.");
|
|
61
|
+
};
|
|
62
|
+
const parsePositiveIntegerQueryValue = (value) => {
|
|
63
|
+
if (value === null) return;
|
|
64
|
+
const parsed = Number.parseInt(value, 10);
|
|
65
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
66
|
+
};
|
|
67
|
+
const toSessionDetail = (snapshot) => ({
|
|
68
|
+
...snapshot.session,
|
|
69
|
+
workflow: {
|
|
70
|
+
status: snapshot.workflowStatus.status,
|
|
71
|
+
error: snapshot.workflowStatus.error,
|
|
72
|
+
output: snapshot.workflowStatus.output
|
|
73
|
+
},
|
|
74
|
+
agent: { state: { messages: snapshot.messages } }
|
|
75
|
+
});
|
|
76
|
+
const piRoutesFactory = defineRoutes(piHarnessDefinition).create(({ config, defineRoute, serviceDeps, services }) => {
|
|
77
|
+
if (config.logging) WorkflowsLogger.configure(config.logging);
|
|
78
|
+
const toSessionDetailLoadError = (err, workflowName, sessionId) => {
|
|
79
|
+
if (err instanceof WorkflowInstanceNotFoundError) return {
|
|
80
|
+
body: {
|
|
81
|
+
message: `Session ${workflowName}/${sessionId} not found.`,
|
|
82
|
+
code: "SESSION_NOT_FOUND"
|
|
83
|
+
},
|
|
84
|
+
init: { status: 404 }
|
|
85
|
+
};
|
|
86
|
+
if (err instanceof PiSessionDataUnavailableError) return {
|
|
87
|
+
body: {
|
|
88
|
+
message: err.message,
|
|
89
|
+
code: "SESSION_DATA_UNAVAILABLE"
|
|
90
|
+
},
|
|
91
|
+
init: { status: 404 }
|
|
92
|
+
};
|
|
93
|
+
if (err instanceof PiSessionDataIntegrityError) return {
|
|
94
|
+
body: {
|
|
95
|
+
message: err.message,
|
|
96
|
+
code: "SESSION_DATA_INTEGRITY_ERROR"
|
|
97
|
+
},
|
|
98
|
+
init: { status: 500 }
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
body: {
|
|
102
|
+
message: err instanceof Error ? err.message : "Failed to load workflow detail.",
|
|
103
|
+
code: "WORKFLOW_INSTANCE_MISSING"
|
|
104
|
+
},
|
|
105
|
+
init: { status: 500 }
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
return [
|
|
109
|
+
defineRoute({
|
|
110
|
+
method: "POST",
|
|
111
|
+
path: "/workflows/:workflowName/sessions",
|
|
112
|
+
inputSchema: z.object({
|
|
113
|
+
name: z.string().optional(),
|
|
114
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
115
|
+
input: z.unknown().optional()
|
|
116
|
+
}),
|
|
117
|
+
outputSchema: sessionBaseSchema,
|
|
118
|
+
errorCodes: [
|
|
119
|
+
"WORKFLOW_NOT_FOUND",
|
|
120
|
+
"WORKFLOW_PARAMS_INVALID",
|
|
121
|
+
"WORKFLOW_CREATE_FAILED"
|
|
122
|
+
],
|
|
123
|
+
handler: async function({ input, pathParams }, { json, error }) {
|
|
124
|
+
const values = await input.valid();
|
|
125
|
+
const workflowName = pathParams.workflowName;
|
|
126
|
+
const now = /* @__PURE__ */ new Date();
|
|
127
|
+
const sessionId = createId();
|
|
128
|
+
try {
|
|
129
|
+
const validatedParams = await validateWorkflowParams(new Map((config.workflows ?? []).map((workflow) => [workflow.name, workflow])), workflowName, values.input);
|
|
130
|
+
if (typeof validatedParams !== "object" || validatedParams === null || Array.isArray(validatedParams)) throw new WorkflowParamsInvalidError(workflowName, ["Workflow parameters must resolve to an object."]);
|
|
131
|
+
const params = { ...validatedParams };
|
|
132
|
+
if (values.metadata !== void 0) params["metadata"] = values.metadata;
|
|
133
|
+
else delete params["metadata"];
|
|
134
|
+
await this.handlerTx().withServiceCalls(() => [services.createWorkflowSession({
|
|
135
|
+
id: sessionId,
|
|
136
|
+
workflowName,
|
|
137
|
+
name: values.name,
|
|
138
|
+
params
|
|
139
|
+
})]).execute();
|
|
140
|
+
return json({
|
|
141
|
+
id: sessionId,
|
|
142
|
+
name: values.name ?? null,
|
|
143
|
+
metadata: values.metadata ?? null,
|
|
144
|
+
workflowName,
|
|
145
|
+
createdAt: now,
|
|
146
|
+
updatedAt: now
|
|
147
|
+
});
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (err instanceof WorkflowNotFoundError) return error({
|
|
150
|
+
message: `Workflow ${workflowName} not found.`,
|
|
151
|
+
code: "WORKFLOW_NOT_FOUND"
|
|
152
|
+
}, { status: 404 });
|
|
153
|
+
if (err instanceof WorkflowParamsInvalidError) return error({
|
|
154
|
+
message: "Workflow input is invalid.",
|
|
155
|
+
code: "WORKFLOW_PARAMS_INVALID"
|
|
156
|
+
}, { status: 400 });
|
|
157
|
+
return error({
|
|
158
|
+
message: err instanceof Error ? err.message : "Failed to create workflow instance.",
|
|
159
|
+
code: "WORKFLOW_CREATE_FAILED"
|
|
160
|
+
}, { status: 500 });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}),
|
|
164
|
+
defineRoute({
|
|
165
|
+
method: "GET",
|
|
166
|
+
path: "/workflows/:workflowName/sessions",
|
|
167
|
+
queryParameters: ["limit"],
|
|
168
|
+
outputSchema: z.array(sessionBaseSchema),
|
|
169
|
+
errorCodes: ["SESSION_DATA_INTEGRITY_ERROR"],
|
|
170
|
+
handler: async function({ pathParams, query }, { json, error }) {
|
|
171
|
+
const workflowName = pathParams.workflowName;
|
|
172
|
+
const limit = Number.parseInt(query.get("limit") ?? `${DEFAULT_PAGE_SIZE}`, 10);
|
|
173
|
+
const normalizedLimit = Number.isFinite(limit) ? Math.max(1, Math.min(MAX_PAGE_SIZE, limit)) : DEFAULT_PAGE_SIZE;
|
|
174
|
+
const result = await this.handlerTx().withServiceCalls(() => [serviceDeps.workflows.listInstances({
|
|
175
|
+
workflowName,
|
|
176
|
+
pageSize: normalizedLimit
|
|
177
|
+
})]).transform(({ serviceResult: [result] }) => result).execute();
|
|
178
|
+
try {
|
|
179
|
+
return json(result.instances.flatMap((instance) => {
|
|
180
|
+
const session = projectPiSessionFromWorkflowInstance({
|
|
181
|
+
id: instance.id,
|
|
182
|
+
workflowName,
|
|
183
|
+
params: instance.params,
|
|
184
|
+
createdAt: instance.createdAt,
|
|
185
|
+
updatedAt: instance.updatedAt
|
|
186
|
+
});
|
|
187
|
+
return session ? [session] : [];
|
|
188
|
+
}));
|
|
189
|
+
} catch (err) {
|
|
190
|
+
if (err instanceof PiSessionDataIntegrityError) return error({
|
|
191
|
+
message: err.message,
|
|
192
|
+
code: "SESSION_DATA_INTEGRITY_ERROR"
|
|
193
|
+
}, { status: 500 });
|
|
194
|
+
throw err;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}),
|
|
198
|
+
defineRoute({
|
|
199
|
+
method: "GET",
|
|
200
|
+
path: "/workflows/:workflowName/sessions/:sessionId",
|
|
201
|
+
outputSchema: sessionDetailSchema,
|
|
202
|
+
errorCodes: [
|
|
203
|
+
"SESSION_NOT_FOUND",
|
|
204
|
+
"SESSION_DATA_UNAVAILABLE",
|
|
205
|
+
"SESSION_DATA_INTEGRITY_ERROR",
|
|
206
|
+
"WORKFLOW_INSTANCE_MISSING"
|
|
207
|
+
],
|
|
208
|
+
handler: async function({ pathParams: { workflowName, sessionId } }, { json, error }) {
|
|
209
|
+
try {
|
|
210
|
+
const result = await this.handlerTx().withServiceCalls(() => [services.getSessionDetailSnapshot(workflowName, sessionId)]).transform(({ serviceResult: [snapshot] }) => snapshot).execute();
|
|
211
|
+
return json(toSessionDetail(result));
|
|
212
|
+
} catch (err) {
|
|
213
|
+
const loadError = toSessionDetailLoadError(err, workflowName, sessionId);
|
|
214
|
+
return error(loadError.body, loadError.init);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}),
|
|
218
|
+
defineRoute({
|
|
219
|
+
method: "GET",
|
|
220
|
+
path: "/workflows/:workflowName/sessions/:sessionId/export/pi-jsonl",
|
|
221
|
+
errorCodes: [
|
|
222
|
+
"SESSION_NOT_FOUND",
|
|
223
|
+
"SESSION_DATA_UNAVAILABLE",
|
|
224
|
+
"SESSION_DATA_INTEGRITY_ERROR",
|
|
225
|
+
"WORKFLOW_INSTANCE_MISSING"
|
|
226
|
+
],
|
|
227
|
+
handler: async function({ pathParams: { workflowName, sessionId } }, { error }) {
|
|
228
|
+
try {
|
|
229
|
+
const snapshot = await this.handlerTx().withServiceCalls(() => [services.getSessionDetailSnapshot(workflowName, sessionId)]).transform(({ serviceResult: [snapshot] }) => snapshot).execute();
|
|
230
|
+
const jsonl = await exportSessionStorageToJsonl(new WorkflowBackedSessionStorage({
|
|
231
|
+
metadata: {
|
|
232
|
+
id: snapshot.session.id,
|
|
233
|
+
createdAt: snapshot.session.createdAt.toISOString()
|
|
234
|
+
},
|
|
235
|
+
entries: snapshot.sessionEntries,
|
|
236
|
+
entryIds: createWorkflowBackedSessionEntryIdAllocator({
|
|
237
|
+
prefix: `${snapshot.session.id}:export:entry`,
|
|
238
|
+
startIndex: snapshot.sessionEntries.length
|
|
239
|
+
})
|
|
240
|
+
}), { cwd: PI_JSONL_EXPORT_CWD });
|
|
241
|
+
return new Response(jsonl, {
|
|
242
|
+
status: 200,
|
|
243
|
+
headers: {
|
|
244
|
+
"content-type": "application/x-ndjson; charset=utf-8",
|
|
245
|
+
"content-disposition": `attachment; filename="pi-session-${sessionId}.jsonl"`
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
} catch (err) {
|
|
249
|
+
const loadError = toSessionDetailLoadError(err, workflowName, sessionId);
|
|
250
|
+
return error(loadError.body, loadError.init);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}),
|
|
254
|
+
defineRoute({
|
|
255
|
+
method: "GET",
|
|
256
|
+
path: "/workflows/:workflowName/sessions/:sessionId/commands/:commandId/wait",
|
|
257
|
+
queryParameters: ["timeoutMs"],
|
|
258
|
+
errorCodes: [
|
|
259
|
+
"SESSION_NOT_FOUND",
|
|
260
|
+
"WORKFLOW_INSTANCE_MISSING",
|
|
261
|
+
"INVALID_COMMAND_ID",
|
|
262
|
+
"COMMAND_NOT_WAITABLE",
|
|
263
|
+
"COMMAND_STEP_TIMEOUT",
|
|
264
|
+
"COMMAND_STEP_FAILED",
|
|
265
|
+
"COMMAND_WORKFLOW_TERMINAL"
|
|
266
|
+
],
|
|
267
|
+
handler: async function({ pathParams, query }, { empty, error }) {
|
|
268
|
+
const timeoutMs = parsePositiveIntegerQueryValue(query.get("timeoutMs"));
|
|
269
|
+
const workflowName = pathParams.workflowName;
|
|
270
|
+
const sessionId = pathParams.sessionId;
|
|
271
|
+
const commandId = pathParams.commandId;
|
|
272
|
+
const waitability = piSessionCommandWaitability(commandId);
|
|
273
|
+
if (waitability === "invalid") return error({
|
|
274
|
+
message: "Invalid command id.",
|
|
275
|
+
code: "INVALID_COMMAND_ID"
|
|
276
|
+
}, { status: 400 });
|
|
277
|
+
if (waitability === "control") return error({
|
|
278
|
+
message: "Control commands cannot be waited on.",
|
|
279
|
+
code: "COMMAND_NOT_WAITABLE"
|
|
280
|
+
}, { status: 400 });
|
|
281
|
+
const waitTimeoutMs = timeoutMs ?? DEFAULT_COMMAND_STEP_WAIT_TIMEOUT_MS;
|
|
282
|
+
try {
|
|
283
|
+
await waitForCommandStep({
|
|
284
|
+
handlerTx: this.handlerTx.bind(this),
|
|
285
|
+
workflows: serviceDeps.workflows,
|
|
286
|
+
workflowName,
|
|
287
|
+
instanceId: sessionId,
|
|
288
|
+
commandId,
|
|
289
|
+
timeoutMs: waitTimeoutMs
|
|
290
|
+
});
|
|
291
|
+
return empty(204);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
if (err instanceof CommandStepWaitTimeoutError) return error({
|
|
294
|
+
message: err.message,
|
|
295
|
+
code: "COMMAND_STEP_TIMEOUT"
|
|
296
|
+
}, { status: 408 });
|
|
297
|
+
if (err instanceof CommandStepFailedError) return error({
|
|
298
|
+
message: err.message,
|
|
299
|
+
code: "COMMAND_STEP_FAILED"
|
|
300
|
+
}, { status: 409 });
|
|
301
|
+
if (err instanceof CommandWorkflowTerminatedError) return error({
|
|
302
|
+
message: err.message,
|
|
303
|
+
code: "COMMAND_WORKFLOW_TERMINAL"
|
|
304
|
+
}, { status: 409 });
|
|
305
|
+
if (err instanceof WorkflowInstanceNotFoundError) return error({
|
|
306
|
+
message: `Session ${workflowName}/${sessionId} not found.`,
|
|
307
|
+
code: "SESSION_NOT_FOUND"
|
|
308
|
+
}, { status: 404 });
|
|
309
|
+
return error({
|
|
310
|
+
message: err instanceof Error ? err.message : "Failed to wait for command step.",
|
|
311
|
+
code: "WORKFLOW_INSTANCE_MISSING"
|
|
312
|
+
}, { status: 500 });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}),
|
|
316
|
+
defineRoute({
|
|
317
|
+
method: "POST",
|
|
318
|
+
path: "/workflows/:workflowName/sessions/:sessionId/command",
|
|
319
|
+
inputSchema: commandInputSchema,
|
|
320
|
+
outputSchema: commandAckSchema,
|
|
321
|
+
errorCodes: ["SESSION_NOT_FOUND", "WORKFLOW_INSTANCE_MISSING"],
|
|
322
|
+
handler: async function({ input, pathParams }, { json, error }) {
|
|
323
|
+
const command = await input.valid();
|
|
324
|
+
const workflowName = pathParams.workflowName;
|
|
325
|
+
const sessionId = pathParams.sessionId;
|
|
326
|
+
const workflowsService = serviceDeps.workflows;
|
|
327
|
+
const commandId = createPiSessionCommandId(command.kind);
|
|
328
|
+
const payload = createCommandPayload(commandId, command);
|
|
329
|
+
try {
|
|
330
|
+
return json({
|
|
331
|
+
accepted: true,
|
|
332
|
+
commandId,
|
|
333
|
+
status: (await this.handlerTx().withServiceCalls(() => serviceCalls(workflowsService.sendEvent(workflowName, sessionId, {
|
|
334
|
+
type: "command",
|
|
335
|
+
payload
|
|
336
|
+
}), workflowsService.getInstanceStatus(workflowName, sessionId))).transform(({ serviceResult: [, workflowStatus] }) => ({ workflowStatus })).execute()).workflowStatus.status
|
|
337
|
+
}, 202);
|
|
338
|
+
} catch (err) {
|
|
339
|
+
if (err instanceof WorkflowInstanceNotFoundError) return error({
|
|
340
|
+
message: `Session ${workflowName}/${sessionId} not found.`,
|
|
341
|
+
code: "SESSION_NOT_FOUND"
|
|
342
|
+
}, { status: 404 });
|
|
343
|
+
return error({
|
|
344
|
+
message: err instanceof Error ? err.message : "Failed to deliver command.",
|
|
345
|
+
code: "WORKFLOW_INSTANCE_MISSING"
|
|
346
|
+
}, { status: 500 });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
];
|
|
351
|
+
});
|
|
352
|
+
//#endregion
|
|
353
|
+
export { piRoutesFactory };
|
|
354
|
+
|
|
355
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","names":[],"sources":["../../src/routes.ts"],"sourcesContent":["import { createId } from \"@fragno-dev/db/id\";\nimport { WorkflowsLogger } from \"@fragno-dev/workflows/debug-log\";\nimport {\n WorkflowInstanceNotFoundError,\n WorkflowNotFoundError,\n WorkflowParamsInvalidError,\n} from \"@fragno-dev/workflows/workflow\";\nimport { z } from \"zod\";\n\nimport { defineRoutes } from \"@fragno-dev/core\";\nimport { serviceCalls } from \"@fragno-dev/db\";\nimport { validateWorkflowParams } from \"@fragno-dev/workflows\";\n\nimport { piHarnessDefinition, type PiSessionDetailSnapshot } from \"./pi/definition\";\nimport {\n createWorkflowBackedSessionEntryIdAllocator,\n WorkflowBackedSessionStorage,\n} from \"./pi/harness/session-storage\";\nimport { exportSessionStorageToJsonl, PI_JSONL_EXPORT_CWD } from \"./pi/pi-jsonl-export\";\nimport {\n commandAckSchema,\n commandInputSchema,\n sessionBaseSchema,\n sessionDetailSchema,\n} from \"./pi/route-schemas\";\nimport {\n createPiSessionCommandId,\n piSessionCommandWaitability,\n} from \"./pi/session-command-protocol\";\nimport {\n PiSessionDataIntegrityError,\n PiSessionDataUnavailableError,\n projectPiSessionFromWorkflowInstance,\n type PiSessionCommandPayload,\n type PiSessionDetail,\n} from \"./pi/types\";\nimport {\n CommandStepFailedError,\n CommandStepWaitTimeoutError,\n CommandWorkflowTerminatedError,\n waitForCommandStep,\n} from \"./pi/wait-for-command-step\";\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst MAX_PAGE_SIZE = 200;\nconst DEFAULT_COMMAND_STEP_WAIT_TIMEOUT_MS = 120_000;\nconst createCommandPayload = (\n commandId: string,\n command: z.infer<typeof commandInputSchema>,\n): PiSessionCommandPayload => {\n switch (command.kind) {\n case \"prompt\":\n return { commandId, kind: command.kind, input: command.input };\n case \"skill\":\n return { commandId, kind: command.kind, input: command.input };\n case \"promptFromTemplate\":\n return { commandId, kind: command.kind, input: command.input };\n case \"compact\":\n return { commandId, kind: command.kind, input: command.input };\n case \"steer\":\n return { commandId, kind: command.kind, input: command.input };\n case \"followUp\":\n return { commandId, kind: command.kind, input: command.input };\n case \"abort\":\n return command.reason\n ? { commandId, kind: command.kind, reason: command.reason }\n : { commandId, kind: command.kind };\n }\n\n throw new Error(\"Unsupported Pi session command kind.\");\n};\n\nconst parsePositiveIntegerQueryValue = (value: string | null): number | undefined => {\n if (value === null) {\n return undefined;\n }\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n};\n\nconst toSessionDetail = (snapshot: PiSessionDetailSnapshot): PiSessionDetail => ({\n ...snapshot.session,\n workflow: {\n status: snapshot.workflowStatus.status,\n error: snapshot.workflowStatus.error,\n output: snapshot.workflowStatus.output,\n },\n agent: {\n state: { messages: snapshot.messages },\n },\n});\n\nexport const piRoutesFactory = defineRoutes(piHarnessDefinition).create(\n ({ config, defineRoute, serviceDeps, services }) => {\n if (config.logging) {\n WorkflowsLogger.configure(config.logging);\n }\n\n const toSessionDetailLoadError = (err: unknown, workflowName: string, sessionId: string) => {\n if (err instanceof WorkflowInstanceNotFoundError) {\n return {\n body: {\n message: `Session ${workflowName}/${sessionId} not found.`,\n code: \"SESSION_NOT_FOUND\" as const,\n },\n init: { status: 404 as const },\n };\n }\n if (err instanceof PiSessionDataUnavailableError) {\n return {\n body: {\n message: err.message,\n code: \"SESSION_DATA_UNAVAILABLE\" as const,\n },\n init: { status: 404 as const },\n };\n }\n if (err instanceof PiSessionDataIntegrityError) {\n return {\n body: {\n message: err.message,\n code: \"SESSION_DATA_INTEGRITY_ERROR\" as const,\n },\n init: { status: 500 as const },\n };\n }\n const message = err instanceof Error ? err.message : \"Failed to load workflow detail.\";\n return {\n body: { message, code: \"WORKFLOW_INSTANCE_MISSING\" as const },\n init: { status: 500 as const },\n };\n };\n\n return [\n defineRoute({\n method: \"POST\",\n path: \"/workflows/:workflowName/sessions\",\n inputSchema: z.object({\n name: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n input: z.unknown().optional(),\n }),\n outputSchema: sessionBaseSchema,\n errorCodes: [\"WORKFLOW_NOT_FOUND\", \"WORKFLOW_PARAMS_INVALID\", \"WORKFLOW_CREATE_FAILED\"],\n handler: async function ({ input, pathParams }, { json, error }) {\n const values = await input.valid();\n\n const workflowName = pathParams.workflowName;\n const now = new Date();\n const sessionId = createId();\n\n try {\n const workflowsByName = new Map(\n (config.workflows ?? []).map((workflow) => [workflow.name, workflow]),\n );\n const validatedParams = await validateWorkflowParams(\n workflowsByName,\n workflowName,\n values.input,\n );\n if (\n typeof validatedParams !== \"object\" ||\n validatedParams === null ||\n Array.isArray(validatedParams)\n ) {\n throw new WorkflowParamsInvalidError(workflowName, [\n \"Workflow parameters must resolve to an object.\",\n ]);\n }\n const params = { ...(validatedParams as Record<string, unknown>) };\n if (values.metadata !== undefined) {\n params[\"metadata\"] = values.metadata;\n } else {\n delete params[\"metadata\"];\n }\n await this.handlerTx()\n .withServiceCalls(() => [\n services.createWorkflowSession({\n id: sessionId,\n workflowName,\n name: values.name,\n params,\n }),\n ])\n .execute();\n\n return json({\n id: sessionId,\n name: values.name ?? null,\n metadata: values.metadata ?? null,\n workflowName,\n createdAt: now,\n updatedAt: now,\n });\n } catch (err) {\n if (err instanceof WorkflowNotFoundError) {\n return error(\n { message: `Workflow ${workflowName} not found.`, code: \"WORKFLOW_NOT_FOUND\" },\n { status: 404 },\n );\n }\n if (err instanceof WorkflowParamsInvalidError) {\n return error(\n { message: \"Workflow input is invalid.\", code: \"WORKFLOW_PARAMS_INVALID\" },\n { status: 400 },\n );\n }\n const message =\n err instanceof Error ? err.message : \"Failed to create workflow instance.\";\n return error({ message, code: \"WORKFLOW_CREATE_FAILED\" }, { status: 500 });\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/workflows/:workflowName/sessions\",\n queryParameters: [\"limit\"],\n outputSchema: z.array(sessionBaseSchema),\n errorCodes: [\"SESSION_DATA_INTEGRITY_ERROR\"],\n handler: async function ({ pathParams, query }, { json, error }) {\n const workflowName = pathParams.workflowName;\n const limit = Number.parseInt(query.get(\"limit\") ?? `${DEFAULT_PAGE_SIZE}`, 10);\n const normalizedLimit = Number.isFinite(limit)\n ? Math.max(1, Math.min(MAX_PAGE_SIZE, limit))\n : DEFAULT_PAGE_SIZE;\n\n // TODO: Apply the limit after excluding workflow instances without Pi metadata, so non-Pi rows do not consume the requested page.\n const result = await this.handlerTx()\n .withServiceCalls(() => [\n serviceDeps.workflows.listInstances({\n workflowName,\n pageSize: normalizedLimit,\n }),\n ])\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n try {\n return json(\n result.instances.flatMap((instance) => {\n const session = projectPiSessionFromWorkflowInstance({\n id: instance.id,\n workflowName,\n params: instance.params,\n createdAt: instance.createdAt,\n updatedAt: instance.updatedAt,\n });\n return session ? [session] : [];\n }),\n );\n } catch (err) {\n if (err instanceof PiSessionDataIntegrityError) {\n return error(\n { message: err.message, code: \"SESSION_DATA_INTEGRITY_ERROR\" },\n { status: 500 },\n );\n }\n throw err;\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/workflows/:workflowName/sessions/:sessionId\",\n outputSchema: sessionDetailSchema,\n errorCodes: [\n \"SESSION_NOT_FOUND\",\n \"SESSION_DATA_UNAVAILABLE\",\n \"SESSION_DATA_INTEGRITY_ERROR\",\n \"WORKFLOW_INSTANCE_MISSING\",\n ],\n handler: async function ({ pathParams: { workflowName, sessionId } }, { json, error }) {\n try {\n const result = await this.handlerTx()\n .withServiceCalls(\n () => [services.getSessionDetailSnapshot(workflowName, sessionId)] as const,\n )\n .transform(({ serviceResult: [snapshot] }) => snapshot)\n .execute();\n return json(toSessionDetail(result));\n } catch (err) {\n const loadError = toSessionDetailLoadError(err, workflowName, sessionId);\n return error(loadError.body, loadError.init);\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/workflows/:workflowName/sessions/:sessionId/export/pi-jsonl\",\n errorCodes: [\n \"SESSION_NOT_FOUND\",\n \"SESSION_DATA_UNAVAILABLE\",\n \"SESSION_DATA_INTEGRITY_ERROR\",\n \"WORKFLOW_INSTANCE_MISSING\",\n ],\n handler: async function ({ pathParams: { workflowName, sessionId } }, { error }) {\n try {\n const snapshot = await this.handlerTx()\n .withServiceCalls(\n () => [services.getSessionDetailSnapshot(workflowName, sessionId)] as const,\n )\n .transform(({ serviceResult: [snapshot] }) => snapshot)\n .execute();\n const storage = new WorkflowBackedSessionStorage({\n metadata: {\n id: snapshot.session.id,\n createdAt: snapshot.session.createdAt.toISOString(),\n },\n entries: snapshot.sessionEntries,\n entryIds: createWorkflowBackedSessionEntryIdAllocator({\n prefix: `${snapshot.session.id}:export:entry`,\n startIndex: snapshot.sessionEntries.length,\n }),\n });\n const jsonl = await exportSessionStorageToJsonl(storage, { cwd: PI_JSONL_EXPORT_CWD });\n\n return new Response(jsonl, {\n status: 200,\n headers: {\n \"content-type\": \"application/x-ndjson; charset=utf-8\",\n \"content-disposition\": `attachment; filename=\"pi-session-${sessionId}.jsonl\"`,\n },\n });\n } catch (err) {\n const loadError = toSessionDetailLoadError(err, workflowName, sessionId);\n return error(loadError.body, loadError.init);\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/workflows/:workflowName/sessions/:sessionId/commands/:commandId/wait\",\n queryParameters: [\"timeoutMs\"],\n errorCodes: [\n \"SESSION_NOT_FOUND\",\n \"WORKFLOW_INSTANCE_MISSING\",\n \"INVALID_COMMAND_ID\",\n \"COMMAND_NOT_WAITABLE\",\n \"COMMAND_STEP_TIMEOUT\",\n \"COMMAND_STEP_FAILED\",\n \"COMMAND_WORKFLOW_TERMINAL\",\n ],\n handler: async function ({ pathParams, query }, { empty, error }) {\n const timeoutMs = parsePositiveIntegerQueryValue(query.get(\"timeoutMs\"));\n const workflowName = pathParams.workflowName;\n const sessionId = pathParams.sessionId;\n const commandId = pathParams.commandId;\n const waitability = piSessionCommandWaitability(commandId);\n if (waitability === \"invalid\") {\n return error(\n { message: \"Invalid command id.\", code: \"INVALID_COMMAND_ID\" },\n { status: 400 },\n );\n }\n if (waitability === \"control\") {\n return error(\n { message: \"Control commands cannot be waited on.\", code: \"COMMAND_NOT_WAITABLE\" },\n { status: 400 },\n );\n }\n const waitTimeoutMs = timeoutMs ?? DEFAULT_COMMAND_STEP_WAIT_TIMEOUT_MS;\n\n try {\n await waitForCommandStep({\n handlerTx: this.handlerTx.bind(this),\n workflows: serviceDeps.workflows,\n workflowName,\n instanceId: sessionId,\n commandId,\n timeoutMs: waitTimeoutMs,\n });\n\n return empty(204);\n } catch (err) {\n if (err instanceof CommandStepWaitTimeoutError) {\n return error({ message: err.message, code: \"COMMAND_STEP_TIMEOUT\" }, { status: 408 });\n }\n if (err instanceof CommandStepFailedError) {\n return error({ message: err.message, code: \"COMMAND_STEP_FAILED\" }, { status: 409 });\n }\n if (err instanceof CommandWorkflowTerminatedError) {\n return error(\n { message: err.message, code: \"COMMAND_WORKFLOW_TERMINAL\" },\n { status: 409 },\n );\n }\n if (err instanceof WorkflowInstanceNotFoundError) {\n return error(\n {\n message: `Session ${workflowName}/${sessionId} not found.`,\n code: \"SESSION_NOT_FOUND\",\n },\n { status: 404 },\n );\n }\n return error(\n {\n message: err instanceof Error ? err.message : \"Failed to wait for command step.\",\n code: \"WORKFLOW_INSTANCE_MISSING\",\n },\n { status: 500 },\n );\n }\n },\n }),\n defineRoute({\n method: \"POST\",\n path: \"/workflows/:workflowName/sessions/:sessionId/command\",\n inputSchema: commandInputSchema,\n outputSchema: commandAckSchema,\n errorCodes: [\"SESSION_NOT_FOUND\", \"WORKFLOW_INSTANCE_MISSING\"],\n handler: async function ({ input, pathParams }, { json, error }) {\n const command = await input.valid();\n const workflowName = pathParams.workflowName;\n const sessionId = pathParams.sessionId;\n const workflowsService = serviceDeps.workflows;\n const commandId = createPiSessionCommandId(command.kind);\n const payload = createCommandPayload(commandId, command);\n\n try {\n const result = await this.handlerTx()\n .withServiceCalls(() =>\n serviceCalls(\n workflowsService.sendEvent(workflowName, sessionId, {\n type: \"command\",\n payload,\n }),\n workflowsService.getInstanceStatus(workflowName, sessionId),\n ),\n )\n .transform(({ serviceResult: [, workflowStatus] }) => ({ workflowStatus }))\n .execute();\n\n return json(\n {\n accepted: true,\n commandId,\n status: result.workflowStatus.status,\n },\n 202,\n );\n } catch (err) {\n if (err instanceof WorkflowInstanceNotFoundError) {\n return error(\n {\n message: `Session ${workflowName}/${sessionId} not found.`,\n code: \"SESSION_NOT_FOUND\",\n },\n { status: 404 },\n );\n }\n const message = err instanceof Error ? err.message : \"Failed to deliver command.\";\n return error({ message, code: \"WORKFLOW_INSTANCE_MISSING\" }, { status: 500 });\n }\n },\n }),\n ];\n },\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/schema.ts"],"mappings":";cAEa,0CAAQ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../src/schema.ts"],"sourcesContent":["import { schema } from \"@fragno-dev/db/schema\";\n\nexport const piSchema = schema(\"pi-harness\", (s) =>\n s.noOp(\"store Pi session metadata in workflow instance params\"),\n);\n"],"mappings":";;AAEA,MAAa,WAAW,OAAO,eAAe,MAC5C,EAAE,KAAK,uDAAuD,CAChE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,178 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragno-dev/pi-harness",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "A Fragno fragment for Pi workflow session harnessing",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fragno",
|
|
7
|
+
"react",
|
|
8
|
+
"solidjs",
|
|
9
|
+
"svelte",
|
|
10
|
+
"typescript",
|
|
11
|
+
"vue"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/rejot-dev/fragno.git",
|
|
16
|
+
"directory": "packages/pi-harness"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"exports": {
|
|
23
|
+
"./client": {
|
|
24
|
+
"types": "./dist/browser/client/clients.d.ts",
|
|
25
|
+
"default": "./dist/browser/client/clients.js"
|
|
26
|
+
},
|
|
27
|
+
"./client/pi-workflow-emission-stream": {
|
|
28
|
+
"types": "./dist/browser/client/pi-workflow-emission-stream.d.ts",
|
|
29
|
+
"default": "./dist/browser/client/pi-workflow-emission-stream.js"
|
|
30
|
+
},
|
|
31
|
+
"./client/workflow-lofi-session-projection": {
|
|
32
|
+
"types": "./dist/browser/client/workflow-lofi-session-projection.d.ts",
|
|
33
|
+
"default": "./dist/browser/client/workflow-lofi-session-projection.js"
|
|
34
|
+
},
|
|
35
|
+
"./context-usage": {
|
|
36
|
+
"types": "./dist/browser/pi/context-usage.d.ts",
|
|
37
|
+
"browser": "./dist/browser/pi/context-usage.js",
|
|
38
|
+
"default": "./dist/node/pi/context-usage.js"
|
|
39
|
+
},
|
|
40
|
+
"./definition": {
|
|
41
|
+
"types": "./dist/node/pi/definition.d.ts",
|
|
42
|
+
"default": "./dist/node/pi/definition.js"
|
|
43
|
+
},
|
|
44
|
+
"./factory": {
|
|
45
|
+
"types": "./dist/node/pi/factory.d.ts",
|
|
46
|
+
"default": "./dist/node/pi/factory.js"
|
|
47
|
+
},
|
|
48
|
+
"./harness/agent-harness-event-protocol": {
|
|
49
|
+
"types": "./dist/browser/pi/harness/agent-harness-event-protocol.d.ts",
|
|
50
|
+
"browser": "./dist/browser/pi/harness/agent-harness-event-protocol.js",
|
|
51
|
+
"default": "./dist/node/pi/harness/agent-harness-event-protocol.js"
|
|
52
|
+
},
|
|
53
|
+
"./harness/pi-operation-completed": {
|
|
54
|
+
"types": "./dist/node/pi/harness/pi-operation-completed.d.ts",
|
|
55
|
+
"default": "./dist/node/pi/harness/pi-operation-completed.js"
|
|
56
|
+
},
|
|
57
|
+
"./harness/session-storage": {
|
|
58
|
+
"types": "./dist/node/pi/harness/session-storage.d.ts",
|
|
59
|
+
"default": "./dist/node/pi/harness/session-storage.js"
|
|
60
|
+
},
|
|
61
|
+
"./react": {
|
|
62
|
+
"types": "./dist/browser/client/react.d.ts",
|
|
63
|
+
"default": "./dist/browser/client/react.js"
|
|
64
|
+
},
|
|
65
|
+
"./pi-jsonl-export": {
|
|
66
|
+
"types": "./dist/node/pi/pi-jsonl-export.d.ts",
|
|
67
|
+
"default": "./dist/node/pi/pi-jsonl-export.js"
|
|
68
|
+
},
|
|
69
|
+
"./route-schemas": {
|
|
70
|
+
"types": "./dist/node/pi/route-schemas.d.ts",
|
|
71
|
+
"browser": "./dist/browser/pi/route-schemas.js",
|
|
72
|
+
"default": "./dist/node/pi/route-schemas.js"
|
|
73
|
+
},
|
|
74
|
+
"./routes": {
|
|
75
|
+
"types": "./dist/node/routes.d.ts",
|
|
76
|
+
"default": "./dist/node/routes.js"
|
|
77
|
+
},
|
|
78
|
+
"./schema": {
|
|
79
|
+
"types": "./dist/node/schema.d.ts",
|
|
80
|
+
"default": "./dist/node/schema.js"
|
|
81
|
+
},
|
|
82
|
+
"./skills": {
|
|
83
|
+
"types": "./dist/node/pi/skills.d.ts",
|
|
84
|
+
"default": "./dist/node/pi/skills.js"
|
|
85
|
+
},
|
|
86
|
+
"./solid": {
|
|
87
|
+
"types": "./dist/browser/client/solid.d.ts",
|
|
88
|
+
"default": "./dist/browser/client/solid.js"
|
|
89
|
+
},
|
|
90
|
+
"./svelte": {
|
|
91
|
+
"types": "./dist/browser/client/svelte.d.ts",
|
|
92
|
+
"default": "./dist/browser/client/svelte.js"
|
|
93
|
+
},
|
|
94
|
+
"./tools": {
|
|
95
|
+
"types": "./dist/node/pi/tools.d.ts",
|
|
96
|
+
"default": "./dist/node/pi/tools.js"
|
|
97
|
+
},
|
|
98
|
+
"./types": {
|
|
99
|
+
"types": "./dist/node/pi/types.d.ts",
|
|
100
|
+
"default": "./dist/node/pi/types.js"
|
|
101
|
+
},
|
|
102
|
+
"./workflow-session-projection": {
|
|
103
|
+
"types": "./dist/browser/pi/workflow-session-projection.d.ts",
|
|
104
|
+
"browser": "./dist/browser/pi/workflow-session-projection.js",
|
|
105
|
+
"default": "./dist/node/pi/workflow-session-projection.js"
|
|
106
|
+
},
|
|
107
|
+
"./vanilla": {
|
|
108
|
+
"types": "./dist/browser/client/vanilla.d.ts",
|
|
109
|
+
"default": "./dist/browser/client/vanilla.js"
|
|
110
|
+
},
|
|
111
|
+
"./vue": {
|
|
112
|
+
"types": "./dist/browser/client/vue.d.ts",
|
|
113
|
+
"default": "./dist/browser/client/vue.js"
|
|
114
|
+
},
|
|
115
|
+
"./workflows/interactive-chat-workflow": {
|
|
116
|
+
"types": "./dist/node/pi/workflows/interactive-chat-workflow.d.ts",
|
|
117
|
+
"default": "./dist/node/pi/workflows/interactive-chat-workflow.js"
|
|
118
|
+
},
|
|
119
|
+
"./workflows/workflow-agent-harness": {
|
|
120
|
+
"types": "./dist/node/pi/workflows/workflow-agent-harness.d.ts",
|
|
121
|
+
"default": "./dist/node/pi/workflows/workflow-agent-harness.js"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"dependencies": {
|
|
125
|
+
"@earendil-works/pi-agent-core": "0.83.0",
|
|
126
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
127
|
+
"@standard-schema/spec": "^1.1.0",
|
|
128
|
+
"nanostores": "^1.2.0",
|
|
129
|
+
"typebox": "1.3.27",
|
|
130
|
+
"zod": "^4.5.4",
|
|
131
|
+
"@fragno-dev/core": "0.2.2",
|
|
132
|
+
"@fragno-dev/db": "0.4.1",
|
|
133
|
+
"@fragno-dev/lofi": "0.0.3",
|
|
134
|
+
"@fragno-dev/workflows": "0.0.3"
|
|
135
|
+
},
|
|
136
|
+
"devDependencies": {
|
|
137
|
+
"@types/node": "^25.2.2",
|
|
138
|
+
"@types/react": "^19.2.14",
|
|
139
|
+
"drizzle-kit": "^0.31.7",
|
|
140
|
+
"drizzle-orm": "^0.44.7",
|
|
141
|
+
"fake-indexeddb": "^6.2.5",
|
|
142
|
+
"tsdown": "^0.22.4",
|
|
143
|
+
"vitest": "^4.1.4",
|
|
144
|
+
"@fragno-dev/test": "2.0.2",
|
|
145
|
+
"@fragno-dev/unplugin-fragno": "0.0.9"
|
|
146
|
+
},
|
|
147
|
+
"peerDependencies": {
|
|
148
|
+
"react": ">=18.0.0",
|
|
149
|
+
"solid-js": ">=1.0.0",
|
|
150
|
+
"svelte": ">=4.0.0",
|
|
151
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
152
|
+
"vue": ">=3.0.0"
|
|
153
|
+
},
|
|
154
|
+
"peerDependenciesMeta": {
|
|
155
|
+
"react": {
|
|
156
|
+
"optional": true
|
|
157
|
+
},
|
|
158
|
+
"svelte": {
|
|
159
|
+
"optional": true
|
|
160
|
+
},
|
|
161
|
+
"vue": {
|
|
162
|
+
"optional": true
|
|
163
|
+
},
|
|
164
|
+
"solid-js": {
|
|
165
|
+
"optional": true
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"scripts": {
|
|
169
|
+
"types:check": "tsc --noEmit",
|
|
170
|
+
"build": "tsdown",
|
|
171
|
+
"test": "vitest run",
|
|
172
|
+
"measure:event-encoder": "pnpm run build && node scripts/measure-event-encoder-allocation.mjs",
|
|
173
|
+
"format:package": "node ../../scripts/run-package-quality.mjs format",
|
|
174
|
+
"format:check:package": "node ../../scripts/run-package-quality.mjs format:check",
|
|
175
|
+
"lint:package": "node ../../scripts/run-package-quality.mjs lint",
|
|
176
|
+
"lint:fix:package": "node ../../scripts/run-package-quality.mjs lint:fix"
|
|
177
|
+
}
|
|
6
178
|
}
|