@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.
Files changed (140) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +181 -2
  3. package/dist/browser/agent-harness-event-protocol-CuKubox1.js +666 -0
  4. package/dist/browser/agent-harness-event-protocol-CuKubox1.js.map +1 -0
  5. package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts +261 -0
  6. package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts.map +1 -0
  7. package/dist/browser/client/clients.d.ts +2 -0
  8. package/dist/browser/client/clients.js +2 -0
  9. package/dist/browser/client/pi-workflow-emission-stream.d.ts +13 -0
  10. package/dist/browser/client/pi-workflow-emission-stream.d.ts.map +1 -0
  11. package/dist/browser/client/pi-workflow-emission-stream.js +29 -0
  12. package/dist/browser/client/pi-workflow-emission-stream.js.map +1 -0
  13. package/dist/browser/client/react.d.ts +147 -0
  14. package/dist/browser/client/react.d.ts.map +1 -0
  15. package/dist/browser/client/react.js +187 -0
  16. package/dist/browser/client/react.js.map +1 -0
  17. package/dist/browser/client/solid.d.ts +150 -0
  18. package/dist/browser/client/solid.d.ts.map +1 -0
  19. package/dist/browser/client/solid.js +130 -0
  20. package/dist/browser/client/solid.js.map +1 -0
  21. package/dist/browser/client/svelte.d.ts +150 -0
  22. package/dist/browser/client/svelte.d.ts.map +1 -0
  23. package/dist/browser/client/svelte.js +132 -0
  24. package/dist/browser/client/svelte.js.map +1 -0
  25. package/dist/browser/client/vanilla.d.ts +177 -0
  26. package/dist/browser/client/vanilla.d.ts.map +1 -0
  27. package/dist/browser/client/vanilla.js +159 -0
  28. package/dist/browser/client/vanilla.js.map +1 -0
  29. package/dist/browser/client/vue.d.ts +150 -0
  30. package/dist/browser/client/vue.d.ts.map +1 -0
  31. package/dist/browser/client/vue.js +128 -0
  32. package/dist/browser/client/vue.js.map +1 -0
  33. package/dist/browser/client/workflow-lofi-session-projection.d.ts +17 -0
  34. package/dist/browser/client/workflow-lofi-session-projection.d.ts.map +1 -0
  35. package/dist/browser/client/workflow-lofi-session-projection.js +107 -0
  36. package/dist/browser/client/workflow-lofi-session-projection.js.map +1 -0
  37. package/dist/browser/clients-DYXj19je.d.ts +247 -0
  38. package/dist/browser/clients-DYXj19je.d.ts.map +1 -0
  39. package/dist/browser/clients-pIAk6ClP.js +1853 -0
  40. package/dist/browser/clients-pIAk6ClP.js.map +1 -0
  41. package/dist/browser/pi/context-usage.d.ts +20 -0
  42. package/dist/browser/pi/context-usage.d.ts.map +1 -0
  43. package/dist/browser/pi/context-usage.js +84 -0
  44. package/dist/browser/pi/context-usage.js.map +1 -0
  45. package/dist/browser/pi/harness/agent-harness-event-protocol.d.ts +2 -0
  46. package/dist/browser/pi/harness/agent-harness-event-protocol.js +2 -0
  47. package/dist/browser/pi/route-schemas.d.ts +2 -0
  48. package/dist/browser/pi/route-schemas.js +130 -0
  49. package/dist/browser/pi/route-schemas.js.map +1 -0
  50. package/dist/browser/pi/workflow-session-projection.d.ts +2 -0
  51. package/dist/browser/pi/workflow-session-projection.js +2 -0
  52. package/dist/browser/route-schemas-DQB5ZR1E.d.ts +109 -0
  53. package/dist/browser/route-schemas-DQB5ZR1E.d.ts.map +1 -0
  54. package/dist/browser/types-8q4RWFXT.js +23 -0
  55. package/dist/browser/types-8q4RWFXT.js.map +1 -0
  56. package/dist/browser/types-Dk856kV1.d.ts +527 -0
  57. package/dist/browser/types-Dk856kV1.d.ts.map +1 -0
  58. package/dist/browser/workflow-session-projection-CJ4MUkpJ.js +443 -0
  59. package/dist/browser/workflow-session-projection-CJ4MUkpJ.js.map +1 -0
  60. package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts +93 -0
  61. package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts.map +1 -0
  62. package/dist/node/pi/compact-command-outcome-projection.js +41 -0
  63. package/dist/node/pi/compact-command-outcome-projection.js.map +1 -0
  64. package/dist/node/pi/context-usage.d.ts +20 -0
  65. package/dist/node/pi/context-usage.d.ts.map +1 -0
  66. package/dist/node/pi/context-usage.js +84 -0
  67. package/dist/node/pi/context-usage.js.map +1 -0
  68. package/dist/node/pi/definition.d.ts +535 -0
  69. package/dist/node/pi/definition.d.ts.map +1 -0
  70. package/dist/node/pi/definition.js +71 -0
  71. package/dist/node/pi/definition.js.map +1 -0
  72. package/dist/node/pi/factory.d.ts +142 -0
  73. package/dist/node/pi/factory.d.ts.map +1 -0
  74. package/dist/node/pi/factory.js +22 -0
  75. package/dist/node/pi/factory.js.map +1 -0
  76. package/dist/node/pi/harness/agent-harness-event-protocol.d.ts +261 -0
  77. package/dist/node/pi/harness/agent-harness-event-protocol.d.ts.map +1 -0
  78. package/dist/node/pi/harness/agent-harness-event-protocol.js +588 -0
  79. package/dist/node/pi/harness/agent-harness-event-protocol.js.map +1 -0
  80. package/dist/node/pi/harness/json-value.js +82 -0
  81. package/dist/node/pi/harness/json-value.js.map +1 -0
  82. package/dist/node/pi/harness/pi-operation-completed.d.ts +16 -0
  83. package/dist/node/pi/harness/pi-operation-completed.d.ts.map +1 -0
  84. package/dist/node/pi/harness/pi-operation-completed.js +71 -0
  85. package/dist/node/pi/harness/pi-operation-completed.js.map +1 -0
  86. package/dist/node/pi/harness/session-storage.d.ts +62 -0
  87. package/dist/node/pi/harness/session-storage.d.ts.map +1 -0
  88. package/dist/node/pi/harness/session-storage.js +174 -0
  89. package/dist/node/pi/harness/session-storage.js.map +1 -0
  90. package/dist/node/pi/pi-jsonl-export.d.ts +11 -0
  91. package/dist/node/pi/pi-jsonl-export.d.ts.map +1 -0
  92. package/dist/node/pi/pi-jsonl-export.js +31 -0
  93. package/dist/node/pi/pi-jsonl-export.js.map +1 -0
  94. package/dist/node/pi/route-schemas.d.ts +109 -0
  95. package/dist/node/pi/route-schemas.d.ts.map +1 -0
  96. package/dist/node/pi/route-schemas.js +130 -0
  97. package/dist/node/pi/route-schemas.js.map +1 -0
  98. package/dist/node/pi/session-command-protocol.d.ts +14 -0
  99. package/dist/node/pi/session-command-protocol.d.ts.map +1 -0
  100. package/dist/node/pi/session-command-protocol.js +25 -0
  101. package/dist/node/pi/session-command-protocol.js.map +1 -0
  102. package/dist/node/pi/session-entry-projection.js +79 -0
  103. package/dist/node/pi/session-entry-projection.js.map +1 -0
  104. package/dist/node/pi/skills.d.ts +70 -0
  105. package/dist/node/pi/skills.d.ts.map +1 -0
  106. package/dist/node/pi/skills.js +150 -0
  107. package/dist/node/pi/skills.js.map +1 -0
  108. package/dist/node/pi/tools.d.ts +12 -0
  109. package/dist/node/pi/tools.d.ts.map +1 -0
  110. package/dist/node/pi/tools.js +8 -0
  111. package/dist/node/pi/tools.js.map +1 -0
  112. package/dist/node/pi/types.d.ts +165 -0
  113. package/dist/node/pi/types.d.ts.map +1 -0
  114. package/dist/node/pi/types.js +49 -0
  115. package/dist/node/pi/types.js.map +1 -0
  116. package/dist/node/pi/wait-for-command-step.js +46 -0
  117. package/dist/node/pi/wait-for-command-step.js.map +1 -0
  118. package/dist/node/pi/workflow-session-live-projection.js +220 -0
  119. package/dist/node/pi/workflow-session-live-projection.js.map +1 -0
  120. package/dist/node/pi/workflow-session-projection.d.ts +84 -0
  121. package/dist/node/pi/workflow-session-projection.d.ts.map +1 -0
  122. package/dist/node/pi/workflow-session-projection.js +100 -0
  123. package/dist/node/pi/workflow-session-projection.js.map +1 -0
  124. package/dist/node/pi/workflows/interactive-chat-workflow.d.ts +37 -0
  125. package/dist/node/pi/workflows/interactive-chat-workflow.d.ts.map +1 -0
  126. package/dist/node/pi/workflows/interactive-chat-workflow.js +219 -0
  127. package/dist/node/pi/workflows/interactive-chat-workflow.js.map +1 -0
  128. package/dist/node/pi/workflows/workflow-agent-harness.d.ts +142 -0
  129. package/dist/node/pi/workflows/workflow-agent-harness.d.ts.map +1 -0
  130. package/dist/node/pi/workflows/workflow-agent-harness.js +450 -0
  131. package/dist/node/pi/workflows/workflow-agent-harness.js.map +1 -0
  132. package/dist/node/routes.d.ts +631 -0
  133. package/dist/node/routes.d.ts.map +1 -0
  134. package/dist/node/routes.js +355 -0
  135. package/dist/node/routes.js.map +1 -0
  136. package/dist/node/schema.d.ts +5 -0
  137. package/dist/node/schema.d.ts.map +1 -0
  138. package/dist/node/schema.js +7 -0
  139. package/dist/node/schema.js.map +1 -0
  140. 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":";;;;;;;;;;;;;;;AA2CA,MAAM,oBAAoB;AAC1B,MAAM,gBAAgB;AACtB,MAAM,uCAAuC;AAC7C,MAAM,wBACJ,WACA,YAC4B;CAC5B,QAAQ,QAAQ,MAAhB;EACE,KAAK,UACH,OAAO;GAAE;GAAW,MAAM,QAAQ;GAAM,OAAO,QAAQ;EAAM;EAC/D,KAAK,SACH,OAAO;GAAE;GAAW,MAAM,QAAQ;GAAM,OAAO,QAAQ;EAAM;EAC/D,KAAK,sBACH,OAAO;GAAE;GAAW,MAAM,QAAQ;GAAM,OAAO,QAAQ;EAAM;EAC/D,KAAK,WACH,OAAO;GAAE;GAAW,MAAM,QAAQ;GAAM,OAAO,QAAQ;EAAM;EAC/D,KAAK,SACH,OAAO;GAAE;GAAW,MAAM,QAAQ;GAAM,OAAO,QAAQ;EAAM;EAC/D,KAAK,YACH,OAAO;GAAE;GAAW,MAAM,QAAQ;GAAM,OAAO,QAAQ;EAAM;EAC/D,KAAK,SACH,OAAO,QAAQ,SACX;GAAE;GAAW,MAAM,QAAQ;GAAM,QAAQ,QAAQ;EAAO,IACxD;GAAE;GAAW,MAAM,QAAQ;EAAK;CACxC;CAEA,MAAM,IAAI,MAAM,sCAAsC;AACxD;AAEA,MAAM,kCAAkC,UAA6C;CACnF,IAAI,UAAU,MACZ;CAEF,MAAM,SAAS,OAAO,SAAS,OAAO,EAAE;CACxC,OAAO,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,SAAS,KAAA;AAC1D;AAEA,MAAM,mBAAmB,cAAwD;CAC/E,GAAG,SAAS;CACZ,UAAU;EACR,QAAQ,SAAS,eAAe;EAChC,OAAO,SAAS,eAAe;EAC/B,QAAQ,SAAS,eAAe;CAClC;CACA,OAAO,EACL,OAAO,EAAE,UAAU,SAAS,SAAS,EACvC;AACF;AAEA,MAAa,kBAAkB,aAAa,mBAAmB,CAAC,CAAC,QAC9D,EAAE,QAAQ,aAAa,aAAa,eAAe;CAClD,IAAI,OAAO,SACT,gBAAgB,UAAU,OAAO,OAAO;CAG1C,MAAM,4BAA4B,KAAc,cAAsB,cAAsB;EAC1F,IAAI,eAAe,+BACjB,OAAO;GACL,MAAM;IACJ,SAAS,WAAW,aAAa,GAAG,UAAU;IAC9C,MAAM;GACR;GACA,MAAM,EAAE,QAAQ,IAAa;EAC/B;EAEF,IAAI,eAAe,+BACjB,OAAO;GACL,MAAM;IACJ,SAAS,IAAI;IACb,MAAM;GACR;GACA,MAAM,EAAE,QAAQ,IAAa;EAC/B;EAEF,IAAI,eAAe,6BACjB,OAAO;GACL,MAAM;IACJ,SAAS,IAAI;IACb,MAAM;GACR;GACA,MAAM,EAAE,QAAQ,IAAa;EAC/B;EAGF,OAAO;GACL,MAAM;IAAE,SAFM,eAAe,QAAQ,IAAI,UAAU;IAElC,MAAM;GAAqC;GAC5D,MAAM,EAAE,QAAQ,IAAa;EAC/B;CACF;CAEA,OAAO;EACL,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa,EAAE,OAAO;IACpB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;IAC1B,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS;IACrD,OAAO,EAAE,QAAQ,CAAC,CAAC,SAAS;GAC9B,CAAC;GACD,cAAc;GACd,YAAY;IAAC;IAAsB;IAA2B;GAAwB;GACtF,SAAS,eAAgB,EAAE,OAAO,cAAc,EAAE,MAAM,SAAS;IAC/D,MAAM,SAAS,MAAM,MAAM,MAAM;IAEjC,MAAM,eAAe,WAAW;IAChC,MAAM,sBAAM,IAAI,KAAK;IACrB,MAAM,YAAY,SAAS;IAE3B,IAAI;KAIF,MAAM,kBAAkB,MAAM,uBAC5B,IAJ0B,KACzB,OAAO,aAAa,CAAC,EAAA,CAAG,KAAK,aAAa,CAAC,SAAS,MAAM,QAAQ,CAAC,CAGtD,GACd,cACA,OAAO,KACT;KACA,IACE,OAAO,oBAAoB,YAC3B,oBAAoB,QACpB,MAAM,QAAQ,eAAe,GAE7B,MAAM,IAAI,2BAA2B,cAAc,CACjD,gDACF,CAAC;KAEH,MAAM,SAAS,EAAE,GAAI,gBAA4C;KACjE,IAAI,OAAO,aAAa,KAAA,GACtB,OAAO,cAAc,OAAO;UAE5B,OAAO,OAAO;KAEhB,MAAM,KAAK,UAAU,CAAC,CACnB,uBAAuB,CACtB,SAAS,sBAAsB;MAC7B,IAAI;MACJ;MACA,MAAM,OAAO;MACb;KACF,CAAC,CACH,CAAC,CAAC,CACD,QAAQ;KAEX,OAAO,KAAK;MACV,IAAI;MACJ,MAAM,OAAO,QAAQ;MACrB,UAAU,OAAO,YAAY;MAC7B;MACA,WAAW;MACX,WAAW;KACb,CAAC;IACH,SAAS,KAAK;KACZ,IAAI,eAAe,uBACjB,OAAO,MACL;MAAE,SAAS,YAAY,aAAa;MAAc,MAAM;KAAqB,GAC7E,EAAE,QAAQ,IAAI,CAChB;KAEF,IAAI,eAAe,4BACjB,OAAO,MACL;MAAE,SAAS;MAA8B,MAAM;KAA0B,GACzE,EAAE,QAAQ,IAAI,CAChB;KAIF,OAAO,MAAM;MAAE,SADb,eAAe,QAAQ,IAAI,UAAU;MACf,MAAM;KAAyB,GAAG,EAAE,QAAQ,IAAI,CAAC;IAC3E;GACF;EACF,CAAC;EACD,YAAY;GACV,QAAQ;GACR,MAAM;GACN,iBAAiB,CAAC,OAAO;GACzB,cAAc,EAAE,MAAM,iBAAiB;GACvC,YAAY,CAAC,8BAA8B;GAC3C,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,eAAe,WAAW;IAChC,MAAM,QAAQ,OAAO,SAAS,MAAM,IAAI,OAAO,KAAK,GAAG,qBAAqB,EAAE;IAC9E,MAAM,kBAAkB,OAAO,SAAS,KAAK,IACzC,KAAK,IAAI,GAAG,KAAK,IAAI,eAAe,KAAK,CAAC,IAC1C;IAGJ,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC,CAClC,uBAAuB,CACtB,YAAY,UAAU,cAAc;KAClC;KACA,UAAU;IACZ,CAAC,CACH,CAAC,CAAC,CACD,WAAW,EAAE,eAAe,CAAC,cAAc,MAAM,CAAC,CAClD,QAAQ;IAEX,IAAI;KACF,OAAO,KACL,OAAO,UAAU,SAAS,aAAa;MACrC,MAAM,UAAU,qCAAqC;OACnD,IAAI,SAAS;OACb;OACA,QAAQ,SAAS;OACjB,WAAW,SAAS;OACpB,WAAW,SAAS;MACtB,CAAC;MACD,OAAO,UAAU,CAAC,OAAO,IAAI,CAAC;KAChC,CAAC,CACH;IACF,SAAS,KAAK;KACZ,IAAI,eAAe,6BACjB,OAAO,MACL;MAAE,SAAS,IAAI;MAAS,MAAM;KAA+B,GAC7D,EAAE,QAAQ,IAAI,CAChB;KAEF,MAAM;IACR;GACF;EACF,CAAC;EACD,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc;GACd,YAAY;IACV;IACA;IACA;IACA;GACF;GACA,SAAS,eAAgB,EAAE,YAAY,EAAE,cAAc,eAAe,EAAE,MAAM,SAAS;IACrF,IAAI;KACF,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC,CAClC,uBACO,CAAC,SAAS,yBAAyB,cAAc,SAAS,CAAC,CACnE,CAAC,CACA,WAAW,EAAE,eAAe,CAAC,gBAAgB,QAAQ,CAAC,CACtD,QAAQ;KACX,OAAO,KAAK,gBAAgB,MAAM,CAAC;IACrC,SAAS,KAAK;KACZ,MAAM,YAAY,yBAAyB,KAAK,cAAc,SAAS;KACvE,OAAO,MAAM,UAAU,MAAM,UAAU,IAAI;IAC7C;GACF;EACF,CAAC;EACD,YAAY;GACV,QAAQ;GACR,MAAM;GACN,YAAY;IACV;IACA;IACA;IACA;GACF;GACA,SAAS,eAAgB,EAAE,YAAY,EAAE,cAAc,eAAe,EAAE,SAAS;IAC/E,IAAI;KACF,MAAM,WAAW,MAAM,KAAK,UAAU,CAAC,CACpC,uBACO,CAAC,SAAS,yBAAyB,cAAc,SAAS,CAAC,CACnE,CAAC,CACA,WAAW,EAAE,eAAe,CAAC,gBAAgB,QAAQ,CAAC,CACtD,QAAQ;KAYX,MAAM,QAAQ,MAAM,4BAA4B,IAX5B,6BAA6B;MAC/C,UAAU;OACR,IAAI,SAAS,QAAQ;OACrB,WAAW,SAAS,QAAQ,UAAU,YAAY;MACpD;MACA,SAAS,SAAS;MAClB,UAAU,4CAA4C;OACpD,QAAQ,GAAG,SAAS,QAAQ,GAAG;OAC/B,YAAY,SAAS,eAAe;MACtC,CAAC;KACH,CACsD,GAAG,EAAE,KAAK,oBAAoB,CAAC;KAErF,OAAO,IAAI,SAAS,OAAO;MACzB,QAAQ;MACR,SAAS;OACP,gBAAgB;OAChB,uBAAuB,oCAAoC,UAAU;MACvE;KACF,CAAC;IACH,SAAS,KAAK;KACZ,MAAM,YAAY,yBAAyB,KAAK,cAAc,SAAS;KACvE,OAAO,MAAM,UAAU,MAAM,UAAU,IAAI;IAC7C;GACF;EACF,CAAC;EACD,YAAY;GACV,QAAQ;GACR,MAAM;GACN,iBAAiB,CAAC,WAAW;GAC7B,YAAY;IACV;IACA;IACA;IACA;IACA;IACA;IACA;GACF;GACA,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,OAAO,SAAS;IAChE,MAAM,YAAY,+BAA+B,MAAM,IAAI,WAAW,CAAC;IACvE,MAAM,eAAe,WAAW;IAChC,MAAM,YAAY,WAAW;IAC7B,MAAM,YAAY,WAAW;IAC7B,MAAM,cAAc,4BAA4B,SAAS;IACzD,IAAI,gBAAgB,WAClB,OAAO,MACL;KAAE,SAAS;KAAuB,MAAM;IAAqB,GAC7D,EAAE,QAAQ,IAAI,CAChB;IAEF,IAAI,gBAAgB,WAClB,OAAO,MACL;KAAE,SAAS;KAAyC,MAAM;IAAuB,GACjF,EAAE,QAAQ,IAAI,CAChB;IAEF,MAAM,gBAAgB,aAAa;IAEnC,IAAI;KACF,MAAM,mBAAmB;MACvB,WAAW,KAAK,UAAU,KAAK,IAAI;MACnC,WAAW,YAAY;MACvB;MACA,YAAY;MACZ;MACA,WAAW;KACb,CAAC;KAED,OAAO,MAAM,GAAG;IAClB,SAAS,KAAK;KACZ,IAAI,eAAe,6BACjB,OAAO,MAAM;MAAE,SAAS,IAAI;MAAS,MAAM;KAAuB,GAAG,EAAE,QAAQ,IAAI,CAAC;KAEtF,IAAI,eAAe,wBACjB,OAAO,MAAM;MAAE,SAAS,IAAI;MAAS,MAAM;KAAsB,GAAG,EAAE,QAAQ,IAAI,CAAC;KAErF,IAAI,eAAe,gCACjB,OAAO,MACL;MAAE,SAAS,IAAI;MAAS,MAAM;KAA4B,GAC1D,EAAE,QAAQ,IAAI,CAChB;KAEF,IAAI,eAAe,+BACjB,OAAO,MACL;MACE,SAAS,WAAW,aAAa,GAAG,UAAU;MAC9C,MAAM;KACR,GACA,EAAE,QAAQ,IAAI,CAChB;KAEF,OAAO,MACL;MACE,SAAS,eAAe,QAAQ,IAAI,UAAU;MAC9C,MAAM;KACR,GACA,EAAE,QAAQ,IAAI,CAChB;IACF;GACF;EACF,CAAC;EACD,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY,CAAC,qBAAqB,2BAA2B;GAC7D,SAAS,eAAgB,EAAE,OAAO,cAAc,EAAE,MAAM,SAAS;IAC/D,MAAM,UAAU,MAAM,MAAM,MAAM;IAClC,MAAM,eAAe,WAAW;IAChC,MAAM,YAAY,WAAW;IAC7B,MAAM,mBAAmB,YAAY;IACrC,MAAM,YAAY,yBAAyB,QAAQ,IAAI;IACvD,MAAM,UAAU,qBAAqB,WAAW,OAAO;IAEvD,IAAI;KAcF,OAAO,KACL;MACE,UAAU;MACV;MACA,SAAQ,MAjBS,KAAK,UAAU,CAAC,CAClC,uBACC,aACE,iBAAiB,UAAU,cAAc,WAAW;OAClD,MAAM;OACN;MACF,CAAC,GACD,iBAAiB,kBAAkB,cAAc,SAAS,CAC5D,CACF,CAAC,CACA,WAAW,EAAE,eAAe,GAAG,uBAAuB,EAAE,eAAe,EAAE,CAAC,CAC1E,QAAQ,EAAA,CAMQ,eAAe;KAChC,GACA,GACF;IACF,SAAS,KAAK;KACZ,IAAI,eAAe,+BACjB,OAAO,MACL;MACE,SAAS,WAAW,aAAa,GAAG,UAAU;MAC9C,MAAM;KACR,GACA,EAAE,QAAQ,IAAI,CAChB;KAGF,OAAO,MAAM;MAAE,SADC,eAAe,QAAQ,IAAI,UAAU;MAC7B,MAAM;KAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;IAC9E;GACF;EACF,CAAC;CACH;AACF,CACF"}
@@ -0,0 +1,5 @@
1
+ //#region src/schema.d.ts
2
+ declare const piSchema: import("@fragno-dev/db/schema").Schema<{}>;
3
+ //#endregion
4
+ export { piSchema };
5
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/schema.ts"],"mappings":";cAEa,0CAAQ"}
@@ -0,0 +1,7 @@
1
+ import { schema } from "@fragno-dev/db/schema";
2
+ //#region src/schema.ts
3
+ const piSchema = schema("pi-harness", (s) => s.noOp("store Pi session metadata in workflow instance params"));
4
+ //#endregion
5
+ export { piSchema };
6
+
7
+ //# sourceMappingURL=schema.js.map
@@ -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.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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
  }