@pikku/core 0.12.20 → 0.12.21

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 (138) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/dev/hot-reload.js +20 -6
  3. package/dist/errors/error-handler.d.ts +1 -1
  4. package/dist/errors/error-handler.js +2 -2
  5. package/dist/function/functions.types.d.ts +3 -2
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.js +2 -2
  8. package/dist/middleware/index.d.ts +2 -2
  9. package/dist/middleware/index.js +2 -2
  10. package/dist/middleware/telemetry.d.ts +2 -2
  11. package/dist/middleware/telemetry.js +2 -2
  12. package/dist/middleware-runner.d.ts +15 -27
  13. package/dist/middleware-runner.js +25 -30
  14. package/dist/permissions.d.ts +15 -22
  15. package/dist/permissions.js +30 -25
  16. package/dist/pikku-request.js +1 -1
  17. package/dist/pikku-state.js +2 -3
  18. package/dist/services/ai-agent-runner-service.d.ts +1 -0
  19. package/dist/services/in-memory-queue-service.js +1 -1
  20. package/dist/services/in-memory-workflow-service.d.ts +15 -13
  21. package/dist/services/in-memory-workflow-service.js +31 -13
  22. package/dist/services/local-content.js +8 -1
  23. package/dist/services/user-session-service.d.ts +1 -1
  24. package/dist/testing/service-tests.js +24 -0
  25. package/dist/types/core.types.d.ts +4 -0
  26. package/dist/types/state.types.d.ts +2 -18
  27. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +24 -5
  28. package/dist/wirings/ai-agent/ai-agent-memory.js +128 -23
  29. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +10 -1
  30. package/dist/wirings/ai-agent/ai-agent-model-config.js +15 -35
  31. package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
  32. package/dist/wirings/ai-agent/ai-agent-runner.js +45 -31
  33. package/dist/wirings/ai-agent/ai-agent-stream.js +63 -34
  34. package/dist/wirings/ai-agent/ai-agent.types.d.ts +20 -0
  35. package/dist/wirings/channel/channel-handler.js +1 -1
  36. package/dist/wirings/channel/channel-store.d.ts +13 -0
  37. package/dist/wirings/channel/channel.types.d.ts +3 -0
  38. package/dist/wirings/channel/local/local-channel-runner.js +23 -5
  39. package/dist/wirings/channel/pikku-abstract-channel-handler.js +8 -0
  40. package/dist/wirings/channel/serverless/serverless-channel-runner.js +9 -0
  41. package/dist/wirings/cli/cli-runner.js +24 -5
  42. package/dist/wirings/cli/command-parser.js +19 -4
  43. package/dist/wirings/http/http-runner.js +72 -36
  44. package/dist/wirings/http/http.types.d.ts +1 -0
  45. package/dist/wirings/http/pikku-fetch-http-request.js +3 -1
  46. package/dist/wirings/http/web-request.js +32 -0
  47. package/dist/wirings/rpc/rpc-runner.js +13 -3
  48. package/dist/wirings/workflow/graph/graph-node.d.ts +8 -0
  49. package/dist/wirings/workflow/graph/graph-node.js +4 -0
  50. package/dist/wirings/workflow/graph/graph-runner.js +12 -10
  51. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +4 -0
  52. package/dist/wirings/workflow/index.d.ts +1 -1
  53. package/dist/wirings/workflow/pikku-workflow-service.d.ts +81 -16
  54. package/dist/wirings/workflow/pikku-workflow-service.js +266 -45
  55. package/dist/wirings/workflow/workflow.types.d.ts +34 -0
  56. package/package.json +1 -1
  57. package/run-tests.sh +4 -1
  58. package/src/dev/hot-reload.test.ts +62 -11
  59. package/src/dev/hot-reload.ts +28 -7
  60. package/src/errors/error-handler.ts +8 -2
  61. package/src/errors/error.test.ts +2 -0
  62. package/src/function/function-runner.test.ts +500 -10
  63. package/src/function/functions.types.ts +3 -2
  64. package/src/index.ts +12 -2
  65. package/src/middleware/index.ts +11 -2
  66. package/src/middleware/telemetry.ts +2 -2
  67. package/src/middleware-runner.test.ts +16 -16
  68. package/src/middleware-runner.ts +42 -30
  69. package/src/permissions.test.ts +27 -24
  70. package/src/permissions.ts +41 -25
  71. package/src/pikku-request.test.ts +35 -0
  72. package/src/pikku-request.ts +1 -1
  73. package/src/pikku-state.ts +2 -3
  74. package/src/run-tests-script.test.ts +18 -0
  75. package/src/services/ai-agent-runner-service.ts +1 -0
  76. package/src/services/in-memory-queue-service.ts +1 -1
  77. package/src/services/in-memory-session-store.ts +1 -2
  78. package/src/services/in-memory-workflow-service.test.ts +33 -11
  79. package/src/services/in-memory-workflow-service.ts +49 -13
  80. package/src/services/local-content.test.ts +54 -0
  81. package/src/services/local-content.ts +12 -1
  82. package/src/services/typed-credential-service.ts +3 -3
  83. package/src/services/typed-secret-service.ts +3 -3
  84. package/src/services/typed-variables-service.ts +3 -3
  85. package/src/services/user-session-service.ts +4 -4
  86. package/src/testing/service-tests.ts +30 -0
  87. package/src/types/core.types.ts +6 -2
  88. package/src/types/state.types.ts +2 -13
  89. package/src/wirings/ai-agent/ai-agent-memory.test.ts +324 -0
  90. package/src/wirings/ai-agent/ai-agent-memory.ts +187 -36
  91. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +12 -90
  92. package/src/wirings/ai-agent/ai-agent-model-config.ts +14 -38
  93. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +292 -0
  94. package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -1
  95. package/src/wirings/ai-agent/ai-agent-registry.test.ts +230 -3
  96. package/src/wirings/ai-agent/ai-agent-runner.test.ts +625 -6
  97. package/src/wirings/ai-agent/ai-agent-runner.ts +65 -50
  98. package/src/wirings/ai-agent/ai-agent-stream.test.ts +544 -5
  99. package/src/wirings/ai-agent/ai-agent-stream.ts +71 -69
  100. package/src/wirings/ai-agent/ai-agent.types.ts +24 -0
  101. package/src/wirings/channel/channel-handler.test.ts +272 -0
  102. package/src/wirings/channel/channel-handler.ts +1 -1
  103. package/src/wirings/channel/channel-middleware-runner.test.ts +163 -0
  104. package/src/wirings/channel/channel-store.ts +19 -0
  105. package/src/wirings/channel/channel.types.ts +4 -0
  106. package/src/wirings/channel/local/local-channel-runner.test.ts +63 -0
  107. package/src/wirings/channel/local/local-channel-runner.ts +41 -5
  108. package/src/wirings/channel/local/local-eventhub-service.ts +3 -3
  109. package/src/wirings/channel/pikku-abstract-channel-handler.ts +9 -2
  110. package/src/wirings/channel/serverless/serverless-channel-runner.ts +23 -5
  111. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +7 -2
  112. package/src/wirings/cli/cli-runner.test.ts +255 -2
  113. package/src/wirings/cli/cli-runner.ts +31 -10
  114. package/src/wirings/cli/cli.types.ts +4 -8
  115. package/src/wirings/cli/command-parser.test.ts +83 -0
  116. package/src/wirings/cli/command-parser.ts +23 -4
  117. package/src/wirings/http/http-runner.test.ts +296 -1
  118. package/src/wirings/http/http-runner.ts +87 -57
  119. package/src/wirings/http/http.types.ts +11 -26
  120. package/src/wirings/http/pikku-fetch-http-request.ts +8 -4
  121. package/src/wirings/http/pikku-fetch-http-response.test.ts +41 -0
  122. package/src/wirings/http/web-request.test.ts +115 -0
  123. package/src/wirings/http/web-request.ts +43 -5
  124. package/src/wirings/mcp/mcp-runner.test.ts +367 -0
  125. package/src/wirings/queue/queue.types.ts +2 -5
  126. package/src/wirings/rpc/rpc-runner.test.ts +511 -0
  127. package/src/wirings/rpc/rpc-runner.ts +15 -3
  128. package/src/wirings/rpc/wire-addon.test.ts +57 -0
  129. package/src/wirings/workflow/graph/graph-node.ts +12 -0
  130. package/src/wirings/workflow/graph/graph-runner.test.ts +98 -0
  131. package/src/wirings/workflow/graph/graph-runner.ts +28 -10
  132. package/src/wirings/workflow/graph/workflow-graph.types.ts +4 -0
  133. package/src/wirings/workflow/index.ts +1 -0
  134. package/src/wirings/workflow/pikku-workflow-service.test.ts +19 -2
  135. package/src/wirings/workflow/pikku-workflow-service.ts +370 -71
  136. package/src/wirings/workflow/workflow-queue-workers.test.ts +131 -0
  137. package/src/wirings/workflow/workflow.types.ts +68 -5
  138. package/tsconfig.tsbuildinfo +1 -1
@@ -526,4 +526,102 @@ describe('graph-runner bugs', () => {
526
526
 
527
527
  delete metaState['testInlineMetaGraph']
528
528
  })
529
+
530
+ test('queueGraphNode forwards node retries to queue attempts and backoff', async () => {
531
+ const ws = new InMemoryWorkflowService()
532
+ const enqueued: Array<{ queueName: string; data: any; options: any }> = []
533
+
534
+ pikkuState(null, 'package', 'singletonServices', {
535
+ queueService: {
536
+ add: async (queueName: string, data: any, options: any) => {
537
+ enqueued.push({ queueName, data, options })
538
+ },
539
+ },
540
+ } as any)
541
+
542
+ const meta: WorkflowRuntimeMeta = {
543
+ name: 'testRetries',
544
+ pikkuFuncId: 'testRetries',
545
+ source: 'graph',
546
+ entryNodeIds: ['a'],
547
+ graphHash: 'retries-hash',
548
+ nodes: {
549
+ a: {
550
+ nodeId: 'a',
551
+ rpcName: 'doA',
552
+ retries: 3,
553
+ retryDelay: 250,
554
+ },
555
+ b: {
556
+ nodeId: 'b',
557
+ rpcName: 'doB',
558
+ retries: 2,
559
+ retryDelay: 'exponential',
560
+ },
561
+ c: {
562
+ nodeId: 'c',
563
+ rpcName: 'doC',
564
+ },
565
+ },
566
+ }
567
+
568
+ const { runId } = await runWorkflowGraph(
569
+ ws,
570
+ 'testRetries',
571
+ {},
572
+ { rpcWithWire: async () => ({}) },
573
+ false,
574
+ undefined,
575
+ undefined,
576
+ meta
577
+ )
578
+
579
+ const aJob = enqueued.find((e) => e.data?.stepName === 'a')
580
+ assert.ok(aJob, 'node a should have been enqueued')
581
+ assert.equal(aJob!.options?.attempts, 4, 'retries=3 → attempts=4')
582
+ assert.deepEqual(aJob!.options?.backoff, { type: 'fixed', delay: 250 })
583
+
584
+ const stepStateA = await ws.getStepState(runId, 'a')
585
+ assert.equal(
586
+ stepStateA.retries,
587
+ 3,
588
+ 'insertStepState should record node retries'
589
+ )
590
+ assert.equal(stepStateA.retryDelay, 250)
591
+
592
+ enqueued.length = 0
593
+ await runWorkflowGraph(
594
+ ws,
595
+ 'testRetries',
596
+ {},
597
+ { rpcWithWire: async () => ({}) },
598
+ false,
599
+ 'b',
600
+ undefined,
601
+ meta
602
+ )
603
+ const bJob = enqueued.find((e) => e.data?.stepName === 'b')
604
+ assert.ok(bJob, 'node b should have been enqueued')
605
+ assert.equal(bJob!.options?.attempts, 3, 'retries=2 → attempts=3')
606
+ assert.equal(bJob!.options?.backoff, 'exponential')
607
+
608
+ enqueued.length = 0
609
+ await runWorkflowGraph(
610
+ ws,
611
+ 'testRetries',
612
+ {},
613
+ { rpcWithWire: async () => ({}) },
614
+ false,
615
+ 'c',
616
+ undefined,
617
+ meta
618
+ )
619
+ const cJob = enqueued.find((e) => e.data?.stepName === 'c')
620
+ assert.ok(cJob, 'node c should have been enqueued')
621
+ assert.equal(
622
+ cJob!.options,
623
+ undefined,
624
+ 'no retries → no queue options (preserves prior queue defaults)'
625
+ )
626
+ })
529
627
  })
@@ -324,12 +324,27 @@ async function queueGraphNode(
324
324
  _graphName: string,
325
325
  nodeId: string,
326
326
  rpcName: string,
327
- input: any
327
+ input: any,
328
+ nodeConfig?: { retries?: number; retryDelay?: string | number }
328
329
  ): Promise<void> {
329
- await workflowService.insertStepState(runId, nodeId, rpcName, input, {
330
- retries: 0,
331
- })
332
- await workflowService.queueStepWorker(runId, nodeId, rpcName, input)
330
+ const stepOptions = {
331
+ retries: nodeConfig?.retries ?? 0,
332
+ retryDelay: nodeConfig?.retryDelay,
333
+ }
334
+ await workflowService.insertStepState(
335
+ runId,
336
+ nodeId,
337
+ rpcName,
338
+ input,
339
+ stepOptions
340
+ )
341
+ await workflowService.queueStepWorker(
342
+ runId,
343
+ nodeId,
344
+ rpcName,
345
+ input,
346
+ stepOptions
347
+ )
333
348
  }
334
349
 
335
350
  export async function continueGraph(
@@ -442,7 +457,8 @@ export async function continueGraph(
442
457
  graphName,
443
458
  nodeId,
444
459
  node.rpcName,
445
- resolvedInput
460
+ resolvedInput,
461
+ node
446
462
  )
447
463
  }
448
464
  }
@@ -553,7 +569,8 @@ export async function executeGraphStep(
553
569
  graphName,
554
570
  errorNodeId,
555
571
  errorNode.rpcName,
556
- { error: { message: (error as Error).message } }
572
+ { error: { message: (error as Error).message } },
573
+ errorNode
557
574
  )
558
575
  }
559
576
  }
@@ -600,7 +617,7 @@ async function executeGraphNodeInline(
600
617
  nodeId,
601
618
  rpcName,
602
619
  input,
603
- { retries: 3 }
620
+ { retries: node.retries ?? 0, retryDelay: node.retryDelay }
604
621
  )
605
622
 
606
623
  await workflowService.setStepRunning(stepState.stepId)
@@ -677,7 +694,7 @@ async function executeGraphNodeInline(
677
694
  message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
678
695
  code: 'RPC_NOT_FOUND',
679
696
  })
680
- return
697
+ throw new WorkflowSuspendedException(runId, 'RPC_NOT_FOUND')
681
698
  }
682
699
  await workflowService.setStepError(stepState.stepId, error as Error)
683
700
 
@@ -932,7 +949,8 @@ export async function runWorkflowGraph(
932
949
  graphName,
933
950
  nodeId,
934
951
  node.rpcName,
935
- resolvedInput
952
+ resolvedInput,
953
+ node
936
954
  )
937
955
  }
938
956
  if (inline) {
@@ -65,6 +65,10 @@ export interface GraphNodeConfig<NodeIds extends string = string> {
65
65
  next?: NextConfig<NodeIds>
66
66
  /** Error routing - node(s) to execute on error */
67
67
  onError?: NodeIds | NodeIds[]
68
+ /** Maximum retry attempts allowed (excludes the initial attempt) */
69
+ retries?: number
70
+ /** Delay between retries — milliseconds, duration string, or 'exponential' */
71
+ retryDelay?: string | number
68
72
  }
69
73
 
70
74
  /**
@@ -51,6 +51,7 @@ export type {
51
51
  WorkflowRunStatus,
52
52
  StepState,
53
53
  WorkflowRunService,
54
+ WorkflowRunMirror,
54
55
  CoreWorkflow,
55
56
  PikkuWorkflow,
56
57
  ContextVariable,
@@ -2,13 +2,30 @@ import { describe, test } from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
3
 
4
4
  import { InMemoryWorkflowService } from '../../services/in-memory-workflow-service.js'
5
- import { pikkuState } from '../../pikku-state.js'
5
+ import { pikkuState, resetPikkuState } from '../../pikku-state.js'
6
6
  import { addWorkflow } from './dsl/workflow-runner.js'
7
7
  import {
8
8
  WorkflowSuspendedException,
9
9
  type PikkuWorkflowWire,
10
10
  } from './pikku-workflow-service.js'
11
11
 
12
+ describe('pikku-workflow-service worker registration', () => {
13
+ test('registers sleeper function metadata', () => {
14
+ resetPikkuState()
15
+
16
+ new InMemoryWorkflowService()
17
+
18
+ const functionMeta = pikkuState(null, 'function', 'meta')
19
+ assert.deepEqual(functionMeta.pikkuWorkflowSleeper, {
20
+ pikkuFuncId: 'pikkuWorkflowSleeper',
21
+ sessionless: true,
22
+ functionType: 'helper',
23
+ inputSchemaName: null,
24
+ outputSchemaName: null,
25
+ })
26
+ })
27
+ })
28
+
12
29
  describe('pikku-workflow-service inline meta flag', () => {
13
30
  test('workflow with inline: true in meta should create inline run and not queue', async () => {
14
31
  const ws = new InMemoryWorkflowService()
@@ -53,7 +70,7 @@ describe('pikku-workflow-service inline meta flag', () => {
53
70
  },
54
71
  })
55
72
 
56
- const { runId } = await ws.startWorkflow(workflowName, {}, {})
73
+ const { runId } = await ws.startWorkflow(workflowName, {}, {}, {})
57
74
 
58
75
  // The run should be created as inline
59
76
  const run = await ws.getRun(runId)