@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.
- package/CHANGELOG.md +11 -0
- package/dist/dev/hot-reload.js +20 -6
- package/dist/errors/error-handler.d.ts +1 -1
- package/dist/errors/error-handler.js +2 -2
- package/dist/function/functions.types.d.ts +3 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +2 -2
- package/dist/middleware/telemetry.d.ts +2 -2
- package/dist/middleware/telemetry.js +2 -2
- package/dist/middleware-runner.d.ts +15 -27
- package/dist/middleware-runner.js +25 -30
- package/dist/permissions.d.ts +15 -22
- package/dist/permissions.js +30 -25
- package/dist/pikku-request.js +1 -1
- package/dist/pikku-state.js +2 -3
- package/dist/services/ai-agent-runner-service.d.ts +1 -0
- package/dist/services/in-memory-queue-service.js +1 -1
- package/dist/services/in-memory-workflow-service.d.ts +15 -13
- package/dist/services/in-memory-workflow-service.js +31 -13
- package/dist/services/local-content.js +8 -1
- package/dist/services/user-session-service.d.ts +1 -1
- package/dist/testing/service-tests.js +24 -0
- package/dist/types/core.types.d.ts +4 -0
- package/dist/types/state.types.d.ts +2 -18
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +24 -5
- package/dist/wirings/ai-agent/ai-agent-memory.js +128 -23
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +10 -1
- package/dist/wirings/ai-agent/ai-agent-model-config.js +15 -35
- package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +45 -31
- package/dist/wirings/ai-agent/ai-agent-stream.js +63 -34
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +20 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-store.d.ts +13 -0
- package/dist/wirings/channel/channel.types.d.ts +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +23 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +8 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +9 -0
- package/dist/wirings/cli/cli-runner.js +24 -5
- package/dist/wirings/cli/command-parser.js +19 -4
- package/dist/wirings/http/http-runner.js +72 -36
- package/dist/wirings/http/http.types.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -1
- package/dist/wirings/http/web-request.js +32 -0
- package/dist/wirings/rpc/rpc-runner.js +13 -3
- package/dist/wirings/workflow/graph/graph-node.d.ts +8 -0
- package/dist/wirings/workflow/graph/graph-node.js +4 -0
- package/dist/wirings/workflow/graph/graph-runner.js +12 -10
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +4 -0
- package/dist/wirings/workflow/index.d.ts +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +81 -16
- package/dist/wirings/workflow/pikku-workflow-service.js +266 -45
- package/dist/wirings/workflow/workflow.types.d.ts +34 -0
- package/package.json +1 -1
- package/run-tests.sh +4 -1
- package/src/dev/hot-reload.test.ts +62 -11
- package/src/dev/hot-reload.ts +28 -7
- package/src/errors/error-handler.ts +8 -2
- package/src/errors/error.test.ts +2 -0
- package/src/function/function-runner.test.ts +500 -10
- package/src/function/functions.types.ts +3 -2
- package/src/index.ts +12 -2
- package/src/middleware/index.ts +11 -2
- package/src/middleware/telemetry.ts +2 -2
- package/src/middleware-runner.test.ts +16 -16
- package/src/middleware-runner.ts +42 -30
- package/src/permissions.test.ts +27 -24
- package/src/permissions.ts +41 -25
- package/src/pikku-request.test.ts +35 -0
- package/src/pikku-request.ts +1 -1
- package/src/pikku-state.ts +2 -3
- package/src/run-tests-script.test.ts +18 -0
- package/src/services/ai-agent-runner-service.ts +1 -0
- package/src/services/in-memory-queue-service.ts +1 -1
- package/src/services/in-memory-session-store.ts +1 -2
- package/src/services/in-memory-workflow-service.test.ts +33 -11
- package/src/services/in-memory-workflow-service.ts +49 -13
- package/src/services/local-content.test.ts +54 -0
- package/src/services/local-content.ts +12 -1
- package/src/services/typed-credential-service.ts +3 -3
- package/src/services/typed-secret-service.ts +3 -3
- package/src/services/typed-variables-service.ts +3 -3
- package/src/services/user-session-service.ts +4 -4
- package/src/testing/service-tests.ts +30 -0
- package/src/types/core.types.ts +6 -2
- package/src/types/state.types.ts +2 -13
- package/src/wirings/ai-agent/ai-agent-memory.test.ts +324 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +187 -36
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +12 -90
- package/src/wirings/ai-agent/ai-agent-model-config.ts +14 -38
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +292 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -1
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +230 -3
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +625 -6
- package/src/wirings/ai-agent/ai-agent-runner.ts +65 -50
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +544 -5
- package/src/wirings/ai-agent/ai-agent-stream.ts +71 -69
- package/src/wirings/ai-agent/ai-agent.types.ts +24 -0
- package/src/wirings/channel/channel-handler.test.ts +272 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-middleware-runner.test.ts +163 -0
- package/src/wirings/channel/channel-store.ts +19 -0
- package/src/wirings/channel/channel.types.ts +4 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +63 -0
- package/src/wirings/channel/local/local-channel-runner.ts +41 -5
- package/src/wirings/channel/local/local-eventhub-service.ts +3 -3
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +9 -2
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +23 -5
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +7 -2
- package/src/wirings/cli/cli-runner.test.ts +255 -2
- package/src/wirings/cli/cli-runner.ts +31 -10
- package/src/wirings/cli/cli.types.ts +4 -8
- package/src/wirings/cli/command-parser.test.ts +83 -0
- package/src/wirings/cli/command-parser.ts +23 -4
- package/src/wirings/http/http-runner.test.ts +296 -1
- package/src/wirings/http/http-runner.ts +87 -57
- package/src/wirings/http/http.types.ts +11 -26
- package/src/wirings/http/pikku-fetch-http-request.ts +8 -4
- package/src/wirings/http/pikku-fetch-http-response.test.ts +41 -0
- package/src/wirings/http/web-request.test.ts +115 -0
- package/src/wirings/http/web-request.ts +43 -5
- package/src/wirings/mcp/mcp-runner.test.ts +367 -0
- package/src/wirings/queue/queue.types.ts +2 -5
- package/src/wirings/rpc/rpc-runner.test.ts +511 -0
- package/src/wirings/rpc/rpc-runner.ts +15 -3
- package/src/wirings/rpc/wire-addon.test.ts +57 -0
- package/src/wirings/workflow/graph/graph-node.ts +12 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +98 -0
- package/src/wirings/workflow/graph/graph-runner.ts +28 -10
- package/src/wirings/workflow/graph/workflow-graph.types.ts +4 -0
- package/src/wirings/workflow/index.ts +1 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +19 -2
- package/src/wirings/workflow/pikku-workflow-service.ts +370 -71
- package/src/wirings/workflow/workflow-queue-workers.test.ts +131 -0
- package/src/wirings/workflow/workflow.types.ts +68 -5
- 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
|
-
|
|
330
|
-
retries: 0,
|
|
331
|
-
|
|
332
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
/**
|
|
@@ -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)
|