@pikku/core 0.12.0 → 0.12.1

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 (262) hide show
  1. package/CHANGELOG.md +24 -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/permissions.d.ts +2 -2
  23. package/dist/pikku-state.d.ts +9 -8
  24. package/dist/pikku-state.js +30 -17
  25. package/dist/schema.d.ts +4 -4
  26. package/dist/schema.js +9 -5
  27. package/dist/services/ai-agent-runner-service.d.ts +22 -3
  28. package/dist/services/ai-run-state-service.d.ts +1 -1
  29. package/dist/services/ai-storage-service.d.ts +1 -1
  30. package/dist/services/content-service.d.ts +6 -0
  31. package/dist/services/gopass-secrets.d.ts +1 -1
  32. package/dist/services/gopass-secrets.js +3 -0
  33. package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
  34. package/dist/services/in-memory-ai-run-state-service.js +44 -0
  35. package/dist/services/in-memory-trigger-service.d.ts +0 -1
  36. package/dist/services/in-memory-trigger-service.js +6 -8
  37. package/dist/services/index.d.ts +3 -2
  38. package/dist/services/index.js +1 -0
  39. package/dist/services/local-content.d.ts +2 -1
  40. package/dist/services/local-content.js +6 -1
  41. package/dist/services/local-secrets.d.ts +2 -2
  42. package/dist/services/local-variables.d.ts +1 -1
  43. package/dist/services/logger-console.d.ts +2 -1
  44. package/dist/services/scheduler-service.d.ts +0 -12
  45. package/dist/services/scheduler-service.js +0 -6
  46. package/dist/services/scoped-secret-service.d.ts +1 -1
  47. package/dist/services/trigger-service.d.ts +0 -7
  48. package/dist/services/user-session-service.d.ts +3 -3
  49. package/dist/services/workflow-service.d.ts +2 -3
  50. package/dist/types/core.types.d.ts +24 -18
  51. package/dist/types/state.types.d.ts +17 -15
  52. package/dist/utils.d.ts +5 -5
  53. package/dist/utils.js +12 -9
  54. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
  55. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
  56. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
  57. package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
  58. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
  59. package/dist/wirings/ai-agent/ai-agent-prepare.js +66 -30
  60. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +1 -1
  61. package/dist/wirings/ai-agent/ai-agent-runner.js +107 -8
  62. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
  63. package/dist/wirings/ai-agent/ai-agent-stream.js +246 -87
  64. package/dist/wirings/ai-agent/ai-agent.types.d.ts +61 -2
  65. package/dist/wirings/ai-agent/index.d.ts +3 -1
  66. package/dist/wirings/ai-agent/index.js +2 -0
  67. package/dist/wirings/channel/channel-common.d.ts +2 -2
  68. package/dist/wirings/channel/channel-handler.d.ts +3 -3
  69. package/dist/wirings/channel/channel-handler.js +4 -4
  70. package/dist/wirings/channel/channel-runner.d.ts +5 -5
  71. package/dist/wirings/channel/channel-runner.js +3 -2
  72. package/dist/wirings/channel/channel-store.d.ts +1 -1
  73. package/dist/wirings/channel/channel.types.d.ts +4 -6
  74. package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
  75. package/dist/wirings/channel/local/local-channel-runner.js +4 -3
  76. package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
  77. package/dist/wirings/channel/log-channels.d.ts +1 -1
  78. package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
  79. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
  80. package/dist/wirings/channel/serverless/serverless-channel-runner.js +25 -19
  81. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
  82. package/dist/wirings/cli/cli-runner.d.ts +2 -2
  83. package/dist/wirings/cli/cli.types.d.ts +3 -3
  84. package/dist/wirings/cli/command-parser.d.ts +1 -1
  85. package/dist/wirings/http/http-runner.d.ts +9 -9
  86. package/dist/wirings/http/http-runner.js +33 -14
  87. package/dist/wirings/http/http.types.d.ts +2 -6
  88. package/dist/wirings/http/log-http-routes.d.ts +1 -1
  89. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
  90. package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
  91. package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
  92. package/dist/wirings/http/routers/http-router.d.ts +1 -1
  93. package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
  94. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  95. package/dist/wirings/mcp/mcp-runner.d.ts +0 -3
  96. package/dist/wirings/mcp/mcp-runner.js +4 -2
  97. package/dist/wirings/mcp/mcp.types.d.ts +2 -2
  98. package/dist/wirings/oauth2/oauth2-client.d.ts +3 -3
  99. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +1 -1
  100. package/dist/wirings/queue/index.d.ts +1 -1
  101. package/dist/wirings/queue/index.js +1 -1
  102. package/dist/wirings/queue/queue-runner.d.ts +1 -12
  103. package/dist/wirings/queue/queue-runner.js +4 -12
  104. package/dist/wirings/queue/queue.types.d.ts +3 -9
  105. package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
  106. package/dist/wirings/queue/register-queue-helper.js +1 -1
  107. package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
  108. package/dist/wirings/rpc/index.d.ts +2 -0
  109. package/dist/wirings/rpc/index.js +1 -0
  110. package/dist/wirings/rpc/rpc-runner.d.ts +36 -14
  111. package/dist/wirings/rpc/rpc-runner.js +56 -28
  112. package/dist/wirings/rpc/rpc-types.d.ts +14 -2
  113. package/dist/wirings/rpc/wire-addon.d.ts +10 -0
  114. package/dist/wirings/rpc/wire-addon.js +9 -0
  115. package/dist/wirings/scheduler/index.d.ts +1 -1
  116. package/dist/wirings/scheduler/index.js +1 -1
  117. package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
  118. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -10
  119. package/dist/wirings/scheduler/scheduler-runner.js +4 -25
  120. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
  121. package/dist/wirings/trigger/pikku-trigger-service.d.ts +2 -6
  122. package/dist/wirings/trigger/pikku-trigger-service.js +11 -16
  123. package/dist/wirings/trigger/trigger-runner.d.ts +1 -5
  124. package/dist/wirings/trigger/trigger-runner.js +4 -3
  125. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -6
  126. package/dist/wirings/workflow/pikku-workflow-service.js +20 -29
  127. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  128. package/package.json +2 -1
  129. package/src/crypto-utils.test.ts +116 -0
  130. package/src/errors/error.test.ts +143 -2
  131. package/src/errors/errors.ts +10 -0
  132. package/src/errors/index.ts +1 -0
  133. package/src/function/function-runner.test.ts +2 -2
  134. package/src/function/function-runner.ts +72 -49
  135. package/src/function/functions.types.ts +1 -0
  136. package/src/handle-error.test.ts +361 -0
  137. package/src/handle-error.ts +4 -4
  138. package/src/index.ts +3 -10
  139. package/src/internal.ts +6 -0
  140. package/src/middleware/auth-apikey.test.ts +1 -1
  141. package/src/middleware/auth-bearer.test.ts +1 -1
  142. package/src/middleware/auth-bearer.ts +2 -5
  143. package/src/middleware/auth-cookie.test.ts +1 -1
  144. package/src/middleware/auth-cookie.ts +3 -5
  145. package/src/middleware/cors.test.ts +424 -0
  146. package/src/middleware/cors.ts +14 -6
  147. package/src/middleware/remote-auth.test.ts +488 -0
  148. package/src/middleware-runner.test.ts +1 -1
  149. package/src/middleware-runner.ts +1 -1
  150. package/src/permissions.test.ts +2 -2
  151. package/src/permissions.ts +2 -2
  152. package/src/pikku-state.test.ts +224 -0
  153. package/src/pikku-state.ts +40 -28
  154. package/src/schema.test.ts +198 -6
  155. package/src/schema.ts +11 -7
  156. package/src/services/ai-agent-runner-service.ts +15 -3
  157. package/src/services/ai-run-state-service.ts +1 -1
  158. package/src/services/ai-storage-service.ts +1 -1
  159. package/src/services/content-service.ts +7 -0
  160. package/src/services/gopass-secrets.ts +4 -1
  161. package/src/services/in-memory-ai-run-state-service.ts +73 -0
  162. package/src/services/in-memory-trigger-service.ts +6 -10
  163. package/src/services/in-memory-workflow-service.test.ts +351 -0
  164. package/src/services/index.ts +2 -1
  165. package/src/services/local-content.ts +9 -3
  166. package/src/services/local-secrets.test.ts +80 -0
  167. package/src/services/local-secrets.ts +2 -2
  168. package/src/services/local-variables.test.ts +61 -0
  169. package/src/services/local-variables.ts +1 -1
  170. package/src/services/logger-console.test.ts +118 -0
  171. package/src/services/logger-console.ts +2 -1
  172. package/src/services/scheduler-service.ts +0 -18
  173. package/src/services/scoped-secret-service.test.ts +74 -0
  174. package/src/services/scoped-secret-service.ts +1 -1
  175. package/src/services/trigger-service.ts +0 -21
  176. package/src/services/typed-secret-service.test.ts +93 -0
  177. package/src/services/typed-variables-service.test.ts +73 -0
  178. package/src/services/user-session-service.test.ts +113 -0
  179. package/src/services/user-session-service.ts +3 -3
  180. package/src/services/workflow-service.ts +2 -12
  181. package/src/time-utils.test.ts +1 -1
  182. package/src/types/core.types.ts +25 -19
  183. package/src/types/state.types.ts +24 -15
  184. package/src/utils.test.ts +350 -0
  185. package/src/utils.ts +14 -13
  186. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
  187. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
  188. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
  189. package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
  190. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
  191. package/src/wirings/ai-agent/ai-agent-prepare.ts +79 -45
  192. package/src/wirings/ai-agent/ai-agent-registry.ts +1 -1
  193. package/src/wirings/ai-agent/ai-agent-runner.test.ts +245 -3
  194. package/src/wirings/ai-agent/ai-agent-runner.ts +121 -7
  195. package/src/wirings/ai-agent/ai-agent-stream.test.ts +430 -24
  196. package/src/wirings/ai-agent/ai-agent-stream.ts +377 -102
  197. package/src/wirings/ai-agent/ai-agent.types.ts +57 -2
  198. package/src/wirings/ai-agent/index.ts +11 -0
  199. package/src/wirings/channel/channel-common.ts +2 -2
  200. package/src/wirings/channel/channel-handler.ts +13 -9
  201. package/src/wirings/channel/channel-runner.ts +6 -6
  202. package/src/wirings/channel/channel-store.ts +1 -1
  203. package/src/wirings/channel/channel.types.ts +4 -8
  204. package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
  205. package/src/wirings/channel/local/local-channel-runner.ts +18 -13
  206. package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
  207. package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
  208. package/src/wirings/channel/log-channels.ts +1 -1
  209. package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
  210. package/src/wirings/channel/serverless/serverless-channel-runner.ts +37 -32
  211. package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
  212. package/src/wirings/cli/cli-runner.test.ts +1 -1
  213. package/src/wirings/cli/cli-runner.ts +11 -4
  214. package/src/wirings/cli/cli.types.ts +3 -3
  215. package/src/wirings/cli/command-parser.test.ts +1 -1
  216. package/src/wirings/cli/command-parser.ts +1 -1
  217. package/src/wirings/http/http-routes.test.ts +1 -1
  218. package/src/wirings/http/http-runner.test.ts +9 -17
  219. package/src/wirings/http/http-runner.ts +43 -27
  220. package/src/wirings/http/http.types.ts +1 -14
  221. package/src/wirings/http/log-http-routes.ts +1 -1
  222. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  223. package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
  224. package/src/wirings/http/routers/http-router.ts +1 -1
  225. package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
  226. package/src/wirings/http/routers/path-to-regex.ts +4 -3
  227. package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
  228. package/src/wirings/mcp/mcp-runner.ts +9 -15
  229. package/src/wirings/mcp/mcp.types.ts +2 -2
  230. package/src/wirings/oauth2/oauth2-client.ts +3 -3
  231. package/src/wirings/oauth2/wire-oauth2-credential.ts +1 -1
  232. package/src/wirings/queue/index.ts +0 -1
  233. package/src/wirings/queue/queue-runner.test.ts +52 -25
  234. package/src/wirings/queue/queue-runner.ts +8 -30
  235. package/src/wirings/queue/queue.types.ts +3 -13
  236. package/src/wirings/queue/register-queue-helper.ts +3 -5
  237. package/src/wirings/queue/validate-worker-config.test.ts +108 -0
  238. package/src/wirings/queue/validate-worker-config.ts +4 -1
  239. package/src/wirings/rpc/index.ts +2 -0
  240. package/src/wirings/rpc/rpc-runner.ts +92 -49
  241. package/src/wirings/rpc/rpc-types.ts +17 -2
  242. package/src/wirings/rpc/wire-addon.ts +20 -0
  243. package/src/wirings/scheduler/index.ts +0 -1
  244. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  245. package/src/wirings/scheduler/scheduler-runner.test.ts +49 -60
  246. package/src/wirings/scheduler/scheduler-runner.ts +9 -56
  247. package/src/wirings/scheduler/scheduler.types.ts +2 -2
  248. package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
  249. package/src/wirings/trigger/pikku-trigger-service.ts +17 -39
  250. package/src/wirings/trigger/trigger-runner.test.ts +79 -0
  251. package/src/wirings/trigger/trigger-runner.ts +8 -11
  252. package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
  253. package/src/wirings/workflow/graph/graph-runner.test.ts +14 -22
  254. package/src/wirings/workflow/graph/template.test.ts +49 -0
  255. package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -27
  256. package/src/wirings/workflow/pikku-workflow-service.ts +29 -45
  257. package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
  258. package/src/wirings/workflow/workflow.types.ts +2 -2
  259. package/tsconfig.tsbuildinfo +1 -1
  260. package/dist/wirings/workflow/workflow-utils.d.ts +0 -1
  261. package/dist/wirings/workflow/workflow-utils.js +0 -1
  262. package/src/wirings/workflow/workflow-utils.ts +0 -0
@@ -1,16 +1,16 @@
1
- import { PikkuError, ErrorDetails } from '../errors/error-handler.js';
2
- import { CorePikkuFunctionConfig, CorePermissionGroup, CorePikkuPermission } from '../function/functions.types.js';
3
- import { CorePikkuTriggerFunctionConfig } from '../wirings/trigger/trigger.types.js';
4
- import { CoreChannel, ChannelsMeta } from '../wirings/channel/channel.types.js';
5
- import { CLIMeta, CLIProgramState } from '../wirings/cli/cli.types.js';
6
- import { HTTPMethod, CoreHTTPFunctionWiring, HTTPWiringsMeta } from '../wirings/http/http.types.js';
7
- import { CoreMCPResource, MCPResourceMeta, MCPToolMeta, CoreMCPPrompt, MCPPromptMeta } from '../wirings/mcp/mcp.types.js';
8
- import { CoreAIAgent, AIAgentMeta } from '../wirings/ai-agent/ai-agent.types.js';
9
- import { CoreQueueWorker, QueueWorkersMeta } from '../wirings/queue/queue.types.js';
10
- import { CoreScheduledTask, ScheduledTasksMeta } from '../wirings/scheduler/scheduler.types.js';
11
- import { CoreWorkflow, WorkflowsRuntimeMeta } from '../wirings/workflow/workflow.types.js';
12
- import { CoreTrigger, CoreTriggerSource, TriggerMeta, TriggerSourceMeta } from '../wirings/trigger/trigger.types.js';
13
- import { FunctionsMeta, CorePikkuMiddleware, CorePikkuMiddlewareGroup, CreateConfig, CreateSingletonServices, CreateWireServices, CoreConfig, CoreSingletonServices, CoreServices, CoreUserSession } from './core.types.js';
1
+ import type { PikkuError, ErrorDetails } from '../errors/error-handler.js';
2
+ import type { CorePikkuFunctionConfig, CorePermissionGroup, CorePikkuPermission } from '../function/functions.types.js';
3
+ import type { CorePikkuTriggerFunctionConfig } from '../wirings/trigger/trigger.types.js';
4
+ import type { CoreChannel, ChannelsMeta } from '../wirings/channel/channel.types.js';
5
+ import type { CLIMeta, CLIProgramState } from '../wirings/cli/cli.types.js';
6
+ import type { HTTPMethod, CoreHTTPFunctionWiring, HTTPWiringsMeta } from '../wirings/http/http.types.js';
7
+ import type { CoreMCPResource, MCPResourceMeta, MCPToolMeta, CoreMCPPrompt, MCPPromptMeta } from '../wirings/mcp/mcp.types.js';
8
+ import type { CoreAIAgent, AIAgentMeta } from '../wirings/ai-agent/ai-agent.types.js';
9
+ import type { CoreQueueWorker, QueueWorkersMeta } from '../wirings/queue/queue.types.js';
10
+ import type { CoreScheduledTask, ScheduledTasksMeta } from '../wirings/scheduler/scheduler.types.js';
11
+ import type { CoreWorkflow, WorkflowsRuntimeMeta } from '../wirings/workflow/workflow.types.js';
12
+ import type { CoreTrigger, CoreTriggerSource, TriggerMeta, TriggerSourceMeta } from '../wirings/trigger/trigger.types.js';
13
+ import type { FunctionsMeta, CorePikkuMiddleware, CorePikkuMiddlewareGroup, CreateConfig, CreateSingletonServices, CreateWireServices, CoreConfig, CoreSingletonServices, CoreServices, CoreUserSession } from './core.types.js';
14
14
  import type { CorePikkuChannelMiddleware } from '../wirings/channel/channel.types.js';
15
15
  /**
16
16
  * State structure for an individual package
@@ -27,9 +27,11 @@ export interface PikkuPackageState {
27
27
  path: string;
28
28
  }>;
29
29
  /** Maps namespace aliases to package config (e.g., 'ext' -> { package: '@pikku/...', rpcEndpoint: '...' }) */
30
- externalPackages: Map<string, {
30
+ addons: Map<string, {
31
31
  package: string;
32
32
  rpcEndpoint?: string;
33
+ auth?: boolean;
34
+ tags?: string[];
33
35
  }>;
34
36
  };
35
37
  http: {
@@ -113,7 +115,7 @@ export interface PikkuPackageState {
113
115
  } | null;
114
116
  };
115
117
  package: {
116
- /** Service factory functions for external packages */
118
+ /** Service factory functions for addon packages */
117
119
  factories: {
118
120
  createConfig?: CreateConfig<CoreConfig>;
119
121
  createSingletonServices?: CreateSingletonServices<CoreConfig, CoreSingletonServices>;
package/dist/utils.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { Logger } from './services/logger.js';
2
- import { CoreSingletonServices, WireServices } from './types/core.types.js';
1
+ import type { Logger } from './services/logger.js';
2
+ import type { WireServices } from './types/core.types.js';
3
3
  export declare const closeWireServices: (logger: Logger, wireServices: WireServices) => Promise<void>;
4
4
  export declare const createWeakUID: () => string;
5
5
  export declare const isSerializable: (data: any) => boolean;
6
6
  export declare const getTagGroups: <T>(tagGroups: Record<string, T>, tag: string) => T[];
7
7
  export declare const freezeDedupe: <T>(arr?: readonly T[] | T[] | undefined) => readonly T[];
8
8
  /**
9
- * Stop all singleton services, including external package services.
10
- * External package services are stopped first, then the parent services.
9
+ * Stop all singleton services, including addon package services.
10
+ * Addon package services are stopped first, then the parent services.
11
11
  *
12
12
  * @param singletonServices - The parent singleton services to stop
13
13
  */
14
- export declare const stopSingletonServices: (singletonServices: CoreSingletonServices) => Promise<void>;
14
+ export declare const stopSingletonServices: () => Promise<void>;
package/dist/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { getSingletonServices, getAllPackageStates } from './pikku-state.js';
1
2
  export const closeWireServices = async (logger, wireServices) => {
2
3
  await Promise.all(Object.values(wireServices).map(async (service) => {
3
4
  if (service?.close) {
@@ -10,9 +11,9 @@ export const closeWireServices = async (logger, wireServices) => {
10
11
  }
11
12
  }));
12
13
  };
13
- export const createWeakUID = () => {
14
- return Date.now().toString(36) + Math.random().toString(36).substring(2, 10);
15
- };
14
+ const _uidPrefix = Date.now().toString(36);
15
+ let _uidCounter = 0;
16
+ export const createWeakUID = () => `${_uidPrefix}-${++_uidCounter}`;
16
17
  export const isSerializable = (data) => {
17
18
  return !(typeof data === 'string' ||
18
19
  data instanceof ArrayBuffer ||
@@ -73,16 +74,18 @@ const stopService = async (logger, name, service) => {
73
74
  }
74
75
  };
75
76
  /**
76
- * Stop all singleton services, including external package services.
77
- * External package services are stopped first, then the parent services.
77
+ * Stop all singleton services, including addon package services.
78
+ * Addon package services are stopped first, then the parent services.
78
79
  *
79
80
  * @param singletonServices - The parent singleton services to stop
80
81
  */
81
- export const stopSingletonServices = async (singletonServices) => {
82
+ export const stopSingletonServices = async () => {
83
+ const singletonServices = getSingletonServices();
82
84
  const logger = singletonServices.logger;
83
- // First, stop all external package singleton services
84
- if (globalThis.pikkuState) {
85
- for (const [packageName, packageState] of globalThis.pikkuState) {
85
+ // First, stop all addon package singleton services
86
+ const stateMap = getAllPackageStates();
87
+ if (stateMap.size > 0) {
88
+ for (const [packageName, packageState] of stateMap) {
86
89
  // Skip main package - we handle it separately
87
90
  if (packageName === '__main__')
88
91
  continue;
@@ -0,0 +1,5 @@
1
+ import type { AIStreamChannel, AIAgentInput } from './ai-agent.types.js';
2
+ export declare function createAssistantUIChannel(parent: AIStreamChannel): AIStreamChannel;
3
+ export declare function parseAssistantUIInput(input: Record<string, unknown>, defaults?: {
4
+ resourceId?: string;
5
+ }): AIAgentInput;
@@ -0,0 +1,146 @@
1
+ import { randomUUID } from 'crypto';
2
+ export function createAssistantUIChannel(parent) {
3
+ const messageId = randomUUID();
4
+ let started = false;
5
+ let totalInputTokens = 0;
6
+ let totalOutputTokens = 0;
7
+ let pendingToolResults = [];
8
+ let hasToolCalls = false;
9
+ let hasPendingApproval = false;
10
+ const sendChunk = (chunk) => {
11
+ parent.send(chunk);
12
+ };
13
+ const ensureStarted = () => {
14
+ if (!started) {
15
+ started = true;
16
+ sendChunk({ type: 'start', messageId });
17
+ }
18
+ };
19
+ const flushToolResults = () => {
20
+ for (const chunk of pendingToolResults) {
21
+ sendChunk(chunk);
22
+ }
23
+ pendingToolResults = [];
24
+ };
25
+ return {
26
+ channelId: parent.channelId,
27
+ openingData: parent.openingData,
28
+ get state() {
29
+ return parent.state;
30
+ },
31
+ close: () => parent.close(),
32
+ send: (event) => {
33
+ switch (event.type) {
34
+ case 'text-delta':
35
+ ensureStarted();
36
+ sendChunk({ type: 'text-delta', textDelta: event.text });
37
+ break;
38
+ case 'reasoning-delta':
39
+ ensureStarted();
40
+ sendChunk({ type: 'reasoning-delta', delta: event.text });
41
+ break;
42
+ case 'tool-call':
43
+ ensureStarted();
44
+ hasToolCalls = true;
45
+ sendChunk({
46
+ type: 'tool-call-start',
47
+ id: event.toolCallId,
48
+ toolCallId: event.toolCallId,
49
+ toolName: event.toolName,
50
+ });
51
+ sendChunk({
52
+ type: 'tool-call-delta',
53
+ argsText: typeof event.args === 'string'
54
+ ? event.args
55
+ : JSON.stringify(event.args),
56
+ });
57
+ sendChunk({ type: 'tool-call-end' });
58
+ break;
59
+ case 'tool-result':
60
+ ensureStarted();
61
+ pendingToolResults.push({
62
+ type: 'tool-result',
63
+ toolCallId: event.toolCallId,
64
+ result: event.result,
65
+ });
66
+ break;
67
+ case 'agent-call':
68
+ case 'agent-result':
69
+ break;
70
+ case 'usage': {
71
+ ensureStarted();
72
+ totalInputTokens += event.tokens.input;
73
+ totalOutputTokens += event.tokens.output;
74
+ const hasPending = pendingToolResults.length > 0;
75
+ sendChunk({
76
+ type: 'finish-step',
77
+ finishReason: hasToolCalls ? 'tool-calls' : 'stop',
78
+ usage: {
79
+ promptTokens: event.tokens.input,
80
+ completionTokens: event.tokens.output,
81
+ },
82
+ isContinued: hasPending,
83
+ });
84
+ flushToolResults();
85
+ hasToolCalls = false;
86
+ break;
87
+ }
88
+ case 'error':
89
+ ensureStarted();
90
+ sendChunk({ type: 'error', errorText: event.message });
91
+ break;
92
+ case 'approval-request':
93
+ ensureStarted();
94
+ hasPendingApproval = true;
95
+ sendChunk({ type: 'data-approval-request', data: event });
96
+ break;
97
+ case 'suspended':
98
+ ensureStarted();
99
+ sendChunk({ type: 'data-suspended', data: event });
100
+ break;
101
+ case 'done':
102
+ ensureStarted();
103
+ flushToolResults();
104
+ sendChunk({
105
+ type: 'finish',
106
+ finishReason: hasPendingApproval ? 'tool-calls' : 'stop',
107
+ usage: {
108
+ promptTokens: totalInputTokens,
109
+ completionTokens: totalOutputTokens,
110
+ },
111
+ });
112
+ parent.send('[DONE]');
113
+ parent.close();
114
+ break;
115
+ }
116
+ },
117
+ };
118
+ }
119
+ export function parseAssistantUIInput(input, defaults) {
120
+ const messages = input.messages;
121
+ if (!messages || !Array.isArray(messages) || messages.length === 0) {
122
+ throw new Error('assistant-ui input must contain a non-empty messages array');
123
+ }
124
+ const lastUserMessage = [...messages].reverse().find((m) => m.role === 'user');
125
+ if (!lastUserMessage) {
126
+ throw new Error('No user message found in assistant-ui input');
127
+ }
128
+ let messageText;
129
+ if (typeof lastUserMessage.content === 'string') {
130
+ messageText = lastUserMessage.content;
131
+ }
132
+ else if (Array.isArray(lastUserMessage.parts)) {
133
+ const textPart = lastUserMessage.parts.find((p) => p.type === 'text');
134
+ messageText = textPart ? String(textPart.text) : '';
135
+ }
136
+ else if (Array.isArray(lastUserMessage.content)) {
137
+ const textPart = lastUserMessage.content.find((p) => p.type === 'text');
138
+ messageText = textPart ? String(textPart.text) : '';
139
+ }
140
+ else {
141
+ messageText = '';
142
+ }
143
+ const threadId = input.threadId ?? input.id ?? randomUUID();
144
+ const resourceId = defaults?.resourceId ?? 'default';
145
+ return { message: messageText, threadId, resourceId };
146
+ }
@@ -0,0 +1,28 @@
1
+ export declare function agent<TAgentMap extends Record<string, {
2
+ output: any;
3
+ }>>(agentName: string & keyof TAgentMap): {
4
+ func: (services: any, data: any, wire: any) => Promise<any>;
5
+ };
6
+ export declare function agentStream<TAgentMap extends Record<string, {
7
+ output: any;
8
+ }>>(agentName?: string & keyof TAgentMap): {
9
+ func: (services: any, data: any, wire: any) => Promise<void>;
10
+ };
11
+ export declare function agentResume(): {
12
+ func: (services: any, data: {
13
+ runId: string;
14
+ toolCallId: string;
15
+ approved: boolean;
16
+ }, wire: any) => Promise<void>;
17
+ };
18
+ export declare function agentApprove<TAgentMap extends Record<string, {
19
+ output: any;
20
+ }>>(_agentName: string & keyof TAgentMap): {
21
+ func: (services: any, data: {
22
+ runId: string;
23
+ approvals: {
24
+ toolCallId: string;
25
+ approved: boolean;
26
+ }[];
27
+ }, wire: any) => Promise<any>;
28
+ };
@@ -0,0 +1,40 @@
1
+ export function agent(agentName) {
2
+ return {
3
+ func: async (_services, data, { rpc }) => {
4
+ return rpc.agent.run(agentName, data);
5
+ },
6
+ };
7
+ }
8
+ export function agentStream(agentName) {
9
+ return {
10
+ func: async (_services, data, { rpc }) => {
11
+ if (agentName) {
12
+ await rpc.agent.stream(agentName, data);
13
+ }
14
+ else {
15
+ const { agentName: name, ...rest } = data;
16
+ if (!name) {
17
+ throw new Error('agentStream requires an agentName either as a parameter or in the input data');
18
+ }
19
+ await rpc.agent.stream(name, rest);
20
+ }
21
+ },
22
+ };
23
+ }
24
+ export function agentResume() {
25
+ return {
26
+ func: async (_services, data, { rpc }) => {
27
+ await rpc.agent.resume(data.runId, {
28
+ toolCallId: data.toolCallId,
29
+ approved: data.approved,
30
+ });
31
+ },
32
+ };
33
+ }
34
+ export function agentApprove(_agentName) {
35
+ return {
36
+ func: async (_services, data, { rpc }) => {
37
+ return rpc.agent.approve(data.runId, data.approvals);
38
+ },
39
+ };
40
+ }
@@ -1,12 +1,10 @@
1
- import { type CoreSingletonServices, type CoreServices, type CoreUserSession, type CreateWireServices } from '../../types/core.types.js';
2
- import type { CoreAIAgent, AIAgentInput, AIAgentToolDef, AIMessage, AIStreamChannel } from './ai-agent.types.js';
1
+ import type { CoreUserSession } from '../../types/core.types.js';
2
+ import type { CoreAIAgent, AIAgentInput, AIAgentToolDef, AIMessage, AIStreamChannel, PikkuAIMiddlewareHooks } from './ai-agent.types.js';
3
3
  import type { AIAgentRunnerParams } from '../../services/ai-agent-runner-service.js';
4
4
  import { PikkuError } from '../../errors/error-handler.js';
5
5
  import type { SessionService } from '../../services/user-session-service.js';
6
6
  export type RunAIAgentParams = {
7
- singletonServices: CoreSingletonServices;
8
7
  sessionService?: SessionService<CoreUserSession>;
9
- createWireServices?: CreateWireServices<CoreSingletonServices, CoreServices<CoreSingletonServices>, CoreUserSession>;
10
8
  };
11
9
  export type StreamAIAgentOptions = {
12
10
  requiresToolApproval?: 'all' | 'explicit' | false;
@@ -40,7 +38,7 @@ export type ScopedChannel = AIStreamChannel & {
40
38
  } | null;
41
39
  };
42
40
  export declare function createScopedChannel(parent: AIStreamChannel, agentName: string, session: string): ScopedChannel;
43
- export declare function buildToolDefs(singletonServices: CoreSingletonServices, params: RunAIAgentParams, agentSessionMap: Map<string, string>, resourceId: string, agentName: string, packageName: string | null, streamContext?: StreamContext): {
41
+ export declare function buildToolDefs(params: RunAIAgentParams, agentSessionMap: Map<string, string>, resourceId: string, agentName: string, packageName: string | null, streamContext?: StreamContext, aiMiddlewares?: PikkuAIMiddlewareHooks[]): {
44
42
  tools: AIAgentToolDef[];
45
43
  missingRpcs: string[];
46
44
  };
@@ -54,6 +52,7 @@ export declare function prepareAgentRun(agentName: string, input: AIAgentInput,
54
52
  threadId: string;
55
53
  userMessage: AIMessage;
56
54
  runnerParams: AIAgentRunnerParams;
55
+ maxSteps: number;
57
56
  missingRpcs: string[];
58
57
  workingMemoryJsonSchema: any;
59
58
  workingMemorySchemaName: string | null;
@@ -1,5 +1,5 @@
1
1
  import { PikkuError } from '../../errors/error-handler.js';
2
- import { pikkuState } from '../../pikku-state.js';
2
+ import { pikkuState, getSingletonServices, getCreateWireServices, } from '../../pikku-state.js';
3
3
  import { runPikkuFunc } from '../../function/function-runner.js';
4
4
  import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js';
5
5
  import { randomUUID } from 'crypto';
@@ -33,8 +33,8 @@ export const resolveAgent = (agentName) => {
33
33
  if (colonIndex !== -1) {
34
34
  const namespace = agentName.substring(0, colonIndex);
35
35
  const localName = agentName.substring(colonIndex + 1);
36
- const externalPackages = pikkuState(null, 'rpc', 'externalPackages');
37
- const pkgConfig = externalPackages.get(namespace);
36
+ const addons = pikkuState(null, 'rpc', 'addons');
37
+ const pkgConfig = addons.get(namespace);
38
38
  if (pkgConfig) {
39
39
  const extAgent = pikkuState(pkgConfig.package, 'agent', 'agents').get(localName);
40
40
  if (extAgent) {
@@ -85,7 +85,8 @@ export function createScopedChannel(parent, agentName, session) {
85
85
  };
86
86
  return;
87
87
  }
88
- if (event.type === 'text-delta' ||
88
+ if (event.type === 'step-start' ||
89
+ event.type === 'text-delta' ||
89
90
  event.type === 'reasoning-delta' ||
90
91
  event.type === 'tool-call' ||
91
92
  event.type === 'tool-result' ||
@@ -99,7 +100,8 @@ export function createScopedChannel(parent, agentName, session) {
99
100
  },
100
101
  };
101
102
  }
102
- export function buildToolDefs(singletonServices, params, agentSessionMap, resourceId, agentName, packageName, streamContext) {
103
+ export function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares) {
104
+ const singletonServices = getSingletonServices();
103
105
  const tools = [];
104
106
  const missingRpcs = [];
105
107
  const approvalPolicy = streamContext?.options?.requiresToolApproval ?? 'explicit';
@@ -131,38 +133,18 @@ export function buildToolDefs(singletonServices, params, agentSessionMap, resour
131
133
  }
132
134
  const needsApproval = approvalPolicy === 'all' ||
133
135
  (approvalPolicy === 'explicit' && fnMeta?.requiresApproval);
134
- if (needsApproval) {
135
- inputSchema = {
136
- ...inputSchema,
137
- properties: {
138
- ...(inputSchema.properties || {}),
139
- toolApprovalReason: {
140
- type: 'string',
141
- description: 'Brief explanation of why this action is needed',
142
- },
143
- },
144
- };
145
- }
146
136
  tools.push({
147
137
  name: pikkuFuncId,
148
138
  description: fnMeta?.description || fnMeta?.title || toolName,
149
139
  inputSchema,
140
+ needsApproval: needsApproval || undefined,
150
141
  execute: async (toolInput) => {
151
- if (needsApproval) {
152
- const { toolApprovalReason, ...cleanArgs } = toolInput;
153
- return {
154
- __approvalRequired: true,
155
- toolName: pikkuFuncId,
156
- args: cleanArgs,
157
- reason: toolApprovalReason,
158
- };
159
- }
160
142
  const wire = params.sessionService
161
143
  ? { ...createMiddlewareSessionWireProps(params.sessionService) }
162
144
  : {};
163
145
  return runPikkuFunc('agent', `tool:${pikkuFuncId}`, pikkuFuncId, {
164
146
  singletonServices,
165
- createWireServices: params.createWireServices,
147
+ createWireServices: getCreateWireServices(),
166
148
  data: () => toolInput,
167
149
  wire,
168
150
  sessionService: params.sessionService,
@@ -237,10 +219,61 @@ export function buildToolDefs(singletonServices, params, agentSessionMap, resour
237
219
  });
238
220
  }
239
221
  }
222
+ const hasToolHooks = aiMiddlewares?.some((mw) => mw.beforeToolCall || mw.afterToolCall);
223
+ if (hasToolHooks) {
224
+ for (const tool of tools) {
225
+ const originalExecute = tool.execute;
226
+ tool.execute = async (toolInput) => {
227
+ const toolCallId = randomUUID();
228
+ let args = (toolInput ?? {});
229
+ for (const mw of aiMiddlewares) {
230
+ if (mw.beforeToolCall) {
231
+ const beforeResult = await mw.beforeToolCall(singletonServices, {
232
+ toolName: tool.name,
233
+ toolCallId,
234
+ args,
235
+ });
236
+ if (beforeResult && 'args' in beforeResult) {
237
+ args = beforeResult.args;
238
+ }
239
+ }
240
+ }
241
+ const startTime = Date.now();
242
+ let result;
243
+ let execError;
244
+ try {
245
+ result = await originalExecute(args);
246
+ }
247
+ catch (err) {
248
+ execError = err;
249
+ result = err instanceof Error ? err.message : String(err);
250
+ }
251
+ const durationMs = Date.now() - startTime;
252
+ for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
253
+ const mw = aiMiddlewares[i];
254
+ if (mw.afterToolCall) {
255
+ const afterResult = await mw.afterToolCall(singletonServices, {
256
+ toolName: tool.name,
257
+ toolCallId,
258
+ args,
259
+ result,
260
+ durationMs,
261
+ });
262
+ if (afterResult && 'result' in afterResult) {
263
+ result = afterResult.result;
264
+ }
265
+ }
266
+ }
267
+ if (execError)
268
+ throw execError;
269
+ return result;
270
+ };
271
+ }
272
+ }
240
273
  return { tools, missingRpcs };
241
274
  }
242
275
  export async function prepareAgentRun(agentName, input, params, agentSessionMap, streamContext) {
243
- const { singletonServices } = params;
276
+ const singletonServices = getSingletonServices();
244
277
  const { agent, packageName, resolvedName } = resolveAgent(agentName);
245
278
  const agentRunner = singletonServices.aiAgentRunner;
246
279
  if (!agentRunner) {
@@ -282,16 +315,18 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
282
315
  };
283
316
  const allMessages = [...contextMessages, ...messages, userMessage];
284
317
  const trimmedMessages = trimMessages(allMessages);
285
- const { tools, missingRpcs } = buildToolDefs(singletonServices, params, agentSessionMap, input.resourceId, resolvedName, packageName, streamContext);
318
+ const aiMiddlewares = agent.aiMiddleware ?? [];
319
+ const { tools, missingRpcs } = buildToolDefs(params, agentSessionMap, input.resourceId, resolvedName, packageName, streamContext, aiMiddlewares);
286
320
  const instructions = buildInstructions(resolvedName, packageName);
287
321
  const resolved = resolveModelConfig(resolvedName, agent);
322
+ const maxSteps = resolved.maxSteps ?? 10;
288
323
  const runnerParams = {
289
324
  model: resolved.model,
290
325
  temperature: resolved.temperature,
291
326
  instructions,
292
327
  messages: trimmedMessages,
293
328
  tools,
294
- maxSteps: resolved.maxSteps ?? 10,
329
+ maxSteps: 1,
295
330
  toolChoice: agent.toolChoice ?? 'auto',
296
331
  outputSchema,
297
332
  };
@@ -305,6 +340,7 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
305
340
  threadId,
306
341
  userMessage,
307
342
  runnerParams,
343
+ maxSteps,
308
344
  missingRpcs,
309
345
  workingMemoryJsonSchema,
310
346
  workingMemorySchemaName,
@@ -1,5 +1,5 @@
1
1
  import type { CoreAIAgent } from './ai-agent.types.js';
2
- import { AIRunStateService } from '../../services/ai-run-state-service.js';
2
+ import type { AIRunStateService } from '../../services/ai-run-state-service.js';
3
3
  export declare const addAIAgent: (agentName: string, agent: CoreAIAgent<any, any>, packageName?: string | null) => void;
4
4
  export declare function approveAIAgent(aiRunState: AIRunStateService, runId: string, approvals: {
5
5
  toolCallId: string;