@pikku/core 0.12.67 → 0.12.70

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 (96) hide show
  1. package/CHANGELOG.md +397 -0
  2. package/README.md +34 -2
  3. package/dist/function/functions.types.d.ts +27 -0
  4. package/dist/index.d.ts +1 -1
  5. package/dist/internal.d.ts +1 -1
  6. package/dist/internal.js +1 -1
  7. package/dist/pikku-state.js +1 -0
  8. package/dist/services/http-scenario-actors.d.ts +12 -4
  9. package/dist/services/http-scenario-actors.js +47 -45
  10. package/dist/services/in-memory-workflow-service.d.ts +2 -2
  11. package/dist/services/in-memory-workflow-service.js +2 -2
  12. package/dist/services/index.d.ts +2 -1
  13. package/dist/services/index.js +1 -0
  14. package/dist/services/meta-service.d.ts +5 -1
  15. package/dist/services/meta-service.js +44 -18
  16. package/dist/services/scenario-actors-service.d.ts +108 -2
  17. package/dist/services/scenario-actors-service.js +40 -1
  18. package/dist/types/core.types.d.ts +21 -3
  19. package/dist/types/state.types.d.ts +3 -1
  20. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -1
  21. package/dist/wirings/actor-flow/index.d.ts +1 -1
  22. package/dist/wirings/actor-flow/run-conversation.d.ts +10 -10
  23. package/dist/wirings/actor-flow/run-conversation.js +27 -27
  24. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +18 -1
  25. package/dist/wirings/ai-agent/ai-agent-prepare.js +26 -4
  26. package/dist/wirings/cli/command-parser.js +11 -1
  27. package/dist/wirings/queue/index.d.ts +1 -1
  28. package/dist/wirings/queue/queue.types.d.ts +30 -0
  29. package/dist/wirings/rpc/rpc-runner.js +1 -1
  30. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +52 -3
  31. package/dist/wirings/workflow/feature.d.ts +28 -0
  32. package/dist/wirings/workflow/feature.js +57 -0
  33. package/dist/wirings/workflow/index.d.ts +13 -2
  34. package/dist/wirings/workflow/index.js +15 -0
  35. package/dist/wirings/workflow/pikku-scenario-service.d.ts +121 -0
  36. package/dist/wirings/workflow/pikku-scenario-service.js +419 -0
  37. package/dist/wirings/workflow/pikku-workflow-service.d.ts +118 -12
  38. package/dist/wirings/workflow/pikku-workflow-service.js +166 -153
  39. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +29 -0
  40. package/dist/wirings/workflow/scenario-cookie-jar.js +51 -0
  41. package/dist/wirings/workflow/scenario-poll.d.ts +20 -0
  42. package/dist/wirings/workflow/scenario-poll.js +25 -0
  43. package/dist/wirings/workflow/scenario-prose.d.ts +38 -0
  44. package/dist/wirings/workflow/scenario-prose.js +45 -0
  45. package/dist/wirings/workflow/scenario-step-guards.d.ts +16 -0
  46. package/dist/wirings/workflow/scenario-step-guards.js +29 -0
  47. package/dist/wirings/workflow/scenario-step.types.d.ts +148 -0
  48. package/dist/wirings/workflow/scenario-step.types.js +1 -0
  49. package/dist/wirings/workflow/workflow.types.d.ts +119 -2
  50. package/package.json +3 -1
  51. package/src/function/functions.types.ts +32 -0
  52. package/src/index.ts +1 -0
  53. package/src/internal.ts +5 -1
  54. package/src/pikku-state.ts +1 -0
  55. package/src/services/http-scenario-actors.test.ts +85 -1
  56. package/src/services/http-scenario-actors.ts +65 -51
  57. package/src/services/in-memory-workflow-service.test.ts +50 -1
  58. package/src/services/in-memory-workflow-service.ts +3 -2
  59. package/src/services/index.ts +5 -0
  60. package/src/services/meta-service.test.ts +79 -0
  61. package/src/services/meta-service.ts +61 -26
  62. package/src/services/scenario-actors-service.ts +157 -2
  63. package/src/types/core.types.ts +27 -2
  64. package/src/types/state.types.ts +3 -0
  65. package/src/wirings/actor-flow/actor-flow.types.ts +1 -1
  66. package/src/wirings/actor-flow/index.ts +1 -1
  67. package/src/wirings/actor-flow/run-conversation.test.ts +12 -6
  68. package/src/wirings/actor-flow/run-conversation.ts +36 -41
  69. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +29 -0
  70. package/src/wirings/ai-agent/ai-agent-prepare.ts +38 -4
  71. package/src/wirings/cli/command-parser.test.ts +60 -0
  72. package/src/wirings/cli/command-parser.ts +12 -1
  73. package/src/wirings/queue/index.ts +2 -0
  74. package/src/wirings/queue/queue.types.ts +32 -0
  75. package/src/wirings/rpc/rpc-runner.test.ts +28 -5
  76. package/src/wirings/rpc/rpc-runner.ts +1 -1
  77. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +86 -2
  78. package/src/wirings/workflow/feature.test.ts +131 -0
  79. package/src/wirings/workflow/feature.ts +78 -0
  80. package/src/wirings/workflow/index.ts +74 -0
  81. package/src/wirings/workflow/pikku-scenario-service.ts +682 -0
  82. package/src/wirings/workflow/pikku-workflow-service.test.ts +126 -0
  83. package/src/wirings/workflow/pikku-workflow-service.ts +306 -228
  84. package/src/wirings/workflow/scenario-cookie-jar.test.ts +108 -0
  85. package/src/wirings/workflow/scenario-cookie-jar.ts +65 -0
  86. package/src/wirings/workflow/scenario-hooks.test.ts +212 -0
  87. package/src/wirings/workflow/scenario-poll.test.ts +66 -0
  88. package/src/wirings/workflow/scenario-poll.ts +36 -0
  89. package/src/wirings/workflow/scenario-prose.test.ts +152 -0
  90. package/src/wirings/workflow/scenario-prose.ts +79 -0
  91. package/src/wirings/workflow/scenario-service.test.ts +155 -0
  92. package/src/wirings/workflow/scenario-step-guards.ts +43 -0
  93. package/src/wirings/workflow/scenario-step.test.ts +441 -8
  94. package/src/wirings/workflow/scenario-step.types.ts +157 -0
  95. package/src/wirings/workflow/workflow.types.ts +137 -1
  96. package/tsconfig.tsbuildinfo +1 -1
@@ -1,10 +1,10 @@
1
- import type { SerializedError } from '../../types/core.types.js';
2
- import type { ApprovalOutcome, PikkuScenarioWire, StepState, StepStatus, WorkflowPlannedStep, WorkflowRun, WorkflowRunMirror, WorkflowRunStatus, WorkflowRunWire, WorkflowStatus, WorkflowVersionStatus, WorkflowStepOptions } from './workflow.types.js';
1
+ import type { PikkuWire, SerializedError } from '../../types/core.types.js';
2
+ import type { ApprovalOutcome, CoreWorkflow, PikkuWorkflowWire, StepState, StepStatus, WorkflowPlannedStep, WorkflowRun, WorkflowRunMirror, WorkflowRunStatus, WorkflowRunWire, WorkflowStatus, WorkflowVersionStatus, WorkflowQueueOptions, WorkflowStepOptions } from './workflow.types.js';
3
3
  import type { WorkflowService } from '../../services/workflow-service.js';
4
4
  import type { ScenarioActors } from '../../services/scenario-actors-service.js';
5
5
  import { PikkuError } from '../../errors/error-handler.js';
6
6
  import { type RunTimeline, type ReconstructedRunState } from './run-timeline.js';
7
- import type { JobOptions } from '../queue/queue.types.js';
7
+ import type { GroupConcurrencyConfig, JobGroup, JobOptions } from '../queue/queue.types.js';
8
8
  /**
9
9
  * Default number of retries for a workflow step when none is specified. The
10
10
  * workflow — not the queue — owns retry policy; a step inherits this unless it
@@ -88,6 +88,72 @@ export declare class WorkflowServiceNotInitialized extends Error {
88
88
  export declare class WorkflowStepNameNotString extends Error {
89
89
  constructor(stepName: any);
90
90
  }
91
+ /**
92
+ * Everything an extension needs to run something of its own around a run's
93
+ * function: the registration it was resolved from, the run itself (so `input`
94
+ * is the same object the function is called with), and the wire it is given.
95
+ */
96
+ export interface RunLifecycleContext {
97
+ runId: string;
98
+ run: WorkflowRun;
99
+ workflowMeta: any;
100
+ workflow: CoreWorkflow;
101
+ wire: PikkuWire;
102
+ packageName: string | null;
103
+ }
104
+ /**
105
+ * The slice of the run engine an extension is allowed to drive, handed to it at
106
+ * construction. It exists so that recording a durable step stays available to
107
+ * an extension without `inlineStep` and friends becoming public API on every
108
+ * workflow service a production app instantiates.
109
+ */
110
+ export interface WorkflowRunEngine {
111
+ inlineStep(runId: string, logicalStepName: string, fn: Function, stepOptions?: WorkflowStepOptions, data?: any, funcName?: string): Promise<any>;
112
+ updateRunStatus(runId: string, status: WorkflowStatus, output?: any, error?: SerializedError): Promise<void>;
113
+ onChildWorkflowFailed(run: WorkflowRun, error: unknown): Promise<void>;
114
+ verifyStepName(stepName: unknown): void;
115
+ }
116
+ /**
117
+ * A capability layered onto a run without being a workflow service itself.
118
+ *
119
+ * The engine names nothing about what an extension is for: a bundler drops an
120
+ * unused *module* but never an unused class member, so the alternative — a
121
+ * subclass carrying the capability — puts it in every server built on Pikku
122
+ * whether or not the app ever uses it. Scenarios are the one implementation
123
+ * today (`PikkuScenarioService` in `@pikku/core/scenario`).
124
+ */
125
+ export interface WorkflowRunExtension {
126
+ /** Per-run state resolved once the run has an id. */
127
+ attachRunContext(runId: string, workflowMeta: any, options?: Record<string, any>): Promise<void>;
128
+ /** Release whatever `attachRunContext` stored. */
129
+ detachRunContext(runId: string): void;
130
+ /** Contribute extra members to the wire a run's function is invoked with. */
131
+ decorateRunWire(wire: PikkuWire, context: {
132
+ runId: string;
133
+ workflowMeta: any;
134
+ workflowWire: PikkuWorkflowWire;
135
+ }): void;
136
+ /** Contribute extra members to the workflow wire itself, in place. */
137
+ decorateWorkflowWire(workflowWire: PikkuWorkflowWire, context: {
138
+ name: string;
139
+ runId: string;
140
+ rpcService: any;
141
+ addonNamespace?: string | null;
142
+ }): void;
143
+ /**
144
+ * Called immediately before the run's function, inside the run lock. Throwing
145
+ * skips the function and fails the run.
146
+ */
147
+ onBeforeRunFunc(context: RunLifecycleContext): Promise<void>;
148
+ /**
149
+ * Called once the run reaches a terminal state, in a `finally`, so it runs
150
+ * whether the function passed or threw. `interrupted` means the run suspended
151
+ * or went async and is still mid-flight. Throwing here propagates, replacing
152
+ * a pending failure, so an extension that must not mask one handles that
153
+ * itself.
154
+ */
155
+ onAfterRunFunc(context: RunLifecycleContext, outcome: 'completed' | 'failed' | 'interrupted', failure: unknown): Promise<void>;
156
+ }
91
157
  /**
92
158
  * Abstract workflow state service
93
159
  * Implementations provide pluggable storage backends (SQLite, PostgreSQL, etc.)
@@ -95,13 +161,16 @@ export declare class WorkflowStepNameNotString extends Error {
95
161
  */
96
162
  export declare abstract class PikkuWorkflowService implements WorkflowService {
97
163
  private inlineRuns;
98
- private runActors;
164
+ private runExtension?;
99
165
  protected get logger(): import("../../services/logger.js").Logger;
100
166
  protected mirror?: WorkflowRunMirror;
167
+ protected readonly queueStrategy: 'per-workflow' | 'shared-groups';
168
+ protected readonly queueConcurrency: number;
169
+ protected readonly queueGroupConcurrency: number | GroupConcurrencyConfig;
101
170
  constructor(options?: {
102
171
  wireQueues?: boolean;
103
172
  mirror?: WorkflowRunMirror;
104
- });
173
+ } & WorkflowQueueOptions);
105
174
  private safeMirror;
106
175
  /**
107
176
  * Wire the queue-based orchestrator/step/sleeper workers.
@@ -176,7 +245,10 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
176
245
  * Creates pending step in both workflow_step and workflow_step_history
177
246
  * @param runId - Run ID
178
247
  * @param stepName - Step cache key
179
- * @param rpcName - RPC function name
248
+ * @param rpcName - The name this step was dispatched by: an RPC for a
249
+ * `workflow.do` step, a step function for a scenario step, null for a
250
+ * closure. Nothing dispatches off this value — it is recorded so a reader
251
+ * can join a step back to the function that ran it.
180
252
  * @param data - Step input data
181
253
  * @param stepOptions - Step options (retries, retryDelay)
182
254
  * @returns Step state with generated stepId
@@ -379,18 +451,28 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
379
451
  * false to fall through to inline `setTimeout` behavior.
380
452
  */
381
453
  protected scheduleSleep(runId: string, stepId: string, duration: number | string): Promise<boolean>;
382
- /** Build HTTP scenario actors for a run started without them; undefined when SCENARIO_ACTOR_SECRET or the API URL is missing */
383
- private resolveScenarioActors;
454
+ /**
455
+ * Install the one extension a run may have, built from a handle onto the run
456
+ * engine so that `inlineStep` and friends stay protected rather than becoming
457
+ * public API. Returns the extension, so the caller keeps a typed reference to
458
+ * whatever it just built.
459
+ */
460
+ setRunExtension<T extends WorkflowRunExtension>(create: (engine: WorkflowRunEngine) => T): T;
461
+ getRunExtension(): WorkflowRunExtension | undefined;
384
462
  /**
385
463
  * Start a new workflow run
386
464
  * Automatically detects workflow type (DSL or graph) from meta and executes accordingly
387
465
  * @param options.inline - If true, execute workflow directly without queue service
388
466
  * @param options.startNode - Starting node ID for graph workflows (from wire config)
467
+ * @param options.onRunCreated - Called with the run id the moment the run exists.
468
+ * An inline run that fails throws instead of returning, so this is the only
469
+ * way a caller can still read that run back — its steps, and which one failed.
389
470
  */
390
471
  startWorkflow<I>(name: string, input: I, wire: WorkflowRunWire, rpcService: any, options?: {
391
472
  inline?: boolean;
392
473
  startNode?: string;
393
474
  actors?: ScenarioActors;
475
+ onRunCreated?: (runId: string) => void;
394
476
  }): Promise<{
395
477
  runId: string;
396
478
  }>;
@@ -413,7 +495,7 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
413
495
  runWorkflowJob(runId: string, rpcService: any): Promise<void>;
414
496
  private runWorkflowJobInner;
415
497
  private onChildWorkflowCompleted;
416
- private onChildWorkflowFailed;
498
+ protected onChildWorkflowFailed(childRun: WorkflowRun, error: Error): Promise<void>;
417
499
  private runVersionMismatchFallback;
418
500
  /**
419
501
  * Execute a single workflow step (called by worker)
@@ -452,7 +534,21 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
452
534
  */
453
535
  private runStepCompensation;
454
536
  private rpcStep;
455
- private inlineStep;
537
+ protected inlineStep(runId: string, logicalStepName: string, fn: Function, stepOptions?: WorkflowStepOptions,
538
+ /**
539
+ * The input this step was called with, recorded on the run so a reporter can
540
+ * name the values under test. A closure step has none; a scenario step does.
541
+ */
542
+ data?: any,
543
+ /**
544
+ * The name this step was dispatched by, for the kinds of inline step that
545
+ * have one. A closure step has no name; a scenario step is a step RPC, so
546
+ * it records the step function that ran — which is the only way to join a
547
+ * step back to its declaration when its durable name was built at runtime
548
+ * (a step called in a loop reaches the run as `sees @pikku/addon-todos`,
549
+ * declared as `sees ${packageName}`).
550
+ */
551
+ rpcName?: string | null): Promise<any>;
456
552
  private sleepStep;
457
553
  /**
458
554
  * Derive the durable step name for a suspend point from its `reason`, so each
@@ -504,8 +600,8 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
504
600
  */
505
601
  approveStep(runId: string, reason: string, decision: unknown): Promise<void>;
506
602
  private approvalStep;
507
- createWorkflowWire(name: string, runId: string, rpcService: any, addonNamespace?: string | null): PikkuScenarioWire;
508
- private verifyStepName;
603
+ createWorkflowWire(name: string, runId: string, rpcService: any, addonNamespace?: string | null): PikkuWorkflowWire;
604
+ protected verifyStepName(stepName: string): void;
509
605
  private getConfig;
510
606
  /**
511
607
  * Get the orchestrator queue name for a specific workflow.
@@ -519,4 +615,14 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
519
615
  */
520
616
  protected getOrchestratorQueueName(workflowName?: string): string;
521
617
  protected getStepWorkerQueueName(rpcName?: string): string;
618
+ /**
619
+ * Fairness key for a job on a shared queue. Under `'per-workflow'` the queue
620
+ * name already isolates workflows, so no group is needed — returning one
621
+ * anyway would cap a workflow inside its own dedicated queue.
622
+ *
623
+ * The tier repeats the id so a workflow can be given its own limit purely
624
+ * from config, with no per-workflow wiring; an unmatched tier falls back to
625
+ * the default limit.
626
+ */
627
+ protected getJobGroup(id?: string): JobGroup | undefined;
522
628
  }