@pikku/core 0.12.2 → 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.
- package/CHANGELOG.md +18 -0
- package/dist/crypto-utils.d.ts +10 -0
- package/dist/crypto-utils.js +62 -0
- package/dist/function/function-runner.js +4 -4
- package/dist/function/functions.types.d.ts +26 -1
- package/dist/function/functions.types.js +16 -0
- package/dist/handle-error.d.ts +1 -1
- package/dist/handle-error.js +7 -3
- package/dist/index.d.ts +14 -2
- package/dist/index.js +1 -1
- package/dist/pikku-state.js +3 -1
- package/dist/schema.js +1 -1
- package/dist/services/in-memory-workflow-service.d.ts +8 -2
- package/dist/services/in-memory-workflow-service.js +28 -1
- package/dist/services/workflow-service.d.ts +8 -2
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/service-tests.d.ts +31 -0
- package/dist/testing/service-tests.js +598 -0
- package/dist/types/core.types.d.ts +9 -1
- package/dist/types/state.types.d.ts +4 -2
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +23 -0
- package/dist/wirings/ai-agent/agent-dynamic-workflow.d.ts +6 -0
- package/dist/wirings/ai-agent/agent-dynamic-workflow.js +348 -0
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +1 -1
- package/dist/wirings/ai-agent/ai-agent-memory.js +6 -5
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -7
- package/dist/wirings/ai-agent/ai-agent-prepare.js +127 -47
- package/dist/wirings/ai-agent/ai-agent-runner.d.ts +4 -0
- package/dist/wirings/ai-agent/ai-agent-runner.js +381 -27
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +7 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +109 -46
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +22 -1
- package/dist/wirings/ai-agent/index.d.ts +1 -2
- package/dist/wirings/ai-agent/index.js +1 -2
- package/dist/wirings/channel/channel-handler.js +5 -1
- package/dist/wirings/channel/channel.types.d.ts +1 -7
- package/dist/wirings/channel/local/local-channel-handler.d.ts +1 -1
- package/dist/wirings/channel/local/local-channel-handler.js +5 -3
- package/dist/wirings/channel/local/local-channel-runner.js +14 -4
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -1
- package/dist/wirings/cli/cli-runner.js +10 -2
- package/dist/wirings/cli/cli.types.d.ts +1 -0
- package/dist/wirings/http/http-routes.js +0 -1
- package/dist/wirings/http/http-runner.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +25 -3
- package/dist/wirings/http/http.types.d.ts +3 -11
- package/dist/wirings/http/index.d.ts +2 -1
- package/dist/wirings/http/index.js +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -0
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.js +4 -4
- package/dist/wirings/http/web-request.d.ts +12 -0
- package/dist/wirings/http/web-request.js +85 -0
- package/dist/wirings/mcp/mcp-endpoint-registry.js +1 -1
- package/dist/wirings/mcp/mcp-runner.js +13 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +30 -6
- package/dist/wirings/rpc/rpc-runner.js +36 -14
- package/dist/wirings/rpc/rpc-types.d.ts +6 -1
- package/dist/wirings/rpc/wire-addon.d.ts +1 -0
- package/dist/wirings/rpc/wire-addon.js +1 -1
- package/dist/wirings/scheduler/scheduler-runner.js +1 -0
- package/dist/wirings/workflow/graph/graph-validation.d.ts +3 -0
- package/dist/wirings/workflow/graph/graph-validation.js +175 -0
- package/dist/wirings/workflow/graph/index.d.ts +1 -0
- package/dist/wirings/workflow/graph/index.js +1 -0
- package/dist/wirings/workflow/index.d.ts +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +8 -2
- package/dist/wirings/workflow/pikku-workflow-service.js +1 -2
- package/dist/wirings/workflow/workflow.types.d.ts +10 -1
- package/package.json +4 -2
- package/src/crypto-utils.test.ts +99 -1
- package/src/crypto-utils.ts +114 -0
- package/src/function/function-runner.ts +5 -5
- package/src/function/functions.types.ts +38 -1
- package/src/handle-error.test.ts +65 -2
- package/src/handle-error.ts +8 -4
- package/src/index.ts +14 -0
- package/src/pikku-state.ts +3 -1
- package/src/schema.ts +1 -1
- package/src/services/in-memory-workflow-service.ts +45 -2
- package/src/services/workflow-service.ts +12 -1
- package/src/testing/index.ts +2 -0
- package/src/testing/service-tests.ts +873 -0
- package/src/types/core.types.ts +9 -1
- package/src/types/state.types.ts +4 -2
- package/src/utils/hash.test.ts +68 -0
- package/src/utils/hash.ts +26 -0
- package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +7 -6
- package/src/wirings/ai-agent/ai-agent-prepare.ts +175 -61
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +3 -1
- package/src/wirings/ai-agent/ai-agent-runner.ts +553 -31
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +209 -2
- package/src/wirings/ai-agent/ai-agent-stream.ts +182 -89
- package/src/wirings/ai-agent/ai-agent.types.ts +23 -1
- package/src/wirings/ai-agent/index.ts +1 -5
- package/src/wirings/channel/channel-handler.ts +11 -2
- package/src/wirings/channel/channel.types.ts +1 -7
- package/src/wirings/channel/local/local-channel-handler.ts +5 -3
- package/src/wirings/channel/local/local-channel-runner.ts +17 -7
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +4 -1
- package/src/wirings/cli/cli-runner.ts +12 -2
- package/src/wirings/cli/cli.types.ts +1 -0
- package/src/wirings/http/http-routes.ts +0 -1
- package/src/wirings/http/http-runner.ts +35 -10
- package/src/wirings/http/http.types.ts +3 -12
- package/src/wirings/http/index.ts +3 -0
- package/src/wirings/http/pikku-fetch-http-request.ts +4 -0
- package/src/wirings/http/pikku-fetch-http-response.ts +4 -4
- package/src/wirings/http/web-request.test.ts +236 -0
- package/src/wirings/http/web-request.ts +104 -0
- package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +30 -12
- package/src/wirings/rpc/rpc-runner.ts +45 -24
- package/src/wirings/rpc/rpc-types.ts +6 -1
- package/src/wirings/rpc/wire-addon.ts +2 -1
- package/src/wirings/scheduler/scheduler-runner.ts +1 -0
- package/src/wirings/workflow/graph/graph-validation.test.ts +170 -0
- package/src/wirings/workflow/graph/graph-validation.ts +237 -0
- package/src/wirings/workflow/graph/index.ts +5 -0
- package/src/wirings/workflow/index.ts +1 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +14 -3
- package/src/wirings/workflow/workflow.types.ts +9 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +0 -5
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +0 -168
- package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +0 -363
- package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +0 -238
|
@@ -11,16 +11,17 @@ import type {
|
|
|
11
11
|
} from './ai-agent.types.js'
|
|
12
12
|
import type { AIAgentRunnerParams } from '../../services/ai-agent-runner-service.js'
|
|
13
13
|
import { PikkuError } from '../../errors/error-handler.js'
|
|
14
|
-
import {
|
|
15
|
-
pikkuState,
|
|
16
|
-
getSingletonServices,
|
|
17
|
-
getCreateWireServices,
|
|
18
|
-
} from '../../pikku-state.js'
|
|
19
|
-
import { runPikkuFunc } from '../../function/function-runner.js'
|
|
14
|
+
import { pikkuState, getSingletonServices } from '../../pikku-state.js'
|
|
20
15
|
import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js'
|
|
21
16
|
import type { SessionService } from '../../services/user-session-service.js'
|
|
22
17
|
import { randomUUID } from 'crypto'
|
|
23
|
-
|
|
18
|
+
import { streamAIAgent } from './ai-agent-stream.js'
|
|
19
|
+
import { runAIAgent } from './ai-agent-runner.js'
|
|
20
|
+
import {
|
|
21
|
+
resolveNamespace,
|
|
22
|
+
ContextAwareRPCService,
|
|
23
|
+
} from '../../wirings/rpc/rpc-runner.js'
|
|
24
|
+
import { buildDynamicWorkflowInstructions, buildWorkflowTools } from './agent-dynamic-workflow.js'
|
|
24
25
|
import {
|
|
25
26
|
resolveMemoryServices,
|
|
26
27
|
loadContextMessages,
|
|
@@ -40,7 +41,7 @@ export class ToolApprovalRequired extends PikkuError {
|
|
|
40
41
|
public readonly toolCallId: string
|
|
41
42
|
public readonly toolName: string
|
|
42
43
|
public readonly args: unknown
|
|
43
|
-
public
|
|
44
|
+
public reason?: string
|
|
44
45
|
public readonly displayToolName?: string
|
|
45
46
|
public readonly displayArgs?: unknown
|
|
46
47
|
public readonly agentRunId?: string
|
|
@@ -68,6 +69,7 @@ export class ToolApprovalRequired extends PikkuError {
|
|
|
68
69
|
export type StreamContext = {
|
|
69
70
|
channel: AIStreamChannel
|
|
70
71
|
options?: StreamAIAgentOptions
|
|
72
|
+
delegateState?: { delegated: boolean }
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
export const resolveAgent = (
|
|
@@ -82,7 +84,7 @@ export const resolveAgent = (
|
|
|
82
84
|
if (colonIndex !== -1) {
|
|
83
85
|
const namespace = agentName.substring(0, colonIndex)
|
|
84
86
|
const localName = agentName.substring(colonIndex + 1)
|
|
85
|
-
const addons = pikkuState(null, '
|
|
87
|
+
const addons = pikkuState(null, 'addons', 'packages')
|
|
86
88
|
const pkgConfig = addons.get(namespace)
|
|
87
89
|
if (pkgConfig) {
|
|
88
90
|
const extAgent = pikkuState(pkgConfig.package, 'agent', 'agents').get(
|
|
@@ -101,31 +103,38 @@ export const resolveAgent = (
|
|
|
101
103
|
throw new Error(`AI agent not found: ${agentName}`)
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
export function buildInstructions(
|
|
106
|
+
export async function buildInstructions(
|
|
105
107
|
agentName: string,
|
|
106
108
|
packageName: string | null
|
|
107
|
-
): string {
|
|
109
|
+
): Promise<string> {
|
|
108
110
|
const meta = pikkuState(packageName, 'agent', 'agentsMeta')[agentName]
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
?
|
|
112
|
-
:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
const rawInstructions = meta?.instructions ?? ''
|
|
112
|
+
let instructions = Array.isArray(rawInstructions)
|
|
113
|
+
? rawInstructions.join('\n')
|
|
114
|
+
: rawInstructions
|
|
115
|
+
|
|
116
|
+
if (meta?.agents?.length) {
|
|
117
|
+
instructions +=
|
|
118
|
+
'\n\nWhen calling a sub-agent, provide a short session name that describes the task. ' +
|
|
119
|
+
'Use the same session name to continue a previous conversation with that agent. ' +
|
|
120
|
+
'Use a new session name for a new independent task. ' +
|
|
121
|
+
'When a request involves multiple actions for the same domain, combine them into a single sub-agent call rather than making separate calls.'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (meta?.dynamicWorkflows && meta.tools?.length) {
|
|
125
|
+
instructions += buildDynamicWorkflowInstructions(meta.tools, meta.dynamicWorkflows)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return instructions
|
|
120
129
|
}
|
|
121
130
|
|
|
122
131
|
export type ScopedChannel = AIStreamChannel & {
|
|
123
|
-
|
|
132
|
+
approvals: Array<{
|
|
124
133
|
toolCallId: string
|
|
125
134
|
toolName: string
|
|
126
135
|
args: unknown
|
|
127
136
|
runId: string
|
|
128
|
-
}
|
|
137
|
+
}>
|
|
129
138
|
}
|
|
130
139
|
|
|
131
140
|
export function createScopedChannel(
|
|
@@ -133,7 +142,7 @@ export function createScopedChannel(
|
|
|
133
142
|
agentName: string,
|
|
134
143
|
session: string
|
|
135
144
|
): ScopedChannel {
|
|
136
|
-
|
|
145
|
+
const capturedApprovals: ScopedChannel['approvals'] = []
|
|
137
146
|
|
|
138
147
|
return {
|
|
139
148
|
channelId: `${parent.channelId}:${agentName}:${session}`,
|
|
@@ -141,20 +150,20 @@ export function createScopedChannel(
|
|
|
141
150
|
get state() {
|
|
142
151
|
return parent.state
|
|
143
152
|
},
|
|
144
|
-
get
|
|
145
|
-
return
|
|
153
|
+
get approvals() {
|
|
154
|
+
return capturedApprovals
|
|
146
155
|
},
|
|
147
156
|
close: () => {},
|
|
148
157
|
sendBinary: (data) => parent.sendBinary(data),
|
|
149
158
|
send: (event: AIStreamEvent) => {
|
|
150
159
|
if (event.type === 'done') return
|
|
151
160
|
if (event.type === 'approval-request') {
|
|
152
|
-
|
|
161
|
+
capturedApprovals.push({
|
|
153
162
|
toolCallId: event.toolCallId,
|
|
154
163
|
toolName: event.toolName,
|
|
155
164
|
args: event.args,
|
|
156
165
|
runId: (event as any).runId,
|
|
157
|
-
}
|
|
166
|
+
})
|
|
158
167
|
return
|
|
159
168
|
}
|
|
160
169
|
if (
|
|
@@ -164,7 +173,8 @@ export function createScopedChannel(
|
|
|
164
173
|
event.type === 'tool-call' ||
|
|
165
174
|
event.type === 'tool-result' ||
|
|
166
175
|
event.type === 'usage' ||
|
|
167
|
-
event.type === 'error'
|
|
176
|
+
event.type === 'error' ||
|
|
177
|
+
event.type === 'workflow-created'
|
|
168
178
|
) {
|
|
169
179
|
parent.send({ ...event, agent: agentName, session } as AIStreamEvent)
|
|
170
180
|
} else {
|
|
@@ -174,15 +184,16 @@ export function createScopedChannel(
|
|
|
174
184
|
}
|
|
175
185
|
}
|
|
176
186
|
|
|
177
|
-
export function buildToolDefs(
|
|
187
|
+
export async function buildToolDefs(
|
|
178
188
|
params: RunAIAgentParams,
|
|
179
189
|
agentSessionMap: Map<string, string>,
|
|
180
190
|
resourceId: string,
|
|
181
191
|
agentName: string,
|
|
182
192
|
packageName: string | null,
|
|
183
193
|
streamContext?: StreamContext,
|
|
184
|
-
aiMiddlewares?: PikkuAIMiddlewareHooks[]
|
|
185
|
-
|
|
194
|
+
aiMiddlewares?: PikkuAIMiddlewareHooks[],
|
|
195
|
+
agentMode?: 'delegate' | 'supervise'
|
|
196
|
+
): Promise<{ tools: AIAgentToolDef[]; missingRpcs: string[] }> {
|
|
186
197
|
const singletonServices = getSingletonServices()
|
|
187
198
|
const tools: AIAgentToolDef[] = []
|
|
188
199
|
const missingRpcs: string[] = []
|
|
@@ -196,18 +207,38 @@ export function buildToolDefs(
|
|
|
196
207
|
const metaAgents = meta.agents
|
|
197
208
|
|
|
198
209
|
if (metaTools?.length) {
|
|
199
|
-
const functionMeta = pikkuState(null, 'function', 'meta')
|
|
200
|
-
const schemas = pikkuState(null, 'misc', 'schemas')
|
|
201
|
-
|
|
202
210
|
for (const toolName of metaTools) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
211
|
+
let fnMeta: any
|
|
212
|
+
let resolvedPkg: string | null = null
|
|
213
|
+
let schemas: Map<string, any>
|
|
214
|
+
|
|
215
|
+
const resolved = toolName.includes(':')
|
|
216
|
+
? resolveNamespace(toolName)
|
|
217
|
+
: null
|
|
218
|
+
|
|
219
|
+
let pikkuFuncId: string | undefined
|
|
220
|
+
|
|
221
|
+
if (resolved) {
|
|
222
|
+
resolvedPkg = resolved.package
|
|
223
|
+
pikkuFuncId = resolved.function
|
|
224
|
+
fnMeta = pikkuState(resolvedPkg, 'function', 'meta')[pikkuFuncId]
|
|
225
|
+
schemas = pikkuState(resolvedPkg, 'misc', 'schemas')
|
|
226
|
+
} else {
|
|
227
|
+
const rpcMeta = pikkuState(null, 'rpc', 'meta')
|
|
228
|
+
pikkuFuncId = rpcMeta[toolName]
|
|
229
|
+
if (!pikkuFuncId) {
|
|
230
|
+
missingRpcs.push(toolName)
|
|
231
|
+
continue
|
|
232
|
+
}
|
|
233
|
+
fnMeta = pikkuState(null, 'function', 'meta')[pikkuFuncId]
|
|
234
|
+
schemas = pikkuState(null, 'misc', 'schemas')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (!fnMeta) {
|
|
206
238
|
missingRpcs.push(toolName)
|
|
207
239
|
continue
|
|
208
240
|
}
|
|
209
241
|
|
|
210
|
-
const fnMeta = functionMeta[pikkuFuncId]
|
|
211
242
|
const inputSchemaName = fnMeta?.inputSchemaName
|
|
212
243
|
let inputSchema = inputSchemaName
|
|
213
244
|
? schemas.get(inputSchemaName)
|
|
@@ -223,24 +254,52 @@ export function buildToolDefs(
|
|
|
223
254
|
|
|
224
255
|
const needsApproval =
|
|
225
256
|
approvalPolicy === 'all' ||
|
|
226
|
-
(approvalPolicy === 'explicit' && fnMeta?.
|
|
257
|
+
(approvalPolicy === 'explicit' && fnMeta?.approvalRequired)
|
|
258
|
+
|
|
259
|
+
// Build approvalDescriptionFn if the function has an approvalDescription configured
|
|
260
|
+
let approvalDescriptionFn:
|
|
261
|
+
| ((input: unknown) => Promise<string>)
|
|
262
|
+
| undefined
|
|
263
|
+
if (needsApproval && pikkuFuncId) {
|
|
264
|
+
const funcConfig = pikkuState(resolvedPkg, 'function', 'functions').get(
|
|
265
|
+
pikkuFuncId
|
|
266
|
+
)
|
|
267
|
+
if (funcConfig?.approvalDescription) {
|
|
268
|
+
const descFn = funcConfig.approvalDescription
|
|
269
|
+
const capturedPkg = resolvedPkg
|
|
270
|
+
approvalDescriptionFn = async (input: unknown) => {
|
|
271
|
+
let services = singletonServices
|
|
272
|
+
if (capturedPkg) {
|
|
273
|
+
const pkgServices = pikkuState(
|
|
274
|
+
capturedPkg,
|
|
275
|
+
'package',
|
|
276
|
+
'singletonServices'
|
|
277
|
+
)
|
|
278
|
+
if (pkgServices) {
|
|
279
|
+
services = pkgServices
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return descFn(services, input)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
227
286
|
|
|
228
287
|
tools.push({
|
|
229
|
-
name:
|
|
288
|
+
name: toolName.replaceAll(':', '__'),
|
|
230
289
|
description: fnMeta?.description || fnMeta?.title || toolName,
|
|
231
290
|
inputSchema,
|
|
232
291
|
needsApproval: needsApproval || undefined,
|
|
292
|
+
approvalDescriptionFn,
|
|
233
293
|
execute: async (toolInput: unknown) => {
|
|
234
294
|
const wire: PikkuWire = params.sessionService
|
|
235
295
|
? { ...createMiddlewareSessionWireProps(params.sessionService) }
|
|
236
296
|
: {}
|
|
237
|
-
|
|
297
|
+
const rpcService = new ContextAwareRPCService(
|
|
238
298
|
singletonServices,
|
|
239
|
-
createWireServices: getCreateWireServices(),
|
|
240
|
-
data: () => toolInput,
|
|
241
299
|
wire,
|
|
242
|
-
sessionService: params.sessionService
|
|
243
|
-
|
|
300
|
+
{ sessionService: params.sessionService }
|
|
301
|
+
)
|
|
302
|
+
return rpcService.rpc(toolName, toolInput)
|
|
244
303
|
},
|
|
245
304
|
})
|
|
246
305
|
}
|
|
@@ -280,12 +339,15 @@ export function buildToolDefs(
|
|
|
280
339
|
const sessionKey = `${subAgentName}::${session}`
|
|
281
340
|
let threadId = agentSessionMap.get(sessionKey)
|
|
282
341
|
if (!threadId) {
|
|
283
|
-
threadId =
|
|
342
|
+
threadId = randomUUID()
|
|
284
343
|
agentSessionMap.set(sessionKey, threadId)
|
|
285
344
|
}
|
|
286
345
|
|
|
287
346
|
if (streamContext) {
|
|
288
|
-
const
|
|
347
|
+
const isDelegate = agentMode !== 'supervise'
|
|
348
|
+
if (isDelegate && streamContext.delegateState) {
|
|
349
|
+
streamContext.delegateState.delegated = true
|
|
350
|
+
}
|
|
289
351
|
const { channel } = streamContext
|
|
290
352
|
channel.send({
|
|
291
353
|
type: 'agent-call',
|
|
@@ -298,34 +360,48 @@ export function buildToolDefs(
|
|
|
298
360
|
subAgentName,
|
|
299
361
|
session
|
|
300
362
|
)
|
|
301
|
-
|
|
363
|
+
// In supervise mode, suppress sub-agent text from reaching the client.
|
|
364
|
+
// Approvals still flow through normally.
|
|
365
|
+
const effectiveChannel = isDelegate
|
|
366
|
+
? subChannel
|
|
367
|
+
: {
|
|
368
|
+
...subChannel,
|
|
369
|
+
send: (event: AIStreamEvent) => {
|
|
370
|
+
if (
|
|
371
|
+
event.type === 'text-delta' ||
|
|
372
|
+
event.type === 'reasoning-delta'
|
|
373
|
+
)
|
|
374
|
+
return
|
|
375
|
+
subChannel.send(event)
|
|
376
|
+
},
|
|
377
|
+
}
|
|
378
|
+
const resultText = await streamAIAgent(
|
|
302
379
|
subAgentName,
|
|
303
380
|
{ message, threadId, resourceId },
|
|
304
|
-
|
|
381
|
+
effectiveChannel,
|
|
305
382
|
params,
|
|
306
383
|
agentSessionMap,
|
|
307
384
|
streamContext.options
|
|
308
385
|
)
|
|
309
|
-
if (subChannel.
|
|
386
|
+
if (subChannel.approvals.length > 0) {
|
|
310
387
|
return {
|
|
311
388
|
__approvalRequired: true,
|
|
312
389
|
toolName: subAgentName,
|
|
313
390
|
args: toolInput,
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
agentRunId: subChannel.approval.runId,
|
|
391
|
+
agentRunId: subChannel.approvals[0].runId,
|
|
392
|
+
subApprovals: subChannel.approvals,
|
|
317
393
|
}
|
|
318
394
|
}
|
|
319
395
|
channel.send({
|
|
320
396
|
type: 'agent-result',
|
|
321
397
|
agentName: subAgentName,
|
|
322
398
|
session,
|
|
323
|
-
result:
|
|
399
|
+
result: resultText,
|
|
324
400
|
})
|
|
325
|
-
return
|
|
401
|
+
return resultText
|
|
326
402
|
}
|
|
327
403
|
|
|
328
|
-
|
|
404
|
+
// No stream context: sub-agent runs non-streaming
|
|
329
405
|
const result = await runAIAgent(
|
|
330
406
|
subAgentName,
|
|
331
407
|
{ message, threadId, resourceId },
|
|
@@ -338,6 +414,18 @@ export function buildToolDefs(
|
|
|
338
414
|
}
|
|
339
415
|
}
|
|
340
416
|
|
|
417
|
+
if (meta.dynamicWorkflows) {
|
|
418
|
+
const workflowTools = buildWorkflowTools(
|
|
419
|
+
agentName,
|
|
420
|
+
packageName,
|
|
421
|
+
meta.tools ?? [],
|
|
422
|
+
meta.dynamicWorkflows,
|
|
423
|
+
streamContext,
|
|
424
|
+
params.sessionService
|
|
425
|
+
)
|
|
426
|
+
tools.push(...workflowTools)
|
|
427
|
+
}
|
|
428
|
+
|
|
341
429
|
const hasToolHooks = aiMiddlewares?.some(
|
|
342
430
|
(mw) => mw.beforeToolCall || mw.afterToolCall
|
|
343
431
|
)
|
|
@@ -412,6 +500,19 @@ export async function prepareAgentRun(
|
|
|
412
500
|
throw new Error('AIAgentRunnerService not available in singletonServices')
|
|
413
501
|
}
|
|
414
502
|
|
|
503
|
+
if (agent.dynamicWorkflows && singletonServices.workflowService) {
|
|
504
|
+
const persisted =
|
|
505
|
+
await singletonServices.workflowService.getAIGeneratedWorkflows(
|
|
506
|
+
resolvedName
|
|
507
|
+
)
|
|
508
|
+
const allMeta = pikkuState(null, 'workflows', 'meta')
|
|
509
|
+
for (const wf of persisted) {
|
|
510
|
+
if (!allMeta[wf.workflowName]) {
|
|
511
|
+
allMeta[wf.workflowName] = wf.graph
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
415
516
|
const { storage } = resolveMemoryServices(agent, singletonServices)
|
|
416
517
|
const memoryConfig = agent.memory
|
|
417
518
|
const threadId = input.threadId
|
|
@@ -478,19 +579,32 @@ export async function prepareAgentRun(
|
|
|
478
579
|
|
|
479
580
|
const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
|
|
480
581
|
|
|
481
|
-
const { tools, missingRpcs } = buildToolDefs(
|
|
582
|
+
const { tools, missingRpcs } = await buildToolDefs(
|
|
482
583
|
params,
|
|
483
584
|
agentSessionMap,
|
|
484
585
|
input.resourceId,
|
|
485
586
|
resolvedName,
|
|
486
587
|
packageName,
|
|
487
588
|
streamContext,
|
|
488
|
-
aiMiddlewares
|
|
589
|
+
aiMiddlewares,
|
|
590
|
+
agent.agentMode
|
|
489
591
|
)
|
|
490
592
|
|
|
491
|
-
const instructions = buildInstructions(resolvedName, packageName)
|
|
593
|
+
const instructions = await buildInstructions(resolvedName, packageName)
|
|
492
594
|
|
|
493
595
|
const resolved = resolveModelConfig(resolvedName, agent)
|
|
596
|
+
|
|
597
|
+
// Per-request overrides
|
|
598
|
+
if (input.model) {
|
|
599
|
+
resolved.model = resolveModelConfig(resolvedName, {
|
|
600
|
+
...agent,
|
|
601
|
+
model: input.model,
|
|
602
|
+
}).model
|
|
603
|
+
}
|
|
604
|
+
if (input.temperature !== undefined) {
|
|
605
|
+
resolved.temperature = input.temperature
|
|
606
|
+
}
|
|
607
|
+
|
|
494
608
|
const maxSteps = resolved.maxSteps ?? 10
|
|
495
609
|
|
|
496
610
|
const runnerParams: AIAgentRunnerParams = {
|
|
@@ -84,7 +84,9 @@ describe('runAIAgent', () => {
|
|
|
84
84
|
expectedError
|
|
85
85
|
)
|
|
86
86
|
|
|
87
|
-
assert.deepEqual(updates, [
|
|
87
|
+
assert.deepEqual(updates, [
|
|
88
|
+
{ status: 'failed', errorMessage: 'runner failed' },
|
|
89
|
+
])
|
|
88
90
|
})
|
|
89
91
|
|
|
90
92
|
test('loops through multiple steps and accumulates usage', async () => {
|