@pikku/core 0.12.1 → 0.12.3

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 (165) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/crypto-utils.d.ts +10 -0
  3. package/dist/crypto-utils.js +62 -0
  4. package/dist/function/function-runner.js +4 -4
  5. package/dist/function/functions.types.d.ts +26 -1
  6. package/dist/function/functions.types.js +16 -0
  7. package/dist/handle-error.d.ts +1 -1
  8. package/dist/handle-error.js +7 -3
  9. package/dist/index.d.ts +14 -2
  10. package/dist/index.js +1 -1
  11. package/dist/middleware-runner.js +1 -0
  12. package/dist/permissions.js +1 -0
  13. package/dist/pikku-state.js +7 -1
  14. package/dist/schema.js +1 -1
  15. package/dist/services/gateway-service.d.ts +19 -0
  16. package/dist/services/gateway-service.js +1 -0
  17. package/dist/services/in-memory-workflow-service.d.ts +8 -2
  18. package/dist/services/in-memory-workflow-service.js +28 -1
  19. package/dist/services/index.d.ts +2 -0
  20. package/dist/services/index.js +1 -0
  21. package/dist/services/local-gateway-service.d.ts +22 -0
  22. package/dist/services/local-gateway-service.js +51 -0
  23. package/dist/services/workflow-service.d.ts +8 -2
  24. package/dist/testing/index.d.ts +2 -0
  25. package/dist/testing/index.js +1 -0
  26. package/dist/testing/service-tests.d.ts +31 -0
  27. package/dist/testing/service-tests.js +598 -0
  28. package/dist/types/core.types.d.ts +12 -2
  29. package/dist/types/state.types.d.ts +9 -2
  30. package/dist/utils/hash.d.ts +2 -0
  31. package/dist/utils/hash.js +23 -0
  32. package/dist/utils.js +1 -1
  33. package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +6 -0
  34. package/dist/wirings/ai-agent/agent-dynamic-workflow.js +348 -0
  35. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +1 -1
  36. package/dist/wirings/ai-agent/ai-agent-memory.js +19 -7
  37. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -7
  38. package/dist/wirings/ai-agent/ai-agent-prepare.js +141 -48
  39. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +4 -0
  40. package/dist/wirings/ai-agent/ai-agent-runner.js +381 -27
  41. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +7 -2
  42. package/dist/wirings/ai-agent/ai-agent-stream.js +126 -48
  43. package/dist/wirings/ai-agent/ai-agent.types.d.ts +57 -3
  44. package/dist/wirings/ai-agent/index.d.ts +2 -3
  45. package/dist/wirings/ai-agent/index.js +1 -2
  46. package/dist/wirings/channel/channel-handler.d.ts +5 -2
  47. package/dist/wirings/channel/channel-handler.js +16 -2
  48. package/dist/wirings/channel/channel-middleware-runner.js +1 -0
  49. package/dist/wirings/channel/channel.types.d.ts +7 -7
  50. package/dist/wirings/channel/index.d.ts +1 -1
  51. package/dist/wirings/channel/local/local-channel-handler.d.ts +8 -1
  52. package/dist/wirings/channel/local/local-channel-handler.js +22 -3
  53. package/dist/wirings/channel/local/local-channel-runner.js +28 -5
  54. package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +2 -1
  55. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  56. package/dist/wirings/channel/serverless/serverless-channel-runner.js +5 -2
  57. package/dist/wirings/cli/cli-runner.js +13 -2
  58. package/dist/wirings/cli/cli.types.d.ts +1 -0
  59. package/dist/wirings/gateway/gateway-runner.d.ts +24 -0
  60. package/dist/wirings/gateway/gateway-runner.js +325 -0
  61. package/dist/wirings/gateway/gateway.types.d.ts +127 -0
  62. package/dist/wirings/gateway/gateway.types.js +1 -0
  63. package/dist/wirings/gateway/index.d.ts +2 -0
  64. package/dist/wirings/gateway/index.js +1 -0
  65. package/dist/wirings/http/http-routes.js +0 -1
  66. package/dist/wirings/http/http-runner.d.ts +1 -1
  67. package/dist/wirings/http/http-runner.js +28 -3
  68. package/dist/wirings/http/http.types.d.ts +3 -11
  69. package/dist/wirings/http/index.d.ts +2 -1
  70. package/dist/wirings/http/index.js +1 -0
  71. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
  72. package/dist/wirings/http/pikku-fetch-http-request.js +3 -0
  73. package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
  74. package/dist/wirings/http/pikku-fetch-http-response.js +4 -4
  75. package/dist/wirings/http/web-request.d.ts +12 -0
  76. package/dist/wirings/http/web-request.js +85 -0
  77. package/dist/wirings/mcp/mcp-endpoint-registry.js +1 -1
  78. package/dist/wirings/mcp/mcp-runner.js +13 -1
  79. package/dist/wirings/rpc/rpc-runner.d.ts +30 -6
  80. package/dist/wirings/rpc/rpc-runner.js +36 -14
  81. package/dist/wirings/rpc/rpc-types.d.ts +6 -1
  82. package/dist/wirings/rpc/wire-addon.d.ts +1 -0
  83. package/dist/wirings/rpc/wire-addon.js +1 -1
  84. package/dist/wirings/scheduler/scheduler-runner.js +1 -0
  85. package/dist/wirings/workflow/graph/graph-validation.d.ts +3 -0
  86. package/dist/wirings/workflow/graph/graph-validation.js +175 -0
  87. package/dist/wirings/workflow/graph/index.d.ts +1 -0
  88. package/dist/wirings/workflow/graph/index.js +1 -0
  89. package/dist/wirings/workflow/index.d.ts +1 -1
  90. package/dist/wirings/workflow/pikku-workflow-service.d.ts +8 -2
  91. package/dist/wirings/workflow/pikku-workflow-service.js +1 -2
  92. package/dist/wirings/workflow/workflow.types.d.ts +10 -1
  93. package/package.json +6 -3
  94. package/src/crypto-utils.test.ts +99 -1
  95. package/src/crypto-utils.ts +114 -0
  96. package/src/function/function-runner.ts +5 -5
  97. package/src/function/functions.types.ts +38 -1
  98. package/src/handle-error.test.ts +65 -2
  99. package/src/handle-error.ts +8 -4
  100. package/src/index.ts +14 -0
  101. package/src/middleware-runner.ts +1 -0
  102. package/src/permissions.ts +1 -0
  103. package/src/pikku-state.ts +8 -1
  104. package/src/schema.ts +1 -1
  105. package/src/services/gateway-service.ts +20 -0
  106. package/src/services/in-memory-workflow-service.ts +45 -2
  107. package/src/services/index.ts +2 -0
  108. package/src/services/local-gateway-service.ts +62 -0
  109. package/src/services/workflow-service.ts +12 -1
  110. package/src/testing/index.ts +2 -0
  111. package/src/testing/service-tests.ts +873 -0
  112. package/src/types/core.types.ts +12 -1
  113. package/src/types/state.types.ts +12 -2
  114. package/src/utils/hash.test.ts +68 -0
  115. package/src/utils/hash.ts +26 -0
  116. package/src/utils.ts +1 -1
  117. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -0
  118. package/src/wirings/ai-agent/ai-agent-memory.ts +17 -7
  119. package/src/wirings/ai-agent/ai-agent-prepare.ts +194 -62
  120. package/src/wirings/ai-agent/ai-agent-runner.test.ts +3 -1
  121. package/src/wirings/ai-agent/ai-agent-runner.ts +553 -31
  122. package/src/wirings/ai-agent/ai-agent-stream.test.ts +209 -2
  123. package/src/wirings/ai-agent/ai-agent-stream.ts +195 -91
  124. package/src/wirings/ai-agent/ai-agent.types.ts +57 -3
  125. package/src/wirings/ai-agent/index.ts +3 -5
  126. package/src/wirings/channel/channel-handler.ts +41 -4
  127. package/src/wirings/channel/channel-middleware-runner.ts +1 -0
  128. package/src/wirings/channel/channel.types.ts +12 -7
  129. package/src/wirings/channel/index.ts +1 -0
  130. package/src/wirings/channel/local/local-channel-handler.ts +31 -3
  131. package/src/wirings/channel/local/local-channel-runner.ts +32 -8
  132. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +2 -0
  133. package/src/wirings/channel/pikku-abstract-channel-handler.ts +8 -1
  134. package/src/wirings/channel/serverless/serverless-channel-runner.ts +5 -2
  135. package/src/wirings/cli/cli-runner.ts +15 -2
  136. package/src/wirings/cli/cli.types.ts +1 -0
  137. package/src/wirings/gateway/gateway-runner.test.ts +474 -0
  138. package/src/wirings/gateway/gateway-runner.ts +411 -0
  139. package/src/wirings/gateway/gateway.types.ts +149 -0
  140. package/src/wirings/gateway/index.ts +13 -0
  141. package/src/wirings/http/http-routes.ts +0 -1
  142. package/src/wirings/http/http-runner.ts +38 -10
  143. package/src/wirings/http/http.types.ts +3 -12
  144. package/src/wirings/http/index.ts +3 -0
  145. package/src/wirings/http/pikku-fetch-http-request.ts +4 -0
  146. package/src/wirings/http/pikku-fetch-http-response.ts +4 -4
  147. package/src/wirings/http/web-request.test.ts +236 -0
  148. package/src/wirings/http/web-request.ts +104 -0
  149. package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
  150. package/src/wirings/mcp/mcp-runner.ts +30 -12
  151. package/src/wirings/rpc/rpc-runner.ts +45 -24
  152. package/src/wirings/rpc/rpc-types.ts +6 -1
  153. package/src/wirings/rpc/wire-addon.ts +2 -1
  154. package/src/wirings/scheduler/scheduler-runner.ts +1 -0
  155. package/src/wirings/workflow/graph/graph-validation.test.ts +170 -0
  156. package/src/wirings/workflow/graph/graph-validation.ts +237 -0
  157. package/src/wirings/workflow/graph/index.ts +5 -0
  158. package/src/wirings/workflow/index.ts +1 -0
  159. package/src/wirings/workflow/pikku-workflow-service.ts +14 -3
  160. package/src/wirings/workflow/workflow.types.ts +9 -1
  161. package/tsconfig.tsbuildinfo +1 -1
  162. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +0 -5
  163. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +0 -146
  164. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +0 -363
  165. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +0 -214
@@ -1,8 +1,11 @@
1
1
  import { PikkuError } from '../../errors/error-handler.js';
2
- import { pikkuState, getSingletonServices, getCreateWireServices, } from '../../pikku-state.js';
3
- import { runPikkuFunc } from '../../function/function-runner.js';
2
+ import { pikkuState, getSingletonServices } from '../../pikku-state.js';
4
3
  import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js';
5
4
  import { randomUUID } from 'crypto';
5
+ import { streamAIAgent } from './ai-agent-stream.js';
6
+ import { runAIAgent } from './ai-agent-runner.js';
7
+ import { resolveNamespace, ContextAwareRPCService, } from '../../wirings/rpc/rpc-runner.js';
8
+ import { buildDynamicWorkflowInstructions, buildWorkflowTools } from './agent-dynamic-workflow.js';
6
9
  import { resolveMemoryServices, loadContextMessages, trimMessages, } from './ai-agent-memory.js';
7
10
  import { resolveModelConfig } from './ai-agent-model-config.js';
8
11
  export class ToolApprovalRequired extends PikkuError {
@@ -33,7 +36,7 @@ export const resolveAgent = (agentName) => {
33
36
  if (colonIndex !== -1) {
34
37
  const namespace = agentName.substring(0, colonIndex);
35
38
  const localName = agentName.substring(colonIndex + 1);
36
- const addons = pikkuState(null, 'rpc', 'addons');
39
+ const addons = pikkuState(null, 'addons', 'packages');
37
40
  const pkgConfig = addons.get(namespace);
38
41
  if (pkgConfig) {
39
42
  const extAgent = pikkuState(pkgConfig.package, 'agent', 'agents').get(localName);
@@ -48,41 +51,47 @@ export const resolveAgent = (agentName) => {
48
51
  }
49
52
  throw new Error(`AI agent not found: ${agentName}`);
50
53
  };
51
- export function buildInstructions(agentName, packageName) {
54
+ export async function buildInstructions(agentName, packageName) {
52
55
  const meta = pikkuState(packageName, 'agent', 'agentsMeta')[agentName];
53
- const instructions = meta?.instructions ?? '';
54
- const baseInstructions = Array.isArray(instructions)
55
- ? instructions.join('\n')
56
- : instructions;
57
- return meta?.agents?.length
58
- ? baseInstructions +
56
+ const rawInstructions = meta?.instructions ?? '';
57
+ let instructions = Array.isArray(rawInstructions)
58
+ ? rawInstructions.join('\n')
59
+ : rawInstructions;
60
+ if (meta?.agents?.length) {
61
+ instructions +=
59
62
  '\n\nWhen calling a sub-agent, provide a short session name that describes the task. ' +
60
- 'Use the same session name to continue a previous conversation with that agent. ' +
61
- 'Use a new session name for a new independent task.'
62
- : baseInstructions;
63
+ 'Use the same session name to continue a previous conversation with that agent. ' +
64
+ 'Use a new session name for a new independent task. ' +
65
+ 'When a request involves multiple actions for the same domain, combine them into a single sub-agent call rather than making separate calls.';
66
+ }
67
+ if (meta?.dynamicWorkflows && meta.tools?.length) {
68
+ instructions += buildDynamicWorkflowInstructions(meta.tools, meta.dynamicWorkflows);
69
+ }
70
+ return instructions;
63
71
  }
64
72
  export function createScopedChannel(parent, agentName, session) {
65
- let capturedApproval = null;
73
+ const capturedApprovals = [];
66
74
  return {
67
75
  channelId: `${parent.channelId}:${agentName}:${session}`,
68
76
  openingData: parent.openingData,
69
77
  get state() {
70
78
  return parent.state;
71
79
  },
72
- get approval() {
73
- return capturedApproval;
80
+ get approvals() {
81
+ return capturedApprovals;
74
82
  },
75
83
  close: () => { },
84
+ sendBinary: (data) => parent.sendBinary(data),
76
85
  send: (event) => {
77
86
  if (event.type === 'done')
78
87
  return;
79
88
  if (event.type === 'approval-request') {
80
- capturedApproval = {
89
+ capturedApprovals.push({
81
90
  toolCallId: event.toolCallId,
82
91
  toolName: event.toolName,
83
92
  args: event.args,
84
93
  runId: event.runId,
85
- };
94
+ });
86
95
  return;
87
96
  }
88
97
  if (event.type === 'step-start' ||
@@ -91,7 +100,8 @@ export function createScopedChannel(parent, agentName, session) {
91
100
  event.type === 'tool-call' ||
92
101
  event.type === 'tool-result' ||
93
102
  event.type === 'usage' ||
94
- event.type === 'error') {
103
+ event.type === 'error' ||
104
+ event.type === 'workflow-created') {
95
105
  parent.send({ ...event, agent: agentName, session });
96
106
  }
97
107
  else {
@@ -100,7 +110,7 @@ export function createScopedChannel(parent, agentName, session) {
100
110
  },
101
111
  };
102
112
  }
103
- export function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares) {
113
+ export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares, agentMode) {
104
114
  const singletonServices = getSingletonServices();
105
115
  const tools = [];
106
116
  const missingRpcs = [];
@@ -111,16 +121,34 @@ export function buildToolDefs(params, agentSessionMap, resourceId, agentName, pa
111
121
  const metaTools = meta.tools;
112
122
  const metaAgents = meta.agents;
113
123
  if (metaTools?.length) {
114
- const functionMeta = pikkuState(null, 'function', 'meta');
115
- const schemas = pikkuState(null, 'misc', 'schemas');
116
124
  for (const toolName of metaTools) {
117
- const rpcMeta = pikkuState(null, 'rpc', 'meta');
118
- const pikkuFuncId = rpcMeta[toolName];
119
- if (!pikkuFuncId) {
125
+ let fnMeta;
126
+ let resolvedPkg = null;
127
+ let schemas;
128
+ const resolved = toolName.includes(':')
129
+ ? resolveNamespace(toolName)
130
+ : null;
131
+ let pikkuFuncId;
132
+ if (resolved) {
133
+ resolvedPkg = resolved.package;
134
+ pikkuFuncId = resolved.function;
135
+ fnMeta = pikkuState(resolvedPkg, 'function', 'meta')[pikkuFuncId];
136
+ schemas = pikkuState(resolvedPkg, 'misc', 'schemas');
137
+ }
138
+ else {
139
+ const rpcMeta = pikkuState(null, 'rpc', 'meta');
140
+ pikkuFuncId = rpcMeta[toolName];
141
+ if (!pikkuFuncId) {
142
+ missingRpcs.push(toolName);
143
+ continue;
144
+ }
145
+ fnMeta = pikkuState(null, 'function', 'meta')[pikkuFuncId];
146
+ schemas = pikkuState(null, 'misc', 'schemas');
147
+ }
148
+ if (!fnMeta) {
120
149
  missingRpcs.push(toolName);
121
150
  continue;
122
151
  }
123
- const fnMeta = functionMeta[pikkuFuncId];
124
152
  const inputSchemaName = fnMeta?.inputSchemaName;
125
153
  let inputSchema = inputSchemaName
126
154
  ? schemas.get(inputSchemaName)
@@ -132,23 +160,38 @@ export function buildToolDefs(params, agentSessionMap, resourceId, agentName, pa
132
160
  inputSchema = { type: 'object', properties: {} };
133
161
  }
134
162
  const needsApproval = approvalPolicy === 'all' ||
135
- (approvalPolicy === 'explicit' && fnMeta?.requiresApproval);
163
+ (approvalPolicy === 'explicit' && fnMeta?.approvalRequired);
164
+ // Build approvalDescriptionFn if the function has an approvalDescription configured
165
+ let approvalDescriptionFn;
166
+ if (needsApproval && pikkuFuncId) {
167
+ const funcConfig = pikkuState(resolvedPkg, 'function', 'functions').get(pikkuFuncId);
168
+ if (funcConfig?.approvalDescription) {
169
+ const descFn = funcConfig.approvalDescription;
170
+ const capturedPkg = resolvedPkg;
171
+ approvalDescriptionFn = async (input) => {
172
+ let services = singletonServices;
173
+ if (capturedPkg) {
174
+ const pkgServices = pikkuState(capturedPkg, 'package', 'singletonServices');
175
+ if (pkgServices) {
176
+ services = pkgServices;
177
+ }
178
+ }
179
+ return descFn(services, input);
180
+ };
181
+ }
182
+ }
136
183
  tools.push({
137
- name: pikkuFuncId,
184
+ name: toolName.replaceAll(':', '__'),
138
185
  description: fnMeta?.description || fnMeta?.title || toolName,
139
186
  inputSchema,
140
187
  needsApproval: needsApproval || undefined,
188
+ approvalDescriptionFn,
141
189
  execute: async (toolInput) => {
142
190
  const wire = params.sessionService
143
191
  ? { ...createMiddlewareSessionWireProps(params.sessionService) }
144
192
  : {};
145
- return runPikkuFunc('agent', `tool:${pikkuFuncId}`, pikkuFuncId, {
146
- singletonServices,
147
- createWireServices: getCreateWireServices(),
148
- data: () => toolInput,
149
- wire,
150
- sessionService: params.sessionService,
151
- });
193
+ const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
194
+ return rpcService.rpc(toolName, toolInput);
152
195
  },
153
196
  });
154
197
  }
@@ -180,11 +223,14 @@ export function buildToolDefs(params, agentSessionMap, resourceId, agentName, pa
180
223
  const sessionKey = `${subAgentName}::${session}`;
181
224
  let threadId = agentSessionMap.get(sessionKey);
182
225
  if (!threadId) {
183
- threadId = `${subAgentName}-${session}-${Date.now()}`;
226
+ threadId = randomUUID();
184
227
  agentSessionMap.set(sessionKey, threadId);
185
228
  }
186
229
  if (streamContext) {
187
- const { streamAIAgent } = await import('./ai-agent-stream.js');
230
+ const isDelegate = agentMode !== 'supervise';
231
+ if (isDelegate && streamContext.delegateState) {
232
+ streamContext.delegateState.delegated = true;
233
+ }
188
234
  const { channel } = streamContext;
189
235
  channel.send({
190
236
  type: 'agent-call',
@@ -193,32 +239,48 @@ export function buildToolDefs(params, agentSessionMap, resourceId, agentName, pa
193
239
  input: message,
194
240
  });
195
241
  const subChannel = createScopedChannel(channel, subAgentName, session);
196
- await streamAIAgent(subAgentName, { message, threadId, resourceId }, subChannel, params, agentSessionMap, streamContext.options);
197
- if (subChannel.approval) {
242
+ // In supervise mode, suppress sub-agent text from reaching the client.
243
+ // Approvals still flow through normally.
244
+ const effectiveChannel = isDelegate
245
+ ? subChannel
246
+ : {
247
+ ...subChannel,
248
+ send: (event) => {
249
+ if (event.type === 'text-delta' ||
250
+ event.type === 'reasoning-delta')
251
+ return;
252
+ subChannel.send(event);
253
+ },
254
+ };
255
+ const resultText = await streamAIAgent(subAgentName, { message, threadId, resourceId }, effectiveChannel, params, agentSessionMap, streamContext.options);
256
+ if (subChannel.approvals.length > 0) {
198
257
  return {
199
258
  __approvalRequired: true,
200
259
  toolName: subAgentName,
201
260
  args: toolInput,
202
- displayToolName: subChannel.approval.toolName,
203
- displayArgs: subChannel.approval.args,
204
- agentRunId: subChannel.approval.runId,
261
+ agentRunId: subChannel.approvals[0].runId,
262
+ subApprovals: subChannel.approvals,
205
263
  };
206
264
  }
207
265
  channel.send({
208
266
  type: 'agent-result',
209
267
  agentName: subAgentName,
210
268
  session,
211
- result: null,
269
+ result: resultText,
212
270
  });
213
- return null;
271
+ return resultText;
214
272
  }
215
- const { runAIAgent } = await import('./ai-agent-runner.js');
273
+ // No stream context: sub-agent runs non-streaming
216
274
  const result = await runAIAgent(subAgentName, { message, threadId, resourceId }, params, agentSessionMap);
217
275
  return result.object ?? result.text;
218
276
  },
219
277
  });
220
278
  }
221
279
  }
280
+ if (meta.dynamicWorkflows) {
281
+ const workflowTools = buildWorkflowTools(agentName, packageName, meta.tools ?? [], meta.dynamicWorkflows, streamContext, params.sessionService);
282
+ tools.push(...workflowTools);
283
+ }
222
284
  const hasToolHooks = aiMiddlewares?.some((mw) => mw.beforeToolCall || mw.afterToolCall);
223
285
  if (hasToolHooks) {
224
286
  for (const tool of tools) {
@@ -279,6 +341,15 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
279
341
  if (!agentRunner) {
280
342
  throw new Error('AIAgentRunnerService not available in singletonServices');
281
343
  }
344
+ if (agent.dynamicWorkflows && singletonServices.workflowService) {
345
+ const persisted = await singletonServices.workflowService.getAIGeneratedWorkflows(resolvedName);
346
+ const allMeta = pikkuState(null, 'workflows', 'meta');
347
+ for (const wf of persisted) {
348
+ if (!allMeta[wf.workflowName]) {
349
+ allMeta[wf.workflowName] = wf.graph;
350
+ }
351
+ }
352
+ }
282
353
  const { storage } = resolveMemoryServices(agent, singletonServices);
283
354
  const memoryConfig = agent.memory;
284
355
  const threadId = input.threadId;
@@ -307,18 +378,40 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
307
378
  });
308
379
  }
309
380
  const contextMessages = await loadContextMessages(memoryConfig, storage, input, workingMemoryJsonSchema);
381
+ const userContent = input.attachments?.length
382
+ ? [
383
+ { type: 'text', text: input.message },
384
+ ...input.attachments.map((a) => ({
385
+ type: a.type,
386
+ data: a.data,
387
+ url: a.url,
388
+ mediaType: a.mediaType,
389
+ ...(a.filename ? { filename: a.filename } : {}),
390
+ })),
391
+ ]
392
+ : input.message;
310
393
  const userMessage = {
311
394
  id: randomUUID(),
312
395
  role: 'user',
313
- content: input.message,
396
+ content: userContent,
314
397
  createdAt: new Date(),
315
398
  };
316
399
  const allMessages = [...contextMessages, ...messages, userMessage];
317
400
  const trimmedMessages = trimMessages(allMessages);
318
401
  const aiMiddlewares = agent.aiMiddleware ?? [];
319
- const { tools, missingRpcs } = buildToolDefs(params, agentSessionMap, input.resourceId, resolvedName, packageName, streamContext, aiMiddlewares);
320
- const instructions = buildInstructions(resolvedName, packageName);
402
+ const { tools, missingRpcs } = await buildToolDefs(params, agentSessionMap, input.resourceId, resolvedName, packageName, streamContext, aiMiddlewares, agent.agentMode);
403
+ const instructions = await buildInstructions(resolvedName, packageName);
321
404
  const resolved = resolveModelConfig(resolvedName, agent);
405
+ // Per-request overrides
406
+ if (input.model) {
407
+ resolved.model = resolveModelConfig(resolvedName, {
408
+ ...agent,
409
+ model: input.model,
410
+ }).model;
411
+ }
412
+ if (input.temperature !== undefined) {
413
+ resolved.temperature = input.temperature;
414
+ }
322
415
  const maxSteps = resolved.maxSteps ?? 10;
323
416
  const runnerParams = {
324
417
  model: resolved.model,
@@ -1,3 +1,7 @@
1
1
  import type { AIAgentInput, AIAgentOutput } from './ai-agent.types.js';
2
2
  import { type RunAIAgentParams } from './ai-agent-prepare.js';
3
3
  export declare function runAIAgent(agentName: string, input: AIAgentInput, params: RunAIAgentParams, agentSessionMap?: Map<string, string>): Promise<AIAgentOutput>;
4
+ export declare function resumeAIAgentSync(runId: string, approvals: {
5
+ toolCallId: string;
6
+ approved: boolean;
7
+ }[], params: RunAIAgentParams, expectedAgentName?: string): Promise<AIAgentOutput>;