@marcoscale98/pi-extensible-workflows 5.17.0-fork.1 → 6.2.1-fork.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +2 -2
  3. package/dist/src/agent-execution.d.ts +43 -10
  4. package/dist/src/agent-execution.js +442 -162
  5. package/dist/src/background-widget.d.ts +5 -1
  6. package/dist/src/background-widget.js +5 -10
  7. package/dist/src/decoders.d.ts +2 -3
  8. package/dist/src/decoders.js +59 -37
  9. package/dist/src/execution.d.ts +6 -2
  10. package/dist/src/execution.js +48 -7
  11. package/dist/src/host-delivery.js +5 -8
  12. package/dist/src/host-navigator.js +5 -2
  13. package/dist/src/host-phases.d.ts +1 -0
  14. package/dist/src/host-recovery.d.ts +11 -8
  15. package/dist/src/host-recovery.js +14 -22
  16. package/dist/src/host-runtime.js +56 -5
  17. package/dist/src/host-view.d.ts +6 -1
  18. package/dist/src/host-view.js +46 -20
  19. package/dist/src/host.d.ts +2 -2
  20. package/dist/src/host.js +246 -118
  21. package/dist/src/index.d.ts +1 -2
  22. package/dist/src/index.js +1985 -1690
  23. package/dist/src/index.js.map +3 -3
  24. package/dist/src/paths.d.ts +8 -5
  25. package/dist/src/paths.js +24 -13
  26. package/dist/src/persistence.d.ts +1 -0
  27. package/dist/src/persistence.js +1 -0
  28. package/dist/src/pi-runtime-runner.js +4 -1
  29. package/dist/src/registry.d.ts +9 -7
  30. package/dist/src/registry.js +29 -71
  31. package/dist/src/runtime/agent-runner.d.ts +2 -0
  32. package/dist/src/script-tools.d.ts +27 -0
  33. package/dist/src/script-tools.js +87 -0
  34. package/dist/src/session-lease.d.ts +1 -1
  35. package/dist/src/session-lease.js +45 -11
  36. package/dist/src/settings.d.ts +19 -3
  37. package/dist/src/settings.js +63 -50
  38. package/dist/src/store.d.ts +3 -1
  39. package/dist/src/store.js +17 -1
  40. package/dist/src/trajectory.d.ts +12 -3
  41. package/dist/src/trajectory.js +32 -11
  42. package/dist/src/types.d.ts +129 -45
  43. package/dist/src/types.js +5 -8
  44. package/dist/src/utils.d.ts +21 -1
  45. package/dist/src/utils.js +46 -6
  46. package/dist/src/validation.d.ts +14 -3
  47. package/dist/src/validation.js +143 -87
  48. package/dist/starter/index.js +8 -11
  49. package/dist/starter/index.js.map +1 -1
  50. package/dist/starter/review-loop.d.ts +0 -13
  51. package/dist/starter/review-loop.js +8 -9
  52. package/dist/subagents/index.js +904 -956
  53. package/dist/subagents/index.js.map +3 -3
  54. package/dist/subagents/src/contracts.d.ts +48 -31
  55. package/dist/subagents/src/contracts.js +20 -9
  56. package/dist/subagents/src/index.d.ts +1 -1
  57. package/dist/subagents/src/index.js +14 -8
  58. package/dist/subagents/src/manager.js +52 -73
  59. package/dist/subagents/src/navigator.js +3 -14
  60. package/dist/subagents/src/view.d.ts +1 -1
  61. package/dist/subagents/src/view.js +15 -68
  62. package/dist/subagents/src/worktree.js +1 -1
  63. package/dist/trajectory/assets/index.html +35 -13
  64. package/dist/trajectory/index.js +576 -932
  65. package/dist/trajectory/index.js.map +3 -3
  66. package/dist/trajectory/src/assets/index.html +35 -13
  67. package/dist/trajectory/src/index.js +134 -104
  68. package/dist/trajectory/src/server.js +268 -27
  69. package/dist/trajectory/src/server.js.map +3 -3
  70. package/dist/trajectory/src/startup-mutex.d.ts +17 -0
  71. package/dist/trajectory/src/startup-mutex.js +172 -0
  72. package/examples/workflow-extension-template/README.md +4 -7
  73. package/examples/workflow-extension-template/extension.test.mjs +4 -8
  74. package/examples/workflow-extension-template/index.js +0 -3
  75. package/package.json +10 -10
  76. package/skills/pi-extensible-workflows/SKILL.md +12 -8
  77. package/src/agent-execution.ts +412 -164
  78. package/src/background-widget.ts +5 -11
  79. package/src/decoders.ts +51 -37
  80. package/src/execution.ts +46 -9
  81. package/src/host-delivery.ts +5 -8
  82. package/src/host-navigator.ts +4 -2
  83. package/src/host-phases.ts +1 -1
  84. package/src/host-recovery.ts +23 -28
  85. package/src/host-runtime.ts +44 -6
  86. package/src/host-view.ts +41 -16
  87. package/src/host.ts +229 -142
  88. package/src/index.ts +1 -2
  89. package/src/paths.ts +18 -9
  90. package/src/persistence.ts +1 -0
  91. package/src/pi-runtime-runner.ts +3 -1
  92. package/src/registry.ts +28 -64
  93. package/src/runtime/agent-runner.ts +2 -0
  94. package/src/script-tools.ts +76 -0
  95. package/src/session-lease.ts +34 -6
  96. package/src/settings.ts +56 -50
  97. package/src/store.ts +18 -2
  98. package/src/trajectory.ts +32 -15
  99. package/src/types.ts +82 -34
  100. package/src/utils.ts +42 -5
  101. package/src/validation.ts +121 -80
  102. package/starter/index.ts +0 -1
  103. package/starter/review-loop.ts +8 -9
  104. package/starter/roles/developer.md +0 -1
  105. package/starter/roles/oracle.md +0 -1
  106. package/starter/roles/researcher.md +0 -1
  107. package/starter/roles/reviewer.md +0 -1
  108. package/starter/roles/scout.md +0 -1
  109. package/subagents/README.md +10 -16
  110. package/subagents/src/contracts.ts +21 -11
  111. package/subagents/src/index.ts +17 -8
  112. package/subagents/src/manager.ts +48 -128
  113. package/subagents/src/navigator.ts +4 -13
  114. package/subagents/src/view.ts +16 -63
  115. package/subagents/src/worktree.ts +1 -1
  116. package/trajectory/src/assets/index.html +35 -13
  117. package/trajectory/src/index.ts +112 -91
  118. package/trajectory/src/server.ts +46 -10
  119. package/trajectory/src/startup-mutex.ts +127 -0
  120. package/dist/src/roles.d.ts +0 -70
  121. package/dist/src/roles.js +0 -325
  122. package/dist/starter/roles/developer.md +0 -6
  123. package/dist/starter/roles/oracle.md +0 -18
  124. package/dist/starter/roles/researcher.md +0 -20
  125. package/dist/starter/roles/reviewer.md +0 -19
  126. package/dist/starter/roles/scout.md +0 -18
  127. package/examples/workflow-extension-template/roles/reviewer.md +0 -4
  128. package/src/roles.ts +0 -326
@@ -23,9 +23,12 @@ export declare const WORKFLOW_CHECKPOINT_STATE_CHANGED_EVENT = "workflow:checkpo
23
23
  export declare const WORKFLOW_BUDGET_EVENT = "workflow:budget-event";
24
24
  export declare const WORKFLOW_WORKTREE_CREATED_EVENT = "workflow:worktree-created";
25
25
  export declare const WORKFLOW_BLOCKED_EVENT = "workflow:blocked";
26
- export declare const ERROR_CODES: readonly ["CONFIG_ERROR", "INVALID_SETTINGS", "INVALID_SYNTAX", "INVALID_METADATA", "DUPLICATE_NAME", "INVALID_SCHEMA", "UNKNOWN_MODEL", "UNKNOWN_TOOL", "UNKNOWN_AGENT_TYPE", "RUN_OWNED", "RUN_NOT_FOUND", "REGISTRY_FROZEN", "GLOBAL_COLLISION", "MISSING_WORKFLOW", "RPC_LIMIT_EXCEEDED", "SHELL_FAILED", "AGENT_TIMEOUT", "AGENT_FAILED", "AGENT_RESULT_COLLECTED", "RESULT_INVALID", "CANCELLED", "WORKER_UNRESPONSIVE", "WORKTREE_FAILED", "RESUME_INCOMPATIBLE", "BUDGET_EXHAUSTED", "INTERNAL_ERROR"];
26
+ export declare const ERROR_CODES: readonly ["CONFIG_ERROR", "INVALID_SETTINGS", "INVALID_SYNTAX", "INVALID_METADATA", "DUPLICATE_NAME", "INVALID_SCHEMA", "UNKNOWN_MODEL", "UNKNOWN_TOOL", "UNKNOWN_AGENT", "RUN_OWNED", "RUN_NOT_FOUND", "REGISTRY_FROZEN", "GLOBAL_COLLISION", "MISSING_WORKFLOW", "RPC_LIMIT_EXCEEDED", "SHELL_FAILED", "AGENT_TIMEOUT", "AGENT_FAILED", "AGENT_RESULT_COLLECTED", "RESULT_INVALID", "TOOL_FAILED", "CANCELLED", "WORKER_UNRESPONSIVE", "WORKTREE_FAILED", "RESUME_INCOMPATIBLE", "BUDGET_EXHAUSTED", "INTERNAL_ERROR"];
27
27
  export declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
28
28
  export type ThinkingLevel = (typeof THINKING_LEVELS)[number];
29
+ export declare const CONTEXT_FILE_SCOPES: readonly ["global", "project", "cwd"];
30
+ export type ContextFileScope = (typeof CONTEXT_FILE_SCOPES)[number];
31
+ export declare function isContextFileScope(value: unknown): value is ContextFileScope;
29
32
  export type WorkflowErrorCode = (typeof ERROR_CODES)[number];
30
33
  export type JsonValue = null | boolean | number | string | JsonValue[] | {
31
34
  [key: string]: JsonValue;
@@ -34,15 +37,15 @@ export type JsonSchema = {
34
37
  [key: string]: JsonValue;
35
38
  };
36
39
  type WorkflowSchema = JsonSchema | TSchema;
37
- export declare function roleNameOf(value: unknown): string | undefined;
38
40
  export interface AgentOptions<Schema extends TSchema = never> {
39
41
  label?: string;
40
42
  model?: string;
41
43
  tools?: string[];
44
+ /** Exact tool names removed after preparation hooks; never widens the parent ceiling. */
45
+ excludeTools?: string[];
42
46
  skills?: string[];
43
47
  extensions?: string[];
44
48
  contextFiles?: ContextFileScope[];
45
- role?: string;
46
49
  outputSchema?: JsonSchema | Schema;
47
50
  retries?: number;
48
51
  timeoutMs?: number | null;
@@ -137,7 +140,6 @@ export interface WorkflowRunFailedEvent extends WorkflowEventBase {
137
140
  export interface WorkflowAgentStateChangedEvent extends WorkflowEventBase {
138
141
  agentId: string;
139
142
  displayLabel: string;
140
- role?: string;
141
143
  structuralPath: readonly string[];
142
144
  parentId?: string;
143
145
  parentBreadcrumb?: string;
@@ -196,13 +198,12 @@ export interface WorkflowExtensionSettings {
196
198
  readonly herdr?: Readonly<HerdrExtensionSettings>;
197
199
  readonly trajectory?: Readonly<TrajectoryExtensionSettings>;
198
200
  }
199
- export type WorkflowExtensionSettingsSource = "global" | "project" | "role" | "effective";
201
+ export type WorkflowExtensionSettingsSource = "global" | "project" | "effective";
200
202
  export interface WorkflowExtensionSettingsValidatorContext {
201
203
  source: WorkflowExtensionSettingsSource;
202
204
  cwd: string;
203
205
  projectTrusted: boolean;
204
206
  settingsPath?: string;
205
- role?: string;
206
207
  }
207
208
  export type WorkflowExtensionSettingsValidator = (settings: Readonly<WorkflowExtensionSettings>, context: Readonly<WorkflowExtensionSettingsValidatorContext>) => void;
208
209
  export interface WorkflowSessionStartEvent {
@@ -215,9 +216,11 @@ export interface WorkflowRetentionSettings {
215
216
  olderThanDays?: number;
216
217
  maxTerminalRuns?: number;
217
218
  }
219
+ export type CodemodeToolsSetting = "all" | "read-only" | "none";
218
220
  export interface WorkflowSettings {
219
221
  concurrency: number;
220
222
  backgroundWidget?: boolean;
223
+ codemodeTools?: CodemodeToolsSetting;
221
224
  modelAliases?: Readonly<Record<string, string>>;
222
225
  skills?: readonly string[];
223
226
  extensions?: readonly string[];
@@ -226,7 +229,7 @@ export interface WorkflowSettings {
226
229
  retention?: Readonly<WorkflowRetentionSettings>;
227
230
  worktreePostCreateCommand?: readonly string[];
228
231
  }
229
- export type WorkflowSettingsOverrides = Partial<Omit<WorkflowSettings, "backgroundWidget">>;
232
+ export type WorkflowSettingsOverrides = Partial<Omit<WorkflowSettings, "backgroundWidget" | "codemodeTools">>;
230
233
  export interface WorkflowSettingsSources {
231
234
  concurrency: string;
232
235
  modelAliases: string;
@@ -238,6 +241,7 @@ export interface WorkflowSettingsSources {
238
241
  worktreePostCreateCommand?: string;
239
242
  }
240
243
  export interface WorkflowSettingsResolution {
244
+ selectorSources?: AgentResourceSelectorSources;
241
245
  globalSettingsPath: string;
242
246
  projectSettingsPath: string;
243
247
  projectTrusted: boolean;
@@ -259,13 +263,14 @@ export interface AgentResourceSelectorSet {
259
263
  export interface AgentResourceSelectorSources {
260
264
  global: AgentResourceSelectors;
261
265
  project: AgentResourceSelectors;
262
- role?: AgentResourceSelectors;
263
266
  call?: AgentResourceSelectors;
264
267
  }
265
- export declare const CONTEXT_FILE_SCOPES: readonly ["global", "project", "cwd"];
266
- export type ContextFileScope = (typeof CONTEXT_FILE_SCOPES)[number];
267
- export declare function isContextFileScope(value: unknown): value is ContextFileScope;
268
268
  export interface AgentResourcePolicy {
269
+ capabilities?: Readonly<{
270
+ tools: readonly string[];
271
+ skills: readonly string[];
272
+ extensions: readonly string[];
273
+ }>;
269
274
  globalSettingsPath: string;
270
275
  projectSettingsPath: string;
271
276
  projectTrusted: boolean;
@@ -279,6 +284,8 @@ export interface AgentResourcePolicy {
279
284
  unmatchedExtensions: readonly string[];
280
285
  unmatchedTools?: readonly string[];
281
286
  selectorSources: AgentResourceSelectorSources;
287
+ /** Skills loaded by the parent session; ceiling for skills that extensions contribute through resources_discover. Absent for top-level agents. */
288
+ parentSkills?: readonly string[];
282
289
  }
283
290
  export interface AgentResourceInspection {
284
291
  selectors: AgentResourceSelectorSet;
@@ -354,7 +361,6 @@ export interface AgentRecord {
354
361
  handle?: string;
355
362
  turn?: number;
356
363
  continuity?: AgentContinuity;
357
- role?: string;
358
364
  requestedModel?: string;
359
365
  model: ModelSpec;
360
366
  tools: readonly string[];
@@ -403,6 +409,21 @@ export interface WorkflowPhaseShellActivity {
403
409
  active: number;
404
410
  startedAt: number;
405
411
  }
412
+ /** A script call recorded for inspection. Tool payloads stay in the replay journal, not this record. Oversized shell inputs are JSON prefixes, with `inputBytes` their full size. */
413
+ export interface WorkflowScriptCall {
414
+ kind: "shell" | "tool";
415
+ name: string;
416
+ path: string;
417
+ input?: JsonValue;
418
+ inputBytes?: number;
419
+ phase?: string;
420
+ startedAt: number;
421
+ finishedAt?: number;
422
+ error?: {
423
+ code: WorkflowErrorCode;
424
+ message?: string;
425
+ };
426
+ }
406
427
  export interface RunRecord {
407
428
  id: string;
408
429
  workflowName: string;
@@ -419,6 +440,11 @@ export interface RunRecord {
419
440
  activeShells?: number;
420
441
  activeShellStartedAt?: number;
421
442
  activeShellsByPhase?: readonly WorkflowPhaseShellActivity[];
443
+ activeTools?: readonly {
444
+ name: string;
445
+ startedAt: number;
446
+ }[];
447
+ scriptCalls?: readonly WorkflowScriptCall[];
422
448
  error?: WorkflowErrorShape;
423
449
  failedAt?: string;
424
450
  budget?: WorkflowBudget;
@@ -428,22 +454,10 @@ export interface RunRecord {
428
454
  events?: readonly WorkflowRunEvent[];
429
455
  delivery?: WorkflowRunDelivery;
430
456
  }
431
- export declare const LAUNCH_SNAPSHOT_IDENTITY_VERSION = 5;
457
+ export declare const LAUNCH_SNAPSHOT_IDENTITY_VERSION = 6;
432
458
  export type WorkflowLaunchMode = "foreground" | "background";
433
- export interface AgentDefinition {
434
- prompt?: string;
435
- description?: string;
436
- model?: string;
437
- thinking?: NonNullable<ModelSpec["thinking"]>;
438
- tools?: readonly string[];
439
- skills?: readonly string[];
440
- extensions?: readonly string[];
441
- overrideSystemPrompt?: boolean;
442
- contextFiles?: readonly ContextFileScope[];
443
- extensionSettings?: Readonly<WorkflowExtensionSettings>;
444
- }
445
459
  export interface LaunchSnapshot {
446
- identityVersion?: number;
460
+ identityVersion: number;
447
461
  launchMode?: WorkflowLaunchMode;
448
462
  script: string;
449
463
  args: JsonValue;
@@ -456,15 +470,12 @@ export interface LaunchSnapshot {
456
470
  phases?: readonly string[];
457
471
  models: readonly string[];
458
472
  tools: readonly string[];
459
- agentTypes: readonly string[];
460
- roles?: Readonly<Record<string, AgentDefinition>>;
461
- projectRoles?: readonly string[];
473
+ agentConfigurations: Readonly<Record<string, PreparedAgentConfiguration>>;
462
474
  schemas: readonly JsonSchema[];
463
475
  }
464
476
  export interface PreflightCapabilities {
465
477
  models: ReadonlySet<string>;
466
478
  tools: ReadonlySet<string>;
467
- agentTypes: ReadonlySet<string>;
468
479
  modelAliases?: Readonly<Record<string, string>>;
469
480
  knownModels?: ReadonlySet<string>;
470
481
  settingsPath?: string;
@@ -476,10 +487,22 @@ export interface PreflightResult {
476
487
  phases: readonly string[];
477
488
  models: readonly string[];
478
489
  tools: readonly string[];
479
- agentTypes: readonly string[];
480
490
  };
481
491
  schemas: readonly JsonSchema[];
482
- dynamicAgentRoles: boolean;
492
+ }
493
+ export interface AgentHandleSendOptions<Schema extends TSchema = never> {
494
+ outputSchema?: JsonSchema | Schema;
495
+ timeoutMs?: number | null;
496
+ }
497
+ /** A persistent agent: each send continues the transcript of the previous completed turn. Sends must be awaited one at a time, in the scope that created the handle. */
498
+ export interface AgentHandle {
499
+ readonly name: string;
500
+ send: {
501
+ <Schema extends TSchema>(prompt: string, options: Readonly<AgentHandleSendOptions<Schema> & {
502
+ outputSchema: Schema;
503
+ }>): Promise<Static<Schema>>;
504
+ (prompt: string, options?: Readonly<AgentHandleSendOptions>): Promise<JsonValue>;
505
+ };
483
506
  }
484
507
  export interface WorkflowOrchestrationContext {
485
508
  agent: {
@@ -487,6 +510,9 @@ export interface WorkflowOrchestrationContext {
487
510
  outputSchema: Schema;
488
511
  }>): Promise<Static<Schema>>;
489
512
  (prompt: string, options?: Readonly<AgentOptions>): Promise<JsonValue>;
513
+ create: (options: Readonly<AgentOptions & {
514
+ name: string;
515
+ }>) => AgentHandle;
490
516
  };
491
517
  shell: (command: string, options?: ShellOptions) => Promise<ShellResult>;
492
518
  prompt: (template: string, values: Readonly<Record<string, JsonValue>>) => string;
@@ -594,6 +620,8 @@ export interface WorkflowAgentSession {
594
620
  getState(): Readonly<WorkflowAgentSessionState>;
595
621
  getSessionStats(): WorkflowAgentSessionStats;
596
622
  getLastAssistant(): WorkflowAgentMessage | undefined;
623
+ /** Set by a transport that already delivered `PreparedAgentSession.turnControl` itself; otherwise the runner steers it before the first prompt. */
624
+ readonly turnControlDelivered?: boolean;
597
625
  subscribe(listener: (event: WorkflowAgentSessionEvent) => void): () => void;
598
626
  subscribeAsync?(listener: (event: WorkflowAgentSessionEvent) => void | Promise<void>): () => void;
599
627
  prompt(text: string): Promise<WorkflowAgentTurnResult>;
@@ -610,7 +638,8 @@ export interface WorkflowAgentSession {
610
638
  type SessionTools = NonNullable<CreateAgentSessionOptions["tools"]>;
611
639
  type SessionCustomTools = NonNullable<CreateAgentSessionOptions["customTools"]>;
612
640
  export interface SessionInput {
613
- cwd: string;
641
+ /** Read-only: setup hooks cannot move an agent, because Pi derives trust, settings and `.pi` resources from cwd. */
642
+ readonly cwd: string;
614
643
  model: ModelSpec;
615
644
  tools: SessionTools;
616
645
  sessionLabel: string;
@@ -639,6 +668,8 @@ export interface PreparedAgentSession {
639
668
  readonly sessionLabel: string;
640
669
  readonly sessionPath?: string;
641
670
  readonly initialPrompt?: string;
671
+ /** Dynamic per-attempt control text (retry state, budget). The runner steers it before the first prompt unless the session reports `turnControlDelivered`. */
672
+ readonly turnControl?: string;
642
673
  readonly agentDir?: string;
643
674
  readonly customTools?: readonly ToolDefinition[];
644
675
  readonly resultTool?: ToolDefinition;
@@ -685,6 +716,64 @@ export interface AgentSetupContext {
685
716
  readonly mode?: AgentInspectionMode;
686
717
  readonly settings: Readonly<WorkflowExtensionSettings>;
687
718
  }
719
+ export interface AgentPreparation {
720
+ label?: string;
721
+ model?: string;
722
+ tools: string[];
723
+ skills: string[];
724
+ extensions: string[];
725
+ contextFiles?: ContextFileScope[];
726
+ systemPrompt?: string;
727
+ systemPromptAppend: string;
728
+ settings: WorkflowExtensionSettings;
729
+ }
730
+ export interface AgentPreparationContext {
731
+ readonly options: Readonly<AgentOptions>;
732
+ readonly cwd: string;
733
+ /** Launch project root that owns project configuration; differs from `cwd` inside worktree scopes. Optional for older hosts. */
734
+ readonly projectCwd?: string;
735
+ readonly agentDir: string;
736
+ readonly projectTrusted: boolean;
737
+ /** `dynamicModelAliasNames` lists the `modelAliases` entries resolved by extensions rather than read from static settings. */
738
+ readonly defaults: Readonly<{
739
+ model: ModelSpec;
740
+ modelAliases: Readonly<Record<string, string>>;
741
+ dynamicModelAliasNames?: readonly string[];
742
+ selectorSources: AgentResourceSelectorSources;
743
+ settings: Readonly<WorkflowExtensionSettings>;
744
+ }>;
745
+ readonly capabilities: Readonly<{
746
+ tools: readonly string[];
747
+ skills: readonly string[];
748
+ extensions: readonly string[];
749
+ }>;
750
+ readonly knownModels: ReadonlySet<string>;
751
+ readonly availableModels: ReadonlySet<string>;
752
+ readonly signal: AbortSignal;
753
+ readonly mode: AgentInspectionMode;
754
+ }
755
+ export interface AgentPreparationHook {
756
+ priority?: number;
757
+ optionsSchema?: JsonSchema;
758
+ prepare: (configuration: AgentPreparation, context: Readonly<AgentPreparationContext>) => void | Promise<void>;
759
+ }
760
+ /** `source` is the registering extension's module provenance, when it declared one. */
761
+ export interface RegisteredAgentPreparationHook {
762
+ name: string;
763
+ priority: number;
764
+ optionsSchema?: JsonSchema;
765
+ source?: string;
766
+ prepare: AgentPreparationHook["prepare"];
767
+ }
768
+ /**
769
+ * `excludeTools` holds the exact tool names the agent and its ancestors excluded, frozen with the configuration so setup and
770
+ * children apply them even when re-evaluated options change. It is absent only in configurations prepared before it existed, which cannot resume.
771
+ */
772
+ export interface PreparedAgentConfiguration extends Omit<AgentPreparation, "model"> {
773
+ model: ModelSpec;
774
+ projectTrusted: boolean;
775
+ excludeTools?: string[];
776
+ }
688
777
  export interface AgentSetupHook {
689
778
  priority?: number;
690
779
  setup: (agent: AgentSetup, context: Readonly<AgentSetupContext>) => void | Promise<void>;
@@ -703,11 +792,6 @@ export interface WorkflowFunctionSource {
703
792
  readonly export: string;
704
793
  readonly dependencies: readonly string[];
705
794
  }
706
- export interface WorkflowRoleDirectoryRegistration {
707
- path: string;
708
- extension: WorkflowExtensionMetadata;
709
- readonly builtin?: true;
710
- }
711
795
  export interface AgentAttemptActionUi {
712
796
  notify(message: string, level?: "info" | "warning" | "error"): void;
713
797
  confirm(title: string, message: string): Promise<boolean>;
@@ -757,9 +841,9 @@ export interface WorkflowExtension extends WorkflowExtensionMetadata {
757
841
  validateSettings?: WorkflowExtensionSettingsValidator;
758
842
  functions?: Readonly<Record<string, WorkflowFunction>>;
759
843
  modelAliases?: Readonly<Record<string, WorkflowModelAlias>>;
844
+ agentPreparationHooks?: Readonly<Record<string, AgentPreparationHook>>;
760
845
  agentSetupHooks?: Readonly<Record<string, AgentSetupHook>>;
761
846
  agentAttemptActions?: Readonly<Record<string, AgentAttemptAction>>;
762
- roleDirectories?: readonly (string | URL)[];
763
847
  }
764
848
  export interface WorkflowJournal {
765
849
  get(path: string): JsonValue | undefined;
@@ -773,7 +857,6 @@ export declare class WorkflowError extends Error {
773
857
  export interface WorkflowFailureAgent {
774
858
  id: string;
775
859
  label?: string;
776
- role?: string;
777
860
  structuralPath: readonly string[];
778
861
  attempt: number;
779
862
  transport?: string;
@@ -782,7 +865,6 @@ export interface WorkflowFailureAgent {
782
865
  export interface WorkflowSiblingAgent {
783
866
  id: string;
784
867
  label?: string;
785
- role?: string;
786
868
  structuralPath: readonly string[];
787
869
  }
788
870
  export interface WorkflowFailureDiagnostics {
@@ -835,6 +917,11 @@ export interface ShellIdentity {
835
917
  occurrence: number;
836
918
  worktreeOwner?: string;
837
919
  }
920
+ /** A script `tools.<id>(args)` call: the n-th call of that tool within one structural scope. */
921
+ export interface ToolIdentity {
922
+ structuralPath: readonly string[];
923
+ occurrence: number;
924
+ }
838
925
  export interface WorkflowBridge {
839
926
  agent?: (prompt: string, options: Readonly<Record<string, JsonValue>>, signal: AbortSignal, identity: AgentIdentity) => Promise<JsonValue>;
840
927
  shell?: (command: string, options: ShellOptions, signal: AbortSignal, identity: ShellIdentity) => Promise<ShellResult>;
@@ -846,6 +933,7 @@ export interface WorkflowBridge {
846
933
  }>>;
847
934
  phase?: (name: string) => void | Promise<void>;
848
935
  log?: (message: string) => void | Promise<void>;
936
+ tool?: (identifier: string, args: Readonly<Record<string, JsonValue>>, signal: AbortSignal, identity: ToolIdentity) => Promise<JsonValue>;
849
937
  }
850
938
  export interface WorkflowExecution {
851
939
  result: Promise<JsonValue>;
@@ -865,7 +953,6 @@ export interface StaticWorkflowCall {
865
953
  prompt: string | null;
866
954
  model: string | null;
867
955
  label?: string | null;
868
- role: string | null;
869
956
  retries?: number | null;
870
957
  outputSchema?: JsonSchema | null;
871
958
  options?: Readonly<Record<string, JsonValue>> | null;
@@ -952,8 +1039,5 @@ export interface WorkflowValidationContext {
952
1039
  export interface ValidatedWorkflowLaunch {
953
1040
  script: string;
954
1041
  checked: PreflightResult;
955
- agentDefinitions: Readonly<Record<string, AgentDefinition>>;
956
- projectAgentDefinitions: Readonly<Record<string, AgentDefinition>>;
957
- roleNames: readonly string[];
958
1042
  }
959
1043
  export {};
package/dist/src/types.js CHANGED
@@ -17,18 +17,15 @@ export const WORKFLOW_BUDGET_EVENT = "workflow:budget-event";
17
17
  export const WORKFLOW_WORKTREE_CREATED_EVENT = "workflow:worktree-created";
18
18
  export const WORKFLOW_BLOCKED_EVENT = "workflow:blocked";
19
19
  export const ERROR_CODES = [
20
- "CONFIG_ERROR", "INVALID_SETTINGS", "INVALID_SYNTAX", "INVALID_METADATA", "DUPLICATE_NAME", "INVALID_SCHEMA", "UNKNOWN_MODEL", "UNKNOWN_TOOL", "UNKNOWN_AGENT_TYPE",
20
+ "CONFIG_ERROR", "INVALID_SETTINGS", "INVALID_SYNTAX", "INVALID_METADATA", "DUPLICATE_NAME", "INVALID_SCHEMA", "UNKNOWN_MODEL", "UNKNOWN_TOOL", "UNKNOWN_AGENT",
21
21
  "RUN_OWNED", "RUN_NOT_FOUND", "REGISTRY_FROZEN", "GLOBAL_COLLISION", "MISSING_WORKFLOW", "RPC_LIMIT_EXCEEDED", "SHELL_FAILED", "AGENT_TIMEOUT", "AGENT_FAILED", "AGENT_RESULT_COLLECTED", "RESULT_INVALID",
22
- "CANCELLED", "WORKER_UNRESPONSIVE", "WORKTREE_FAILED", "RESUME_INCOMPATIBLE", "BUDGET_EXHAUSTED", "INTERNAL_ERROR",
22
+ "TOOL_FAILED", "CANCELLED", "WORKER_UNRESPONSIVE", "WORKTREE_FAILED", "RESUME_INCOMPATIBLE", "BUDGET_EXHAUSTED", "INTERNAL_ERROR",
23
23
  ];
24
24
  export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
25
- export function roleNameOf(value) {
26
- return typeof value === "string" ? value : undefined;
27
- }
28
- export const BUDGET_DIMENSIONS = ["tokens", "costUsd", "durationMs", "agentLaunches"];
29
- export const BUDGET_EVENT_TYPES = ["soft_crossed", "hard_overrun", "hard_exhausted", "adjustment_requested", "adjustment_approved", "adjustment_rejected"];
30
25
  export const CONTEXT_FILE_SCOPES = ["global", "project", "cwd"];
31
26
  export function isContextFileScope(value) { return CONTEXT_FILE_SCOPES.some((scope) => scope === value); }
27
+ export const BUDGET_DIMENSIONS = ["tokens", "costUsd", "durationMs", "agentLaunches"];
28
+ export const BUDGET_EVENT_TYPES = ["soft_crossed", "hard_overrun", "hard_exhausted", "adjustment_requested", "adjustment_approved", "adjustment_rejected"];
32
29
  export const WORKFLOW_AGENT_STALL_THRESHOLD_MS = 10 * 60 * 1000;
33
30
  export function zeroAccounting() { return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 }; }
34
31
  export function addAccounting(left, right) { return { input: left.input + right.input, output: left.output + right.output, cacheRead: left.cacheRead + right.cacheRead, cacheWrite: left.cacheWrite + right.cacheWrite, cost: left.cost + right.cost }; }
@@ -38,7 +35,7 @@ export function sumAccounting(values) {
38
35
  total = addAccounting(total, value);
39
36
  return total;
40
37
  }
41
- export const LAUNCH_SNAPSHOT_IDENTITY_VERSION = 5;
38
+ export const LAUNCH_SNAPSHOT_IDENTITY_VERSION = 6;
42
39
  export function defineWorkflowFunction(workflowFunction) { return workflowFunction; }
43
40
  // The brand keeps instanceof working across the bundled extension entries, which each inline their own copy of this class.
44
41
  const WORKFLOW_ERROR_BRAND = Symbol.for("pi-extensible-workflows.workflow-error");
@@ -1,4 +1,5 @@
1
- import { WorkflowError, type JsonSchema, type JsonValue, type ModelSpec, type ThinkingLevel, type WorkflowErrorCode, type WorkflowExtensionSettings } from "./types.js";
1
+ import { WorkflowError, type JsonSchema, type JsonValue, type ModelSpec, type WorkflowErrorCode, type WorkflowExtensionSettings } from "./types.js";
2
+ import { type ThinkingLevel } from "./types.js";
2
3
  export declare class SerialLane {
3
4
  #private;
4
5
  run<T>(task: () => Promise<T>): Promise<T>;
@@ -6,6 +7,8 @@ export declare class SerialLane {
6
7
  export declare function object(value: unknown): value is Record<string, unknown>;
7
8
  export declare function sanitizeDisplayText(value: string): string;
8
9
  export { object as isObject };
10
+ /** A short digest of a JSON value that ignores object key order. */
11
+ export declare function jsonDigest(value: JsonValue): string;
9
12
  export declare function jsonValue(value: unknown, seen?: Set<object>): value is JsonValue;
10
13
  export declare function jsonObject(value: unknown): value is Record<string, JsonValue>;
11
14
  export declare function mergeWorkflowExtensionSettings(...layers: readonly (Readonly<WorkflowExtensionSettings> | undefined)[]): Readonly<WorkflowExtensionSettings> | undefined;
@@ -45,6 +48,23 @@ export declare function validateModelAliases(value: unknown, settingsPath?: stri
45
48
  export declare function unknownModel(value: string, target: string | undefined, settingsPath?: string): never;
46
49
  export declare function resolveModelReference(value: string, aliases?: Readonly<Record<string, string>>, knownModels?: ReadonlySet<string>, settingsPath?: string): ModelSpec;
47
50
  export declare function modelCapability(value: string | ModelSpec, aliases?: Readonly<Record<string, string>>, knownModels?: ReadonlySet<string>, settingsPath?: string): string;
51
+ type ToolSource = {
52
+ getActiveTools(): string[];
53
+ getAllTools?(): readonly {
54
+ name: string;
55
+ exposure?: string;
56
+ }[];
57
+ };
58
+ /**
59
+ * Tools a session can reach, and so the ceiling for its agents: the declared tools plus the ones
60
+ * only codemode scripts call or tool_search loads, such as MCP tools with the default exposure.
61
+ * Agent sessions allow tools by name, so leaving these out would make them unreachable there.
62
+ */
63
+ export declare function reachableTools(pi: ToolSource): string[];
64
+ /** Provider of the virtual models that expose workflow model aliases in `/model`. */
65
+ export declare const VIRTUAL_MODEL_PROVIDER = "workflow";
66
+ /** Child sessions do not load the workflow extension, so they receive the alias target instead of its virtual model. */
67
+ export declare function physicalModel(spec: ModelSpec, aliases?: Readonly<Record<string, string>>, knownModels?: ReadonlySet<string>, settingsPath?: string): ModelSpec;
48
68
  export declare function aliasDrift(previous: Readonly<Record<string, string>>, current: Readonly<Record<string, string>>): string[];
49
69
  export declare function validateResourcePattern(pattern: string): void;
50
70
  export declare function resourcePatternMatches(resource: string, pattern: string): boolean;
package/dist/src/utils.js CHANGED
@@ -1,5 +1,7 @@
1
- import { ERROR_CODES, LAUNCH_SNAPSHOT_IDENTITY_VERSION, THINKING_LEVELS, WorkflowError } from "./types.js";
1
+ import { createHash } from "node:crypto";
2
+ import { ERROR_CODES, LAUNCH_SNAPSHOT_IDENTITY_VERSION, WorkflowError } from "./types.js";
2
3
  import { Minimatch } from "minimatch";
4
+ import { THINKING_LEVELS } from "./types.js";
3
5
  export class SerialLane {
4
6
  #tail = Promise.resolve();
5
7
  run(task) {
@@ -17,6 +19,17 @@ export function sanitizeDisplayText(value) { return value.replace(ANSI_ESCAPE_SE
17
19
  export { object as isObject };
18
20
  function isStringKey(key) { return typeof key === "string"; }
19
21
  function stringKeyValue(value, key) { return object(value) ? value[key] : undefined; }
22
+ function sortedJson(value) {
23
+ if (Array.isArray(value))
24
+ return value.map(sortedJson);
25
+ if (value === null || typeof value !== "object")
26
+ return value;
27
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortedJson(value[key])]));
28
+ }
29
+ /** A short digest of a JSON value that ignores object key order. */
30
+ export function jsonDigest(value) {
31
+ return createHash("sha256").update(JSON.stringify(sortedJson(value))).digest("hex").slice(0, 16);
32
+ }
20
33
  export function jsonValue(value, seen = new Set()) {
21
34
  if (value === null || typeof value === "boolean" || typeof value === "string")
22
35
  return true;
@@ -91,13 +104,22 @@ export const WORKFLOW_EXTENSION_NAMESPACE = /^[A-Za-z][A-Za-z0-9_-]*$/;
91
104
  export function validWorkflowExtensionNamespace(value) { return WORKFLOW_EXTENSION_NAMESPACE.test(value) && value !== "__proto__" && value !== "constructor" && value !== "prototype"; }
92
105
  export function parseThinking(value) { return isThinkingLevel(value) ? value : undefined; }
93
106
  export function parseModelReference(value) {
94
- const match = /^([^/:\s]+)\/([^:\s]+)(?::([^:\s]+))?$/.exec(value);
107
+ const match = /^([^/:\s]+)\/([^\s]+)$/.exec(value);
95
108
  if (!match?.[1] || !match[2])
96
109
  fail("UNKNOWN_MODEL", `Invalid model spec: ${value}`);
97
- const thinking = match[3];
98
- if (thinking !== undefined && !isThinkingLevel(thinking))
99
- fail("UNKNOWN_MODEL", `Invalid thinking level: ${thinking}`);
100
- return { provider: match[1], model: match[2], ...(thinking !== undefined ? { thinking } : {}) };
110
+ // The model id is everything after the first slash, so namespaced ids such as
111
+ // `deepseek/deepseek-v4.1-flash:nitro` survive intact. Only a trailing segment
112
+ // that names a thinking level is one.
113
+ const reference = match[2];
114
+ const separator = reference.lastIndexOf(":");
115
+ const suffix = separator === -1 ? undefined : reference.slice(separator + 1);
116
+ if (suffix === "")
117
+ fail("UNKNOWN_MODEL", `Invalid model spec: ${value}`);
118
+ const thinking = suffix !== undefined && isThinkingLevel(suffix) ? suffix : undefined;
119
+ const model = thinking === undefined ? reference : reference.slice(0, separator);
120
+ if (model === "")
121
+ fail("UNKNOWN_MODEL", `Invalid model spec: ${value}`);
122
+ return { provider: match[1], model, ...(thinking === undefined ? {} : { thinking }) };
101
123
  }
102
124
  export function assertModelThinking(value, path = "model") {
103
125
  if (value.includes("/") && parseModelReference(value).thinking === undefined)
@@ -182,6 +204,24 @@ export function modelCapability(value, aliases, knownModels, settingsPath) {
182
204
  const parsed = typeof value === "string" ? resolveModelReference(value, aliases, knownModels, settingsPath) : value;
183
205
  return `${parsed.provider}/${parsed.model}`;
184
206
  }
207
+ /**
208
+ * Tools a session can reach, and so the ceiling for its agents: the declared tools plus the ones
209
+ * only codemode scripts call or tool_search loads, such as MCP tools with the default exposure.
210
+ * Agent sessions allow tools by name, so leaving these out would make them unreachable there.
211
+ */
212
+ export function reachableTools(pi) {
213
+ const undeclared = pi.getAllTools?.().filter(({ exposure }) => exposure === "codemode" || exposure === "deferred").map(({ name }) => name) ?? [];
214
+ return [...new Set([...pi.getActiveTools(), ...undeclared])];
215
+ }
216
+ /** Provider of the virtual models that expose workflow model aliases in `/model`. */
217
+ export const VIRTUAL_MODEL_PROVIDER = "workflow";
218
+ /** Child sessions do not load the workflow extension, so they receive the alias target instead of its virtual model. */
219
+ export function physicalModel(spec, aliases = {}, knownModels, settingsPath) {
220
+ if (spec.provider !== VIRTUAL_MODEL_PROVIDER || !modelAliasName(spec.model, aliases))
221
+ return spec;
222
+ const target = resolveModelReference(spec.model, aliases, knownModels, settingsPath);
223
+ return spec.thinking === undefined ? target : { ...target, thinking: spec.thinking };
224
+ }
185
225
  export function aliasDrift(previous, current) {
186
226
  return [...new Set([...Object.keys(previous), ...Object.keys(current)])].sort().flatMap((name) => previous[name] === current[name] ? [] : [`${name}: ${previous[name] ?? "(missing)"} -> ${current[name] ?? "(missing)"}`]);
187
227
  }
@@ -1,16 +1,27 @@
1
1
  import type { CheckpointInput, JsonValue, PreflightCapabilities, PreflightResult, ShellOptions, StaticWorkflowCall, ValidatedWorkflowLaunch, WorkflowMetadata, WorkflowValidationContext, WorkflowValidationParameters } from "./types.js";
2
2
  import type { WorkflowRegistryApi } from "./registry.js";
3
3
  export { validateSchema } from "./utils.js";
4
- export { loadAgentDefinitions, loadProjectAgentDefinitions, parseRoleMarkdown, workflowRoleDirectories } from "./roles.js";
5
- export type { WorkflowRoleDirectoryInput } from "./roles.js";
6
- export { DEFAULT_SETTINGS, loadSettings, loadSettingsOverrides, resolveAgentResourcePolicy, resolveWorkflowSettings, saveModelAliases, validateContextFileScopes, validateModelAliasAvailability, validateSelectorList, validateWorkflowExtensionSettings, workflowProjectSettingsPath, workflowSettingsPath } from "./settings.js";
4
+ export { DEFAULT_SETTINGS, loadCodemodeToolsSetting, loadSettings, loadSettingsOverrides, resolveAgentResourcePolicy, resolveWorkflowSettings, saveModelAliases, validateContextFileScopes, validateModelAliasAvailability, validateSelectorList, validateWorkflowExtensionSettings, workflowProjectSettingsPath, workflowSettingsPath, workflowToolExposure } from "./settings.js";
7
5
  export declare function validateCheckpoint(value: unknown): CheckpointInput;
6
+ /**
7
+ * The `tools.<id>` members a workflow script names statically. Any other use of `tools`, such as a
8
+ * local declaration that shadows the global or passing it around, makes the set unknowable: undefined.
9
+ */
10
+ export declare function scriptToolReferences(script: string): string[] | undefined;
8
11
  export declare function instrumentWorkflow(script: string): string;
9
12
  export declare function workflowPrompt(template: string, values: Readonly<Record<string, JsonValue>>): string;
13
+ export declare function isCoreAgentOption(key: string): boolean;
10
14
  export declare function validateAgentOptions(value: unknown): Readonly<Record<string, JsonValue>>;
11
15
  export declare function validateShellOptions(value: unknown): ShellOptions;
12
16
  export declare function validateShellCommand(value: unknown): string;
13
17
  export declare function inspectWorkflowScript(script: string): StaticWorkflowCall[];
18
+ /**
19
+ * Distinct, completely static option objects of agent(...) and agent.create(...) calls, so launch can inspect them
20
+ * before any effect. Calls with any dynamic option stay runtime-checked, and so do handles whose sends may add options.
21
+ */
22
+ export declare function staticAgentPreparationOptions(script: string, registered?: Readonly<Record<string, {
23
+ run: (...args: never[]) => unknown;
24
+ }>>): Array<Readonly<Record<string, JsonValue>>>;
14
25
  export declare function preflight(script: string, capabilities: PreflightCapabilities, schemas?: readonly unknown[], metadata?: WorkflowMetadata, compatibility?: boolean): PreflightResult;
15
26
  export declare function validateWorkflowLaunch(params: WorkflowValidationParameters, context: WorkflowValidationContext, registry?: WorkflowRegistryApi): ValidatedWorkflowLaunch;
16
27
  export declare function validateWorkflowLaunchWithRegistry(params: WorkflowValidationParameters, context: WorkflowValidationContext, registry?: WorkflowRegistryApi): ValidatedWorkflowLaunch;