@nt-ai-lab/deterministic-agent-workflow-pi 0.4.3 → 0.5.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/dist/features/pi-extension/entrypoint/pi-workflow-extension-platform.d.ts +15 -0
- package/dist/features/pi-extension/entrypoint/pi-workflow-extension-platform.js +67 -0
- package/dist/features/pi-extension/entrypoint/pi-workflow-extension.d.ts +2 -2
- package/dist/features/pi-extension/entrypoint/pi-workflow-extension.js +90 -78
- package/dist/platform/domain/pi-workflow-extension-types.d.ts +5 -3
- package/package.json +4 -4
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import type { RunnerResult } from '@nt-ai-lab/deterministic-agent-workflow-cli';
|
|
3
|
+
import type { PiSessionIdResult } from '../../../platform/domain/pi-workflow-extension-types';
|
|
4
|
+
/** @riviere-role cli-entrypoint */
|
|
5
|
+
export declare function translationNote(toolName: string): string;
|
|
6
|
+
/** @riviere-role cli-entrypoint */
|
|
7
|
+
export declare function resolveDatabasePath(configured: string | undefined): string;
|
|
8
|
+
/** @riviere-role cli-entrypoint */
|
|
9
|
+
export declare function readSessionId(ctx: ExtensionContext): PiSessionIdResult;
|
|
10
|
+
/** @riviere-role cli-entrypoint */
|
|
11
|
+
export declare function requireSessionFile(ctx: ExtensionContext): string;
|
|
12
|
+
/** @riviere-role cli-entrypoint */
|
|
13
|
+
export declare function notifyRouteResult(ctx: ExtensionContext, pi: ExtensionAPI, result: RunnerResult): void;
|
|
14
|
+
/** @riviere-role cli-entrypoint */
|
|
15
|
+
export declare function readWorkflowInstruction(path: string, note: string): string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/** @riviere-role cli-entrypoint */
|
|
5
|
+
export function translationNote(toolName) {
|
|
6
|
+
return [
|
|
7
|
+
`> **Pi**: When instructions say to run a workflow command, call the \`${toolName}\` tool instead:`,
|
|
8
|
+
'> `operation: "<op>", args: ["<arg>", ...]`.',
|
|
9
|
+
'',
|
|
10
|
+
'---',
|
|
11
|
+
'',
|
|
12
|
+
'',
|
|
13
|
+
].join('\n');
|
|
14
|
+
}
|
|
15
|
+
/** @riviere-role cli-entrypoint */
|
|
16
|
+
export function resolveDatabasePath(configured) {
|
|
17
|
+
if (configured !== undefined && configured !== '')
|
|
18
|
+
return configured;
|
|
19
|
+
const fromEnvironment = process.env['WORKFLOW_EVENTS_DB'];
|
|
20
|
+
if (fromEnvironment !== undefined && fromEnvironment !== '')
|
|
21
|
+
return fromEnvironment;
|
|
22
|
+
return join(homedir(), 'ai-workflow-database', '.workflow-events.db');
|
|
23
|
+
}
|
|
24
|
+
/** @riviere-role cli-entrypoint */
|
|
25
|
+
export function readSessionId(ctx) {
|
|
26
|
+
try {
|
|
27
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
28
|
+
if (sessionId.trim().length === 0)
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
reason: 'Pi returned an empty session UUID.'
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
ok: true,
|
|
35
|
+
sessionId
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
reason: `Pi session UUID is unavailable: ${String(error)}`
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** @riviere-role cli-entrypoint */
|
|
46
|
+
export function requireSessionFile(ctx) {
|
|
47
|
+
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
48
|
+
if (sessionFile === undefined)
|
|
49
|
+
throw new TypeError('Ephemeral Pi sessions are unsupported because no persistent transcript file is available.');
|
|
50
|
+
return sessionFile;
|
|
51
|
+
}
|
|
52
|
+
/** @riviere-role cli-entrypoint */
|
|
53
|
+
export function notifyRouteResult(ctx, pi, result) {
|
|
54
|
+
if (result.exitCode !== 0) {
|
|
55
|
+
ctx.ui.notify(result.output, 'error');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (result.output === '') {
|
|
59
|
+
ctx.ui.notify('Workflow operation completed.', 'info');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
pi.sendUserMessage(result.output);
|
|
63
|
+
}
|
|
64
|
+
/** @riviere-role cli-entrypoint */
|
|
65
|
+
export function readWorkflowInstruction(path, note) {
|
|
66
|
+
return `${note}${readFileSync(path, 'utf8')}`;
|
|
67
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { BaseWorkflowState, RehydratableWorkflow } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
1
|
+
import type { BaseWorkflowState, RehydratableWorkflow, TransitionContext } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
2
2
|
import type { PiWorkflowExtension, PiWorkflowExtensionConfig } from '../../../platform/domain/pi-workflow-extension-types';
|
|
3
3
|
export declare const PI_IDLE_RECOVERY_MESSAGE = "You have stopped. You should never stop until the workflow is complete unless your current state permits stopping.";
|
|
4
4
|
export declare const PI_SESSION_BRANCH_BLOCK_MESSAGE = "Pi session tree navigation and forks are disabled while a workflow is active.";
|
|
5
5
|
/** @riviere-role cli-entrypoint */
|
|
6
|
-
export declare function createPiWorkflowExtension<TWorkflow extends RehydratableWorkflow<TState>, TState extends BaseWorkflowState<TStateName>, TDeps, TStateName extends string = string, TOperation extends string = string>(config: PiWorkflowExtensionConfig<TWorkflow, TState, TDeps, TStateName, TOperation>): PiWorkflowExtension;
|
|
6
|
+
export declare function createPiWorkflowExtension<TWorkflow extends RehydratableWorkflow<TState>, TState extends BaseWorkflowState<TStateName>, TDeps, TStateName extends string = string, TOperation extends string = string, TTransitionContext extends TransitionContext<TState, TStateName> = TransitionContext<TState, TStateName>>(config: PiWorkflowExtensionConfig<TWorkflow, TState, TDeps, TStateName, TOperation, TTransitionContext>): PiWorkflowExtension;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
1
|
import { join } from 'node:path';
|
|
4
2
|
import { WorkflowEngine } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
5
3
|
import { createPreToolUseHandler, createWorkflowRunner, getRepositoryName, } from '@nt-ai-lab/deterministic-agent-workflow-cli';
|
|
@@ -8,77 +6,25 @@ import { Type } from 'typebox';
|
|
|
8
6
|
import { parsePiCommandArguments } from '../../../platform/domain/pi-command-arguments.js';
|
|
9
7
|
import { hasPiWorkflowMarker, PI_WORKFLOW_MARKER_CUSTOM_TYPE, readPiSessionMetadata, } from '../../../platform/infra/external-clients/pi/pi-session-file.js';
|
|
10
8
|
import { getLatestPiAssistantSettlement, PiTranscriptReader, } from '../../../platform/infra/external-clients/pi/pi-transcript-reader.js';
|
|
9
|
+
import { notifyRouteResult, readSessionId, readWorkflowInstruction, requireSessionFile, resolveDatabasePath, translationNote, } from './pi-workflow-extension-platform.js';
|
|
11
10
|
const PI_QUESTION_TOOL = 'question';
|
|
12
11
|
const DEFAULT_COMMAND_NAME = 'workflow';
|
|
13
12
|
const DEFAULT_TOOL_NAME = 'workflow';
|
|
14
13
|
const INITIALIZATION_PENDING_REASON = 'Pi workflow initialization has not completed safely. Tool execution is blocked.';
|
|
14
|
+
const INACTIVE_WORKFLOW_REASON = 'Pi workflow is inactive. Run the workflow init command before using workflow operations.';
|
|
15
15
|
export const PI_IDLE_RECOVERY_MESSAGE = 'You have stopped. You should never stop until the workflow is complete unless your current state permits stopping.';
|
|
16
16
|
export const PI_SESSION_BRANCH_BLOCK_MESSAGE = 'Pi session tree navigation and forks are disabled while a workflow is active.';
|
|
17
17
|
const workflowToolParameters = Type.Object({
|
|
18
18
|
operation: Type.String({ description: 'Workflow operation, for example init or transition' }),
|
|
19
19
|
args: Type.Optional(Type.Array(Type.String({ description: 'One workflow operation argument' }))),
|
|
20
20
|
});
|
|
21
|
-
function translationNote(toolName) {
|
|
22
|
-
return [
|
|
23
|
-
`> **Pi**: When instructions say to run a workflow command, call the \`${toolName}\` tool instead:`,
|
|
24
|
-
'> `operation: "<op>", args: ["<arg>", ...]`.',
|
|
25
|
-
'',
|
|
26
|
-
'---',
|
|
27
|
-
'',
|
|
28
|
-
'',
|
|
29
|
-
].join('\n');
|
|
30
|
-
}
|
|
31
|
-
function resolveDatabasePath(configured) {
|
|
32
|
-
if (configured !== undefined && configured !== '')
|
|
33
|
-
return configured;
|
|
34
|
-
const fromEnvironment = process.env['WORKFLOW_EVENTS_DB'];
|
|
35
|
-
if (fromEnvironment !== undefined && fromEnvironment !== '')
|
|
36
|
-
return fromEnvironment;
|
|
37
|
-
return join(homedir(), 'ai-workflow-database', '.workflow-events.db');
|
|
38
|
-
}
|
|
39
|
-
function readSessionId(ctx) {
|
|
40
|
-
try {
|
|
41
|
-
const sessionId = ctx.sessionManager.getSessionId();
|
|
42
|
-
if (sessionId.trim().length === 0)
|
|
43
|
-
return {
|
|
44
|
-
ok: false,
|
|
45
|
-
reason: 'Pi returned an empty session UUID.',
|
|
46
|
-
};
|
|
47
|
-
return {
|
|
48
|
-
ok: true,
|
|
49
|
-
sessionId,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
return {
|
|
54
|
-
ok: false,
|
|
55
|
-
reason: `Pi session UUID is unavailable: ${String(error)}`,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function requireSessionFile(ctx) {
|
|
60
|
-
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
61
|
-
if (sessionFile === undefined)
|
|
62
|
-
throw new TypeError('Ephemeral Pi sessions are unsupported because no persistent transcript file is available.');
|
|
63
|
-
return sessionFile;
|
|
64
|
-
}
|
|
65
|
-
function notifyRouteResult(ctx, pi, result) {
|
|
66
|
-
if (result.exitCode !== 0) {
|
|
67
|
-
ctx.ui.notify(result.output, 'error');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
if (result.output === '') {
|
|
71
|
-
ctx.ui.notify('Workflow operation completed.', 'info');
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
pi.sendUserMessage(result.output);
|
|
75
|
-
}
|
|
76
21
|
/** @riviere-role cli-entrypoint */
|
|
77
22
|
export function createPiWorkflowExtension(config) {
|
|
78
23
|
const databasePath = resolveDatabasePath(config.databasePath);
|
|
79
24
|
const commandName = config.commandName ?? DEFAULT_COMMAND_NAME;
|
|
80
25
|
const toolName = config.toolName ?? DEFAULT_TOOL_NAME;
|
|
81
26
|
const initializationBySession = new Map();
|
|
27
|
+
const sessionStartsById = new Map();
|
|
82
28
|
const recoveredAssistantBySession = new Map();
|
|
83
29
|
const preToolUse = createPreToolUseHandler({
|
|
84
30
|
bashForbidden: config.bashForbidden,
|
|
@@ -94,23 +40,28 @@ export function createPiWorkflowExtension(config) {
|
|
|
94
40
|
questionToolName: PI_QUESTION_TOOL,
|
|
95
41
|
customGates: config.customGates,
|
|
96
42
|
});
|
|
43
|
+
function buildEngineDeps(ctx, store) {
|
|
44
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
45
|
+
const now = () => new Date().toISOString();
|
|
46
|
+
const note = translationNote(toolName);
|
|
47
|
+
return {
|
|
48
|
+
store,
|
|
49
|
+
getPluginRoot: () => config.pluginRoot,
|
|
50
|
+
getEnvFilePath: () => join(config.pluginRoot, '.pi', 'unused.env'),
|
|
51
|
+
getRepositoryName: () => getRepositoryName(ctx.cwd),
|
|
52
|
+
readFile: (path) => readWorkflowInstruction(path, note),
|
|
53
|
+
appendToFile: () => undefined,
|
|
54
|
+
now,
|
|
55
|
+
transcriptReader: new PiTranscriptReader(() => ctx.sessionManager.getBranch()),
|
|
56
|
+
sessionContext: { getMainSessionId: () => sessionId },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
97
59
|
function useEngine(ctx, operation) {
|
|
98
60
|
const store = createStore(databasePath);
|
|
99
61
|
try {
|
|
62
|
+
const engineDeps = buildEngineDeps(ctx, store);
|
|
63
|
+
const now = engineDeps.now;
|
|
100
64
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
101
|
-
const now = () => new Date().toISOString();
|
|
102
|
-
const note = translationNote(toolName);
|
|
103
|
-
const engineDeps = {
|
|
104
|
-
store,
|
|
105
|
-
getPluginRoot: () => config.pluginRoot,
|
|
106
|
-
getEnvFilePath: () => join(config.pluginRoot, '.pi', 'unused.env'),
|
|
107
|
-
getRepositoryName: () => getRepositoryName(ctx.cwd),
|
|
108
|
-
readFile: (path) => `${note}${readFileSync(path, 'utf8')}`,
|
|
109
|
-
appendToFile: () => undefined,
|
|
110
|
-
now,
|
|
111
|
-
transcriptReader: new PiTranscriptReader(() => ctx.sessionManager.getBranch()),
|
|
112
|
-
sessionContext: { getMainSessionId: () => sessionId },
|
|
113
|
-
};
|
|
114
65
|
const platform = {
|
|
115
66
|
getPluginRoot: () => config.pluginRoot,
|
|
116
67
|
now,
|
|
@@ -125,8 +76,22 @@ export function createPiWorkflowExtension(config) {
|
|
|
125
76
|
store.db.close();
|
|
126
77
|
}
|
|
127
78
|
}
|
|
79
|
+
function hasPersistedWorkflowState(sessionId) {
|
|
80
|
+
const store = createStore(databasePath);
|
|
81
|
+
try {
|
|
82
|
+
return store.hasSessionStarted(sessionId);
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
store.db.close();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
128
88
|
function markInitializationFailed(ctx, sessionId, detail) {
|
|
129
|
-
|
|
89
|
+
return failSession(ctx, sessionId, `Pi workflow initialization failed: ${detail}`);
|
|
90
|
+
}
|
|
91
|
+
function markSafetyUnavailable(ctx, sessionId, detail) {
|
|
92
|
+
return failSession(ctx, sessionId, `Pi workflow safety is unavailable: ${detail}`);
|
|
93
|
+
}
|
|
94
|
+
function failSession(ctx, sessionId, reason) {
|
|
130
95
|
initializationBySession.set(sessionId, {
|
|
131
96
|
type: 'failed',
|
|
132
97
|
reason,
|
|
@@ -142,8 +107,14 @@ export function createPiWorkflowExtension(config) {
|
|
|
142
107
|
const status = initializationBySession.get(session.sessionId);
|
|
143
108
|
if (status?.type === 'ready')
|
|
144
109
|
return undefined;
|
|
110
|
+
if (status?.type === 'inactive')
|
|
111
|
+
return INACTIVE_WORKFLOW_REASON;
|
|
145
112
|
return status?.type === 'failed' ? status.reason : INITIALIZATION_PENDING_REASON;
|
|
146
113
|
}
|
|
114
|
+
function isInactive(ctx) {
|
|
115
|
+
const session = readSessionId(ctx);
|
|
116
|
+
return session.ok && initializationBySession.get(session.sessionId)?.type === 'inactive';
|
|
117
|
+
}
|
|
147
118
|
function parentSafetyFailure(event, ctx) {
|
|
148
119
|
const parentSessionFile = ctx.sessionManager.getHeader()?.parentSession;
|
|
149
120
|
if (parentSessionFile === undefined) {
|
|
@@ -211,7 +182,29 @@ export function createPiWorkflowExtension(config) {
|
|
|
211
182
|
return String(error);
|
|
212
183
|
}
|
|
213
184
|
}
|
|
214
|
-
function runRoute(ctx, args) {
|
|
185
|
+
function runRoute(ctx, args, pi) {
|
|
186
|
+
if (isInactive(ctx) && args[0] === 'init') {
|
|
187
|
+
const session = readSessionId(ctx);
|
|
188
|
+
if (!session.ok)
|
|
189
|
+
return {
|
|
190
|
+
output: session.reason,
|
|
191
|
+
exitCode: 1,
|
|
192
|
+
};
|
|
193
|
+
const event = sessionStartsById.get(session.sessionId);
|
|
194
|
+
if (event === undefined)
|
|
195
|
+
return {
|
|
196
|
+
output: INITIALIZATION_PENDING_REASON,
|
|
197
|
+
exitCode: 1,
|
|
198
|
+
};
|
|
199
|
+
initializationBySession.set(session.sessionId, { type: 'initializing' });
|
|
200
|
+
const failure = initializeSession(event, ctx, pi, session.sessionId);
|
|
201
|
+
if (failure !== undefined)
|
|
202
|
+
return {
|
|
203
|
+
output: markInitializationFailed(ctx, session.sessionId, failure),
|
|
204
|
+
exitCode: 1,
|
|
205
|
+
};
|
|
206
|
+
initializationBySession.set(session.sessionId, { type: 'ready' });
|
|
207
|
+
}
|
|
215
208
|
const notReady = readinessFailure(ctx);
|
|
216
209
|
if (notReady !== undefined)
|
|
217
210
|
return {
|
|
@@ -235,7 +228,7 @@ export function createPiWorkflowExtension(config) {
|
|
|
235
228
|
}
|
|
236
229
|
catch (error) {
|
|
237
230
|
return {
|
|
238
|
-
output:
|
|
231
|
+
output: markSafetyUnavailable(ctx, session.sessionId, `Workflow operation could not establish safe state: ${String(error)}`),
|
|
239
232
|
exitCode: 1,
|
|
240
233
|
};
|
|
241
234
|
}
|
|
@@ -248,6 +241,19 @@ export function createPiWorkflowExtension(config) {
|
|
|
248
241
|
ctx.shutdown();
|
|
249
242
|
return;
|
|
250
243
|
}
|
|
244
|
+
sessionStartsById.set(session.sessionId, event);
|
|
245
|
+
try {
|
|
246
|
+
const hasPersistedWorkflow = hasPersistedWorkflowState(session.sessionId);
|
|
247
|
+
const hasTranscriptWorkflow = hasPiWorkflowMarker(ctx.sessionManager.getEntries());
|
|
248
|
+
if (!hasPersistedWorkflow && !hasTranscriptWorkflow) {
|
|
249
|
+
initializationBySession.set(session.sessionId, { type: 'inactive' });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
markInitializationFailed(ctx, session.sessionId, String(error));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
251
257
|
initializationBySession.set(session.sessionId, { type: 'initializing' });
|
|
252
258
|
const failure = initializeSession(event, ctx, pi, session.sessionId);
|
|
253
259
|
if (failure !== undefined) {
|
|
@@ -257,6 +263,8 @@ export function createPiWorkflowExtension(config) {
|
|
|
257
263
|
initializationBySession.set(session.sessionId, { type: 'ready' });
|
|
258
264
|
});
|
|
259
265
|
pi.on('tool_call', (event, ctx) => {
|
|
266
|
+
if (isInactive(ctx))
|
|
267
|
+
return;
|
|
260
268
|
const notReady = readinessFailure(ctx);
|
|
261
269
|
if (notReady !== undefined)
|
|
262
270
|
return {
|
|
@@ -281,11 +289,13 @@ export function createPiWorkflowExtension(config) {
|
|
|
281
289
|
catch (error) {
|
|
282
290
|
return {
|
|
283
291
|
block: true,
|
|
284
|
-
reason:
|
|
292
|
+
reason: markSafetyUnavailable(ctx, session.sessionId, `Tool safety could not be established: ${String(error)}`),
|
|
285
293
|
};
|
|
286
294
|
}
|
|
287
295
|
});
|
|
288
296
|
pi.on('input', (_event, ctx) => {
|
|
297
|
+
if (isInactive(ctx))
|
|
298
|
+
return;
|
|
289
299
|
const notReady = readinessFailure(ctx);
|
|
290
300
|
if (notReady === undefined)
|
|
291
301
|
return;
|
|
@@ -293,7 +303,7 @@ export function createPiWorkflowExtension(config) {
|
|
|
293
303
|
return { action: 'handled' };
|
|
294
304
|
});
|
|
295
305
|
pi.on('agent_settled', (_event, ctx) => {
|
|
296
|
-
if (readinessFailure(ctx) !== undefined)
|
|
306
|
+
if (isInactive(ctx) || readinessFailure(ctx) !== undefined)
|
|
297
307
|
return;
|
|
298
308
|
const session = readSessionId(ctx);
|
|
299
309
|
if (!session.ok)
|
|
@@ -311,7 +321,7 @@ export function createPiWorkflowExtension(config) {
|
|
|
311
321
|
}
|
|
312
322
|
}
|
|
313
323
|
catch (error) {
|
|
314
|
-
|
|
324
|
+
markSafetyUnavailable(ctx, session.sessionId, `Stopping safety could not be established: ${String(error)}`);
|
|
315
325
|
}
|
|
316
326
|
});
|
|
317
327
|
const blockSessionBranching = (ctx) => {
|
|
@@ -321,6 +331,8 @@ export function createPiWorkflowExtension(config) {
|
|
|
321
331
|
ctx.shutdown();
|
|
322
332
|
return { cancel: true };
|
|
323
333
|
}
|
|
334
|
+
if (isInactive(ctx))
|
|
335
|
+
return undefined;
|
|
324
336
|
const notReady = readinessFailure(ctx);
|
|
325
337
|
if (notReady !== undefined) {
|
|
326
338
|
markInitializationFailed(ctx, session.sessionId, notReady);
|
|
@@ -339,7 +351,7 @@ export function createPiWorkflowExtension(config) {
|
|
|
339
351
|
parameters: workflowToolParameters,
|
|
340
352
|
executionMode: 'sequential',
|
|
341
353
|
async execute(_toolCallId, parameters, _signal, _onUpdate, ctx) {
|
|
342
|
-
const result = runRoute(ctx, [parameters.operation, ...(parameters.args ?? [])]);
|
|
354
|
+
const result = runRoute(ctx, [parameters.operation, ...(parameters.args ?? [])], pi);
|
|
343
355
|
return {
|
|
344
356
|
content: [{
|
|
345
357
|
type: 'text',
|
|
@@ -354,7 +366,7 @@ export function createPiWorkflowExtension(config) {
|
|
|
354
366
|
description: `Execute a deterministic workflow operation: /${commandName} <operation> [args]`,
|
|
355
367
|
handler: async (rawArguments, ctx) => {
|
|
356
368
|
try {
|
|
357
|
-
const result = runRoute(ctx, parsePiCommandArguments(rawArguments));
|
|
369
|
+
const result = runRoute(ctx, parsePiCommandArguments(rawArguments), pi);
|
|
358
370
|
notifyRouteResult(ctx, pi, result);
|
|
359
371
|
}
|
|
360
372
|
catch (error) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ExtensionFactory } from '@earendil-works/pi-coding-agent';
|
|
2
|
-
import type { BaseWorkflowState, RehydratableWorkflow, WorkflowDefinition } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
2
|
+
import type { BaseWorkflowState, RehydratableWorkflow, TransitionContext, WorkflowDefinition } from '@nt-ai-lab/deterministic-agent-workflow-engine';
|
|
3
3
|
import type { PlatformContext, PreToolUseHandlerConfig, RouteMap } from '@nt-ai-lab/deterministic-agent-workflow-cli';
|
|
4
4
|
/** @riviere-role value-object */
|
|
5
5
|
export type PiWorkflowExtension = ExtensionFactory;
|
|
6
6
|
/** @riviere-role value-object */
|
|
7
7
|
export type PiInitializationStatus = {
|
|
8
|
+
readonly type: 'inactive';
|
|
9
|
+
} | {
|
|
8
10
|
readonly type: 'initializing';
|
|
9
11
|
} | {
|
|
10
12
|
readonly type: 'ready';
|
|
@@ -21,8 +23,8 @@ export type PiSessionIdResult = {
|
|
|
21
23
|
readonly reason: string;
|
|
22
24
|
};
|
|
23
25
|
/** @riviere-role value-object */
|
|
24
|
-
export type PiWorkflowExtensionConfig<TWorkflow extends RehydratableWorkflow<TState>, TState extends BaseWorkflowState<TStateName>, TDeps, TStateName extends string = string, TOperation extends string = string> = Omit<PreToolUseHandlerConfig<TWorkflow, TState, TStateName>, 'questionToolName'> & {
|
|
25
|
-
readonly workflowDefinition: WorkflowDefinition<TWorkflow, TState, TDeps, TStateName, TOperation>;
|
|
26
|
+
export type PiWorkflowExtensionConfig<TWorkflow extends RehydratableWorkflow<TState>, TState extends BaseWorkflowState<TStateName>, TDeps, TStateName extends string = string, TOperation extends string = string, TTransitionContext extends TransitionContext<TState, TStateName> = TransitionContext<TState, TStateName>> = Omit<PreToolUseHandlerConfig<TWorkflow, TState, TStateName>, 'questionToolName'> & {
|
|
27
|
+
readonly workflowDefinition: WorkflowDefinition<TWorkflow, TState, TDeps, TStateName, TOperation, TTransitionContext>;
|
|
26
28
|
readonly routes: RouteMap<TWorkflow, TState>;
|
|
27
29
|
readonly buildWorkflowDeps: (platform: PlatformContext) => TDeps;
|
|
28
30
|
readonly pluginRoot: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nt-ai-lab/deterministic-agent-workflow-pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"typebox": "^1.3.7",
|
|
26
|
-
"@nt-ai-lab/deterministic-agent-workflow-cli": "0.4.
|
|
27
|
-
"@nt-ai-lab/deterministic-agent-workflow-event-store": "0.4.
|
|
28
|
-
"@nt-ai-lab/deterministic-agent-workflow-engine": "0.4.
|
|
26
|
+
"@nt-ai-lab/deterministic-agent-workflow-cli": "0.4.6",
|
|
27
|
+
"@nt-ai-lab/deterministic-agent-workflow-event-store": "0.4.6",
|
|
28
|
+
"@nt-ai-lab/deterministic-agent-workflow-engine": "0.4.6"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@earendil-works/pi-coding-agent": "^0.84.4",
|