@nt-ai-lab/deterministic-agent-workflow-pi 0.5.2 → 0.5.4

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.
@@ -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
- 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.";
3
+ export declare const PI_IDLE_RECOVERY_MESSAGE: string;
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,6 +1,6 @@
1
1
  import { join } from 'node:path';
2
2
  import { WorkflowEngine } from '@nt-ai-lab/deterministic-agent-workflow-engine';
3
- import { createPreToolUseHandler, createWorkflowRunner, getRepositoryName, } from '@nt-ai-lab/deterministic-agent-workflow-cli';
3
+ import { createPreToolUseHandler, createWorkflowRunner, formatStopPreventionMessage, getRepositoryName, } from '@nt-ai-lab/deterministic-agent-workflow-cli';
4
4
  import { createStore } from '@nt-ai-lab/deterministic-agent-workflow-event-store';
5
5
  import { Type } from 'typebox';
6
6
  import { parsePiCommandArguments } from '../../../platform/domain/pi-command-arguments.js';
@@ -12,7 +12,7 @@ const DEFAULT_COMMAND_NAME = 'workflow';
12
12
  const DEFAULT_TOOL_NAME = 'workflow';
13
13
  const INITIALIZATION_PENDING_REASON = 'Pi workflow initialization has not completed safely. Tool execution is blocked.';
14
14
  const INACTIVE_WORKFLOW_REASON = 'Pi workflow is inactive. Run the workflow init command before using workflow operations.';
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.';
15
+ export const PI_IDLE_RECOVERY_MESSAGE = formatStopPreventionMessage();
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' }),
@@ -40,23 +40,28 @@ export function createPiWorkflowExtension(config) {
40
40
  questionToolName: PI_QUESTION_TOOL,
41
41
  customGates: config.customGates,
42
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
+ }
43
59
  function useEngine(ctx, operation) {
44
60
  const store = createStore(databasePath);
45
61
  try {
62
+ const engineDeps = buildEngineDeps(ctx, store);
63
+ const now = engineDeps.now;
46
64
  const sessionId = ctx.sessionManager.getSessionId();
47
- const now = () => new Date().toISOString();
48
- const note = translationNote(toolName);
49
- const engineDeps = {
50
- store,
51
- getPluginRoot: () => config.pluginRoot,
52
- getEnvFilePath: () => join(config.pluginRoot, '.pi', 'unused.env'),
53
- getRepositoryName: () => getRepositoryName(ctx.cwd),
54
- readFile: (path) => readWorkflowInstruction(path, note),
55
- appendToFile: () => undefined,
56
- now,
57
- transcriptReader: new PiTranscriptReader(() => ctx.sessionManager.getBranch()),
58
- sessionContext: { getMainSessionId: () => sessionId },
59
- };
60
65
  const platform = {
61
66
  getPluginRoot: () => config.pluginRoot,
62
67
  now,
@@ -71,8 +76,22 @@ export function createPiWorkflowExtension(config) {
71
76
  store.db.close();
72
77
  }
73
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
+ }
74
88
  function markInitializationFailed(ctx, sessionId, detail) {
75
- const reason = `Pi workflow initialization failed: ${detail}`;
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) {
76
95
  initializationBySession.set(sessionId, {
77
96
  type: 'failed',
78
97
  reason,
@@ -209,7 +228,7 @@ export function createPiWorkflowExtension(config) {
209
228
  }
210
229
  catch (error) {
211
230
  return {
212
- output: markInitializationFailed(ctx, session.sessionId, `Workflow operation could not establish safe state: ${String(error)}`),
231
+ output: markSafetyUnavailable(ctx, session.sessionId, `Workflow operation could not establish safe state: ${String(error)}`),
213
232
  exitCode: 1,
214
233
  };
215
234
  }
@@ -224,7 +243,7 @@ export function createPiWorkflowExtension(config) {
224
243
  }
225
244
  sessionStartsById.set(session.sessionId, event);
226
245
  try {
227
- const hasPersistedWorkflow = useEngine(ctx, (engine) => engine.hasSessionStarted(session.sessionId));
246
+ const hasPersistedWorkflow = hasPersistedWorkflowState(session.sessionId);
228
247
  const hasTranscriptWorkflow = hasPiWorkflowMarker(ctx.sessionManager.getEntries());
229
248
  if (!hasPersistedWorkflow && !hasTranscriptWorkflow) {
230
249
  initializationBySession.set(session.sessionId, { type: 'inactive' });
@@ -270,7 +289,7 @@ export function createPiWorkflowExtension(config) {
270
289
  catch (error) {
271
290
  return {
272
291
  block: true,
273
- reason: markInitializationFailed(ctx, session.sessionId, `Tool safety could not be established: ${String(error)}`),
292
+ reason: markSafetyUnavailable(ctx, session.sessionId, `Tool safety could not be established: ${String(error)}`),
274
293
  };
275
294
  }
276
295
  });
@@ -298,11 +317,11 @@ export function createPiWorkflowExtension(config) {
298
317
  const result = useEngine(ctx, (engine) => engine.checkStopping(session.sessionId, 'stop'));
299
318
  if (result.type === 'blocked' && ctx.isIdle() && !ctx.hasPendingMessages()) {
300
319
  recoveredAssistantBySession.set(session.sessionId, settlement.id);
301
- pi.sendUserMessage(PI_IDLE_RECOVERY_MESSAGE);
320
+ pi.sendUserMessage(formatStopPreventionMessage(result.output, config.stopPreventionMessage));
302
321
  }
303
322
  }
304
323
  catch (error) {
305
- markInitializationFailed(ctx, session.sessionId, `Stopping safety could not be established: ${String(error)}`);
324
+ markSafetyUnavailable(ctx, session.sessionId, `Stopping safety could not be established: ${String(error)}`);
306
325
  }
307
326
  });
308
327
  const blockSessionBranching = (ctx) => {
@@ -1,5 +1,5 @@
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;
@@ -23,12 +23,13 @@ export type PiSessionIdResult = {
23
23
  readonly reason: string;
24
24
  };
25
25
  /** @riviere-role value-object */
26
- 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'> & {
27
- 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>;
28
28
  readonly routes: RouteMap<TWorkflow, TState>;
29
29
  readonly buildWorkflowDeps: (platform: PlatformContext) => TDeps;
30
30
  readonly pluginRoot: string;
31
31
  readonly databasePath?: string;
32
32
  readonly commandName?: string;
33
33
  readonly toolName?: string;
34
+ readonly stopPreventionMessage?: string;
34
35
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nt-ai-lab/deterministic-agent-workflow-pi",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
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.5",
27
- "@nt-ai-lab/deterministic-agent-workflow-event-store": "0.4.5",
28
- "@nt-ai-lab/deterministic-agent-workflow-engine": "0.4.5"
26
+ "@nt-ai-lab/deterministic-agent-workflow-cli": "0.4.7",
27
+ "@nt-ai-lab/deterministic-agent-workflow-engine": "0.4.7",
28
+ "@nt-ai-lab/deterministic-agent-workflow-event-store": "0.4.7"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@earendil-works/pi-coding-agent": "^0.84.4",