@parcha/agentrun-pi 0.1.0-beta.2 → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -19
- package/dist/cli.js +5 -3
- package/dist/demo.js +1 -0
- package/dist/extension-service.js +11 -4
- package/dist/extension.js +329 -57
- package/dist/host-addendum.d.ts +4 -0
- package/dist/host-addendum.js +19 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/presentation.js +2 -2
- package/dist/skills/author/SKILL.md +135 -0
- package/{skills → dist/skills}/author/references/jev-decisions.md +9 -8
- package/dist/skills/author/references/language.md +128 -0
- package/dist/skills/author/references/sdk-authoring.md +9 -0
- package/{skills → dist/skills}/author/references/workflow-format.md +7 -15
- package/dist/triage-demo.d.ts +62 -0
- package/dist/triage-demo.js +153 -0
- package/dist/types.d.ts +3 -0
- package/dist/workflow-inspector.d.ts +47 -0
- package/dist/workflow-inspector.js +235 -0
- package/dist/workflow-session.d.ts +19 -0
- package/dist/workflow-session.js +167 -0
- package/dist/workflow-store.d.ts +30 -0
- package/dist/workflow-store.js +249 -0
- package/dist/workflow-view.d.ts +64 -0
- package/dist/workflow-view.js +268 -0
- package/package.json +5 -6
- package/dist/admission.d.ts +0 -6
- package/dist/admission.js +0 -51
- package/dist/author.d.ts +0 -21
- package/dist/author.js +0 -72
- package/dist/benchmark-contract.d.ts +0 -88
- package/dist/benchmark-contract.js +0 -50
- package/dist/benchmark-freeze.d.ts +0 -9
- package/dist/benchmark-freeze.js +0 -9
- package/dist/benchmark.d.ts +0 -127
- package/dist/benchmark.js +0 -260
- package/dist/comparison.d.ts +0 -69
- package/dist/comparison.js +0 -229
- package/dist/skill-bundle.d.ts +0 -5
- package/dist/skill-bundle.js +0 -15
- package/skills/author/SKILL.md +0 -102
- package/skills/author/references/sdk-authoring.md +0 -16
- /package/{skills → dist/skills}/author/examples/evidence-gate.input.json +0 -0
- /package/{skills → dist/skills}/author/examples/evidence-gate.json +0 -0
- /package/{skills → dist/skills}/author/examples/read-file.input.json +0 -0
- /package/{skills → dist/skills}/author/examples/read-file.json +0 -0
- /package/{skills → dist/skills}/author/examples/read-source-decision.input.json +0 -0
- /package/{skills → dist/skills}/author/examples/read-source-decision.json +0 -0
- /package/{skills → dist/skills}/author/examples/release-note.txt +0 -0
- /package/{skills → dist/skills}/author/examples/review-release-notes.input.json +0 -0
- /package/{skills → dist/skills}/author/examples/review-release-notes.json +0 -0
package/dist/extension.js
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
import { Type } from 'typebox';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
2
4
|
import { Compile } from 'typebox/compile';
|
|
3
5
|
import { Text } from '@earendil-works/pi-tui';
|
|
4
6
|
import { createReadToolDefinition, createBashToolDefinition, createEditToolDefinition, createWriteToolDefinition, createGrepToolDefinition, createFindToolDefinition, createLsToolDefinition, VERSION as PI_VERSION, } from '@earendil-works/pi-coding-agent';
|
|
5
|
-
import { formatWorkflowTree, inspectWorkflow } from '@parcha/agentrun-dsl';
|
|
7
|
+
import { formatWorkflowTree, inspectWorkflow, AUTHOR_SKILL_NAME, loadAuthorReference, renderAuthorHostAddendum, } from '@parcha/agentrun-dsl';
|
|
6
8
|
import { createJevRunner } from '@parcha/agentrun-jev';
|
|
7
9
|
import { createPiHostRunner, PI_MODEL_SETUP_MESSAGE } from './host-session.js';
|
|
8
|
-
import {
|
|
10
|
+
import { PI_HOST_ADDENDUM } from './host-addendum.js';
|
|
11
|
+
import { WorkflowExtensionService, ExtensionServiceError, extensionStructuralLimits } from './extension-service.js';
|
|
9
12
|
import { demoInput, demoSearchTool, demoWorkflow, scriptedDemoDeps } from './demo.js';
|
|
10
13
|
import { cleanText as safe, formatRunReport, modelJson } from './presentation.js';
|
|
11
|
-
import { loadPiJevGuide, loadPiWorkflowGuide } from './skill-bundle.js';
|
|
12
14
|
import { ToolInputValidationError, toolInputProblems } from './tool-input-error.js';
|
|
15
|
+
import { WorkflowStore, WorkflowStoreError } from './workflow-store.js';
|
|
16
|
+
import { WorkflowObservation, workflowView, formatWorkflowView, progressLines, readable } from './workflow-view.js';
|
|
17
|
+
import { showWorkflowInspector } from './workflow-inspector.js';
|
|
18
|
+
import { supportTriageWorkflow, supportTriageInputs, supportTriageTools, scriptedSupportTriageDeps } from './triage-demo.js';
|
|
19
|
+
import { restoreWorkflowSession, workflowRunHistory } from './workflow-session.js';
|
|
13
20
|
const constructors = {
|
|
14
21
|
read: createReadToolDefinition, bash: createBashToolDefinition, edit: createEditToolDefinition,
|
|
15
22
|
write: createWriteToolDefinition, grep: createGrepToolDefinition, find: createFindToolDefinition, ls: createLsToolDefinition,
|
|
16
23
|
};
|
|
17
24
|
const mutatingTools = new Set(['bash', 'edit', 'write']);
|
|
18
|
-
const help = 'Describe a task: /agentrun <what you want done>\nTry
|
|
25
|
+
const help = 'Describe a task: /agentrun <what you want done>\nTry support triage: /agentrun triage (fictional, no model calls)\nInspect: /agentrun · Change input: /agentrun input\nSave: /agentrun save <name> · Load: /agentrun load <name>\nLibrary: /agentrun list · History: /agentrun history\nRun: /agentrun run · Setup: /agentrun status\nStop: /agentrun stop (closing the inspector does not stop a run)\nOther examples: /agentrun demo | demo empty | demo live';
|
|
19
26
|
const textResult = (text, details = {}) => ({ content: [{ type: 'text', text: safe(text) }], details });
|
|
27
|
+
function singleTextInput(workflow) {
|
|
28
|
+
const source = workflow;
|
|
29
|
+
const schema = source?.input?.schemaId && source.schemas?.[source.input.schemaId];
|
|
30
|
+
if (schema?.type !== 'object' || !schema.properties || typeof schema.properties !== 'object')
|
|
31
|
+
return;
|
|
32
|
+
const keys = Object.keys(schema.properties);
|
|
33
|
+
return keys.length === 1 && schema.required?.length === 1 && schema.required[0] === keys[0]
|
|
34
|
+
&& schema.properties[keys[0]]?.type === 'string' ? keys[0] : undefined;
|
|
35
|
+
}
|
|
20
36
|
const nativeLimits = Object.freeze({ deadlineMs: 600_000, modelRequests: 50, judgeCalls: 100, toolAttempts: 100,
|
|
21
37
|
nodeMaxTurns: 8, nodeMaxSubmissions: 3, nodeTimeoutMs: 120_000 });
|
|
22
38
|
/** Configure the native extension without granting configuration to workflow authors. */
|
|
@@ -61,15 +77,17 @@ function registerExtension(pi, configuration) {
|
|
|
61
77
|
if (typeof tool.execute !== 'function' || !tool.parameters || typeof tool.parameters !== 'object')
|
|
62
78
|
throw new Error('Host tools require an executable definition and parameter schema');
|
|
63
79
|
Compile(tool.parameters);
|
|
80
|
+
if (tool.resultSchema)
|
|
81
|
+
Compile(tool.resultSchema);
|
|
64
82
|
names.add(tool.name);
|
|
65
|
-
return { ...tool, parameters: structuredClone(tool.parameters) };
|
|
83
|
+
return { ...tool, parameters: structuredClone(tool.parameters), ...(tool.resultSchema ? { resultSchema: structuredClone(tool.resultSchema) } : {}) };
|
|
66
84
|
});
|
|
67
85
|
}
|
|
68
86
|
const active = new Set(pi.getActiveTools());
|
|
69
87
|
const builtins = new Set(pi.getAllTools().filter(t => t.sourceInfo.source === 'builtin').map(t => t.name));
|
|
70
88
|
const definitions = Object.entries(constructors).filter(([name]) => active.has(name) && builtins.has(name) && (trusted || !mutatingTools.has(name)))
|
|
71
89
|
.map(([, factory]) => factory(ctx.cwd));
|
|
72
|
-
return [demoSearchTool(), ...definitions];
|
|
90
|
+
return [demoSearchTool(), ...supportTriageTools(), ...definitions];
|
|
73
91
|
};
|
|
74
92
|
const state = async (ctx) => {
|
|
75
93
|
const key = `${ctx.sessionManager.getSessionId()}:${ctx.cwd}`;
|
|
@@ -84,15 +102,47 @@ function registerExtension(pi, configuration) {
|
|
|
84
102
|
await old.inFlight;
|
|
85
103
|
}
|
|
86
104
|
const tools = toolSet(ctx);
|
|
87
|
-
current = { key, clearStatus: () => { if (ctx.hasUI) {
|
|
105
|
+
current = { key, sessionFile: () => ctx.sessionManager.getSessionFile(), clearStatus: () => { if (ctx.hasUI) {
|
|
88
106
|
ctx.ui.setStatus('agentrun', undefined);
|
|
89
107
|
ctx.ui.setWidget('agentrun', undefined);
|
|
90
108
|
} }, tools, toolNames: tools.map(t => t.name), input: {}, busy: false, closed: false,
|
|
91
109
|
service: new WorkflowExtensionService({ allowedTools: tools.map(t => t.name), limits: serviceLimits }) };
|
|
110
|
+
const restored = restoreWorkflowSession(ctx.sessionManager.getBranch());
|
|
111
|
+
if (restored) {
|
|
112
|
+
current.draft = restored.workflow;
|
|
113
|
+
current.input = restored.input;
|
|
114
|
+
current.demo = restored.demo;
|
|
115
|
+
current.savedName = restored.savedName;
|
|
116
|
+
current.report = restored.report;
|
|
117
|
+
current.observation = restored.observation;
|
|
118
|
+
current.runId = restored.runId;
|
|
119
|
+
}
|
|
92
120
|
return current;
|
|
93
121
|
};
|
|
122
|
+
const persist = (s, running = false, closing = false) => {
|
|
123
|
+
if (current !== s || s.closed && !closing || !s.draft)
|
|
124
|
+
return;
|
|
125
|
+
const record = { version: 1, workflow: s.draft,
|
|
126
|
+
input: s.input, running, createdAt: new Date().toISOString(),
|
|
127
|
+
...(s.savedName ? { savedName: s.savedName } : {}), ...(s.demo ? { demo: s.demo } : {}),
|
|
128
|
+
...(s.runId ? { runId: s.runId } : {}), ...(s.report ? { report: s.report } : {}),
|
|
129
|
+
...(s.observation ? { observation: s.observation } : {}), };
|
|
130
|
+
try {
|
|
131
|
+
const data = structuredClone(record);
|
|
132
|
+
// Never advertise history that this release cannot restore (including
|
|
133
|
+
// non-JSON or oversized receipts). Display/retention limits are not run limits.
|
|
134
|
+
if (!restoreWorkflowSession([{ type: 'custom', customType: 'agentrun:snapshot', data }]))
|
|
135
|
+
throw new Error('Unrestorable workflow receipt');
|
|
136
|
+
pi.appendEntry('agentrun:snapshot', data);
|
|
137
|
+
const file = s.sessionFile();
|
|
138
|
+
s.persistenceWarning = file && existsSync(file) ? undefined : 'Run receipts are in memory only: Pi has not yet persisted this session. Named procedure saves are durable; begin a normal Pi conversation to persist native session history.';
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
s.persistenceWarning = 'Run state could not be retained in the Pi session. Keep this session open; named workflow saving is separate.';
|
|
142
|
+
}
|
|
143
|
+
};
|
|
94
144
|
const readiness = (ctx, s) => ({
|
|
95
|
-
skill: pi.getCommands().some(item => item.name ===
|
|
145
|
+
skill: pi.getCommands().some(item => item.name === `skill:${AUTHOR_SKILL_NAME}` && item.source === 'skill'),
|
|
96
146
|
pi: !!ctx.model && ctx.modelRegistry.getAll().some(model => model.id === ctx.model?.id && model.provider === ctx.model?.provider && model.api === ctx.model?.api),
|
|
97
147
|
jev: !!configuration.createJudge || !!process.env.TYPESAFE_API_KEY?.trim(), sop: false, running: s.busy, workflow: !!s.draft,
|
|
98
148
|
mode: s.draft ? s.demo ? 'scripted' : 'live' : undefined,
|
|
@@ -103,7 +153,7 @@ function registerExtension(pi, configuration) {
|
|
|
103
153
|
pi.sendMessage({ customType: 'agentrun', content: safe(content), display: true, details });
|
|
104
154
|
};
|
|
105
155
|
const commandError = (s, error) => {
|
|
106
|
-
const message = error instanceof Error && (error.name === 'ExtensionServiceError' || /^(No workflow|Inspect a workflow|A workflow|Cannot inspect|Workflow|Code|Executable|Unsupported|Invalid workflow|AgentRun requires|AgentRun authoring|The active Pi)/.test(error.message))
|
|
156
|
+
const message = error instanceof Error && (error instanceof WorkflowStoreError || error.name === 'ExtensionServiceError' || /^(No workflow|Inspect a workflow|A workflow|Cannot inspect|Workflow|Code|Executable|Unsupported|Invalid workflow|AgentRun requires|AgentRun authoring|The active Pi|Saved workflow)/.test(error.message))
|
|
107
157
|
? error.message.slice(0, 2000) : 'AgentRun could not complete this operation. Use /agentrun status to check setup and /agentrun to inspect the workflow. No fallback was selected.';
|
|
108
158
|
show(s, message);
|
|
109
159
|
};
|
|
@@ -138,11 +188,34 @@ function registerExtension(pi, configuration) {
|
|
|
138
188
|
const changed = !s.draft || inspectWorkflow(s.draft).sha256 !== inspection.sha256;
|
|
139
189
|
const nextInput = input === undefined ? changed ? {} : s.input : structuredClone(input);
|
|
140
190
|
s.draft = nextDraft;
|
|
141
|
-
if (changed)
|
|
191
|
+
if (changed) {
|
|
142
192
|
s.demo = undefined;
|
|
193
|
+
s.savedName = undefined;
|
|
194
|
+
s.observation = undefined;
|
|
195
|
+
s.report = undefined;
|
|
196
|
+
s.runId = undefined;
|
|
197
|
+
}
|
|
198
|
+
if (input !== undefined) {
|
|
199
|
+
s.observation = undefined;
|
|
200
|
+
s.report = undefined;
|
|
201
|
+
s.runId = undefined;
|
|
202
|
+
}
|
|
143
203
|
s.input = nextInput;
|
|
204
|
+
if (workflow !== undefined || input !== undefined)
|
|
205
|
+
persist(s);
|
|
144
206
|
return { inspection, tree: formatWorkflowTree(inspection) };
|
|
145
207
|
};
|
|
208
|
+
const view = (ctx, s) => {
|
|
209
|
+
const result = workflowView(s.draft, { input: s.input,
|
|
210
|
+
observation: s.observation, report: s.report, running: s.busy, savedName: s.savedName,
|
|
211
|
+
mode: s.demo ? 'scripted · fictional · no model calls' : 'live adapters',
|
|
212
|
+
model: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : 'not selected', limits,
|
|
213
|
+
availableTools: toolSet(ctx).map(tool => tool.name),
|
|
214
|
+
});
|
|
215
|
+
if (s.persistenceWarning)
|
|
216
|
+
result.summary.push(s.persistenceWarning);
|
|
217
|
+
return result;
|
|
218
|
+
};
|
|
146
219
|
const depsFor = (ctx, s, signal) => {
|
|
147
220
|
let modelCalls = 0, toolCalls = 0;
|
|
148
221
|
const countTool = () => {
|
|
@@ -219,7 +292,7 @@ function registerExtension(pi, configuration) {
|
|
|
219
292
|
throw new ToolInputValidationError(node.label, tool.name, error.problems);
|
|
220
293
|
throw error;
|
|
221
294
|
}
|
|
222
|
-
return !configuration.hostTools && node.tool
|
|
295
|
+
return !configuration.hostTools && ['search', 'support_demo_lookup', 'support_demo_handoff'].includes(node.tool ?? '') ? result.details : { content: result.content, ...(result.details === undefined ? {} : { details: result.details }) };
|
|
223
296
|
},
|
|
224
297
|
};
|
|
225
298
|
};
|
|
@@ -247,46 +320,54 @@ function registerExtension(pi, configuration) {
|
|
|
247
320
|
}
|
|
248
321
|
// Resolve implementations from the execution context even if names are unchanged.
|
|
249
322
|
s.tools = available;
|
|
323
|
+
// Validate the actual input before asking for model credentials or executing code probes.
|
|
324
|
+
s.service.preflight(s.draft, input);
|
|
250
325
|
const prepared = s.service.prepare(s.draft, { allowExecutableCandidates: options.trusted ?? false });
|
|
326
|
+
// Adapter admission is not a run. Failed setup must not leave a running receipt.
|
|
327
|
+
const deps = scripted
|
|
328
|
+
? s.demo === 'triage' || s.demo === 'triage-failure' ? scriptedSupportTriageDeps({ failLookup: s.demo === 'triage-failure' }) : scriptedDemoDeps(s.demo === 'empty')
|
|
329
|
+
: depsFor(ctx, s, signal);
|
|
251
330
|
s.input = structuredClone(input);
|
|
252
331
|
const tree = formatWorkflowTree(inspectWorkflow(s.draft));
|
|
253
332
|
const label = scripted ? 'Scripted demo — fictional sources; no model calls.' : `Running with Pi · ${limits.deadlineMs === null ? 'no workflow deadline; operator cancellation remains available' : `${limits.deadlineMs / 1000}-second workflow deadline`}. Jev is used only for system one nodes.`;
|
|
254
333
|
options.update?.(textResult(`${label}\n\n${tree}`));
|
|
255
334
|
stage(ctx, s, 'agent.run() · starting');
|
|
256
|
-
|
|
257
|
-
|
|
335
|
+
const observation = new WorkflowObservation();
|
|
336
|
+
s.observation = observation.data;
|
|
337
|
+
s.report = undefined;
|
|
338
|
+
s.runId = randomUUID();
|
|
339
|
+
persist(s, true);
|
|
258
340
|
const ordinal = ++runOrdinal;
|
|
259
341
|
let sequence = 0;
|
|
260
342
|
const report = await s.service.run(s.input, {
|
|
261
|
-
deps:
|
|
343
|
+
deps: observation.observe(deps), signal,
|
|
262
344
|
...(configuration.onWorkflowEvent ? { onTraceEvent: (event) => configuration.onWorkflowEvent({ workflowDigest: prepared.digest, runOrdinal: ordinal, sequence: ++sequence, event }) } : {}),
|
|
263
345
|
onEvent: event => {
|
|
264
|
-
|
|
346
|
+
observation.record(event);
|
|
347
|
+
if (current !== s || s.closed)
|
|
265
348
|
return;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const count = (active.get(event.label) ?? 1) - 1;
|
|
270
|
-
if (count)
|
|
271
|
-
active.set(event.label, count);
|
|
272
|
-
else
|
|
273
|
-
active.delete(event.label);
|
|
274
|
-
completed++;
|
|
275
|
-
}
|
|
349
|
+
const progress = progressLines(observation.data);
|
|
350
|
+
if (ctx.mode === 'tui')
|
|
351
|
+
ctx.ui.setWidget('agentrun', [safe(prepared.inspection.name), ...progress.map(safe), '/agentrun inspect · /agentrun stop']);
|
|
276
352
|
else
|
|
277
|
-
|
|
278
|
-
const running = [...active].map(([name, count]) => count > 1 ? `${name} ×${count}` : name).join(', ');
|
|
279
|
-
const progress = `agent.run() · ${completed} finished${running ? ` · ${running}` : ''}`;
|
|
280
|
-
stage(ctx, s, progress);
|
|
281
|
-
if (ctx.hasUI)
|
|
282
|
-
ctx.ui.setWidget('agentrun', [safe(progress), '/agentrun stop to cancel']);
|
|
283
|
-
options.update?.(textResult(`${label}\n\n${tree}\n\n${progress}`));
|
|
353
|
+
options.update?.(textResult(`${label}\n\n${progress.join('\n')}`));
|
|
284
354
|
},
|
|
285
355
|
});
|
|
356
|
+
s.report = report;
|
|
357
|
+
persist(s);
|
|
286
358
|
const summary = formatRunReport(report, scripted);
|
|
287
359
|
const { events: _events, ...modelReport } = report;
|
|
288
360
|
const mode = scripted ? 'scripted' : 'live';
|
|
289
|
-
return textResult(options.modelResult ? modelJson({ mode, ...modelReport }) : summary, { mode, ...report
|
|
361
|
+
return textResult(options.modelResult ? modelJson({ mode, ...modelReport }) : summary + (s.persistenceWarning ? `\n${s.persistenceWarning}` : ''), { mode, ...report,
|
|
362
|
+
// Failure diagnostics must not echo rejected raw arguments. The operator
|
|
363
|
+
// can inspect the retained draft explicitly; the error receipt stays sanitized.
|
|
364
|
+
...(report.error ? {} : { view: workflowView(s.draft, { input: s.input, observation: s.observation, report, mode }) }) });
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
if (error instanceof ExtensionServiceError && error.code === 'admission' && error.message.includes('code requires allowExecutableCandidates')) {
|
|
368
|
+
throw new ExtensionServiceError(error.code, error.message.replaceAll('code requires allowExecutableCandidates', 'Code requires the user command /agentrun run --trusted for each run. This permits local, unsandboxed execution.'));
|
|
369
|
+
}
|
|
370
|
+
throw error;
|
|
290
371
|
}
|
|
291
372
|
finally {
|
|
292
373
|
s.busy = false;
|
|
@@ -314,10 +395,12 @@ function registerExtension(pi, configuration) {
|
|
|
314
395
|
};
|
|
315
396
|
pi.registerTool({
|
|
316
397
|
name: 'agentrun', label: 'AgentRun workflow',
|
|
317
|
-
description:
|
|
398
|
+
description: `Use the ${AUTHOR_SKILL_NAME} skill to compose workflows.` + ' Describe lists available tools and their schemas. Inspect or run an AgentRun DSL workflow in this Pi session. First inspect to show its graph. Agent nodes capture the active Pi model when execution starts. Code needs the user command /agentrun run --trusted for each run. ' + (configuration.hostTools
|
|
318
399
|
? 'Only the explicit host-configured tools are available, including during trusted runs. Outer permission hooks are not inherited. '
|
|
319
|
-
: 'Enabled read-only Pi built-ins are available to declared steps. Shell/write/edit need the trusted command for each run; custom extension tools and permission hooks are not inherited. The search
|
|
320
|
-
parameters: Type.Object({ action: Type.Union([
|
|
400
|
+
: 'Enabled read-only Pi built-ins are available to declared steps. Shell/write/edit need the trusted command for each run; custom extension tools and permission hooks are not inherited. The search and support_demo tools use fictional supplied sources only. ') + 'Save stores a named procedure revision, not its input or permission. Load preflights current host capabilities. Run always restarts; there is no checkpoint resume. Scripted demos stay scripted on rerun.',
|
|
401
|
+
parameters: Type.Object({ action: Type.Union(['describe', 'inspect', 'run', 'save', 'load', 'list'].map(value => Type.Literal(value))),
|
|
402
|
+
name: Type.Optional(Type.String({ description: 'Saved procedure name: lowercase letters, digits, hyphens or underscores.' })),
|
|
403
|
+
digest: Type.Optional(Type.String({ description: 'Optional exact saved SHA-256 revision to load.' })),
|
|
321
404
|
workflow: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
322
405
|
description: 'The complete AgentRun workflow JSON object. Pass the object directly, not a JSON-encoded string. Inspection validates its DSL structure.',
|
|
323
406
|
})), input: Type.Optional(Type.Record(Type.String(), Type.Unknown())) }),
|
|
@@ -325,22 +408,56 @@ function registerExtension(pi, configuration) {
|
|
|
325
408
|
renderResult(result, options) {
|
|
326
409
|
const details = result.details;
|
|
327
410
|
const text = details?.status && details.calls ? options?.expanded
|
|
328
|
-
?
|
|
329
|
-
: result.content.filter(part => part.type === 'text').map(part => part.text).join('\n');
|
|
411
|
+
? details.view ? formatWorkflowView({ ...details.view, output: undefined }) + (details.output === undefined ? '' : `\n\nOutput:\n${readable(details.output, Number.MAX_SAFE_INTEGER)}`) : formatRunReport(details, details.mode === 'scripted') : formatRunReport(details, details.mode === 'scripted')
|
|
412
|
+
: details?.view ? formatWorkflowView(details.view) : result.content.filter(part => part.type === 'text').map(part => part.text).join('\n');
|
|
330
413
|
return new Text(safe(text), 0, 0);
|
|
331
414
|
},
|
|
332
415
|
async execute(_id, args, signal, onUpdate, ctx) {
|
|
333
416
|
const s = await state(ctx);
|
|
417
|
+
const store = new WorkflowStore(ctx.cwd);
|
|
418
|
+
if (args.action === 'save') {
|
|
419
|
+
if (s.busy)
|
|
420
|
+
throw new Error('A workflow is running. Save after it stops.');
|
|
421
|
+
if (!s.draft)
|
|
422
|
+
throw new Error('No workflow to save. Inspect a workflow first.');
|
|
423
|
+
const saved = await store.save(args.name ?? '', s.draft);
|
|
424
|
+
s.savedName = saved.name;
|
|
425
|
+
persist(s);
|
|
426
|
+
return textResult(`Saved ${saved.name} · ${saved.digest.slice(0, 12)}. Input and execution permission are not saved.\nLoad this revision: /agentrun load ${saved.name} ${saved.digest}${s.demo ? '\nScripted demo adapters are not saved. Loading this definition uses live adapters.' : ''}`, saved);
|
|
427
|
+
}
|
|
428
|
+
if (args.action === 'list') {
|
|
429
|
+
const workflows = await store.list();
|
|
430
|
+
return textResult(modelJson(workflows), { workflows });
|
|
431
|
+
}
|
|
432
|
+
if (args.action === 'load') {
|
|
433
|
+
const saved = await store.load(args.name ?? '', args.digest);
|
|
434
|
+
const result = inspect(ctx, s, saved.workflow, args.input);
|
|
435
|
+
s.input = structuredClone(args.input ?? {});
|
|
436
|
+
s.savedName = saved.name;
|
|
437
|
+
s.demo = undefined;
|
|
438
|
+
s.report = undefined;
|
|
439
|
+
s.observation = undefined;
|
|
440
|
+
s.runId = undefined;
|
|
441
|
+
persist(s);
|
|
442
|
+
const preview = view(ctx, s);
|
|
443
|
+
return textResult(modelJson({ preview: formatWorkflowView(preview), workflow: s.draft, input: s.input }), { ...result, saved, view: preview });
|
|
444
|
+
}
|
|
334
445
|
if (args.action === 'describe') {
|
|
335
|
-
const details = { tools: toolSet(ctx).map(t => ({ name: t.name, description: t.description, parameters: t.parameters
|
|
336
|
-
|
|
446
|
+
const details = { tools: toolSet(ctx).map(t => ({ name: t.name, description: t.description, parameters: t.parameters,
|
|
447
|
+
resultSchema: t.resultSchema ?? { type: 'object', properties: { content: { type: 'array', items: { type: 'object' } }, details: {} }, required: ['content'] },
|
|
448
|
+
resultContract: t.resultSchema ? 'Host-declared direct workflow call result.' : 'Pi result envelope; tool-specific details are not declared. Do not invent fields inside details.',
|
|
449
|
+
})),
|
|
450
|
+
limits: { ...limits }, structuralLimits: { ...extensionStructuralLimits }, ...readiness(ctx, s), authoring: { language: loadAuthorReference('language'), workflow: loadAuthorReference('workflow-format'), jev: loadAuthorReference('jev-decisions'), host: renderAuthorHostAddendum(PI_HOST_ADDENDUM) } };
|
|
337
451
|
return textResult(JSON.stringify(details, null, 2), details);
|
|
338
452
|
}
|
|
339
453
|
if (args.action === 'run' && args.workflow !== undefined)
|
|
340
454
|
throw new Error('Inspect the workflow first with action inspect, then run without a workflow argument.');
|
|
341
455
|
if (args.action === 'inspect') {
|
|
342
456
|
const result = inspect(ctx, s, args.workflow, args.input);
|
|
343
|
-
|
|
457
|
+
const preview = view(ctx, s);
|
|
458
|
+
// The author needs the exact definition when editing a restored procedure.
|
|
459
|
+
// Pi's renderer shows the readable view, not this model-facing JSON.
|
|
460
|
+
return textResult(modelJson({ preview: formatWorkflowView(preview), workflow: s.draft, input: s.input }), { ...result, view: preview, tools: toolSet(ctx).map(t => t.name) });
|
|
344
461
|
}
|
|
345
462
|
return execute(ctx, s, args.input ?? s.input, { signal, update: onUpdate, modelResult: true });
|
|
346
463
|
},
|
|
@@ -349,21 +466,157 @@ function registerExtension(pi, configuration) {
|
|
|
349
466
|
description: 'Describe a task, inspect its workflow, or try /agentrun demo',
|
|
350
467
|
async handler(args, ctx) {
|
|
351
468
|
const s = await state(ctx);
|
|
352
|
-
|
|
353
|
-
const command = /^(help|status|stop|demo|run)(?:\s|$)/i.test(raw) ? raw.toLowerCase().replace(/\s+/g, ' ') : raw;
|
|
354
|
-
const words = command.split(/\s+/);
|
|
355
|
-
const commandLike = /^(help|status|stop|demo|run)(?:-|$)/i.test(words[0])
|
|
356
|
-
&& words.slice(1).every(word => word.startsWith('-') || ['live', 'empty'].includes(word));
|
|
469
|
+
let raw = args.trim();
|
|
357
470
|
try {
|
|
471
|
+
if ((!raw || raw === 'inspect') && s.draft && ctx.mode === 'tui') {
|
|
472
|
+
const action = await showWorkflowInspector(ctx, () => view(ctx, s));
|
|
473
|
+
if (!action)
|
|
474
|
+
return;
|
|
475
|
+
if (action === 'save') {
|
|
476
|
+
const name = await ctx.ui.input('Save procedure', s.savedName ?? 'support-triage');
|
|
477
|
+
if (!name)
|
|
478
|
+
return;
|
|
479
|
+
raw = `save ${name}`;
|
|
480
|
+
}
|
|
481
|
+
else if (action === 'load') {
|
|
482
|
+
const stored = await new WorkflowStore(ctx.cwd).list();
|
|
483
|
+
const names = [...new Set(stored.map(item => item.name))];
|
|
484
|
+
if (!names.length) {
|
|
485
|
+
show(s, 'No saved procedures yet. Use /agentrun save <name>.');
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const name = await ctx.ui.select('Load procedure', names);
|
|
489
|
+
if (!name)
|
|
490
|
+
return;
|
|
491
|
+
raw = `load ${name}`;
|
|
492
|
+
}
|
|
493
|
+
else if (action === 'edit') {
|
|
494
|
+
const request = await ctx.ui.input('Edit procedure', 'Describe the change; Pi will preview a candidate before running it.');
|
|
495
|
+
if (!request)
|
|
496
|
+
return;
|
|
497
|
+
pi.sendUserMessage(`/skill:agentrun-author Edit the current procedure: ${request}. Inspect the candidate and explain the change. Do not run it yet.`, { expandPromptTemplates: true });
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
else
|
|
501
|
+
raw = action;
|
|
502
|
+
}
|
|
503
|
+
const command = /^(help|status|stop|demo|triage|run|inspect)(?:\s|$)/i.test(raw) ? raw.toLowerCase().replace(/\s+/g, ' ') : raw;
|
|
504
|
+
const words = command.split(/\s+/);
|
|
505
|
+
const commandLike = /^(help|status|stop|demo|run)(?:-|$)/i.test(words[0])
|
|
506
|
+
&& words.slice(1).every(word => word.startsWith('-') || ['live', 'empty'].includes(word));
|
|
358
507
|
if (command === 'help' || command === '--help' || command === '-h') {
|
|
359
508
|
show(s, help);
|
|
360
509
|
}
|
|
361
|
-
else if (!command) {
|
|
362
|
-
show(s, s.draft ?
|
|
510
|
+
else if (!command || command === 'inspect') {
|
|
511
|
+
show(s, s.draft ? formatWorkflowView(view(ctx, s)) : help);
|
|
512
|
+
}
|
|
513
|
+
else if (/^save(?:\s|$)/.test(command)) {
|
|
514
|
+
if (s.busy)
|
|
515
|
+
throw new Error('A workflow is running. Save after it stops.');
|
|
516
|
+
if (!s.draft)
|
|
517
|
+
throw new Error('No workflow to save. Inspect a workflow first.');
|
|
518
|
+
const saved = await new WorkflowStore(ctx.cwd).save(command.slice(4).trim(), s.draft);
|
|
519
|
+
s.savedName = saved.name;
|
|
520
|
+
persist(s);
|
|
521
|
+
show(s, `Saved ${saved.name} · ${saved.digest.slice(0, 12)}. Input and execution permission are not saved.\nReuse: /agentrun load ${saved.name}\nLoad this revision: /agentrun load ${saved.name} ${saved.digest}${s.demo ? '\nScripted demo adapters are not saved. Loading this definition uses live adapters.' : ''}`, saved);
|
|
522
|
+
}
|
|
523
|
+
else if (/^load(?:\s|$)/.test(command)) {
|
|
524
|
+
const [, name, digest] = command.split(/\s+/);
|
|
525
|
+
const saved = await new WorkflowStore(ctx.cwd).load(name ?? '', digest);
|
|
526
|
+
inspect(ctx, s, saved.workflow);
|
|
527
|
+
s.savedName = saved.name;
|
|
528
|
+
s.input = {};
|
|
529
|
+
s.demo = undefined;
|
|
530
|
+
s.report = undefined;
|
|
531
|
+
s.observation = undefined;
|
|
532
|
+
s.runId = undefined;
|
|
533
|
+
persist(s);
|
|
534
|
+
show(s, `Loaded procedure. Supply new input with /agentrun input. Loading never executes it.\n\n${formatWorkflowView(view(ctx, s))}`);
|
|
535
|
+
}
|
|
536
|
+
else if (command === 'list') {
|
|
537
|
+
const stored = await new WorkflowStore(ctx.cwd).list();
|
|
538
|
+
show(s, stored.length ? stored.map(item => `${item.name} · ${item.workflowName}\n/agentrun load ${item.name} ${item.digest}`).join('\n') : 'No saved procedures yet. Use /agentrun save <name>.', { workflows: stored });
|
|
539
|
+
}
|
|
540
|
+
else if (/^history(?:\s|$)/.test(command)) {
|
|
541
|
+
const history = workflowRunHistory(ctx.sessionManager.getBranch());
|
|
542
|
+
if (!history.length) {
|
|
543
|
+
show(s, 'No retained runs on this Pi session branch yet.');
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
const labels = history.map((run, index) => `${index + 1}. ${inspectWorkflow(run.workflow).name} · ${run.report?.status ?? 'interrupted'} · ${run.createdAt}`);
|
|
547
|
+
let index = Number(command.slice(7).trim()) - 1;
|
|
548
|
+
if (command === 'history' && ctx.mode === 'tui') {
|
|
549
|
+
const selected = await ctx.ui.select('Retained runs on this session branch', labels);
|
|
550
|
+
if (!selected)
|
|
551
|
+
return;
|
|
552
|
+
index = labels.indexOf(selected);
|
|
553
|
+
}
|
|
554
|
+
if (!Number.isInteger(index) || index < 0 || index >= history.length) {
|
|
555
|
+
show(s, `${labels.join('\n')}\n\nInspect: /agentrun history <number>`, { runs: history.map(run => ({ runId: run.runId, createdAt: run.createdAt, digest: run.report?.digest, status: run.report?.status })) });
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const run = history[index];
|
|
559
|
+
const receipt = workflowView(run.workflow, { input: run.input, observation: run.observation, report: run.report, mode: run.demo ? 'scripted' : 'live adapters', savedName: run.savedName });
|
|
560
|
+
// History is read-only. It never replaces the active draft or replays a run.
|
|
561
|
+
if (ctx.mode === 'tui')
|
|
562
|
+
await showWorkflowInspector(ctx, () => ({ ...receipt, readOnly: true }));
|
|
563
|
+
else
|
|
564
|
+
show(s, formatWorkflowView(receipt), { run });
|
|
565
|
+
}
|
|
566
|
+
else if (/^input(?:\s|$)/.test(command)) {
|
|
567
|
+
if (!s.draft)
|
|
568
|
+
throw new Error('No workflow yet. Load or describe a procedure first.');
|
|
569
|
+
if (s.busy)
|
|
570
|
+
throw new Error('A workflow is running. Stop it before changing its input.');
|
|
571
|
+
let supplied = raw.slice(5).trim();
|
|
572
|
+
if (!supplied && ctx.hasUI)
|
|
573
|
+
supplied = await ctx.ui.input('New workflow input', 'Describe the new case in plain language, or paste a JSON object.') ?? '';
|
|
574
|
+
if (!supplied) {
|
|
575
|
+
show(s, 'Use /agentrun input <describe the new case>, or ask Pi to use new input. Nothing was run.');
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (supplied.startsWith('{')) {
|
|
579
|
+
let input;
|
|
580
|
+
try {
|
|
581
|
+
input = JSON.parse(supplied);
|
|
582
|
+
}
|
|
583
|
+
catch {
|
|
584
|
+
throw new Error('Workflow input must be valid JSON, or describe it in plain language.');
|
|
585
|
+
}
|
|
586
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
587
|
+
throw new Error('Workflow input must be an object.');
|
|
588
|
+
inspect(ctx, s, undefined, input);
|
|
589
|
+
show(s, `Input updated. Nothing was run.\n\n${formatWorkflowView(view(ctx, s))}`);
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
const key = singleTextInput(s.draft);
|
|
593
|
+
if (key) {
|
|
594
|
+
inspect(ctx, s, undefined, { [key]: supplied });
|
|
595
|
+
show(s, `Input updated. Nothing was run.\n\n${formatWorkflowView(view(ctx, s))}`);
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
pi.sendUserMessage(`/skill:agentrun-author Set new input for the current inspected workflow: ${supplied}. Keep the procedure unchanged; inspect with input only. Ask for missing facts instead of inventing them. Do not run yet.`, { expandPromptTemplates: true });
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
else if (/^triage(?:\s|$)/.test(command)) {
|
|
603
|
+
const parts = command.split(/\s+/).slice(1);
|
|
604
|
+
const live = parts[0] === 'live';
|
|
605
|
+
const name = parts[live ? 1 : 0] ?? 'billing';
|
|
606
|
+
if (!['billing', 'technical', 'ambiguous', 'failure'].includes(name) || parts.length > (live ? 2 : 1) || live && name === 'failure') {
|
|
607
|
+
show(s, 'Use /agentrun triage [billing|technical|ambiguous|failure], or /agentrun triage live [billing|technical|ambiguous].');
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const input = structuredClone(supportTriageInputs[name === 'failure' ? 'billing' : name]);
|
|
611
|
+
inspect(ctx, s, supportTriageWorkflow, input);
|
|
612
|
+
s.demo = live ? undefined : name === 'failure' ? 'triage-failure' : 'triage';
|
|
613
|
+
show(s, `Fictional support triage · ${live ? 'real model calls' : 'scripted, no model calls'}. No customer actions.\n${formatWorkflowView(view(ctx, s))}`);
|
|
614
|
+
const result = await execute(ctx, s, input);
|
|
615
|
+
show(s, result.content[0].text, result.details);
|
|
363
616
|
}
|
|
364
617
|
else if (command === 'status') {
|
|
365
618
|
const ready = readiness(ctx, s);
|
|
366
|
-
show(s, `agent.run() · ${s.busy ? 'running' : 'idle'}\nDemo: ready — /agentrun demo (no keys or model calls)\nWorkflow: ${s.draft ? `${modelJson(inspectWorkflow(s.draft).name)} · ${s.demo ? 'scripted' : 'live adapters'}` : 'none — run the demo or describe a task
|
|
619
|
+
show(s, `agent.run() · ${s.busy ? 'running' : 'idle'}\nDemo: ready — /agentrun demo (no keys or model calls)\nWorkflow: ${s.draft ? `${modelJson(inspectWorkflow(s.draft).name)} · ${s.demo ? 'scripted' : 'live adapters'}` : 'none — load a saved procedure, run the demo, or describe a task'}\n\nFor your own workflows:\nPi host: ${PI_VERSION}${PI_VERSION === '0.87.0' ? '' : ' (tested on 0.87.0; use the bundled ./node_modules/.bin/pi)'}\nSkill: ${ready.skill ? 'loaded — /agentrun <task>' : 'missing — enable package skills, then /reload'}\nPi: ${ready.pi ? 'selected model available (connection not tested)' : 'no usable active model — /login to connect a provider, then /model to select it'}\nJev: ${ready.jev ? 'configuration present (connection not tested)' : 'not configured — only needed for system one decisions; set TYPESAFE_API_KEY before starting Pi'}`, ready);
|
|
367
620
|
}
|
|
368
621
|
else if (command === 'stop') {
|
|
369
622
|
s.controller?.abort();
|
|
@@ -385,12 +638,12 @@ function registerExtension(pi, configuration) {
|
|
|
385
638
|
else {
|
|
386
639
|
if (s.busy)
|
|
387
640
|
throw new Error('A workflow is running. Stop it before starting another.');
|
|
388
|
-
if (!pi.getCommands().some(item => item.name ===
|
|
641
|
+
if (!pi.getCommands().some(item => item.name === `skill:${AUTHOR_SKILL_NAME}` && item.source === 'skill')) {
|
|
389
642
|
throw new Error('AgentRun authoring skill is unavailable. Enable package skills, then /reload. Run /agentrun status to check discovery.');
|
|
390
643
|
}
|
|
391
644
|
if (!readiness(ctx, s).pi)
|
|
392
645
|
throw new Error(PI_MODEL_SETUP_MESSAGE);
|
|
393
|
-
pi.sendUserMessage(`/skill
|
|
646
|
+
pi.sendUserMessage(`/skill:${AUTHOR_SKILL_NAME} ${raw}`, { expandPromptTemplates: true });
|
|
394
647
|
}
|
|
395
648
|
}
|
|
396
649
|
catch (error) {
|
|
@@ -398,22 +651,41 @@ function registerExtension(pi, configuration) {
|
|
|
398
651
|
}
|
|
399
652
|
},
|
|
400
653
|
});
|
|
401
|
-
const closeSession = async () => {
|
|
654
|
+
const closeSession = async (retainFinal = false) => {
|
|
402
655
|
if (!current)
|
|
403
656
|
return;
|
|
404
|
-
const old = current;
|
|
657
|
+
const old = current, wasRunning = old.busy;
|
|
405
658
|
old.clearStatus();
|
|
406
|
-
current = undefined;
|
|
407
659
|
old.closed = true;
|
|
408
660
|
old.controller?.abort();
|
|
409
661
|
await old.service.dispose();
|
|
410
662
|
await old.inFlight;
|
|
663
|
+
// Only before-switch/shutdown hooks still own the originating branch. A
|
|
664
|
+
// session_tree event is already on another branch and must never receive this receipt.
|
|
665
|
+
if (retainFinal && wasRunning && old.report)
|
|
666
|
+
persist(old, false, true);
|
|
667
|
+
if (current === old)
|
|
668
|
+
current = undefined;
|
|
411
669
|
};
|
|
412
|
-
pi.on('session_shutdown', closeSession);
|
|
413
|
-
pi.on('session_before_switch', closeSession);
|
|
414
|
-
pi.on('session_before_fork', closeSession);
|
|
670
|
+
pi.on('session_shutdown', () => closeSession(true));
|
|
671
|
+
pi.on('session_before_switch', () => closeSession(true));
|
|
672
|
+
pi.on('session_before_fork', () => closeSession(true));
|
|
415
673
|
pi.on('session_start', async (_event, ctx) => {
|
|
416
674
|
if (current && current.key !== `${ctx.sessionManager.getSessionId()}:${ctx.cwd}`)
|
|
417
675
|
await closeSession();
|
|
676
|
+
await state(ctx);
|
|
677
|
+
});
|
|
678
|
+
pi.on('session_tree', async (_event, ctx) => { await closeSession(); await state(ctx); });
|
|
679
|
+
pi.registerEntryRenderer('agentrun:snapshot', (entry, options) => {
|
|
680
|
+
if (entry.data?.running)
|
|
681
|
+
return undefined;
|
|
682
|
+
const snapshot = restoreWorkflowSession([entry]);
|
|
683
|
+
if (!snapshot)
|
|
684
|
+
return undefined;
|
|
685
|
+
if (!snapshot.report && !snapshot.running)
|
|
686
|
+
return undefined;
|
|
687
|
+
return new Text(safe(options.expanded ? formatWorkflowView(workflowView(snapshot.workflow, {
|
|
688
|
+
input: snapshot.input, report: snapshot.report, observation: snapshot.observation, mode: snapshot.demo ? 'scripted' : 'live adapters',
|
|
689
|
+
})) : `AgentRun receipt · ${snapshot.report?.status ?? 'interrupted'} · ${inspectWorkflow(snapshot.workflow).name}`), 0, 0);
|
|
418
690
|
});
|
|
419
691
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AuthorHostAddendum } from '@parcha/agentrun-dsl';
|
|
2
|
+
/** What this extension adds to the shared workflow language: its commands, tools and unavailable transports.
|
|
3
|
+
* The packaged skill is rendered with it, and `describe` returns it as `authoring.host`. */
|
|
4
|
+
export declare const PI_HOST_ADDENDUM: AuthorHostAddendum;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { WORKFLOW_NODE_KINDS } from '@parcha/agentrun-dsl';
|
|
2
|
+
/** What this extension adds to the shared workflow language: its commands, tools and unavailable transports.
|
|
3
|
+
* The packaged skill is rendered with it, and `describe` returns it as `authoring.host`. */
|
|
4
|
+
export const PI_HOST_ADDENDUM = Object.freeze({
|
|
5
|
+
name: 'Pi extension',
|
|
6
|
+
nodeKinds: WORKFLOW_NODE_KINDS.filter(kind => kind !== 'artifact'),
|
|
7
|
+
rules: [
|
|
8
|
+
'Call agentrun with action describe first, then inspect the complete workflow with its input, then run without a workflow argument.',
|
|
9
|
+
'Use exactly the tools describe returns. Without host-configured tools these are the active read-only built-ins (read, grep, find, ls), and bash, edit and write exist only in a trusted run; a host that configures its tools offers only those, including in trusted runs. The search tool reads fictional demo sources only.',
|
|
10
|
+
'Code nodes and mutating tools run only after the user issues /agentrun run --trusted for that run. Trusted execution is local and unsandboxed.',
|
|
11
|
+
'A call uses via tool with a tool describe returns. Shell and executor calls and artifact delivery are unavailable.',
|
|
12
|
+
'This extension supplies no SOP text: do not run a workflow with sopSection here; it needs an SDK host that supplies the authoritative SOP.',
|
|
13
|
+
'Custom extension tools and outer permission hooks are not inherited, including in trusted runs.',
|
|
14
|
+
'A preview, procedure edit or input change does not authorize execution: inspect it, report Inspected — not run, and execute only when requested.',
|
|
15
|
+
'Use /agentrun to inspect the current graph, /agentrun input to change input, /agentrun save and /agentrun load for named definition revisions, /agentrun history for retained receipts, /agentrun run to restart, and /agentrun stop to request cancellation; closing the inspector does not stop a run.',
|
|
16
|
+
'Saving retains the definition without input or execution permission; loading rechecks current host capabilities and never resumes an interrupted run.',
|
|
17
|
+
'The structural limits describe returns bound node count, map concurrency and parallel branches.',
|
|
18
|
+
],
|
|
19
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from "./runner.js";
|
|
2
|
-
export * from "./author.js";
|
|
3
2
|
export * from "./types.js";
|
|
4
3
|
export { createPiHostRunner, createPiHostSessionFactory } from './host-session.js';
|
|
5
4
|
export { WorkflowExtensionService } from './extension-service.js';
|
|
6
|
-
export {
|
|
5
|
+
export { PI_HOST_ADDENDUM } from './host-addendum.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from "./runner.js";
|
|
2
|
-
export * from "./author.js";
|
|
3
2
|
export * from "./types.js";
|
|
4
3
|
export { createPiHostRunner, createPiHostSessionFactory } from './host-session.js';
|
|
5
4
|
export { WorkflowExtensionService } from './extension-service.js';
|
|
6
|
-
export {
|
|
5
|
+
export { PI_HOST_ADDENDUM } from './host-addendum.js';
|
package/dist/presentation.js
CHANGED
|
@@ -12,7 +12,7 @@ function lines(value, depth = 0) {
|
|
|
12
12
|
}).concat(value.length > 30 ? [`… ${value.length - 30} more items in the structured result`] : []);
|
|
13
13
|
const entries = Object.entries(value);
|
|
14
14
|
return entries.slice(0, 30).flatMap(([key, item]) => {
|
|
15
|
-
const label = key.replace(/([a-z])([A-Z])/g,
|
|
15
|
+
const label = key.replace(/([a-z])([A-Z])/g, (_, first, upper) => `${first} ${upper.toLowerCase()}`).replace(/_/g, ' ');
|
|
16
16
|
const children = lines(item, depth + 1);
|
|
17
17
|
return children.length === 1 ? [`${label}: ${children[0]}`] : [`${label}:`, ...children.map(line => ` ${line}`)];
|
|
18
18
|
}).concat(entries.length > 30 ? [`… ${entries.length - 30} more fields in the structured result`] : []);
|
|
@@ -30,5 +30,5 @@ export function formatRunReport(report, scripted = false) {
|
|
|
30
30
|
const trace = report.traceTruncated ? `\nTrace retention is partial${report.trace ? ` (${report.trace.droppedEvents} valid events omitted, ${report.trace.rejectedEvents} rejected)` : ''}; this does not mean the output is truncated.` : '';
|
|
31
31
|
const clipped = body.length > 12_000 ? `${body.slice(0, 12_000)}\n… Full output is in the structured result.` : body;
|
|
32
32
|
const status = report.status === 'escalated' ? 'stopped — needs attention (escalated)' : report.status;
|
|
33
|
-
return cleanText(`${scripted ? 'Scripted demo' : 'Workflow'}: ${status}${report.error ? ` (${report.error.code})` : ''}\n\n${clipped}${recovery}${uncertain}${trace}\n\nWorkflow calls: ${report.calls.tool} direct tool call${report.calls.tool === 1 ? '' : 's'}, ${report.calls.judge} system one decision${report.calls.judge === 1 ? '' : 's'}, ${report.calls.agent} model step${report.calls.agent === 1 ? '' : 's'}.${scripted ? '\nScripted responses; no model calls. Replay: /agentrun run.
|
|
33
|
+
return cleanText(`${scripted ? 'Scripted demo' : 'Workflow'}: ${status}${report.error ? ` (${report.error.code})` : ''}\n\n${clipped}${recovery}${uncertain}${trace}\n\nWorkflow calls: ${report.calls.tool} direct tool call${report.calls.tool === 1 ? '' : 's'}, ${report.calls.judge} system one decision${report.calls.judge === 1 ? '' : 's'}, ${report.calls.agent} model step${report.calls.agent === 1 ? '' : 's'}.${scripted ? '\nScripted responses; no model calls. Replay: /agentrun run. Example modes: /agentrun help.' : ''}`);
|
|
34
34
|
}
|