@pikku/core 0.12.20 → 0.12.22

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 (141) hide show
  1. package/CHANGELOG.md +17 -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/handle-error.js +3 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +2 -2
  9. package/dist/middleware/index.d.ts +2 -2
  10. package/dist/middleware/index.js +2 -2
  11. package/dist/middleware/telemetry.d.ts +2 -2
  12. package/dist/middleware/telemetry.js +2 -2
  13. package/dist/middleware-runner.d.ts +15 -27
  14. package/dist/middleware-runner.js +25 -30
  15. package/dist/permissions.d.ts +15 -22
  16. package/dist/permissions.js +30 -25
  17. package/dist/pikku-request.js +1 -1
  18. package/dist/pikku-state.js +2 -3
  19. package/dist/services/ai-agent-runner-service.d.ts +1 -0
  20. package/dist/services/in-memory-queue-service.js +1 -1
  21. package/dist/services/in-memory-workflow-service.d.ts +15 -13
  22. package/dist/services/in-memory-workflow-service.js +31 -13
  23. package/dist/services/local-content.js +8 -1
  24. package/dist/services/user-session-service.d.ts +1 -1
  25. package/dist/testing/service-tests.js +24 -0
  26. package/dist/types/core.types.d.ts +4 -0
  27. package/dist/types/state.types.d.ts +2 -18
  28. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +24 -5
  29. package/dist/wirings/ai-agent/ai-agent-memory.js +128 -23
  30. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +10 -1
  31. package/dist/wirings/ai-agent/ai-agent-model-config.js +15 -35
  32. package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
  33. package/dist/wirings/ai-agent/ai-agent-runner.js +45 -31
  34. package/dist/wirings/ai-agent/ai-agent-stream.js +63 -34
  35. package/dist/wirings/ai-agent/ai-agent.types.d.ts +20 -0
  36. package/dist/wirings/channel/channel-handler.js +1 -1
  37. package/dist/wirings/channel/channel-store.d.ts +13 -0
  38. package/dist/wirings/channel/channel.types.d.ts +3 -0
  39. package/dist/wirings/channel/local/local-channel-runner.js +23 -5
  40. package/dist/wirings/channel/pikku-abstract-channel-handler.js +8 -0
  41. package/dist/wirings/channel/serverless/serverless-channel-runner.js +9 -0
  42. package/dist/wirings/cli/cli-runner.js +24 -5
  43. package/dist/wirings/cli/command-parser.js +19 -4
  44. package/dist/wirings/http/http-runner.js +72 -36
  45. package/dist/wirings/http/http.types.d.ts +1 -0
  46. package/dist/wirings/http/pikku-fetch-http-request.js +3 -1
  47. package/dist/wirings/http/web-request.js +32 -0
  48. package/dist/wirings/rpc/rpc-runner.js +13 -3
  49. package/dist/wirings/workflow/graph/graph-node.d.ts +8 -0
  50. package/dist/wirings/workflow/graph/graph-node.js +4 -0
  51. package/dist/wirings/workflow/graph/graph-runner.js +12 -10
  52. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +4 -0
  53. package/dist/wirings/workflow/index.d.ts +1 -1
  54. package/dist/wirings/workflow/pikku-workflow-service.d.ts +81 -16
  55. package/dist/wirings/workflow/pikku-workflow-service.js +266 -45
  56. package/dist/wirings/workflow/workflow.types.d.ts +34 -0
  57. package/package.json +1 -1
  58. package/run-tests.sh +4 -1
  59. package/src/dev/hot-reload.test.ts +62 -11
  60. package/src/dev/hot-reload.ts +28 -7
  61. package/src/errors/error-handler.ts +8 -2
  62. package/src/errors/error.test.ts +2 -0
  63. package/src/function/function-runner.test.ts +500 -10
  64. package/src/function/functions.types.ts +3 -2
  65. package/src/handle-error.test.ts +1 -1
  66. package/src/handle-error.ts +4 -1
  67. package/src/index.ts +12 -2
  68. package/src/middleware/index.ts +11 -2
  69. package/src/middleware/telemetry.ts +2 -2
  70. package/src/middleware-runner.test.ts +16 -16
  71. package/src/middleware-runner.ts +42 -30
  72. package/src/permissions.test.ts +27 -24
  73. package/src/permissions.ts +41 -25
  74. package/src/pikku-request.test.ts +35 -0
  75. package/src/pikku-request.ts +1 -1
  76. package/src/pikku-state.ts +2 -3
  77. package/src/run-tests-script.test.ts +18 -0
  78. package/src/services/ai-agent-runner-service.ts +1 -0
  79. package/src/services/in-memory-queue-service.ts +1 -1
  80. package/src/services/in-memory-session-store.ts +1 -2
  81. package/src/services/in-memory-workflow-service.test.ts +33 -11
  82. package/src/services/in-memory-workflow-service.ts +49 -13
  83. package/src/services/local-content.test.ts +54 -0
  84. package/src/services/local-content.ts +12 -1
  85. package/src/services/typed-credential-service.ts +3 -3
  86. package/src/services/typed-secret-service.ts +3 -3
  87. package/src/services/typed-variables-service.ts +3 -3
  88. package/src/services/user-session-service.ts +4 -4
  89. package/src/testing/service-tests.ts +30 -0
  90. package/src/types/core.types.ts +6 -2
  91. package/src/types/state.types.ts +2 -13
  92. package/src/wirings/ai-agent/ai-agent-memory.test.ts +324 -0
  93. package/src/wirings/ai-agent/ai-agent-memory.ts +187 -36
  94. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +12 -90
  95. package/src/wirings/ai-agent/ai-agent-model-config.ts +14 -38
  96. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +292 -0
  97. package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -1
  98. package/src/wirings/ai-agent/ai-agent-registry.test.ts +230 -3
  99. package/src/wirings/ai-agent/ai-agent-runner.test.ts +625 -6
  100. package/src/wirings/ai-agent/ai-agent-runner.ts +65 -50
  101. package/src/wirings/ai-agent/ai-agent-stream.test.ts +544 -5
  102. package/src/wirings/ai-agent/ai-agent-stream.ts +71 -69
  103. package/src/wirings/ai-agent/ai-agent.types.ts +24 -0
  104. package/src/wirings/channel/channel-handler.test.ts +272 -0
  105. package/src/wirings/channel/channel-handler.ts +1 -1
  106. package/src/wirings/channel/channel-middleware-runner.test.ts +163 -0
  107. package/src/wirings/channel/channel-store.ts +19 -0
  108. package/src/wirings/channel/channel.types.ts +4 -0
  109. package/src/wirings/channel/local/local-channel-runner.test.ts +63 -0
  110. package/src/wirings/channel/local/local-channel-runner.ts +41 -5
  111. package/src/wirings/channel/local/local-eventhub-service.ts +3 -3
  112. package/src/wirings/channel/pikku-abstract-channel-handler.ts +9 -2
  113. package/src/wirings/channel/serverless/serverless-channel-runner.ts +23 -5
  114. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +7 -2
  115. package/src/wirings/cli/cli-runner.test.ts +255 -2
  116. package/src/wirings/cli/cli-runner.ts +31 -10
  117. package/src/wirings/cli/cli.types.ts +4 -8
  118. package/src/wirings/cli/command-parser.test.ts +83 -0
  119. package/src/wirings/cli/command-parser.ts +23 -4
  120. package/src/wirings/http/http-runner.test.ts +296 -1
  121. package/src/wirings/http/http-runner.ts +87 -57
  122. package/src/wirings/http/http.types.ts +11 -26
  123. package/src/wirings/http/pikku-fetch-http-request.ts +8 -4
  124. package/src/wirings/http/pikku-fetch-http-response.test.ts +41 -0
  125. package/src/wirings/http/web-request.test.ts +115 -0
  126. package/src/wirings/http/web-request.ts +43 -5
  127. package/src/wirings/mcp/mcp-runner.test.ts +367 -0
  128. package/src/wirings/queue/queue.types.ts +2 -5
  129. package/src/wirings/rpc/rpc-runner.test.ts +511 -0
  130. package/src/wirings/rpc/rpc-runner.ts +15 -3
  131. package/src/wirings/rpc/wire-addon.test.ts +57 -0
  132. package/src/wirings/workflow/graph/graph-node.ts +12 -0
  133. package/src/wirings/workflow/graph/graph-runner.test.ts +98 -0
  134. package/src/wirings/workflow/graph/graph-runner.ts +28 -10
  135. package/src/wirings/workflow/graph/workflow-graph.types.ts +4 -0
  136. package/src/wirings/workflow/index.ts +1 -0
  137. package/src/wirings/workflow/pikku-workflow-service.test.ts +19 -2
  138. package/src/wirings/workflow/pikku-workflow-service.ts +370 -71
  139. package/src/wirings/workflow/workflow-queue-workers.test.ts +131 -0
  140. package/src/wirings/workflow/workflow.types.ts +68 -5
  141. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,8 @@
1
1
  import { describe, test, beforeEach } from 'node:test'
2
2
  import assert from 'node:assert'
3
3
  import { InMemoryWorkflowService } from './in-memory-workflow-service.js'
4
+ import { getQueueWorkers } from '../wirings/queue/queue-runner.js'
5
+ import { pikkuState } from '../pikku-state.js'
4
6
 
5
7
  let service: InMemoryWorkflowService
6
8
 
@@ -48,17 +50,10 @@ describe('InMemoryWorkflowService', () => {
48
50
  })
49
51
 
50
52
  test('should persist deterministic planned steps metadata', async () => {
51
- const runId = await service.createRun(
52
- 'wf',
53
- {},
54
- true,
55
- 'h',
56
- {} as any,
57
- {
58
- deterministic: true,
59
- plannedSteps: [{ stepName: 'Step 1' }, { stepName: 'Step 2' }],
60
- }
61
- )
53
+ const runId = await service.createRun('wf', {}, true, 'h', {} as any, {
54
+ deterministic: true,
55
+ plannedSteps: [{ stepName: 'Step 1' }, { stepName: 'Step 2' }],
56
+ })
62
57
 
63
58
  const run = await service.getRun(runId)
64
59
  assert.strictEqual(run?.deterministic, true)
@@ -369,4 +364,31 @@ describe('InMemoryWorkflowService', () => {
369
364
  assert.deepStrictEqual(history, [])
370
365
  })
371
366
  })
367
+
368
+ describe('queue worker registration', () => {
369
+ test('rewireQueueWorkers registers workflow queues added after construction', () => {
370
+ const stepQueue = 'wf-step-regression-enrich'
371
+ const orchQueue = 'wf-orchestrator-regression-onboarding'
372
+
373
+ const ws = new InMemoryWorkflowService()
374
+
375
+ const queueMeta = pikkuState(null, 'queue', 'meta')
376
+ queueMeta[stepQueue] = {
377
+ name: stepQueue,
378
+ pikkuFuncId: 'pikkuWorkflowWorker:regressionEnrich',
379
+ }
380
+ queueMeta[orchQueue] = {
381
+ name: orchQueue,
382
+ pikkuFuncId: 'pikkuWorkflowOrchestrator:regressionOnboarding',
383
+ }
384
+
385
+ assert.strictEqual(getQueueWorkers().has(stepQueue), false)
386
+ assert.strictEqual(getQueueWorkers().has(orchQueue), false)
387
+
388
+ ws.rewireQueueWorkers()
389
+
390
+ assert.strictEqual(getQueueWorkers().has(stepQueue), true)
391
+ assert.strictEqual(getQueueWorkers().has(orchQueue), true)
392
+ })
393
+ })
372
394
  })
@@ -37,6 +37,7 @@ export class InMemoryWorkflowService
37
37
  extends PikkuWorkflowService
38
38
  implements WorkflowRunService
39
39
  {
40
+ private sleepTimers = new Set<ReturnType<typeof setTimeout>>()
40
41
  private runs = new Map<string, WorkflowRun>()
41
42
  private steps = new Map<string, StepState>() // keyed by `${runId}:${stepName}`
42
43
  private stepData = new Map<string, InternalStepData>() // keyed by stepId
@@ -51,7 +52,7 @@ export class InMemoryWorkflowService
51
52
  { graph: any; source: string; status: WorkflowVersionStatus }
52
53
  >() // keyed by `${name}:${graphHash}`
53
54
 
54
- async createRun(
55
+ protected async createRunImpl(
55
56
  workflowName: string,
56
57
  input: any,
57
58
  inline: boolean,
@@ -90,6 +91,25 @@ export class InMemoryWorkflowService
90
91
  return runId
91
92
  }
92
93
 
94
+ protected override async scheduleSleep(
95
+ runId: string,
96
+ stepId: string,
97
+ duration: number
98
+ ): Promise<boolean> {
99
+ const timer = setTimeout(async () => {
100
+ this.sleepTimers.delete(timer)
101
+ try {
102
+ await this.executeWorkflowSleepCompleted(runId, stepId)
103
+ } catch (error: any) {
104
+ this.logger?.error(
105
+ `Failed to resume workflow sleep for runId ${runId}: ${error?.message ?? error}`
106
+ )
107
+ }
108
+ }, duration)
109
+ this.sleepTimers.add(timer)
110
+ return true
111
+ }
112
+
93
113
  async getRun(id: string): Promise<WorkflowRun | null> {
94
114
  return this.runs.get(id) || null
95
115
  }
@@ -100,7 +120,7 @@ export class InMemoryWorkflowService
100
120
  return this.stepHistory.get(runId) || []
101
121
  }
102
122
 
103
- async updateRunStatus(
123
+ protected async updateRunStatusImpl(
104
124
  id: string,
105
125
  status: WorkflowStatus,
106
126
  output?: any,
@@ -115,7 +135,7 @@ export class InMemoryWorkflowService
115
135
  }
116
136
  }
117
137
 
118
- async insertStepState(
138
+ protected async insertStepStateImpl(
119
139
  runId: string,
120
140
  stepName: string,
121
141
  rpcName: string | null,
@@ -159,7 +179,7 @@ export class InMemoryWorkflowService
159
179
  return step
160
180
  }
161
181
 
162
- async setStepRunning(stepId: string): Promise<void> {
182
+ protected async setStepRunningImpl(stepId: string): Promise<void> {
163
183
  for (const step of this.steps.values()) {
164
184
  if (step.stepId === stepId) {
165
185
  step.status = 'running'
@@ -170,7 +190,7 @@ export class InMemoryWorkflowService
170
190
  }
171
191
  }
172
192
 
173
- async setStepScheduled(stepId: string): Promise<void> {
193
+ protected async setStepScheduledImpl(stepId: string): Promise<void> {
174
194
  for (const step of this.steps.values()) {
175
195
  if (step.stepId === stepId) {
176
196
  step.status = 'scheduled'
@@ -181,7 +201,10 @@ export class InMemoryWorkflowService
181
201
  }
182
202
  }
183
203
 
184
- async setStepResult(stepId: string, result: any): Promise<void> {
204
+ protected async setStepResultImpl(
205
+ stepId: string,
206
+ result: any
207
+ ): Promise<void> {
185
208
  for (const step of this.steps.values()) {
186
209
  if (step.stepId === stepId) {
187
210
  step.status = 'succeeded'
@@ -193,7 +216,10 @@ export class InMemoryWorkflowService
193
216
  }
194
217
  }
195
218
 
196
- async setStepError(stepId: string, error: Error): Promise<void> {
219
+ protected async setStepErrorImpl(
220
+ stepId: string,
221
+ error: Error
222
+ ): Promise<void> {
197
223
  for (const step of this.steps.values()) {
198
224
  if (step.stepId === stepId) {
199
225
  step.status = 'failed'
@@ -209,7 +235,10 @@ export class InMemoryWorkflowService
209
235
  }
210
236
  }
211
237
 
212
- async setStepChildRunId(stepId: string, childRunId: string): Promise<void> {
238
+ protected async setStepChildRunIdImpl(
239
+ stepId: string,
240
+ childRunId: string
241
+ ): Promise<void> {
213
242
  for (const step of this.steps.values()) {
214
243
  if (step.stepId === stepId) {
215
244
  step.childRunId = childRunId
@@ -219,7 +248,7 @@ export class InMemoryWorkflowService
219
248
  }
220
249
  }
221
250
 
222
- async createRetryAttempt(
251
+ protected async createRetryAttemptImpl(
223
252
  failedStepId: string,
224
253
  status: 'pending' | 'running'
225
254
  ): Promise<StepState> {
@@ -354,6 +383,10 @@ export class InMemoryWorkflowService
354
383
  }
355
384
 
356
385
  async close(): Promise<void> {
386
+ for (const timer of this.sleepTimers) {
387
+ clearTimeout(timer)
388
+ }
389
+ this.sleepTimers.clear()
357
390
  // Clear all in-memory state
358
391
  this.runs.clear()
359
392
  this.steps.clear()
@@ -439,11 +472,14 @@ export class InMemoryWorkflowService
439
472
  }
440
473
  }
441
474
 
442
- async setBranchTaken(stepId: string, branchKey: string): Promise<void> {
475
+ protected async setBranchTakenImpl(
476
+ stepId: string,
477
+ branchKey: string
478
+ ): Promise<void> {
443
479
  this.branchKeys.set(stepId, branchKey)
444
480
  }
445
481
 
446
- async updateRunState(
482
+ protected async updateRunStateImpl(
447
483
  runId: string,
448
484
  name: string,
449
485
  value: unknown
@@ -457,7 +493,7 @@ export class InMemoryWorkflowService
457
493
  return this.runState.get(runId) || {}
458
494
  }
459
495
 
460
- async upsertWorkflowVersion(
496
+ protected async upsertWorkflowVersionImpl(
461
497
  name: string,
462
498
  graphHash: string,
463
499
  graph: any,
@@ -471,7 +507,7 @@ export class InMemoryWorkflowService
471
507
  })
472
508
  }
473
509
 
474
- async updateWorkflowVersionStatus(
510
+ protected async updateWorkflowVersionStatusImpl(
475
511
  name: string,
476
512
  graphHash: string,
477
513
  status: WorkflowVersionStatus
@@ -0,0 +1,54 @@
1
+ import assert from 'node:assert/strict'
2
+ import { describe, test } from 'node:test'
3
+
4
+ import { LocalContent } from './local-content.js'
5
+
6
+ describe('LocalContent signing', () => {
7
+ test('binds notBefore into the signature payload', async () => {
8
+ let capturedPayload:
9
+ | { signedAt: number; expiresAt: number; notBefore?: number }
10
+ | undefined
11
+
12
+ const content = new LocalContent(
13
+ {
14
+ localFileUploadPath: '/tmp/uploads',
15
+ uploadUrlPrefix: '/reaper',
16
+ assetUrlPrefix: '/assets',
17
+ server: 'http://localhost:3000',
18
+ },
19
+ {
20
+ info: () => {},
21
+ warn: () => {},
22
+ error: () => {},
23
+ debug: () => {},
24
+ setLevel: () => {},
25
+ } as any,
26
+ {
27
+ encode: async (_expiresIn: any, payload: any) => {
28
+ capturedPayload = payload
29
+ return 'signed-token'
30
+ },
31
+ decode: async () => ({}),
32
+ }
33
+ )
34
+
35
+ const dateGreaterThan = new Date(Date.now() + 60_000)
36
+ const dateLessThan = new Date(Date.now() + 120_000)
37
+ const signedUrl = await content.signContentKey({
38
+ bucket: 'avatars',
39
+ contentKey: 'user-1.png',
40
+ dateLessThan,
41
+ dateGreaterThan,
42
+ })
43
+
44
+ const url = new URL(signedUrl)
45
+ assert.equal(url.searchParams.get('signature'), 'signed-token')
46
+ assert.ok(capturedPayload)
47
+ assert.equal(capturedPayload?.expiresAt, dateLessThan.getTime())
48
+ assert.equal(capturedPayload?.notBefore, dateGreaterThan.getTime())
49
+ assert.equal(
50
+ url.searchParams.get('notBefore'),
51
+ String(dateGreaterThan.getTime())
52
+ )
53
+ })
54
+ })
@@ -65,9 +65,20 @@ export class LocalContent implements ContentService {
65
65
  1,
66
66
  Math.floor((expiresAt - signedAt) / 1000)
67
67
  )
68
+ const payload: {
69
+ signedAt: number
70
+ expiresAt: number
71
+ notBefore?: number
72
+ } = {
73
+ signedAt,
74
+ expiresAt,
75
+ }
76
+ if (dateGreaterThan) {
77
+ payload.notBefore = dateGreaterThan.getTime()
78
+ }
68
79
  const signature = await this.jwt.encode(
69
80
  { value: expiresInSeconds, unit: 'second' },
70
- { signedAt, expiresAt }
81
+ payload
71
82
  )
72
83
  params.set('signature', signature)
73
84
  }
@@ -15,9 +15,9 @@ export type CredentialMetaInfo = {
15
15
  oauth2?: boolean
16
16
  }
17
17
 
18
- export class TypedCredentialService<TMap = Record<string, unknown>>
19
- implements CredentialService
20
- {
18
+ export class TypedCredentialService<
19
+ TMap = Record<string, unknown>,
20
+ > implements CredentialService {
21
21
  constructor(
22
22
  private credentials: CredentialService,
23
23
  private credentialsMeta: Record<string, CredentialMetaInfo>
@@ -14,9 +14,9 @@ export type CredentialMeta = {
14
14
  oauth2?: { tokenSecretId: string }
15
15
  }
16
16
 
17
- export class TypedSecretService<TMap = Record<string, unknown>>
18
- implements SecretService
19
- {
17
+ export class TypedSecretService<
18
+ TMap = Record<string, unknown>,
19
+ > implements SecretService {
20
20
  constructor(
21
21
  private secrets: SecretService,
22
22
  private credentialsMeta: Record<string, CredentialMeta>
@@ -12,9 +12,9 @@ export type VariableMeta = {
12
12
  displayName: string
13
13
  }
14
14
 
15
- export class TypedVariablesService<TMap = Record<string, unknown>>
16
- implements VariablesService
17
- {
15
+ export class TypedVariablesService<
16
+ TMap = Record<string, unknown>,
17
+ > implements VariablesService {
18
18
  constructor(
19
19
  private variables: VariablesService,
20
20
  private variablesMeta: Record<string, VariableMeta>
@@ -11,12 +11,12 @@ export interface SessionService<UserSession extends CoreUserSession> {
11
11
  get(): UserSession | undefined
12
12
  }
13
13
 
14
- export class PikkuSessionService<UserSession extends CoreUserSession>
15
- implements SessionService<UserSession>
16
- {
14
+ export class PikkuSessionService<
15
+ UserSession extends CoreUserSession,
16
+ > implements SessionService<UserSession> {
17
17
  public sessionChanged = false
18
18
  public initial: UserSession | undefined
19
- private session: UserSession | undefined
19
+ protected session: UserSession | undefined
20
20
  private pikkuUserId?: string
21
21
 
22
22
  constructor(private sessionStore?: SessionStore<UserSession>) {}
@@ -102,6 +102,36 @@ export function defineServiceTests(config: ServiceTestConfig): void {
102
102
  test('removeChannels with empty array is no-op', async () => {
103
103
  await store.removeChannels([])
104
104
  })
105
+
106
+ test('session round-trip — set / get / clear', async () => {
107
+ await store.addChannel({
108
+ channelId: 'ch-state',
109
+ channelName: 'test-channel',
110
+ })
111
+
112
+ // initially undefined
113
+ const empty = await store.getState('ch-state')
114
+ assert.equal(empty, undefined)
115
+
116
+ // set + get
117
+ const payload = { userId: 'u-7', meta: { foo: 1 } }
118
+ await store.setState('ch-state', payload)
119
+ const got = await store.getState('ch-state')
120
+ assert.deepEqual(got, payload)
121
+
122
+ // overwrite
123
+ const next = { userId: 'u-8' }
124
+ await store.setState('ch-state', next)
125
+ const got2 = await store.getState('ch-state')
126
+ assert.deepEqual(got2, next)
127
+
128
+ // clear
129
+ await store.clearState('ch-state')
130
+ const after = await store.getState('ch-state')
131
+ assert.equal(after, undefined)
132
+
133
+ await store.removeChannels(['ch-state'])
134
+ })
105
135
  })
106
136
  }
107
137
 
@@ -9,6 +9,7 @@ import type {
9
9
  CorePikkuChannelMiddleware,
10
10
  CorePikkuChannelMiddlewareFactory,
11
11
  } from '../wirings/channel/channel.types.js'
12
+ import type { EventHubService } from '../wirings/channel/eventhub-service.js'
12
13
  import type { PikkuRPC } from '../wirings/rpc/rpc-types.js'
13
14
  import type { PikkuMCP } from '../wirings/mcp/mcp.types.js'
14
15
  import type { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js'
@@ -115,6 +116,7 @@ export type FunctionRuntimeMeta = {
115
116
  version?: number
116
117
  approvalRequired?: boolean
117
118
  approvalDescription?: string
119
+ implementationHash?: string
118
120
  contractHash?: string
119
121
  inputHash?: string
120
122
  outputHash?: string
@@ -216,6 +218,8 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
216
218
  workflowService?: WorkflowService
217
219
  /** The queue service */
218
220
  queueService?: QueueService
221
+ /** Event hub for realtime pub/sub across channels */
222
+ eventHub?: EventHubService<Record<string, any>>
219
223
  /** The scheduler service */
220
224
  schedulerService?: SchedulerService
221
225
  /** The deployment service for service discovery */
@@ -485,8 +489,8 @@ export type CreateSingletonServices<
485
489
  */
486
490
  export type CreateWireServices<
487
491
  SingletonServices extends CoreSingletonServices = CoreSingletonServices,
488
- Services extends
489
- CoreServices<SingletonServices> = CoreServices<SingletonServices>,
492
+ Services extends CoreServices<SingletonServices> =
493
+ CoreServices<SingletonServices>,
490
494
  UserSession extends CoreUserSession = CoreUserSession,
491
495
  > = (
492
496
  services: SingletonServices,
@@ -138,6 +138,7 @@ export interface PikkuPackageState {
138
138
  middleware: {
139
139
  tagGroup: Record<string, CorePikkuMiddlewareGroup>
140
140
  httpGroup: Record<string, CorePikkuMiddlewareGroup>
141
+ global: CorePikkuMiddlewareGroup
141
142
  }
142
143
  channelMiddleware: {
143
144
  tagGroup: Record<string, CorePikkuChannelMiddleware[]>
@@ -145,6 +146,7 @@ export interface PikkuPackageState {
145
146
  permissions: {
146
147
  tagGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
147
148
  httpGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
149
+ global: (CorePermissionGroup | CorePikkuPermission)[]
148
150
  }
149
151
  misc: {
150
152
  errors: Map<PikkuError, ErrorDetails>
@@ -153,19 +155,6 @@ export interface PikkuPackageState {
153
155
  channelMiddleware: Record<string, CorePikkuChannelMiddleware[]>
154
156
  permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>
155
157
  }
156
- models: {
157
- config: {
158
- models?: Record<
159
- string,
160
- string | { model: string; temperature?: number; maxSteps?: number }
161
- >
162
- agentDefaults?: { temperature?: number; maxSteps?: number }
163
- agentOverrides?: Record<
164
- string,
165
- { model?: string; temperature?: number; maxSteps?: number }
166
- >
167
- } | null
168
- }
169
158
  package: {
170
159
  /** Service factory functions for addon packages */
171
160
  factories: {