acpx 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-registry-DGw0-3Tc.js +54 -0
- package/dist/agent-registry-DGw0-3Tc.js.map +1 -0
- package/dist/{cli-5s-E-Y99.js → cli-CLRrs6eQ.js} +8 -12
- package/dist/cli-CLRrs6eQ.js.map +1 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1018 -1009
- package/dist/cli.js.map +1 -1
- package/dist/client-DLTWuu4w.d.ts +116 -0
- package/dist/client-DLTWuu4w.d.ts.map +1 -0
- package/dist/{flags-BkWInxAq.js → flags-BmubjvOw.js} +5 -55
- package/dist/flags-BmubjvOw.js.map +1 -0
- package/dist/{flows-DnIYoHI1.js → flows-CR7xCmkR.js} +471 -281
- package/dist/flows-CR7xCmkR.js.map +1 -0
- package/dist/flows.d.ts +5 -9
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{queue-ipc-CgWf63GN.js → ipc-DN6M4Ui9.js} +12 -571
- package/dist/ipc-DN6M4Ui9.js.map +1 -0
- package/dist/{acp-jsonrpc-C7pPk9Tw.js → jsonrpc-M3y-qzy8.js} +16 -3
- package/dist/jsonrpc-M3y-qzy8.js.map +1 -0
- package/dist/{output-C58ukIo3.js → output-Di0M9Et8.js} +8 -22
- package/dist/output-Di0M9Et8.js.map +1 -0
- package/dist/perf-metrics-D9QC81lB.js +568 -0
- package/dist/perf-metrics-D9QC81lB.js.map +1 -0
- package/dist/{session-BtpTC2pM.js → prompt-turn-Bt8T3SRR.js} +2304 -3632
- package/dist/prompt-turn-Bt8T3SRR.js.map +1 -0
- package/dist/{output-render-C7w9NZ2H.js → render-BL5ynRkN.js} +7 -6
- package/dist/render-BL5ynRkN.js.map +1 -0
- package/dist/runtime.d.ts +266 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +984 -0
- package/dist/runtime.js.map +1 -0
- package/dist/session-BbN0SBgf.js +1488 -0
- package/dist/session-BbN0SBgf.js.map +1 -0
- package/dist/{types-CeRKmEQ1.d.ts → types-DXxLBQc3.d.ts} +40 -3
- package/dist/types-DXxLBQc3.d.ts.map +1 -0
- package/package.json +20 -9
- package/dist/acp-jsonrpc-C7pPk9Tw.js.map +0 -1
- package/dist/cli-5s-E-Y99.js.map +0 -1
- package/dist/flags-BkWInxAq.js.map +0 -1
- package/dist/flows-DnIYoHI1.js.map +0 -1
- package/dist/output-C58ukIo3.js.map +0 -1
- package/dist/output-render-C7w9NZ2H.js.map +0 -1
- package/dist/queue-ipc-CgWf63GN.js.map +0 -1
- package/dist/session-BtpTC2pM.js.map +0 -1
- package/dist/types-CeRKmEQ1.d.ts.map +0 -1
|
@@ -1,44 +1,233 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { A as PERMISSION_MODES, g as textPrompt, h as promptToDisplayText, j as SESSION_RECORD_SCHEMA } from "./perf-metrics-D9QC81lB.js";
|
|
2
|
+
import { A as resolveSessionRecord, H as TimeoutError, P as defaultSessionEventLog, U as withInterrupt, V as InterruptedError, W as withTimeout, _ as recordSessionUpdate, f as cloneSessionAcpxState, g as recordPromptSubmission, h as recordClientOperation, m as createSessionConversation } from "./prompt-turn-Bt8T3SRR.js";
|
|
3
|
+
import { c as createSessionWithClient, i as sendSessionDirect, l as cancelSessionPrompt, r as runOnce } from "./session-BbN0SBgf.js";
|
|
4
|
+
import { t as createOutputFormatter } from "./output-Di0M9Et8.js";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
6
7
|
import os from "node:os";
|
|
7
8
|
import { spawn } from "node:child_process";
|
|
8
9
|
import { createHash, randomUUID } from "node:crypto";
|
|
10
|
+
import { ZodError, z } from "zod";
|
|
11
|
+
//#region src/flows/authoring.ts
|
|
12
|
+
const FLOW_DEFINITION_BRAND = Symbol.for("acpx.flow.definition");
|
|
13
|
+
function markDefinedFlow(definition) {
|
|
14
|
+
if (isDefinedFlow(definition)) return definition;
|
|
15
|
+
Object.defineProperty(definition, FLOW_DEFINITION_BRAND, {
|
|
16
|
+
value: true,
|
|
17
|
+
enumerable: false,
|
|
18
|
+
configurable: false,
|
|
19
|
+
writable: false
|
|
20
|
+
});
|
|
21
|
+
return definition;
|
|
22
|
+
}
|
|
23
|
+
function isDefinedFlow(value) {
|
|
24
|
+
return value != null && typeof value === "object" && value[FLOW_DEFINITION_BRAND] === true;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/flows/schema.ts
|
|
28
|
+
const FLOW_NODE_TYPES = [
|
|
29
|
+
"acp",
|
|
30
|
+
"compute",
|
|
31
|
+
"action",
|
|
32
|
+
"checkpoint"
|
|
33
|
+
];
|
|
34
|
+
const finiteNonNegativeNumberSchema = z.number().finite().nonnegative();
|
|
35
|
+
const nonEmptyTrimmedStringSchema = z.string().refine((value) => value.trim().length > 0, { message: "must not be empty" });
|
|
36
|
+
function extensibleObject(shape) {
|
|
37
|
+
return z.object(shape).passthrough();
|
|
38
|
+
}
|
|
39
|
+
function functionSchema(label) {
|
|
40
|
+
return z.custom((value) => typeof value === "function", { message: `${label} must be a function` });
|
|
41
|
+
}
|
|
42
|
+
const flowNodeCommonShape = {
|
|
43
|
+
timeoutMs: finiteNonNegativeNumberSchema.optional(),
|
|
44
|
+
heartbeatMs: finiteNonNegativeNumberSchema.optional(),
|
|
45
|
+
statusDetail: z.string().optional()
|
|
46
|
+
};
|
|
47
|
+
const flowPermissionRequirementsSchema = extensibleObject({
|
|
48
|
+
requiredMode: z.enum(PERMISSION_MODES),
|
|
49
|
+
requireExplicitGrant: z.boolean().optional(),
|
|
50
|
+
reason: nonEmptyTrimmedStringSchema.optional()
|
|
51
|
+
});
|
|
52
|
+
const flowRunDefinitionSchema = extensibleObject({ title: z.union([z.string(), functionSchema("run.title")]).optional() });
|
|
53
|
+
const acpSessionSchema = extensibleObject({
|
|
54
|
+
handle: z.string().optional(),
|
|
55
|
+
isolated: z.boolean().optional()
|
|
56
|
+
});
|
|
57
|
+
const acpNodeSchema = extensibleObject({
|
|
58
|
+
...flowNodeCommonShape,
|
|
59
|
+
nodeType: z.literal("acp"),
|
|
60
|
+
profile: z.string().optional(),
|
|
61
|
+
cwd: z.union([z.string(), functionSchema("cwd")]).optional(),
|
|
62
|
+
session: acpSessionSchema.optional(),
|
|
63
|
+
prompt: functionSchema("prompt"),
|
|
64
|
+
parse: functionSchema("parse").optional()
|
|
65
|
+
});
|
|
66
|
+
const computeNodeSchema = extensibleObject({
|
|
67
|
+
...flowNodeCommonShape,
|
|
68
|
+
nodeType: z.literal("compute"),
|
|
69
|
+
run: functionSchema("run")
|
|
70
|
+
});
|
|
71
|
+
const functionActionNodeSchema = extensibleObject({
|
|
72
|
+
...flowNodeCommonShape,
|
|
73
|
+
nodeType: z.literal("action"),
|
|
74
|
+
run: functionSchema("run")
|
|
75
|
+
});
|
|
76
|
+
const shellActionNodeSchema = extensibleObject({
|
|
77
|
+
...flowNodeCommonShape,
|
|
78
|
+
nodeType: z.literal("action"),
|
|
79
|
+
exec: functionSchema("exec"),
|
|
80
|
+
parse: functionSchema("parse").optional()
|
|
81
|
+
}).refine((node) => !hasOwn(node, "run"), { message: "shell action nodes must not define run" });
|
|
82
|
+
const checkpointNodeSchema = extensibleObject({
|
|
83
|
+
...flowNodeCommonShape,
|
|
84
|
+
nodeType: z.literal("checkpoint"),
|
|
85
|
+
summary: z.string().optional(),
|
|
86
|
+
run: functionSchema("run").optional()
|
|
87
|
+
});
|
|
88
|
+
const directFlowEdgeSchema = extensibleObject({
|
|
89
|
+
from: z.string(),
|
|
90
|
+
to: z.string()
|
|
91
|
+
});
|
|
92
|
+
const switchFlowEdgeSchema = extensibleObject({
|
|
93
|
+
from: z.string(),
|
|
94
|
+
switch: extensibleObject({
|
|
95
|
+
on: z.string(),
|
|
96
|
+
cases: z.record(z.string(), z.string())
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
const flowDefinitionSchema = extensibleObject({
|
|
100
|
+
name: nonEmptyTrimmedStringSchema,
|
|
101
|
+
run: flowRunDefinitionSchema.optional(),
|
|
102
|
+
permissions: flowPermissionRequirementsSchema.optional(),
|
|
103
|
+
startAt: z.string(),
|
|
104
|
+
nodes: z.record(z.string(), z.unknown()),
|
|
105
|
+
edges: z.array(z.unknown())
|
|
106
|
+
});
|
|
107
|
+
const flowNodeTypeSchema = z.object({ nodeType: z.enum(FLOW_NODE_TYPES) });
|
|
108
|
+
function assertValidFlowDefinitionShape(flow) {
|
|
109
|
+
const parsed = parseWithSchema("flow definition", flowDefinitionSchema, flow);
|
|
110
|
+
for (const [nodeId, node] of Object.entries(parsed.nodes)) assertValidFlowNodeDefinitionShape(node, `flow node "${nodeId}"`);
|
|
111
|
+
parsed.edges.forEach((edge, index) => {
|
|
112
|
+
assertValidFlowEdgeShape(edge, `flow definition: edges.${index}`);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function assertValidAcpNodeDefinition(node) {
|
|
116
|
+
parseWithSchema("acp node definition", acpNodeSchema, node);
|
|
117
|
+
}
|
|
118
|
+
function assertValidComputeNodeDefinition(node) {
|
|
119
|
+
parseWithSchema("compute node definition", computeNodeSchema, node);
|
|
120
|
+
}
|
|
121
|
+
function assertValidActionNodeDefinition(node) {
|
|
122
|
+
assertValidActionNodeDefinitionShape(node, "action node definition");
|
|
123
|
+
}
|
|
124
|
+
function assertValidShellActionNodeDefinition(node) {
|
|
125
|
+
parseWithSchema("shell action node definition", shellActionNodeSchema, node);
|
|
126
|
+
}
|
|
127
|
+
function assertValidCheckpointNodeDefinition(node) {
|
|
128
|
+
parseWithSchema("checkpoint node definition", checkpointNodeSchema, node);
|
|
129
|
+
}
|
|
130
|
+
function assertValidFlowNodeDefinitionShape(node, label) {
|
|
131
|
+
const { nodeType } = parseWithSchema(label, flowNodeTypeSchema, node);
|
|
132
|
+
switch (nodeType) {
|
|
133
|
+
case "acp":
|
|
134
|
+
parseWithSchema(label, acpNodeSchema, node);
|
|
135
|
+
return;
|
|
136
|
+
case "compute":
|
|
137
|
+
parseWithSchema(label, computeNodeSchema, node);
|
|
138
|
+
return;
|
|
139
|
+
case "action":
|
|
140
|
+
assertValidActionNodeDefinitionShape(node, label);
|
|
141
|
+
return;
|
|
142
|
+
case "checkpoint":
|
|
143
|
+
parseWithSchema(label, checkpointNodeSchema, node);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function assertValidActionNodeDefinitionShape(node, label) {
|
|
148
|
+
const hasRun = hasOwn(node, "run");
|
|
149
|
+
const hasExec = hasOwn(node, "exec");
|
|
150
|
+
if (hasRun === hasExec) throw new Error(`Invalid ${label}: action nodes must define exactly one of run or exec`);
|
|
151
|
+
if (hasExec) {
|
|
152
|
+
parseWithSchema(label, shellActionNodeSchema, node);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
parseWithSchema(label, functionActionNodeSchema, node);
|
|
156
|
+
}
|
|
157
|
+
function assertValidFlowEdgeShape(edge, label) {
|
|
158
|
+
const hasTo = hasOwn(edge, "to");
|
|
159
|
+
if (hasTo === hasOwn(edge, "switch")) throw new Error(`Invalid ${label}: edge must define exactly one of to or switch`);
|
|
160
|
+
if (hasTo) {
|
|
161
|
+
parseWithSchema(label, directFlowEdgeSchema, edge);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
parseWithSchema(label, switchFlowEdgeSchema, edge);
|
|
165
|
+
}
|
|
166
|
+
function parseWithSchema(label, schema, value) {
|
|
167
|
+
try {
|
|
168
|
+
return schema.parse(value);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (error instanceof ZodError) throw new Error(formatValidationError(label, error), { cause: error });
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function formatValidationError(label, error) {
|
|
175
|
+
return `Invalid ${label}: ${Array.from(new Set(error.issues.flatMap((issue) => formatIssue(issue)))).join("; ")}`;
|
|
176
|
+
}
|
|
177
|
+
function formatIssue(issue, parentPath = []) {
|
|
178
|
+
const path = [...parentPath, ...issue.path.map(String)];
|
|
179
|
+
if (issue.code === "invalid_union") return issue.errors.flatMap((branch) => branch.flatMap((nestedIssue) => formatIssue(nestedIssue, path)));
|
|
180
|
+
const renderedPath = path.join(".");
|
|
181
|
+
return [renderedPath ? `${renderedPath}: ${issue.message}` : issue.message];
|
|
182
|
+
}
|
|
183
|
+
function hasOwn(value, key) {
|
|
184
|
+
return value != null && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, key);
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
9
187
|
//#region src/flows/definition.ts
|
|
10
188
|
function defineFlow(definition) {
|
|
11
|
-
|
|
189
|
+
assertValidFlowDefinitionShape(definition);
|
|
190
|
+
return markDefinedFlow(definition);
|
|
12
191
|
}
|
|
13
192
|
function acp(definition) {
|
|
14
|
-
|
|
193
|
+
const node = {
|
|
15
194
|
nodeType: "acp",
|
|
16
195
|
...definition
|
|
17
196
|
};
|
|
197
|
+
assertValidAcpNodeDefinition(node);
|
|
198
|
+
return node;
|
|
18
199
|
}
|
|
19
200
|
function compute(definition) {
|
|
20
|
-
|
|
201
|
+
const node = {
|
|
21
202
|
nodeType: "compute",
|
|
22
203
|
...definition
|
|
23
204
|
};
|
|
205
|
+
assertValidComputeNodeDefinition(node);
|
|
206
|
+
return node;
|
|
24
207
|
}
|
|
25
208
|
function action(definition) {
|
|
26
|
-
|
|
209
|
+
const node = {
|
|
27
210
|
nodeType: "action",
|
|
28
211
|
...definition
|
|
29
212
|
};
|
|
213
|
+
assertValidActionNodeDefinition(node);
|
|
214
|
+
return node;
|
|
30
215
|
}
|
|
31
216
|
function shell(definition) {
|
|
32
|
-
|
|
217
|
+
const node = {
|
|
33
218
|
nodeType: "action",
|
|
34
219
|
...definition
|
|
35
220
|
};
|
|
221
|
+
assertValidShellActionNodeDefinition(node);
|
|
222
|
+
return node;
|
|
36
223
|
}
|
|
37
224
|
function checkpoint(definition = {}) {
|
|
38
|
-
|
|
225
|
+
const node = {
|
|
39
226
|
nodeType: "checkpoint",
|
|
40
227
|
...definition
|
|
41
228
|
};
|
|
229
|
+
assertValidCheckpointNodeDefinition(node);
|
|
230
|
+
return node;
|
|
42
231
|
}
|
|
43
232
|
//#endregion
|
|
44
233
|
//#region src/flows/executors/shell.ts
|
|
@@ -122,8 +311,7 @@ async function runShellAction(spec) {
|
|
|
122
311
|
//#endregion
|
|
123
312
|
//#region src/flows/graph.ts
|
|
124
313
|
function validateFlowDefinition(flow) {
|
|
125
|
-
|
|
126
|
-
if (flow.permissions?.reason !== void 0 && !flow.permissions.reason.trim()) throw new Error("Flow permission reason must not be empty");
|
|
314
|
+
assertValidFlowDefinitionShape(flow);
|
|
127
315
|
if (!flow.nodes[flow.startAt]) throw new Error(`Flow start node is missing: ${flow.startAt}`);
|
|
128
316
|
const outgoingEdges = /* @__PURE__ */ new Set();
|
|
129
317
|
for (const edge of flow.edges) {
|
|
@@ -170,6 +358,244 @@ function getByPath(value, jsonPath) {
|
|
|
170
358
|
}, value);
|
|
171
359
|
}
|
|
172
360
|
//#endregion
|
|
361
|
+
//#region src/flows/runtime-support.ts
|
|
362
|
+
function isoNow$1() {
|
|
363
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
364
|
+
}
|
|
365
|
+
function persistRunFailure(store, runDir, state, error) {
|
|
366
|
+
if (state.finishedAt !== void 0 && (state.status === "failed" || state.status === "timed_out")) return Promise.resolve();
|
|
367
|
+
state.status = error instanceof TimeoutError ? "timed_out" : "failed";
|
|
368
|
+
state.updatedAt = isoNow$1();
|
|
369
|
+
state.finishedAt = state.updatedAt;
|
|
370
|
+
state.error = error instanceof Error ? error.message : String(error);
|
|
371
|
+
state.statusDetail = state.currentNode ? `Failed in ${state.currentNode}: ${state.error}` : state.error;
|
|
372
|
+
return store.writeSnapshot(runDir, state, {
|
|
373
|
+
scope: "run",
|
|
374
|
+
type: "run_failed",
|
|
375
|
+
payload: {
|
|
376
|
+
status: state.status,
|
|
377
|
+
error: state.error
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function makeFlowNodeContext(state, input, services) {
|
|
382
|
+
return {
|
|
383
|
+
input,
|
|
384
|
+
outputs: state.outputs,
|
|
385
|
+
results: state.results,
|
|
386
|
+
state,
|
|
387
|
+
services
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function markNodeStarted(state, nodeId, attemptId, nodeType, startedAt, detail) {
|
|
391
|
+
state.status = "running";
|
|
392
|
+
state.waitingOn = void 0;
|
|
393
|
+
state.currentNode = nodeId;
|
|
394
|
+
state.currentAttemptId = attemptId;
|
|
395
|
+
state.currentNodeType = nodeType;
|
|
396
|
+
state.currentNodeStartedAt = startedAt;
|
|
397
|
+
state.lastHeartbeatAt = startedAt;
|
|
398
|
+
state.statusDetail = detail ?? `Running ${nodeType} node ${nodeId}`;
|
|
399
|
+
}
|
|
400
|
+
function clearActiveNode(state, detail) {
|
|
401
|
+
state.currentNode = void 0;
|
|
402
|
+
state.currentAttemptId = void 0;
|
|
403
|
+
state.currentNodeType = void 0;
|
|
404
|
+
state.currentNodeStartedAt = void 0;
|
|
405
|
+
state.lastHeartbeatAt = void 0;
|
|
406
|
+
state.statusDetail = detail;
|
|
407
|
+
}
|
|
408
|
+
function updateStatusDetail(state, detail) {
|
|
409
|
+
if (!detail) return;
|
|
410
|
+
state.statusDetail = detail;
|
|
411
|
+
}
|
|
412
|
+
async function finalizeStepTrace(store, runDir, state, nodeId, attemptId, output, baseTrace) {
|
|
413
|
+
const trace = baseTrace ? structuredClone(baseTrace) : {};
|
|
414
|
+
if (output !== void 0) {
|
|
415
|
+
const inlineOutput = toInlineOutput(output);
|
|
416
|
+
if (inlineOutput !== void 0) trace.outputInline = inlineOutput;
|
|
417
|
+
else trace.outputArtifact = await store.writeArtifact(runDir, state, output, {
|
|
418
|
+
mediaType: outputArtifactMediaType(output),
|
|
419
|
+
extension: outputArtifactExtension(output),
|
|
420
|
+
nodeId,
|
|
421
|
+
attemptId
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return Object.keys(trace).length > 0 ? trace : null;
|
|
425
|
+
}
|
|
426
|
+
function normalizePromptInput(prompt) {
|
|
427
|
+
return typeof prompt === "string" ? textPrompt(prompt) : prompt;
|
|
428
|
+
}
|
|
429
|
+
async function resolveNodeCwd(defaultCwd, cwd, context) {
|
|
430
|
+
if (typeof cwd === "function") {
|
|
431
|
+
const resolved = await cwd(context) ?? defaultCwd;
|
|
432
|
+
return path.resolve(defaultCwd, resolved);
|
|
433
|
+
}
|
|
434
|
+
return path.resolve(defaultCwd, cwd ?? defaultCwd);
|
|
435
|
+
}
|
|
436
|
+
function resolveShellActionCwd(defaultCwd, cwd) {
|
|
437
|
+
return path.resolve(defaultCwd, cwd ?? defaultCwd);
|
|
438
|
+
}
|
|
439
|
+
function summarizePrompt(promptText, explicitDetail) {
|
|
440
|
+
if (explicitDetail) return explicitDetail;
|
|
441
|
+
const line = promptText.split("\n").map((candidate) => candidate.trim()).find((candidate) => candidate.length > 0);
|
|
442
|
+
if (!line) return "Running ACP prompt";
|
|
443
|
+
return `ACP: ${line.length > 120 ? `${line.slice(0, 117)}...` : line}`;
|
|
444
|
+
}
|
|
445
|
+
function createQuietCaptureOutput() {
|
|
446
|
+
const chunks = [];
|
|
447
|
+
return {
|
|
448
|
+
formatter: createOutputFormatter("quiet", { stdout: { write(chunk) {
|
|
449
|
+
chunks.push(chunk);
|
|
450
|
+
} } }),
|
|
451
|
+
read: () => chunks.join("").trim()
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
async function resolveFlowRunTitle(flow, input, flowPath) {
|
|
455
|
+
const titleDefinition = flow.run?.title;
|
|
456
|
+
if (titleDefinition === void 0) return;
|
|
457
|
+
return normalizeFlowRunTitle(typeof titleDefinition === "function" ? await Promise.resolve(titleDefinition({
|
|
458
|
+
input,
|
|
459
|
+
flowName: flow.name,
|
|
460
|
+
flowPath
|
|
461
|
+
})) : titleDefinition);
|
|
462
|
+
}
|
|
463
|
+
function normalizeFlowRunTitle(value) {
|
|
464
|
+
const trimmed = value?.trim();
|
|
465
|
+
return trimmed ? trimmed : void 0;
|
|
466
|
+
}
|
|
467
|
+
function createRunId(flowName) {
|
|
468
|
+
return `${isoNow$1().replaceAll(":", "").replaceAll(".", "")}-${flowName.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase()}-${randomUUID().slice(0, 8)}`;
|
|
469
|
+
}
|
|
470
|
+
function createSessionBindingKey(agentCommand, cwd, handle) {
|
|
471
|
+
return `${agentCommand}::${cwd}::${handle}`;
|
|
472
|
+
}
|
|
473
|
+
function createSessionName(flowName, handle, cwd, runId) {
|
|
474
|
+
return `${flowName}-${handle}-${stableShortHash(cwd)}-${runId.slice(-8)}`;
|
|
475
|
+
}
|
|
476
|
+
function createSessionBundleId(handle, key) {
|
|
477
|
+
return `${handle.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase() || "session"}-${stableShortHash(key)}`;
|
|
478
|
+
}
|
|
479
|
+
function createIsolatedSessionBinding(flowName, runId, attemptId, profile, agent) {
|
|
480
|
+
const key = `isolated::${attemptId}`;
|
|
481
|
+
const handle = "isolated";
|
|
482
|
+
return {
|
|
483
|
+
key,
|
|
484
|
+
handle,
|
|
485
|
+
bundleId: createSessionBundleId(`${handle}-${attemptId}`, `${key}::${agent.cwd}`),
|
|
486
|
+
name: `${flowName}-${attemptId}-${runId.slice(-8)}`,
|
|
487
|
+
profile,
|
|
488
|
+
agentName: agent.agentName,
|
|
489
|
+
agentCommand: agent.agentCommand,
|
|
490
|
+
cwd: agent.cwd,
|
|
491
|
+
acpxRecordId: key,
|
|
492
|
+
acpSessionId: key
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function createSyntheticSessionRecord(options) {
|
|
496
|
+
return {
|
|
497
|
+
schema: SESSION_RECORD_SCHEMA,
|
|
498
|
+
acpxRecordId: options.binding.acpxRecordId,
|
|
499
|
+
acpSessionId: options.binding.acpSessionId,
|
|
500
|
+
agentSessionId: options.binding.agentSessionId,
|
|
501
|
+
agentCommand: options.binding.agentCommand,
|
|
502
|
+
cwd: options.binding.cwd,
|
|
503
|
+
name: options.binding.name,
|
|
504
|
+
createdAt: options.createdAt,
|
|
505
|
+
lastUsedAt: options.updatedAt,
|
|
506
|
+
lastSeq: options.lastSeq,
|
|
507
|
+
lastRequestId: void 0,
|
|
508
|
+
eventLog: defaultSessionEventLog(options.binding.acpxRecordId),
|
|
509
|
+
closed: true,
|
|
510
|
+
closedAt: options.updatedAt,
|
|
511
|
+
title: options.conversation.title,
|
|
512
|
+
messages: options.conversation.messages,
|
|
513
|
+
updated_at: options.conversation.updated_at,
|
|
514
|
+
cumulative_token_usage: options.conversation.cumulative_token_usage,
|
|
515
|
+
request_token_usage: options.conversation.request_token_usage,
|
|
516
|
+
acpx: options.acpxState
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function createNodeResult(options) {
|
|
520
|
+
return {
|
|
521
|
+
attemptId: options.attemptId,
|
|
522
|
+
nodeId: options.nodeId,
|
|
523
|
+
nodeType: options.nodeType,
|
|
524
|
+
outcome: options.outcome,
|
|
525
|
+
startedAt: options.startedAt,
|
|
526
|
+
finishedAt: options.finishedAt,
|
|
527
|
+
durationMs: new Date(options.finishedAt).getTime() - new Date(options.startedAt).getTime(),
|
|
528
|
+
output: options.output,
|
|
529
|
+
error: options.error
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
function outcomeForError(error) {
|
|
533
|
+
if (error instanceof TimeoutError) return "timed_out";
|
|
534
|
+
if (error instanceof InterruptedError) return "cancelled";
|
|
535
|
+
return "failed";
|
|
536
|
+
}
|
|
537
|
+
function stableShortHash(value) {
|
|
538
|
+
return createHash("sha1").update(value).digest("hex").slice(0, 8);
|
|
539
|
+
}
|
|
540
|
+
function nextAttemptId(attemptCounts, nodeId) {
|
|
541
|
+
const next = (attemptCounts.get(nodeId) ?? 0) + 1;
|
|
542
|
+
attemptCounts.set(nodeId, next);
|
|
543
|
+
return `${nodeId}#${next}`;
|
|
544
|
+
}
|
|
545
|
+
function createNodeOutcomePayload(result, trace) {
|
|
546
|
+
return {
|
|
547
|
+
nodeType: result.nodeType,
|
|
548
|
+
outcome: result.outcome,
|
|
549
|
+
durationMs: result.durationMs,
|
|
550
|
+
error: result.error ?? null,
|
|
551
|
+
...trace
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
function attachStepTrace(error, trace) {
|
|
555
|
+
const attached = error instanceof Error ? error : new Error(typeof error === "string" ? error : String(error));
|
|
556
|
+
attached.flowStepTrace = trace;
|
|
557
|
+
return attached;
|
|
558
|
+
}
|
|
559
|
+
function extractAttachedStepTrace(error) {
|
|
560
|
+
if (!(error instanceof Error)) return;
|
|
561
|
+
return error.flowStepTrace;
|
|
562
|
+
}
|
|
563
|
+
function toInlineOutput(value) {
|
|
564
|
+
if (value == null || typeof value === "number" || typeof value === "boolean") return value;
|
|
565
|
+
if (typeof value === "string") return value.length <= 200 && !value.includes("\n") ? value : void 0;
|
|
566
|
+
try {
|
|
567
|
+
const serialized = JSON.stringify(value);
|
|
568
|
+
if (serialized.length <= 200 && !serialized.includes("\n")) return value;
|
|
569
|
+
} catch {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function outputArtifactMediaType(value) {
|
|
574
|
+
return typeof value === "string" ? "text/plain" : "application/json";
|
|
575
|
+
}
|
|
576
|
+
function outputArtifactExtension(value) {
|
|
577
|
+
return typeof value === "string" ? "txt" : "json";
|
|
578
|
+
}
|
|
579
|
+
function findConversationDeltaStart(before, after) {
|
|
580
|
+
const maxOverlap = Math.min(before.length, after.length);
|
|
581
|
+
for (let overlap = maxOverlap; overlap >= 0; overlap -= 1) {
|
|
582
|
+
let matches = true;
|
|
583
|
+
for (let index = 0; index < overlap; index += 1) {
|
|
584
|
+
const beforeMessage = before[before.length - overlap + index];
|
|
585
|
+
const afterMessage = after[index];
|
|
586
|
+
if (!deepEqualJson(beforeMessage, afterMessage)) {
|
|
587
|
+
matches = false;
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (matches) return overlap;
|
|
592
|
+
}
|
|
593
|
+
return 0;
|
|
594
|
+
}
|
|
595
|
+
function deepEqualJson(left, right) {
|
|
596
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
597
|
+
}
|
|
598
|
+
//#endregion
|
|
173
599
|
//#region src/flows/store.ts
|
|
174
600
|
const FLOW_BUNDLE_SCHEMA = "acpx.flow-run-bundle.v1";
|
|
175
601
|
const FLOW_TRACE_SCHEMA = "acpx.flow-trace-event.v1";
|
|
@@ -245,7 +671,7 @@ var FlowRunStore = class {
|
|
|
245
671
|
});
|
|
246
672
|
}
|
|
247
673
|
async writeSnapshot(runDir, state, event) {
|
|
248
|
-
state.updatedAt = isoNow
|
|
674
|
+
state.updatedAt = isoNow();
|
|
249
675
|
await writeJsonAtomic(this.resolveRunPath(runDir, RUN_PROJECTION_PATH), state);
|
|
250
676
|
await writeJsonAtomic(this.resolveRunPath(runDir, LIVE_PROJECTION_PATH), createLiveState(state));
|
|
251
677
|
await writeJsonAtomic(this.resolveRunPath(runDir, STEPS_PROJECTION_PATH), state.steps);
|
|
@@ -253,7 +679,7 @@ var FlowRunStore = class {
|
|
|
253
679
|
await this.appendTrace(runDir, state, event);
|
|
254
680
|
}
|
|
255
681
|
async writeLive(runDir, state, event) {
|
|
256
|
-
state.updatedAt = isoNow
|
|
682
|
+
state.updatedAt = isoNow();
|
|
257
683
|
await writeJsonAtomic(this.resolveRunPath(runDir, LIVE_PROJECTION_PATH), createLiveState(state));
|
|
258
684
|
await this.writeManifest(runDir, state);
|
|
259
685
|
await this.appendTrace(runDir, state, event);
|
|
@@ -261,7 +687,7 @@ var FlowRunStore = class {
|
|
|
261
687
|
async appendTrace(runDir, state, event) {
|
|
262
688
|
const traceEvent = {
|
|
263
689
|
seq: this.nextTraceSeq(runDir),
|
|
264
|
-
at: isoNow
|
|
690
|
+
at: isoNow(),
|
|
265
691
|
runId: state.runId,
|
|
266
692
|
...event
|
|
267
693
|
};
|
|
@@ -340,7 +766,7 @@ var FlowRunStore = class {
|
|
|
340
766
|
this.sessionSeqByBundle.set(sessionKey, seq);
|
|
341
767
|
await this.appendJsonLine(this.resolveRunPath(runDir, path.posix.join(sessionDirPath(binding.bundleId), "events.ndjson")), {
|
|
342
768
|
seq,
|
|
343
|
-
at: isoNow
|
|
769
|
+
at: isoNow(),
|
|
344
770
|
direction,
|
|
345
771
|
message
|
|
346
772
|
});
|
|
@@ -525,7 +951,7 @@ function normalizeArtifactExtension(extension) {
|
|
|
525
951
|
function sessionDirPath(bundleId) {
|
|
526
952
|
return path.posix.join(SESSIONS_DIR, bundleId);
|
|
527
953
|
}
|
|
528
|
-
function isoNow
|
|
954
|
+
function isoNow() {
|
|
529
955
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
530
956
|
}
|
|
531
957
|
//#endregion
|
|
@@ -574,8 +1000,8 @@ var FlowRunner = class {
|
|
|
574
1000
|
flowName: flow.name,
|
|
575
1001
|
runTitle,
|
|
576
1002
|
flowPath: options.flowPath,
|
|
577
|
-
startedAt: isoNow(),
|
|
578
|
-
updatedAt: isoNow(),
|
|
1003
|
+
startedAt: isoNow$1(),
|
|
1004
|
+
updatedAt: isoNow$1(),
|
|
579
1005
|
status: "running",
|
|
580
1006
|
input,
|
|
581
1007
|
outputs: {},
|
|
@@ -602,15 +1028,15 @@ var FlowRunner = class {
|
|
|
602
1028
|
const node = flow.nodes[current];
|
|
603
1029
|
if (!node) throw new Error(`Unknown flow node: ${current}`);
|
|
604
1030
|
const attemptId = nextAttemptId(attemptCounts, current);
|
|
605
|
-
const startedAt = isoNow();
|
|
606
|
-
const context =
|
|
1031
|
+
const startedAt = isoNow$1();
|
|
1032
|
+
const context = makeFlowNodeContext(state, input, this.services);
|
|
607
1033
|
let output;
|
|
608
1034
|
let promptText = null;
|
|
609
1035
|
let rawText = null;
|
|
610
1036
|
let sessionInfo = null;
|
|
611
1037
|
let agentInfo = null;
|
|
612
1038
|
let trace = null;
|
|
613
|
-
|
|
1039
|
+
markNodeStarted(state, current, attemptId, node.nodeType, startedAt, node.statusDetail);
|
|
614
1040
|
await this.store.writeSnapshot(runDir, state, {
|
|
615
1041
|
scope: "node",
|
|
616
1042
|
type: "node_started",
|
|
@@ -626,27 +1052,27 @@ var FlowRunner = class {
|
|
|
626
1052
|
let executionError;
|
|
627
1053
|
try {
|
|
628
1054
|
({output, promptText, rawText, sessionInfo, agentInfo, trace} = await this.executeNode(runDir, state, flow, current, node, context));
|
|
629
|
-
trace = await this.
|
|
1055
|
+
trace = await finalizeStepTrace(this.store, runDir, state, current, attemptId, output, trace);
|
|
630
1056
|
nodeResult = createNodeResult({
|
|
631
1057
|
attemptId,
|
|
632
1058
|
nodeId: current,
|
|
633
1059
|
nodeType: node.nodeType,
|
|
634
1060
|
outcome: "ok",
|
|
635
1061
|
startedAt,
|
|
636
|
-
finishedAt: isoNow(),
|
|
1062
|
+
finishedAt: isoNow$1(),
|
|
637
1063
|
output
|
|
638
1064
|
});
|
|
639
1065
|
} catch (error) {
|
|
640
1066
|
executionError = error;
|
|
641
1067
|
trace = extractAttachedStepTrace(error) ?? trace;
|
|
642
|
-
trace = await this.
|
|
1068
|
+
trace = await finalizeStepTrace(this.store, runDir, state, current, attemptId, void 0, trace);
|
|
643
1069
|
nodeResult = createNodeResult({
|
|
644
1070
|
attemptId,
|
|
645
1071
|
nodeId: current,
|
|
646
1072
|
nodeType: node.nodeType,
|
|
647
1073
|
outcome: outcomeForError(error),
|
|
648
1074
|
startedAt,
|
|
649
|
-
finishedAt: isoNow(),
|
|
1075
|
+
finishedAt: isoNow$1(),
|
|
650
1076
|
error: error instanceof Error ? error.message : String(error)
|
|
651
1077
|
});
|
|
652
1078
|
}
|
|
@@ -654,9 +1080,9 @@ var FlowRunner = class {
|
|
|
654
1080
|
if (nodeResult.outcome === "ok" && node.nodeType === "checkpoint") {
|
|
655
1081
|
state.outputs[current] = output;
|
|
656
1082
|
state.waitingOn = current;
|
|
657
|
-
state.updatedAt = isoNow();
|
|
1083
|
+
state.updatedAt = isoNow$1();
|
|
658
1084
|
state.status = "waiting";
|
|
659
|
-
|
|
1085
|
+
clearActiveNode(state, output?.summary ?? current);
|
|
660
1086
|
state.steps.push({
|
|
661
1087
|
attemptId,
|
|
662
1088
|
nodeId: current,
|
|
@@ -684,8 +1110,8 @@ var FlowRunner = class {
|
|
|
684
1110
|
};
|
|
685
1111
|
}
|
|
686
1112
|
if (nodeResult.outcome === "ok") state.outputs[current] = output;
|
|
687
|
-
state.updatedAt = isoNow();
|
|
688
|
-
|
|
1113
|
+
state.updatedAt = isoNow$1();
|
|
1114
|
+
clearActiveNode(state);
|
|
689
1115
|
state.steps.push({
|
|
690
1116
|
attemptId,
|
|
691
1117
|
nodeId: current,
|
|
@@ -720,9 +1146,9 @@ var FlowRunner = class {
|
|
|
720
1146
|
throw executionError;
|
|
721
1147
|
}
|
|
722
1148
|
state.status = "completed";
|
|
723
|
-
state.finishedAt = isoNow();
|
|
1149
|
+
state.finishedAt = isoNow$1();
|
|
724
1150
|
state.updatedAt = state.finishedAt;
|
|
725
|
-
|
|
1151
|
+
clearActiveNode(state);
|
|
726
1152
|
await this.store.writeSnapshot(runDir, state, {
|
|
727
1153
|
scope: "run",
|
|
728
1154
|
type: "run_completed",
|
|
@@ -733,41 +1159,16 @@ var FlowRunner = class {
|
|
|
733
1159
|
state
|
|
734
1160
|
};
|
|
735
1161
|
} catch (error) {
|
|
736
|
-
await this.
|
|
1162
|
+
await persistRunFailure(this.store, runDir, state, error);
|
|
737
1163
|
throw error;
|
|
738
1164
|
}
|
|
739
1165
|
}, async () => {
|
|
740
|
-
await this.
|
|
1166
|
+
await persistRunFailure(this.store, runDir, state, new InterruptedError());
|
|
741
1167
|
});
|
|
742
1168
|
} finally {
|
|
743
1169
|
await this.closePendingPersistentSessionClients();
|
|
744
1170
|
}
|
|
745
1171
|
}
|
|
746
|
-
async persistRunFailure(runDir, state, error) {
|
|
747
|
-
if (state.finishedAt !== void 0 && (state.status === "failed" || state.status === "timed_out")) return;
|
|
748
|
-
state.status = error instanceof TimeoutError ? "timed_out" : "failed";
|
|
749
|
-
state.updatedAt = isoNow();
|
|
750
|
-
state.finishedAt = state.updatedAt;
|
|
751
|
-
state.error = error instanceof Error ? error.message : String(error);
|
|
752
|
-
state.statusDetail = state.currentNode ? `Failed in ${state.currentNode}: ${state.error}` : state.error;
|
|
753
|
-
await this.store.writeSnapshot(runDir, state, {
|
|
754
|
-
scope: "run",
|
|
755
|
-
type: "run_failed",
|
|
756
|
-
payload: {
|
|
757
|
-
status: state.status,
|
|
758
|
-
error: state.error
|
|
759
|
-
}
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
makeContext(state, input) {
|
|
763
|
-
return {
|
|
764
|
-
input,
|
|
765
|
-
outputs: state.outputs,
|
|
766
|
-
results: state.results,
|
|
767
|
-
state,
|
|
768
|
-
services: this.services
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
1172
|
async executeNode(runDir, state, flow, nodeId, node, context) {
|
|
772
1173
|
switch (node.nodeType) {
|
|
773
1174
|
case "compute": return await this.executeComputeNode(runDir, state, node, context);
|
|
@@ -805,7 +1206,7 @@ var FlowRunner = class {
|
|
|
805
1206
|
cwd: resolveShellActionCwd(this.defaultCwd, execution.cwd),
|
|
806
1207
|
timeoutMs: execution.timeoutMs ?? nodeTimeoutMs
|
|
807
1208
|
};
|
|
808
|
-
|
|
1209
|
+
updateStatusDetail(state, formatShellActionSummary(effectiveExecution));
|
|
809
1210
|
await this.store.writeLive(runDir, state, {
|
|
810
1211
|
scope: "node",
|
|
811
1212
|
type: "node_heartbeat",
|
|
@@ -916,7 +1317,7 @@ var FlowRunner = class {
|
|
|
916
1317
|
};
|
|
917
1318
|
const prompt = normalizePromptInput(await Promise.resolve(node.prompt(context)));
|
|
918
1319
|
const promptText = promptToDisplayText(prompt);
|
|
919
|
-
|
|
1320
|
+
updateStatusDetail(state, summarizePrompt(promptText, node.statusDetail));
|
|
920
1321
|
await this.store.writeLive(runDir, state, {
|
|
921
1322
|
scope: "node",
|
|
922
1323
|
type: "node_heartbeat",
|
|
@@ -934,9 +1335,9 @@ var FlowRunner = class {
|
|
|
934
1335
|
const isolatedBinding = createIsolatedSessionBinding(flow.name, state.runId, state.currentAttemptId ?? randomUUID(), node.profile, agentInfo);
|
|
935
1336
|
const initialIsolatedRecord = createSyntheticSessionRecord({
|
|
936
1337
|
binding: isolatedBinding,
|
|
937
|
-
createdAt: state.currentNodeStartedAt ?? isoNow(),
|
|
938
|
-
updatedAt: state.currentNodeStartedAt ?? isoNow(),
|
|
939
|
-
conversation: createSessionConversation(state.currentNodeStartedAt ?? isoNow()),
|
|
1338
|
+
createdAt: state.currentNodeStartedAt ?? isoNow$1(),
|
|
1339
|
+
updatedAt: state.currentNodeStartedAt ?? isoNow$1(),
|
|
1340
|
+
conversation: createSessionConversation(state.currentNodeStartedAt ?? isoNow$1()),
|
|
940
1341
|
acpxState: void 0,
|
|
941
1342
|
lastSeq: 0
|
|
942
1343
|
});
|
|
@@ -1050,49 +1451,13 @@ var FlowRunner = class {
|
|
|
1050
1451
|
await cancelSessionPrompt({ sessionId: boundSession.acpxRecordId });
|
|
1051
1452
|
});
|
|
1052
1453
|
}
|
|
1053
|
-
markNodeStarted(state, nodeId, attemptId, nodeType, startedAt, detail) {
|
|
1054
|
-
state.status = "running";
|
|
1055
|
-
state.waitingOn = void 0;
|
|
1056
|
-
state.currentNode = nodeId;
|
|
1057
|
-
state.currentAttemptId = attemptId;
|
|
1058
|
-
state.currentNodeType = nodeType;
|
|
1059
|
-
state.currentNodeStartedAt = startedAt;
|
|
1060
|
-
state.lastHeartbeatAt = startedAt;
|
|
1061
|
-
state.statusDetail = detail ?? `Running ${nodeType} node ${nodeId}`;
|
|
1062
|
-
}
|
|
1063
|
-
clearActiveNode(state, detail) {
|
|
1064
|
-
state.currentNode = void 0;
|
|
1065
|
-
state.currentAttemptId = void 0;
|
|
1066
|
-
state.currentNodeType = void 0;
|
|
1067
|
-
state.currentNodeStartedAt = void 0;
|
|
1068
|
-
state.lastHeartbeatAt = void 0;
|
|
1069
|
-
state.statusDetail = detail;
|
|
1070
|
-
}
|
|
1071
|
-
updateStatusDetail(state, detail) {
|
|
1072
|
-
if (!detail) return;
|
|
1073
|
-
state.statusDetail = detail;
|
|
1074
|
-
}
|
|
1075
|
-
async finalizeStepTrace(runDir, state, nodeId, attemptId, output, baseTrace) {
|
|
1076
|
-
const trace = baseTrace ? structuredClone(baseTrace) : {};
|
|
1077
|
-
if (output !== void 0) {
|
|
1078
|
-
const inlineOutput = toInlineOutput(output);
|
|
1079
|
-
if (inlineOutput !== void 0) trace.outputInline = inlineOutput;
|
|
1080
|
-
else trace.outputArtifact = await this.store.writeArtifact(runDir, state, output, {
|
|
1081
|
-
mediaType: outputArtifactMediaType(output),
|
|
1082
|
-
extension: outputArtifactExtension(output),
|
|
1083
|
-
nodeId,
|
|
1084
|
-
attemptId
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
return Object.keys(trace).length > 0 ? trace : null;
|
|
1088
|
-
}
|
|
1089
1454
|
async runWithHeartbeat(runDir, state, nodeId, node, timeoutMs, run, onTimeout) {
|
|
1090
1455
|
const heartbeatMs = Math.max(0, Math.round(node.heartbeatMs ?? DEFAULT_FLOW_HEARTBEAT_MS));
|
|
1091
1456
|
let timer;
|
|
1092
1457
|
let active = true;
|
|
1093
1458
|
const heartbeat = async () => {
|
|
1094
1459
|
if (!active) return;
|
|
1095
|
-
state.lastHeartbeatAt = isoNow();
|
|
1460
|
+
state.lastHeartbeatAt = isoNow$1();
|
|
1096
1461
|
state.updatedAt = state.lastHeartbeatAt;
|
|
1097
1462
|
await this.store.writeLive(runDir, state, {
|
|
1098
1463
|
scope: "node",
|
|
@@ -1229,9 +1594,9 @@ var FlowRunner = class {
|
|
|
1229
1594
|
}
|
|
1230
1595
|
async runIsolatedPrompt(runDir, state, binding, agent, prompt, timeoutMs) {
|
|
1231
1596
|
const capture = createQuietCaptureOutput();
|
|
1232
|
-
const conversation = createSessionConversation(state.currentNodeStartedAt ?? isoNow());
|
|
1597
|
+
const conversation = createSessionConversation(state.currentNodeStartedAt ?? isoNow$1());
|
|
1233
1598
|
let acpxState;
|
|
1234
|
-
recordPromptSubmission(conversation, prompt, state.currentNodeStartedAt ?? isoNow());
|
|
1599
|
+
recordPromptSubmission(conversation, prompt, state.currentNodeStartedAt ?? isoNow$1());
|
|
1235
1600
|
let eventStartSeq;
|
|
1236
1601
|
let eventEndSeq;
|
|
1237
1602
|
const pendingEventWrites = [];
|
|
@@ -1272,7 +1637,7 @@ var FlowRunner = class {
|
|
|
1272
1637
|
await this.store.ensureSessionBundle(runDir, state, sessionInfo);
|
|
1273
1638
|
const syntheticRecord = createSyntheticSessionRecord({
|
|
1274
1639
|
binding: sessionInfo,
|
|
1275
|
-
createdAt: state.currentNodeStartedAt ?? isoNow(),
|
|
1640
|
+
createdAt: state.currentNodeStartedAt ?? isoNow$1(),
|
|
1276
1641
|
updatedAt: conversation.updated_at,
|
|
1277
1642
|
conversation,
|
|
1278
1643
|
acpxState: cloneSessionAcpxState(acpxState),
|
|
@@ -1296,181 +1661,6 @@ var FlowRunner = class {
|
|
|
1296
1661
|
};
|
|
1297
1662
|
}
|
|
1298
1663
|
};
|
|
1299
|
-
function normalizePromptInput(prompt) {
|
|
1300
|
-
return typeof prompt === "string" ? textPrompt(prompt) : prompt;
|
|
1301
|
-
}
|
|
1302
|
-
async function resolveNodeCwd(defaultCwd, cwd, context) {
|
|
1303
|
-
if (typeof cwd === "function") {
|
|
1304
|
-
const resolved = await cwd(context) ?? defaultCwd;
|
|
1305
|
-
return path.resolve(defaultCwd, resolved);
|
|
1306
|
-
}
|
|
1307
|
-
return path.resolve(defaultCwd, cwd ?? defaultCwd);
|
|
1308
|
-
}
|
|
1309
|
-
function resolveShellActionCwd(defaultCwd, cwd) {
|
|
1310
|
-
return path.resolve(defaultCwd, cwd ?? defaultCwd);
|
|
1311
|
-
}
|
|
1312
|
-
function summarizePrompt(promptText, explicitDetail) {
|
|
1313
|
-
if (explicitDetail) return explicitDetail;
|
|
1314
|
-
const line = promptText.split("\n").map((candidate) => candidate.trim()).find((candidate) => candidate.length > 0);
|
|
1315
|
-
if (!line) return "Running ACP prompt";
|
|
1316
|
-
return `ACP: ${line.length > 120 ? `${line.slice(0, 117)}...` : line}`;
|
|
1317
|
-
}
|
|
1318
|
-
function createQuietCaptureOutput() {
|
|
1319
|
-
const chunks = [];
|
|
1320
|
-
return {
|
|
1321
|
-
formatter: createOutputFormatter("quiet", { stdout: { write(chunk) {
|
|
1322
|
-
chunks.push(chunk);
|
|
1323
|
-
} } }),
|
|
1324
|
-
read: () => chunks.join("").trim()
|
|
1325
|
-
};
|
|
1326
|
-
}
|
|
1327
|
-
async function resolveFlowRunTitle(flow, input, flowPath) {
|
|
1328
|
-
const titleDefinition = flow.run?.title;
|
|
1329
|
-
if (titleDefinition === void 0) return;
|
|
1330
|
-
return normalizeFlowRunTitle(typeof titleDefinition === "function" ? await Promise.resolve(titleDefinition({
|
|
1331
|
-
input,
|
|
1332
|
-
flowName: flow.name,
|
|
1333
|
-
flowPath
|
|
1334
|
-
})) : titleDefinition);
|
|
1335
|
-
}
|
|
1336
|
-
function normalizeFlowRunTitle(value) {
|
|
1337
|
-
const trimmed = value?.trim();
|
|
1338
|
-
return trimmed ? trimmed : void 0;
|
|
1339
|
-
}
|
|
1340
|
-
function createRunId(flowName) {
|
|
1341
|
-
return `${isoNow().replaceAll(":", "").replaceAll(".", "")}-${flowName.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase()}-${randomUUID().slice(0, 8)}`;
|
|
1342
|
-
}
|
|
1343
|
-
function createSessionBindingKey(agentCommand, cwd, handle) {
|
|
1344
|
-
return `${agentCommand}::${cwd}::${handle}`;
|
|
1345
|
-
}
|
|
1346
|
-
function createSessionName(flowName, handle, cwd, runId) {
|
|
1347
|
-
return `${flowName}-${handle}-${stableShortHash(cwd)}-${runId.slice(-8)}`;
|
|
1348
|
-
}
|
|
1349
|
-
function createSessionBundleId(handle, key) {
|
|
1350
|
-
return `${handle.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase() || "session"}-${stableShortHash(key)}`;
|
|
1351
|
-
}
|
|
1352
|
-
function createIsolatedSessionBinding(flowName, runId, attemptId, profile, agent) {
|
|
1353
|
-
const key = `isolated::${attemptId}`;
|
|
1354
|
-
const handle = "isolated";
|
|
1355
|
-
return {
|
|
1356
|
-
key,
|
|
1357
|
-
handle,
|
|
1358
|
-
bundleId: createSessionBundleId(`${handle}-${attemptId}`, `${key}::${agent.cwd}`),
|
|
1359
|
-
name: `${flowName}-${attemptId}-${runId.slice(-8)}`,
|
|
1360
|
-
profile,
|
|
1361
|
-
agentName: agent.agentName,
|
|
1362
|
-
agentCommand: agent.agentCommand,
|
|
1363
|
-
cwd: agent.cwd,
|
|
1364
|
-
acpxRecordId: key,
|
|
1365
|
-
acpSessionId: key
|
|
1366
|
-
};
|
|
1367
|
-
}
|
|
1368
|
-
function createSyntheticSessionRecord(options) {
|
|
1369
|
-
return {
|
|
1370
|
-
schema: SESSION_RECORD_SCHEMA,
|
|
1371
|
-
acpxRecordId: options.binding.acpxRecordId,
|
|
1372
|
-
acpSessionId: options.binding.acpSessionId,
|
|
1373
|
-
agentSessionId: options.binding.agentSessionId,
|
|
1374
|
-
agentCommand: options.binding.agentCommand,
|
|
1375
|
-
cwd: options.binding.cwd,
|
|
1376
|
-
name: options.binding.name,
|
|
1377
|
-
createdAt: options.createdAt,
|
|
1378
|
-
lastUsedAt: options.updatedAt,
|
|
1379
|
-
lastSeq: options.lastSeq,
|
|
1380
|
-
lastRequestId: void 0,
|
|
1381
|
-
eventLog: defaultSessionEventLog(options.binding.acpxRecordId),
|
|
1382
|
-
closed: true,
|
|
1383
|
-
closedAt: options.updatedAt,
|
|
1384
|
-
title: options.conversation.title,
|
|
1385
|
-
messages: options.conversation.messages,
|
|
1386
|
-
updated_at: options.conversation.updated_at,
|
|
1387
|
-
cumulative_token_usage: options.conversation.cumulative_token_usage,
|
|
1388
|
-
request_token_usage: options.conversation.request_token_usage,
|
|
1389
|
-
acpx: options.acpxState
|
|
1390
|
-
};
|
|
1391
|
-
}
|
|
1392
|
-
function createNodeResult(options) {
|
|
1393
|
-
return {
|
|
1394
|
-
attemptId: options.attemptId,
|
|
1395
|
-
nodeId: options.nodeId,
|
|
1396
|
-
nodeType: options.nodeType,
|
|
1397
|
-
outcome: options.outcome,
|
|
1398
|
-
startedAt: options.startedAt,
|
|
1399
|
-
finishedAt: options.finishedAt,
|
|
1400
|
-
durationMs: new Date(options.finishedAt).getTime() - new Date(options.startedAt).getTime(),
|
|
1401
|
-
output: options.output,
|
|
1402
|
-
error: options.error
|
|
1403
|
-
};
|
|
1404
|
-
}
|
|
1405
|
-
function outcomeForError(error) {
|
|
1406
|
-
if (error instanceof TimeoutError) return "timed_out";
|
|
1407
|
-
if (error instanceof InterruptedError) return "cancelled";
|
|
1408
|
-
return "failed";
|
|
1409
|
-
}
|
|
1410
|
-
function stableShortHash(value) {
|
|
1411
|
-
return createHash("sha1").update(value).digest("hex").slice(0, 8);
|
|
1412
|
-
}
|
|
1413
|
-
function nextAttemptId(attemptCounts, nodeId) {
|
|
1414
|
-
const next = (attemptCounts.get(nodeId) ?? 0) + 1;
|
|
1415
|
-
attemptCounts.set(nodeId, next);
|
|
1416
|
-
return `${nodeId}#${next}`;
|
|
1417
|
-
}
|
|
1418
|
-
function createNodeOutcomePayload(result, trace) {
|
|
1419
|
-
return {
|
|
1420
|
-
nodeType: result.nodeType,
|
|
1421
|
-
outcome: result.outcome,
|
|
1422
|
-
durationMs: result.durationMs,
|
|
1423
|
-
error: result.error ?? null,
|
|
1424
|
-
...trace
|
|
1425
|
-
};
|
|
1426
|
-
}
|
|
1427
|
-
function attachStepTrace(error, trace) {
|
|
1428
|
-
const attached = error instanceof Error ? error : new Error(typeof error === "string" ? error : String(error));
|
|
1429
|
-
attached.flowStepTrace = trace;
|
|
1430
|
-
return attached;
|
|
1431
|
-
}
|
|
1432
|
-
function extractAttachedStepTrace(error) {
|
|
1433
|
-
if (!(error instanceof Error)) return;
|
|
1434
|
-
return error.flowStepTrace;
|
|
1435
|
-
}
|
|
1436
|
-
function toInlineOutput(value) {
|
|
1437
|
-
if (value == null || typeof value === "number" || typeof value === "boolean") return value;
|
|
1438
|
-
if (typeof value === "string") return value.length <= 200 && !value.includes("\n") ? value : void 0;
|
|
1439
|
-
try {
|
|
1440
|
-
const serialized = JSON.stringify(value);
|
|
1441
|
-
if (serialized.length <= 200 && !serialized.includes("\n")) return value;
|
|
1442
|
-
} catch {
|
|
1443
|
-
return;
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
function outputArtifactMediaType(value) {
|
|
1447
|
-
return typeof value === "string" ? "text/plain" : "application/json";
|
|
1448
|
-
}
|
|
1449
|
-
function outputArtifactExtension(value) {
|
|
1450
|
-
return typeof value === "string" ? "txt" : "json";
|
|
1451
|
-
}
|
|
1452
|
-
function findConversationDeltaStart(before, after) {
|
|
1453
|
-
const maxOverlap = Math.min(before.length, after.length);
|
|
1454
|
-
for (let overlap = maxOverlap; overlap >= 0; overlap -= 1) {
|
|
1455
|
-
let matches = true;
|
|
1456
|
-
for (let index = 0; index < overlap; index += 1) {
|
|
1457
|
-
const beforeMessage = before[before.length - overlap + index];
|
|
1458
|
-
const afterMessage = after[index];
|
|
1459
|
-
if (!deepEqualJson(beforeMessage, afterMessage)) {
|
|
1460
|
-
matches = false;
|
|
1461
|
-
break;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
if (matches) return overlap;
|
|
1465
|
-
}
|
|
1466
|
-
return 0;
|
|
1467
|
-
}
|
|
1468
|
-
function deepEqualJson(left, right) {
|
|
1469
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
1470
|
-
}
|
|
1471
|
-
function isoNow() {
|
|
1472
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1473
|
-
}
|
|
1474
1664
|
//#endregion
|
|
1475
1665
|
//#region src/flows/json.ts
|
|
1476
1666
|
function parseJsonObject(text, options = {}) {
|
|
@@ -1546,6 +1736,6 @@ function scanBalanced(text, startIndex) {
|
|
|
1546
1736
|
return null;
|
|
1547
1737
|
}
|
|
1548
1738
|
//#endregion
|
|
1549
|
-
export { flowRunsBaseDir as a,
|
|
1739
|
+
export { flowRunsBaseDir as a, action as c, defineFlow as d, shell as f, FlowRunner as i, checkpoint as l, parseJsonObject as n, validateFlowDefinition as o, isDefinedFlow as p, parseStrictJsonObject as r, acp as s, extractJsonObject as t, compute as u };
|
|
1550
1740
|
|
|
1551
|
-
//# sourceMappingURL=flows-
|
|
1741
|
+
//# sourceMappingURL=flows-CR7xCmkR.js.map
|