@pikku/core 0.12.0 → 0.12.2

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 (290) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/errors/errors.d.ts +6 -0
  3. package/dist/errors/errors.js +10 -0
  4. package/dist/errors/index.d.ts +1 -0
  5. package/dist/errors/index.js +1 -0
  6. package/dist/function/function-runner.d.ts +3 -3
  7. package/dist/function/function-runner.js +66 -44
  8. package/dist/function/functions.types.d.ts +1 -0
  9. package/dist/handle-error.d.ts +2 -2
  10. package/dist/handle-error.js +2 -2
  11. package/dist/index.d.ts +5 -3
  12. package/dist/index.js +2 -1
  13. package/dist/internal.d.ts +3 -0
  14. package/dist/internal.js +2 -0
  15. package/dist/middleware/auth-bearer.d.ts +1 -1
  16. package/dist/middleware/auth-bearer.js +1 -1
  17. package/dist/middleware/auth-cookie.d.ts +2 -2
  18. package/dist/middleware/auth-cookie.js +1 -1
  19. package/dist/middleware/cors.d.ts +2 -2
  20. package/dist/middleware/cors.js +45 -37
  21. package/dist/middleware-runner.d.ts +1 -1
  22. package/dist/middleware-runner.js +1 -0
  23. package/dist/permissions.d.ts +2 -2
  24. package/dist/permissions.js +1 -0
  25. package/dist/pikku-state.d.ts +9 -8
  26. package/dist/pikku-state.js +34 -17
  27. package/dist/schema.d.ts +4 -4
  28. package/dist/schema.js +9 -5
  29. package/dist/services/ai-agent-runner-service.d.ts +22 -3
  30. package/dist/services/ai-run-state-service.d.ts +1 -1
  31. package/dist/services/ai-storage-service.d.ts +1 -1
  32. package/dist/services/content-service.d.ts +6 -0
  33. package/dist/services/gateway-service.d.ts +19 -0
  34. package/dist/services/gopass-secrets.d.ts +1 -1
  35. package/dist/services/gopass-secrets.js +3 -0
  36. package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
  37. package/dist/services/in-memory-ai-run-state-service.js +44 -0
  38. package/dist/services/in-memory-trigger-service.d.ts +0 -1
  39. package/dist/services/in-memory-trigger-service.js +6 -8
  40. package/dist/services/index.d.ts +5 -2
  41. package/dist/services/index.js +2 -0
  42. package/dist/services/local-content.d.ts +2 -1
  43. package/dist/services/local-content.js +6 -1
  44. package/dist/services/local-gateway-service.d.ts +22 -0
  45. package/dist/services/local-gateway-service.js +51 -0
  46. package/dist/services/local-secrets.d.ts +2 -2
  47. package/dist/services/local-variables.d.ts +1 -1
  48. package/dist/services/logger-console.d.ts +2 -1
  49. package/dist/services/scheduler-service.d.ts +0 -12
  50. package/dist/services/scheduler-service.js +0 -6
  51. package/dist/services/scoped-secret-service.d.ts +1 -1
  52. package/dist/services/trigger-service.d.ts +0 -7
  53. package/dist/services/user-session-service.d.ts +3 -3
  54. package/dist/services/workflow-service.d.ts +2 -3
  55. package/dist/types/core.types.d.ts +27 -19
  56. package/dist/types/state.types.d.ts +22 -15
  57. package/dist/utils.d.ts +5 -5
  58. package/dist/utils.js +12 -9
  59. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
  60. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +168 -0
  61. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
  62. package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
  63. package/dist/wirings/ai-agent/ai-agent-memory.js +13 -2
  64. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
  65. package/dist/wirings/ai-agent/ai-agent-prepare.js +80 -31
  66. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +1 -1
  67. package/dist/wirings/ai-agent/ai-agent-runner.js +107 -8
  68. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
  69. package/dist/wirings/ai-agent/ai-agent-stream.js +263 -89
  70. package/dist/wirings/ai-agent/ai-agent.types.d.ts +96 -4
  71. package/dist/wirings/ai-agent/index.d.ts +3 -1
  72. package/dist/wirings/ai-agent/index.js +2 -0
  73. package/dist/wirings/channel/channel-common.d.ts +2 -2
  74. package/dist/wirings/channel/channel-handler.d.ts +7 -4
  75. package/dist/wirings/channel/channel-handler.js +15 -5
  76. package/dist/wirings/channel/channel-middleware-runner.js +1 -0
  77. package/dist/wirings/channel/channel-runner.d.ts +5 -5
  78. package/dist/wirings/channel/channel-runner.js +3 -2
  79. package/dist/wirings/channel/channel-store.d.ts +1 -1
  80. package/dist/wirings/channel/channel.types.d.ts +10 -6
  81. package/dist/wirings/channel/index.d.ts +1 -1
  82. package/dist/wirings/channel/local/local-channel-handler.d.ts +7 -0
  83. package/dist/wirings/channel/local/local-channel-handler.js +17 -0
  84. package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
  85. package/dist/wirings/channel/local/local-channel-runner.js +18 -4
  86. package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
  87. package/dist/wirings/channel/log-channels.d.ts +1 -1
  88. package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +2 -1
  89. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  90. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
  91. package/dist/wirings/channel/serverless/serverless-channel-runner.js +26 -20
  92. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
  93. package/dist/wirings/cli/cli-runner.d.ts +2 -2
  94. package/dist/wirings/cli/cli-runner.js +3 -0
  95. package/dist/wirings/cli/cli.types.d.ts +3 -3
  96. package/dist/wirings/cli/command-parser.d.ts +1 -1
  97. package/dist/wirings/gateway/gateway-runner.d.ts +24 -0
  98. package/dist/wirings/gateway/gateway-runner.js +325 -0
  99. package/dist/wirings/gateway/gateway.types.d.ts +127 -0
  100. package/dist/wirings/gateway/index.d.ts +2 -0
  101. package/dist/wirings/gateway/index.js +1 -0
  102. package/dist/wirings/http/http-runner.d.ts +9 -9
  103. package/dist/wirings/http/http-runner.js +36 -14
  104. package/dist/wirings/http/http.types.d.ts +2 -6
  105. package/dist/wirings/http/log-http-routes.d.ts +1 -1
  106. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
  107. package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
  108. package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
  109. package/dist/wirings/http/routers/http-router.d.ts +1 -1
  110. package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
  111. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  112. package/dist/wirings/mcp/mcp-runner.d.ts +0 -3
  113. package/dist/wirings/mcp/mcp-runner.js +4 -2
  114. package/dist/wirings/mcp/mcp.types.d.ts +2 -2
  115. package/dist/wirings/oauth2/oauth2-client.d.ts +3 -3
  116. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +1 -1
  117. package/dist/wirings/queue/index.d.ts +1 -1
  118. package/dist/wirings/queue/index.js +1 -1
  119. package/dist/wirings/queue/queue-runner.d.ts +1 -12
  120. package/dist/wirings/queue/queue-runner.js +4 -12
  121. package/dist/wirings/queue/queue.types.d.ts +3 -9
  122. package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
  123. package/dist/wirings/queue/register-queue-helper.js +1 -1
  124. package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
  125. package/dist/wirings/rpc/index.d.ts +2 -0
  126. package/dist/wirings/rpc/index.js +1 -0
  127. package/dist/wirings/rpc/rpc-runner.d.ts +36 -14
  128. package/dist/wirings/rpc/rpc-runner.js +56 -28
  129. package/dist/wirings/rpc/rpc-types.d.ts +14 -2
  130. package/dist/wirings/rpc/wire-addon.d.ts +10 -0
  131. package/dist/wirings/rpc/wire-addon.js +9 -0
  132. package/dist/wirings/scheduler/index.d.ts +1 -1
  133. package/dist/wirings/scheduler/index.js +1 -1
  134. package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
  135. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -10
  136. package/dist/wirings/scheduler/scheduler-runner.js +4 -25
  137. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
  138. package/dist/wirings/trigger/pikku-trigger-service.d.ts +2 -6
  139. package/dist/wirings/trigger/pikku-trigger-service.js +11 -16
  140. package/dist/wirings/trigger/trigger-runner.d.ts +1 -5
  141. package/dist/wirings/trigger/trigger-runner.js +4 -3
  142. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -6
  143. package/dist/wirings/workflow/pikku-workflow-service.js +20 -29
  144. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  145. package/package.json +4 -2
  146. package/src/crypto-utils.test.ts +116 -0
  147. package/src/errors/error.test.ts +143 -2
  148. package/src/errors/errors.ts +10 -0
  149. package/src/errors/index.ts +1 -0
  150. package/src/function/function-runner.test.ts +2 -2
  151. package/src/function/function-runner.ts +72 -49
  152. package/src/function/functions.types.ts +1 -0
  153. package/src/handle-error.test.ts +361 -0
  154. package/src/handle-error.ts +4 -4
  155. package/src/index.ts +3 -10
  156. package/src/internal.ts +6 -0
  157. package/src/middleware/auth-apikey.test.ts +1 -1
  158. package/src/middleware/auth-bearer.test.ts +1 -1
  159. package/src/middleware/auth-bearer.ts +2 -5
  160. package/src/middleware/auth-cookie.test.ts +1 -1
  161. package/src/middleware/auth-cookie.ts +3 -5
  162. package/src/middleware/cors.test.ts +424 -0
  163. package/src/middleware/cors.ts +14 -6
  164. package/src/middleware/remote-auth.test.ts +488 -0
  165. package/src/middleware-runner.test.ts +1 -1
  166. package/src/middleware-runner.ts +2 -1
  167. package/src/permissions.test.ts +2 -2
  168. package/src/permissions.ts +3 -2
  169. package/src/pikku-state.test.ts +224 -0
  170. package/src/pikku-state.ts +45 -28
  171. package/src/schema.test.ts +198 -6
  172. package/src/schema.ts +11 -7
  173. package/src/services/ai-agent-runner-service.ts +15 -3
  174. package/src/services/ai-run-state-service.ts +1 -1
  175. package/src/services/ai-storage-service.ts +1 -1
  176. package/src/services/content-service.ts +7 -0
  177. package/src/services/gateway-service.ts +20 -0
  178. package/src/services/gopass-secrets.ts +4 -1
  179. package/src/services/in-memory-ai-run-state-service.ts +73 -0
  180. package/src/services/in-memory-trigger-service.ts +6 -10
  181. package/src/services/in-memory-workflow-service.test.ts +351 -0
  182. package/src/services/index.ts +4 -1
  183. package/src/services/local-content.ts +9 -3
  184. package/src/services/local-gateway-service.ts +62 -0
  185. package/src/services/local-secrets.test.ts +80 -0
  186. package/src/services/local-secrets.ts +2 -2
  187. package/src/services/local-variables.test.ts +61 -0
  188. package/src/services/local-variables.ts +1 -1
  189. package/src/services/logger-console.test.ts +118 -0
  190. package/src/services/logger-console.ts +2 -1
  191. package/src/services/scheduler-service.ts +0 -18
  192. package/src/services/scoped-secret-service.test.ts +74 -0
  193. package/src/services/scoped-secret-service.ts +1 -1
  194. package/src/services/trigger-service.ts +0 -21
  195. package/src/services/typed-secret-service.test.ts +93 -0
  196. package/src/services/typed-variables-service.test.ts +73 -0
  197. package/src/services/user-session-service.test.ts +113 -0
  198. package/src/services/user-session-service.ts +3 -3
  199. package/src/services/workflow-service.ts +2 -12
  200. package/src/time-utils.test.ts +1 -1
  201. package/src/types/core.types.ts +28 -19
  202. package/src/types/state.types.ts +32 -15
  203. package/src/utils.test.ts +350 -0
  204. package/src/utils.ts +14 -13
  205. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
  206. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +238 -0
  207. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
  208. package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
  209. package/src/wirings/ai-agent/ai-agent-memory.ts +10 -1
  210. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
  211. package/src/wirings/ai-agent/ai-agent-prepare.ts +98 -46
  212. package/src/wirings/ai-agent/ai-agent-registry.ts +1 -1
  213. package/src/wirings/ai-agent/ai-agent-runner.test.ts +245 -3
  214. package/src/wirings/ai-agent/ai-agent-runner.ts +121 -7
  215. package/src/wirings/ai-agent/ai-agent-stream.test.ts +430 -24
  216. package/src/wirings/ai-agent/ai-agent-stream.ts +390 -104
  217. package/src/wirings/ai-agent/ai-agent.types.ts +91 -4
  218. package/src/wirings/ai-agent/index.ts +13 -0
  219. package/src/wirings/channel/channel-common.ts +2 -2
  220. package/src/wirings/channel/channel-handler.ts +43 -11
  221. package/src/wirings/channel/channel-middleware-runner.ts +1 -0
  222. package/src/wirings/channel/channel-runner.ts +6 -6
  223. package/src/wirings/channel/channel-store.ts +1 -1
  224. package/src/wirings/channel/channel.types.ts +15 -8
  225. package/src/wirings/channel/index.ts +1 -0
  226. package/src/wirings/channel/local/local-channel-handler.ts +26 -0
  227. package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
  228. package/src/wirings/channel/local/local-channel-runner.ts +33 -14
  229. package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
  230. package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
  231. package/src/wirings/channel/log-channels.ts +1 -1
  232. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +2 -0
  233. package/src/wirings/channel/pikku-abstract-channel-handler.ts +8 -1
  234. package/src/wirings/channel/serverless/serverless-channel-runner.ts +38 -33
  235. package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
  236. package/src/wirings/cli/cli-runner.test.ts +1 -1
  237. package/src/wirings/cli/cli-runner.ts +14 -4
  238. package/src/wirings/cli/cli.types.ts +3 -3
  239. package/src/wirings/cli/command-parser.test.ts +1 -1
  240. package/src/wirings/cli/command-parser.ts +1 -1
  241. package/src/wirings/gateway/gateway-runner.test.ts +474 -0
  242. package/src/wirings/gateway/gateway-runner.ts +411 -0
  243. package/src/wirings/gateway/gateway.types.ts +149 -0
  244. package/src/wirings/gateway/index.ts +13 -0
  245. package/src/wirings/http/http-routes.test.ts +1 -1
  246. package/src/wirings/http/http-runner.test.ts +9 -17
  247. package/src/wirings/http/http-runner.ts +46 -27
  248. package/src/wirings/http/http.types.ts +1 -14
  249. package/src/wirings/http/log-http-routes.ts +1 -1
  250. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  251. package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
  252. package/src/wirings/http/routers/http-router.ts +1 -1
  253. package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
  254. package/src/wirings/http/routers/path-to-regex.ts +4 -3
  255. package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
  256. package/src/wirings/mcp/mcp-runner.ts +9 -15
  257. package/src/wirings/mcp/mcp.types.ts +2 -2
  258. package/src/wirings/oauth2/oauth2-client.ts +3 -3
  259. package/src/wirings/oauth2/wire-oauth2-credential.ts +1 -1
  260. package/src/wirings/queue/index.ts +0 -1
  261. package/src/wirings/queue/queue-runner.test.ts +52 -25
  262. package/src/wirings/queue/queue-runner.ts +8 -30
  263. package/src/wirings/queue/queue.types.ts +3 -13
  264. package/src/wirings/queue/register-queue-helper.ts +3 -5
  265. package/src/wirings/queue/validate-worker-config.test.ts +108 -0
  266. package/src/wirings/queue/validate-worker-config.ts +4 -1
  267. package/src/wirings/rpc/index.ts +2 -0
  268. package/src/wirings/rpc/rpc-runner.ts +92 -49
  269. package/src/wirings/rpc/rpc-types.ts +17 -2
  270. package/src/wirings/rpc/wire-addon.ts +20 -0
  271. package/src/wirings/scheduler/index.ts +0 -1
  272. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  273. package/src/wirings/scheduler/scheduler-runner.test.ts +49 -60
  274. package/src/wirings/scheduler/scheduler-runner.ts +9 -56
  275. package/src/wirings/scheduler/scheduler.types.ts +2 -2
  276. package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
  277. package/src/wirings/trigger/pikku-trigger-service.ts +17 -39
  278. package/src/wirings/trigger/trigger-runner.test.ts +79 -0
  279. package/src/wirings/trigger/trigger-runner.ts +8 -11
  280. package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
  281. package/src/wirings/workflow/graph/graph-runner.test.ts +14 -22
  282. package/src/wirings/workflow/graph/template.test.ts +49 -0
  283. package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -27
  284. package/src/wirings/workflow/pikku-workflow-service.ts +29 -45
  285. package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
  286. package/src/wirings/workflow/workflow.types.ts +2 -2
  287. package/tsconfig.tsbuildinfo +1 -1
  288. package/src/wirings/workflow/workflow-utils.ts +0 -0
  289. /package/dist/{wirings/workflow/workflow-utils.d.ts → services/gateway-service.js} +0 -0
  290. /package/dist/wirings/{workflow/workflow-utils.js → gateway/gateway.types.js} +0 -0
@@ -1,8 +1,8 @@
1
- import {
1
+ import type {
2
2
  CorePermissionGroup,
3
3
  CorePikkuPermission,
4
4
  } from '../../function/functions.types.js'
5
- import {
5
+ import type {
6
6
  CorePikkuMiddleware,
7
7
  MiddlewareMetadata,
8
8
  PermissionMetadata,
@@ -19,6 +19,17 @@ export interface AIThread {
19
19
  updatedAt: Date
20
20
  }
21
21
 
22
+ export type AIContentPart =
23
+ | { type: 'text'; text: string }
24
+ | { type: 'image'; data?: string; url?: string; mediaType?: string }
25
+ | {
26
+ type: 'file'
27
+ data?: string
28
+ url?: string
29
+ mediaType: string
30
+ filename?: string
31
+ }
32
+
22
33
  export interface AIToolCall {
23
34
  id: string
24
35
  name: string
@@ -34,7 +45,7 @@ export interface AIToolResult {
34
45
  export interface AIMessage {
35
46
  id: string
36
47
  role: 'system' | 'user' | 'assistant' | 'tool'
37
- content?: string
48
+ content?: string | AIContentPart[]
38
49
  toolCalls?: AIToolCall[]
39
50
  toolResults?: AIToolResult[]
40
51
  createdAt: Date
@@ -45,10 +56,19 @@ export interface AIAgentStep {
45
56
  toolCalls?: { name: string; args: Record<string, unknown>; result: string }[]
46
57
  }
47
58
 
59
+ export interface AIAgentInputAttachment {
60
+ type: 'image' | 'file'
61
+ data?: string
62
+ url?: string
63
+ mediaType?: string
64
+ filename?: string
65
+ }
66
+
48
67
  export interface AIAgentInput {
49
68
  message: string
50
69
  threadId: string
51
70
  resourceId: string
71
+ attachments?: AIAgentInputAttachment[]
52
72
  }
53
73
 
54
74
  export interface AIAgentOutput {
@@ -65,6 +85,7 @@ export interface AIAgentToolDef {
65
85
  description: string
66
86
  inputSchema: Record<string, unknown>
67
87
  execute: (input: unknown) => Promise<unknown>
88
+ needsApproval?: boolean
68
89
  }
69
90
 
70
91
  export interface PikkuAIMiddlewareHooks<
@@ -85,7 +106,11 @@ export interface PikkuAIMiddlewareHooks<
85
106
  allEvents: readonly AIStreamEvent[]
86
107
  state: State
87
108
  }
88
- ) => Promise<AIStreamEvent | null> | AIStreamEvent | null
109
+ ) =>
110
+ | Promise<AIStreamEvent | AIStreamEvent[] | null>
111
+ | AIStreamEvent
112
+ | AIStreamEvent[]
113
+ | null
89
114
 
90
115
  modifyOutput?: (
91
116
  services: Services,
@@ -97,6 +122,50 @@ export interface PikkuAIMiddlewareHooks<
97
122
  ) =>
98
123
  | Promise<{ text: string; messages: AIMessage[] }>
99
124
  | { text: string; messages: AIMessage[] }
125
+
126
+ beforeToolCall?: (
127
+ services: Services,
128
+ ctx: {
129
+ toolName: string
130
+ toolCallId: string
131
+ args: Record<string, unknown>
132
+ }
133
+ ) =>
134
+ | Promise<{ args: Record<string, unknown> } | void>
135
+ | { args: Record<string, unknown> }
136
+ | void
137
+
138
+ afterToolCall?: (
139
+ services: Services,
140
+ ctx: {
141
+ toolName: string
142
+ toolCallId: string
143
+ args: Record<string, unknown>
144
+ result: unknown
145
+ durationMs: number
146
+ }
147
+ ) => Promise<{ result: unknown } | void> | { result: unknown } | void
148
+
149
+ afterStep?: (
150
+ services: Services,
151
+ ctx: {
152
+ stepNumber: number
153
+ text: string
154
+ toolCalls: { toolCallId: string; toolName: string; args: unknown }[]
155
+ toolResults: { toolCallId: string; toolName: string; result: unknown }[]
156
+ usage: { inputTokens: number; outputTokens: number }
157
+ finishReason: string
158
+ }
159
+ ) => Promise<void> | void
160
+
161
+ onError?: (
162
+ services: Services,
163
+ ctx: {
164
+ error: Error
165
+ stepNumber: number
166
+ messages: AIMessage[]
167
+ }
168
+ ) => Promise<void> | void
100
169
  }
101
170
 
102
171
  export type AIAgentMemoryConfig = {
@@ -126,6 +195,15 @@ export type CoreAIAgent<
126
195
  input?: unknown
127
196
  output?: unknown
128
197
  tags?: string[]
198
+ protocol?: 'ui-message-stream'
199
+ prepareStep?: (ctx: {
200
+ stepNumber: number
201
+ messages: AIMessage[]
202
+ tools: AIAgentToolDef[]
203
+ toolChoice: 'auto' | 'required' | 'none'
204
+ model: string
205
+ stop: () => void
206
+ }) => void | Promise<void>
129
207
  middleware?: PikkuMiddleware[]
130
208
  channelMiddleware?: CorePikkuChannelMiddleware<any, any>[]
131
209
  aiMiddleware?: PikkuAIMiddlewareHooks<any, any>[]
@@ -133,6 +211,7 @@ export type CoreAIAgent<
133
211
  }
134
212
 
135
213
  export type AIStreamEvent =
214
+ | { type: 'step-start'; stepNumber: number; agent?: string; session?: string }
136
215
  | { type: 'text-delta'; text: string; agent?: string; session?: string }
137
216
  | { type: 'reasoning-delta'; text: string; agent?: string; session?: string }
138
217
  | {
@@ -180,6 +259,14 @@ export type AIStreamEvent =
180
259
  session?: string
181
260
  }
182
261
  | { type: 'error'; message: string; agent?: string; session?: string }
262
+ | {
263
+ type: 'audio-delta'
264
+ data: string
265
+ format: string
266
+ agent?: string
267
+ session?: string
268
+ }
269
+ | { type: 'audio-done'; agent?: string; session?: string }
183
270
  | {
184
271
  type: 'suspended'
185
272
  reason: 'rpc-missing'
@@ -1,5 +1,15 @@
1
+ export {
2
+ agent,
3
+ agentStream,
4
+ agentResume,
5
+ agentApprove,
6
+ } from './ai-agent-helpers.js'
1
7
  export { runAIAgent } from './ai-agent-runner.js'
2
8
  export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js'
9
+ export {
10
+ createAssistantUIChannel,
11
+ parseAssistantUIInput,
12
+ } from './ai-agent-assistant-ui.js'
3
13
  export {
4
14
  type RunAIAgentParams,
5
15
  type StreamAIAgentOptions,
@@ -12,9 +22,12 @@ export {
12
22
  getAIAgentsMeta,
13
23
  } from './ai-agent-registry.js'
14
24
  export type {
25
+ AIAgentInput,
26
+ AIAgentInputAttachment,
15
27
  AIAgentMeta,
16
28
  AIAgentMemoryConfig,
17
29
  AIAgentStep,
30
+ AIContentPart,
18
31
  AgentRunRow,
19
32
  AgentRunService,
20
33
  AgentRunState,
@@ -1,10 +1,10 @@
1
- import {
1
+ import type {
2
2
  CoreSingletonServices,
3
3
  CorePikkuMiddleware,
4
4
  PikkuWire,
5
5
  MiddlewareMetadata,
6
6
  } from '../../types/core.types.js'
7
- import { CoreChannel, ChannelMessageMeta } from './channel.types.js'
7
+ import type { CoreChannel, ChannelMessageMeta } from './channel.types.js'
8
8
  import { combineMiddleware, runMiddleware } from '../../middleware-runner.js'
9
9
  import { runPikkuFuncDirectly } from '../../function/function-runner.js'
10
10
  import {
@@ -1,19 +1,18 @@
1
- import {
1
+ import type {
2
2
  CoreServices,
3
3
  JSONValue,
4
4
  CoreUserSession,
5
5
  } from '../../types/core.types.js'
6
- import {
6
+ import type {
7
+ BinaryData,
7
8
  ChannelMessageMeta,
8
9
  CoreChannel,
9
10
  PikkuChannelHandler,
10
11
  } from './channel.types.js'
11
12
  import { pikkuState } from '../../pikku-state.js'
12
13
  import { runPikkuFunc } from '../../function/function-runner.js'
13
- import {
14
- SessionService,
15
- createMiddlewareSessionWireProps,
16
- } from '../../services/user-session-service.js'
14
+ import type { SessionService } from '../../services/user-session-service.js'
15
+ import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js'
17
16
 
18
17
  const getChannelMeta = (channelName: string) => {
19
18
  return pikkuState(null, 'channel', 'meta')[channelName]
@@ -81,7 +80,13 @@ export const processMessageHandlers = (
81
80
  routingProperty?: string,
82
81
  routerValue?: string
83
82
  ): Promise<unknown> => {
84
- if (!validateAuth(requiresSession, channelHandler, onMessage)) {
83
+ if (
84
+ !validateAuth(
85
+ requiresSession,
86
+ userSession?.get() as CoreUserSession | undefined,
87
+ onMessage
88
+ )
89
+ ) {
85
90
  const routeMessage = routingProperty
86
91
  ? `route '${routingProperty}:${routerValue}'`
87
92
  : 'the default message route'
@@ -150,7 +155,7 @@ export const processMessageHandlers = (
150
155
  })
151
156
  }
152
157
 
153
- return async (rawData): Promise<unknown> => {
158
+ const onMessage = async (rawData: unknown): Promise<unknown> => {
154
159
  let result: unknown
155
160
  let processed = false
156
161
 
@@ -159,7 +164,7 @@ export const processMessageHandlers = (
159
164
  let messageData: any
160
165
  try {
161
166
  messageData = JSON.parse(rawData)
162
- } catch (error) {
167
+ } catch {
163
168
  // Most likely a json error.. ignore
164
169
  }
165
170
 
@@ -194,16 +199,43 @@ export const processMessageHandlers = (
194
199
  // Default handler if no routes matched and json data wasn't parsed
195
200
  if (!processed && channelConfig.onMessage) {
196
201
  processed = true
197
- result = await processMessage(rawData, channelConfig.onMessage)
202
+ result = await processMessage(
203
+ rawData as JSONValue,
204
+ channelConfig.onMessage
205
+ )
198
206
  }
199
207
 
200
208
  if (!processed) {
201
209
  logger.error(
202
210
  `No handler found for message in channel ${channelConfig.name} for ${JSON.stringify(rawData)}`
203
211
  )
204
- logger.error(`Channel ${JSON.stringify(channelConfig)}`)
212
+ logger.error(`Channel config name: ${channelConfig.name}`)
205
213
  }
206
214
 
207
215
  return result
208
216
  }
217
+
218
+ const onBinaryMessage = channelConfig.onBinaryMessage
219
+ ? async (data: BinaryData): Promise<BinaryData | void> => {
220
+ if (
221
+ !validateAuth(
222
+ requiresSession,
223
+ userSession?.get() as CoreUserSession | undefined,
224
+ channelConfig
225
+ )
226
+ ) {
227
+ logger.error(
228
+ `Channel ${channelConfig.name} with id ${channelHandler.getChannel().channelId} requires a session for binary message`
229
+ )
230
+ return
231
+ }
232
+ return channelConfig.onBinaryMessage!(
233
+ services,
234
+ data,
235
+ channelHandler.getChannel()
236
+ )
237
+ }
238
+ : undefined
239
+
240
+ return { onMessage, onBinaryMessage }
209
241
  }
@@ -114,6 +114,7 @@ export function wrapChannelWithMiddleware<Out>(
114
114
  channel: {
115
115
  ...channel,
116
116
  send: ((data: Out) => dispatch(0, data)) as typeof channel.send,
117
+ sendBinary: channel.sendBinary,
117
118
  },
118
119
  }
119
120
  }
@@ -1,12 +1,12 @@
1
1
  import { NotFoundError, PikkuMissingMetaError } from '../../errors/errors.js'
2
2
  import { addFunction } from '../../function/function-runner.js'
3
- import { CorePikkuPermission } from '../../function/functions.types.js'
4
- import { pikkuState } from '../../pikku-state.js'
3
+ import type { CorePikkuPermission } from '../../function/functions.types.js'
4
+ import { pikkuState, getSingletonServices } from '../../pikku-state.js'
5
5
  import { coerceTopLevelDataFromSchema, validateSchema } from '../../schema.js'
6
- import { SessionService } from '../../services/user-session-service.js'
7
- import { CorePikkuMiddleware } from '../../types/core.types.js'
6
+ import type { SessionService } from '../../services/user-session-service.js'
7
+ import type { CorePikkuMiddleware } from '../../types/core.types.js'
8
8
  import { httpRouter } from '../http/routers/http-router.js'
9
- import {
9
+ import type {
10
10
  ChannelMeta,
11
11
  CoreChannel,
12
12
  RunChannelOptions,
@@ -122,7 +122,6 @@ const getMatchingChannelConfig = (path: string) => {
122
122
 
123
123
  export const openChannel = async ({
124
124
  route,
125
- singletonServices,
126
125
  coerceDataFromSchema = true,
127
126
  request,
128
127
  }: Pick<CoreChannel<unknown, string>, 'route'> &
@@ -133,6 +132,7 @@ export const openChannel = async ({
133
132
  channelConfig: CoreChannel<unknown, any>
134
133
  meta: ChannelMeta
135
134
  }> => {
135
+ const singletonServices = getSingletonServices()
136
136
  const matchingChannel = getMatchingChannelConfig(route)
137
137
  if (!matchingChannel) {
138
138
  singletonServices.logger.info(`Channel not found: ${route}`)
@@ -1,4 +1,4 @@
1
- import { CoreUserSession } from '../../types/core.types.js'
1
+ import type { CoreUserSession } from '../../types/core.types.js'
2
2
 
3
3
  export type Channel<ChannelType = unknown, OpeningData = unknown> = {
4
4
  channelId: string
@@ -1,17 +1,17 @@
1
- import { PikkuError } from '../../errors/error-handler.js'
2
- import {
1
+ import type { PikkuError } from '../../errors/error-handler.js'
2
+ import type {
3
3
  HTTPFunctionMetaInputTypes,
4
4
  PikkuHTTPRequest,
5
5
  PikkuHTTPResponse,
6
6
  } from '../http/http.types.js'
7
- import {
8
- CoreSingletonServices,
9
- CreateWireServices,
7
+ import type {
10
8
  CorePikkuMiddleware,
11
9
  MiddlewareMetadata,
12
10
  PermissionMetadata,
13
11
  } from '../../types/core.types.js'
14
12
 
13
+ export type BinaryData = ArrayBuffer | Uint8Array
14
+
15
15
  export type CorePikkuChannelMiddleware<Services = any, Event = unknown> = (
16
16
  services: Services,
17
17
  event: Event,
@@ -23,7 +23,7 @@ export type CorePikkuChannelMiddlewareFactory<
23
23
  Services = any,
24
24
  Event = unknown,
25
25
  > = (input: In) => CorePikkuChannelMiddleware<Services, Event>
26
- import {
26
+ import type {
27
27
  CorePermissionGroup,
28
28
  CorePikkuFunction,
29
29
  CorePikkuFunctionConfig,
@@ -41,10 +41,8 @@ export type RunChannelOptions = Partial<{
41
41
 
42
42
  export type RunChannelParams<ChannelData> = {
43
43
  channelId: string
44
- singletonServices: CoreSingletonServices
45
44
  request?: PikkuHTTPRequest<ChannelData>
46
45
  response?: PikkuHTTPResponse
47
- createWireServices?: CreateWireServices
48
46
  }
49
47
 
50
48
  export interface ChannelMessageMeta {
@@ -68,6 +66,7 @@ export interface ChannelMeta {
68
66
  disconnect: ChannelMessageMeta | null
69
67
  message: ChannelMessageMeta | null
70
68
  messageWirings: Record<string, Record<string, ChannelMessageMeta>>
69
+ binary?: boolean | null
71
70
  summary?: string
72
71
  description?: string
73
72
  errors?: string[]
@@ -136,6 +135,12 @@ export type CoreChannel<
136
135
  >
137
136
  permissions?: CorePermissionGroup<PikkuPermission>
138
137
  auth?: boolean
138
+ binary?: boolean | null
139
+ onBinaryMessage?: (
140
+ services: any,
141
+ data: BinaryData,
142
+ channel: PikkuChannel<ChannelData, any>
143
+ ) => Promise<BinaryData | void> | BinaryData | void
139
144
  docs?: Partial<{
140
145
  description: string
141
146
  response: string
@@ -153,6 +158,7 @@ export interface PikkuChannel<OpeningData, out Out> {
153
158
  openingData: OpeningData
154
159
  // The data to send. This will fail is the stream has been closed.
155
160
  send(data: Out, isBinary?: boolean): Promise<void> | void
161
+ sendBinary(data: BinaryData): Promise<void> | void
156
162
  // This will close the channel.
157
163
  close(): Promise<void> | void
158
164
  // The current state of the channel
@@ -161,6 +167,7 @@ export interface PikkuChannel<OpeningData, out Out> {
161
167
 
162
168
  export interface PikkuChannelHandler<OpeningData = unknown, Out = unknown> {
163
169
  send(message: Out, isBinary?: boolean): Promise<void> | void
170
+ sendBinary(data: BinaryData): Promise<void> | void
164
171
  getChannel(): PikkuChannel<OpeningData, Out>
165
172
  }
166
173
 
@@ -11,6 +11,7 @@ export { ChannelStore } from './channel-store.js'
11
11
  export type { Channel } from './channel-store.js'
12
12
  export { EventHubStore } from './eventhub-store.js'
13
13
  export type {
14
+ BinaryData,
14
15
  ChannelsMeta,
15
16
  CoreChannel,
16
17
  CorePikkuChannelMiddleware,
@@ -1,3 +1,4 @@
1
+ import type { BinaryData } from '../channel.types.js'
1
2
  import { PikkuAbstractChannelHandler } from '../pikku-abstract-channel-handler.js'
2
3
 
3
4
  export class PikkuLocalChannelHandler<
@@ -5,9 +6,11 @@ export class PikkuLocalChannelHandler<
5
6
  Out = unknown,
6
7
  > extends PikkuAbstractChannelHandler<OpeningData, Out> {
7
8
  private onMessageCallback?: (message: unknown) => void
9
+ private onBinaryMessageCallback?: (data: BinaryData) => void
8
10
  private openCallBack?: () => void
9
11
  private closeCallback?: () => void
10
12
  private sendCallback?: (message: Out, isBinary?: boolean) => void
13
+ private sendBinaryCallback?: (data: BinaryData) => void
11
14
 
12
15
  public registerOnOpen(callback: () => void): void {
13
16
  this.openCallBack = callback
@@ -28,6 +31,18 @@ export class PikkuLocalChannelHandler<
28
31
  return this.onMessageCallback?.(data)
29
32
  }
30
33
 
34
+ public registerOnBinaryMessage(
35
+ callback: (
36
+ data: BinaryData
37
+ ) => Promise<BinaryData | void> | BinaryData | void
38
+ ): void {
39
+ this.onBinaryMessageCallback = callback
40
+ }
41
+
42
+ public async binaryMessage(data: BinaryData): Promise<BinaryData | void> {
43
+ return this.onBinaryMessageCallback?.(data)
44
+ }
45
+
31
46
  public registerOnClose(callback: () => void): void {
32
47
  this.closeCallback = callback
33
48
  }
@@ -50,4 +65,15 @@ export class PikkuLocalChannelHandler<
50
65
  }
51
66
  return this.sendCallback?.(message, isBinary)
52
67
  }
68
+
69
+ public registerOnSendBinary(send: (data: BinaryData) => void) {
70
+ this.sendBinaryCallback = send
71
+ }
72
+
73
+ public sendBinary(data: BinaryData): void {
74
+ if (!this.sendBinaryCallback) {
75
+ throw new Error('No sendBinary callback registered')
76
+ }
77
+ this.sendBinaryCallback(data)
78
+ }
53
79
  }
@@ -3,13 +3,13 @@ import * as assert from 'node:assert/strict'
3
3
  import { runLocalChannel } from './local-channel-runner.js'
4
4
  import { pikkuState, resetPikkuState } from '../../../pikku-state.js'
5
5
  import { wireChannel } from '../channel-runner.js'
6
- import {
6
+ import type {
7
7
  HTTPMethod,
8
8
  PikkuHTTPRequest,
9
9
  PikkuHTTPResponse,
10
10
  PikkuQuery,
11
11
  } from '../../http/http.types.js'
12
- import { SerializeOptions } from 'cookie'
12
+ import type { SerializeOptions } from 'cookie'
13
13
  import { httpRouter } from '../../http/routers/http-router.js'
14
14
 
15
15
  /**
@@ -102,6 +102,10 @@ const mockCreateWireServices = async () => ({
102
102
  beforeEach(() => {
103
103
  resetPikkuState()
104
104
  httpRouter.reset()
105
+ pikkuState(null, 'package', 'singletonServices', mockSingletonServices as any)
106
+ pikkuState(null, 'package', 'factories', {
107
+ createWireServices: mockCreateWireServices,
108
+ } as any)
105
109
  })
106
110
 
107
111
  afterEach(() => {
@@ -113,11 +117,9 @@ test('runChannel should return undefined and 404 if no matching channel is found
113
117
  const mockResponse = new PikkuMockResponse()
114
118
 
115
119
  const result = await runLocalChannel({
116
- singletonServices: mockSingletonServices,
117
120
  channelId: 'test-channel-id',
118
121
  request: new PikkuMockRequest('/non-existent-channel', 'get'),
119
122
  response: mockResponse,
120
- createWireServices: mockCreateWireServices,
121
123
  })
122
124
 
123
125
  assert.equal(
@@ -131,6 +133,10 @@ test('runChannel should return undefined and 404 if no matching channel is found
131
133
 
132
134
  test('runChannel should return a channel handler if channel matches and no auth required', async () => {
133
135
  resetPikkuState()
136
+ pikkuState(null, 'package', 'singletonServices', mockSingletonServices as any)
137
+ pikkuState(null, 'package', 'factories', {
138
+ createWireServices: mockCreateWireServices,
139
+ } as any)
134
140
 
135
141
  pikkuState(null, 'channel', 'meta', {
136
142
  test: {
@@ -148,12 +154,10 @@ test('runChannel should return a channel handler if channel matches and no auth
148
154
  httpRouter.initialize()
149
155
 
150
156
  const result = await runLocalChannel({
151
- singletonServices: mockSingletonServices,
152
157
  channelId: 'test-channel-id',
153
158
  request: new PikkuMockRequest('/test-channel', 'get'),
154
159
  response: new PikkuMockResponse(),
155
160
  route: '/test-channel',
156
- createWireServices: mockCreateWireServices,
157
161
  })
158
162
 
159
163
  assert.ok(result, 'Should return a PikkuChannelHandler instance')
@@ -164,6 +168,7 @@ test('runChannel should return a channel handler if channel matches and no auth
164
168
 
165
169
  test('runChannel should close wire services once when channel closes', async () => {
166
170
  resetPikkuState()
171
+ pikkuState(null, 'package', 'singletonServices', mockSingletonServices as any)
167
172
  let closeCount = 0
168
173
 
169
174
  pikkuState(null, 'channel', 'meta', {
@@ -180,12 +185,7 @@ test('runChannel should close wire services once when channel closes', async ()
180
185
 
181
186
  httpRouter.initialize()
182
187
 
183
- const result = await runLocalChannel({
184
- singletonServices: mockSingletonServices,
185
- channelId: 'test-channel-id',
186
- request: new PikkuMockRequest('/test-channel', 'get'),
187
- response: new PikkuMockResponse(),
188
- route: '/test-channel',
188
+ pikkuState(null, 'package', 'factories', {
189
189
  createWireServices: async () => ({
190
190
  tracked: {
191
191
  close: async () => {
@@ -193,6 +193,13 @@ test('runChannel should close wire services once when channel closes', async ()
193
193
  },
194
194
  },
195
195
  }),
196
+ } as any)
197
+
198
+ const result = await runLocalChannel({
199
+ channelId: 'test-channel-id',
200
+ request: new PikkuMockRequest('/test-channel', 'get'),
201
+ response: new PikkuMockResponse(),
202
+ route: '/test-channel',
196
203
  })
197
204
 
198
205
  assert.ok(result)
@@ -2,36 +2,43 @@ import { openChannel } from '../channel-runner.js'
2
2
  import { createHTTPWire } from '../../http/http-runner.js'
3
3
  import { closeWireServices } from '../../../utils.js'
4
4
  import { processMessageHandlers } from '../channel-handler.js'
5
- import {
6
- CoreChannel,
7
- RunChannelOptions,
8
- RunChannelParams,
9
- } from '../channel.types.js'
5
+ import type { CoreChannel, RunChannelOptions } from '../channel.types.js'
10
6
  import { PikkuLocalChannelHandler } from './local-channel-handler.js'
11
- import { PikkuWire, WireServices } from '../../../types/core.types.js'
7
+ import type { PikkuWire, WireServices } from '../../../types/core.types.js'
12
8
  import { handleHTTPError } from '../../../handle-error.js'
13
9
  import {
14
10
  PikkuSessionService,
15
11
  createMiddlewareSessionWireProps,
16
12
  } from '../../../services/user-session-service.js'
17
- import { PikkuHTTP } from '../../http/http.types.js'
13
+ import type {
14
+ PikkuHTTP,
15
+ PikkuHTTPRequest,
16
+ PikkuHTTPResponse,
17
+ } from '../../http/http.types.js'
18
18
  import { runChannelLifecycleWithMiddleware } from '../channel-common.js'
19
+ import {
20
+ getSingletonServices,
21
+ getCreateWireServices,
22
+ } from '../../../pikku-state.js'
19
23
 
20
24
  export const runLocalChannel = async ({
21
- singletonServices,
22
25
  channelId,
23
26
  request,
24
27
  response,
25
28
  route,
26
- createWireServices,
27
29
  skipUserSession = false,
28
30
  respondWith404 = true,
29
31
  coerceDataFromSchema = true,
30
32
  logWarningsForStatusCodes = [],
31
33
  bubbleErrors = false,
32
34
  }: Partial<Pick<CoreChannel<unknown, any>, 'route'>> &
33
- RunChannelOptions &
34
- RunChannelParams<unknown>): Promise<PikkuLocalChannelHandler | void> => {
35
+ RunChannelOptions & {
36
+ channelId: string
37
+ request?: PikkuHTTPRequest
38
+ response?: PikkuHTTPResponse
39
+ }): Promise<PikkuLocalChannelHandler | void> => {
40
+ const singletonServices = getSingletonServices()
41
+ const createWireServices = getCreateWireServices()
35
42
  let wireServices: WireServices<typeof singletonServices> | undefined
36
43
  let closedWireServices = false
37
44
 
@@ -48,12 +55,10 @@ export const runLocalChannel = async ({
48
55
  try {
49
56
  ;({ openingData, channelConfig, meta } = await openChannel({
50
57
  channelId,
51
- createWireServices,
52
58
  respondWith404,
53
59
  request,
54
60
  response,
55
61
  route,
56
- singletonServices,
57
62
  skipUserSession,
58
63
  coerceDataFromSchema,
59
64
  userSession,
@@ -142,7 +147,7 @@ export const runLocalChannel = async ({
142
147
  await closeServices()
143
148
  })
144
149
 
145
- const onMessage = processMessageHandlers(
150
+ const { onMessage, onBinaryMessage } = processMessageHandlers(
146
151
  services,
147
152
  channelConfig as any,
148
153
  channelHandler,
@@ -157,6 +162,20 @@ export const runLocalChannel = async ({
157
162
  channel.send({ error: e.message || 'Unknown error' })
158
163
  }
159
164
  })
165
+ if (onBinaryMessage) {
166
+ channelHandler.registerOnBinaryMessage(async (data) => {
167
+ try {
168
+ const result = await onBinaryMessage(data)
169
+ if (result) {
170
+ await channel.sendBinary(result)
171
+ }
172
+ } catch (e) {
173
+ singletonServices.logger.error(
174
+ `Error handling binary message: ${e.message}`
175
+ )
176
+ }
177
+ })
178
+ }
160
179
  } catch (e: any) {
161
180
  handleHTTPError(
162
181
  e,