@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.
- package/CHANGELOG.md +34 -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/middleware-runner.js +1 -0
- package/dist/permissions.js +1 -0
- package/dist/pikku-state.js +7 -1
- package/dist/schema.js +1 -1
- package/dist/services/gateway-service.d.ts +19 -0
- package/dist/services/gateway-service.js +1 -0
- package/dist/services/in-memory-workflow-service.d.ts +8 -2
- package/dist/services/in-memory-workflow-service.js +28 -1
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.js +1 -0
- package/dist/services/local-gateway-service.d.ts +22 -0
- package/dist/services/local-gateway-service.js +51 -0
- 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 +12 -2
- package/dist/types/state.types.d.ts +9 -2
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +23 -0
- package/dist/utils.js +1 -1
- 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 +19 -7
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -7
- package/dist/wirings/ai-agent/ai-agent-prepare.js +141 -48
- 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 +126 -48
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +57 -3
- package/dist/wirings/ai-agent/index.d.ts +2 -3
- package/dist/wirings/ai-agent/index.js +1 -2
- package/dist/wirings/channel/channel-handler.d.ts +5 -2
- package/dist/wirings/channel/channel-handler.js +16 -2
- package/dist/wirings/channel/channel-middleware-runner.js +1 -0
- package/dist/wirings/channel/channel.types.d.ts +7 -7
- package/dist/wirings/channel/index.d.ts +1 -1
- package/dist/wirings/channel/local/local-channel-handler.d.ts +8 -1
- package/dist/wirings/channel/local/local-channel-handler.js +22 -3
- package/dist/wirings/channel/local/local-channel-runner.js +28 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +2 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +5 -2
- package/dist/wirings/cli/cli-runner.js +13 -2
- package/dist/wirings/cli/cli.types.d.ts +1 -0
- package/dist/wirings/gateway/gateway-runner.d.ts +24 -0
- package/dist/wirings/gateway/gateway-runner.js +325 -0
- package/dist/wirings/gateway/gateway.types.d.ts +127 -0
- package/dist/wirings/gateway/gateway.types.js +1 -0
- package/dist/wirings/gateway/index.d.ts +2 -0
- package/dist/wirings/gateway/index.js +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 +28 -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 +6 -3
- 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/middleware-runner.ts +1 -0
- package/src/permissions.ts +1 -0
- package/src/pikku-state.ts +8 -1
- package/src/schema.ts +1 -1
- package/src/services/gateway-service.ts +20 -0
- package/src/services/in-memory-workflow-service.ts +45 -2
- package/src/services/index.ts +2 -0
- package/src/services/local-gateway-service.ts +62 -0
- 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 +12 -1
- package/src/types/state.types.ts +12 -2
- package/src/utils/hash.test.ts +68 -0
- package/src/utils/hash.ts +26 -0
- package/src/utils.ts +1 -1
- package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +17 -7
- package/src/wirings/ai-agent/ai-agent-prepare.ts +194 -62
- 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 +195 -91
- package/src/wirings/ai-agent/ai-agent.types.ts +57 -3
- package/src/wirings/ai-agent/index.ts +3 -5
- package/src/wirings/channel/channel-handler.ts +41 -4
- package/src/wirings/channel/channel-middleware-runner.ts +1 -0
- package/src/wirings/channel/channel.types.ts +12 -7
- package/src/wirings/channel/index.ts +1 -0
- package/src/wirings/channel/local/local-channel-handler.ts +31 -3
- package/src/wirings/channel/local/local-channel-runner.ts +32 -8
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +2 -0
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +8 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +5 -2
- package/src/wirings/cli/cli-runner.ts +15 -2
- package/src/wirings/cli/cli.types.ts +1 -0
- package/src/wirings/gateway/gateway-runner.test.ts +474 -0
- package/src/wirings/gateway/gateway-runner.ts +411 -0
- package/src/wirings/gateway/gateway.types.ts +149 -0
- package/src/wirings/gateway/index.ts +13 -0
- package/src/wirings/http/http-routes.ts +0 -1
- package/src/wirings/http/http-runner.ts +38 -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 -146
- package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +0 -363
- package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +0 -214
|
@@ -39,10 +39,6 @@ import {
|
|
|
39
39
|
type StreamAIAgentOptions,
|
|
40
40
|
type StreamContext,
|
|
41
41
|
} from './ai-agent-prepare.js'
|
|
42
|
-
import {
|
|
43
|
-
createAssistantUIChannel,
|
|
44
|
-
parseAssistantUIInput,
|
|
45
|
-
} from './ai-agent-assistant-ui.js'
|
|
46
42
|
import { resolveModelConfig } from './ai-agent-model-config.js'
|
|
47
43
|
import type { AIRunStateService } from '../../services/ai-run-state-service.js'
|
|
48
44
|
import type { AIAgentRunnerService } from '../../services/ai-agent-runner-service.js'
|
|
@@ -114,6 +110,7 @@ function createPersistingChannel(
|
|
|
114
110
|
},
|
|
115
111
|
flush: flushStep,
|
|
116
112
|
close: () => parent.close(),
|
|
113
|
+
sendBinary: (data) => parent.sendBinary(data),
|
|
117
114
|
send: (event: AIStreamEvent) => {
|
|
118
115
|
if (storage) {
|
|
119
116
|
switch (event.type) {
|
|
@@ -237,7 +234,7 @@ type StepLoopParams = {
|
|
|
237
234
|
|
|
238
235
|
type StepLoopResult =
|
|
239
236
|
| { outcome: 'done' }
|
|
240
|
-
| { outcome: 'approval';
|
|
237
|
+
| { outcome: 'approval'; approvals: ToolApprovalRequired[] }
|
|
241
238
|
|
|
242
239
|
async function runStreamStepLoop(
|
|
243
240
|
params: StepLoopParams
|
|
@@ -290,13 +287,26 @@ async function runStreamStepLoop(
|
|
|
290
287
|
|
|
291
288
|
if (stepResult.toolCalls.length === 0) break
|
|
292
289
|
|
|
293
|
-
const
|
|
290
|
+
const approvalsNeeded = checkForApprovals(
|
|
294
291
|
stepResult,
|
|
295
292
|
runnerParams.tools,
|
|
296
293
|
runId
|
|
297
294
|
)
|
|
298
|
-
if (
|
|
299
|
-
|
|
295
|
+
if (approvalsNeeded.length > 0) {
|
|
296
|
+
// For each approval, call approvalDescriptionFn if available
|
|
297
|
+
for (const approval of approvalsNeeded) {
|
|
298
|
+
const toolDef = runnerParams.tools.find(
|
|
299
|
+
(t) => t.name === approval.toolName
|
|
300
|
+
)
|
|
301
|
+
if (toolDef?.approvalDescriptionFn && !approval.reason) {
|
|
302
|
+
try {
|
|
303
|
+
approval.reason = await toolDef.approvalDescriptionFn(approval.args)
|
|
304
|
+
} catch {
|
|
305
|
+
// If description generation fails, continue without it
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return { outcome: 'approval', approvals: approvalsNeeded }
|
|
300
310
|
}
|
|
301
311
|
|
|
302
312
|
appendStepMessages(runnerParams, stepResult)
|
|
@@ -305,16 +315,20 @@ async function runStreamStepLoop(
|
|
|
305
315
|
return { outcome: 'done' }
|
|
306
316
|
}
|
|
307
317
|
|
|
308
|
-
function
|
|
318
|
+
export function checkForApprovals(
|
|
309
319
|
stepResult: AIAgentStepResult,
|
|
310
320
|
tools: AIAgentRunnerParams['tools'],
|
|
311
321
|
runId: string
|
|
312
|
-
): ToolApprovalRequired
|
|
322
|
+
): ToolApprovalRequired[] {
|
|
323
|
+
const approvals: ToolApprovalRequired[] = []
|
|
313
324
|
for (const tc of stepResult.toolCalls) {
|
|
314
325
|
const toolDef = tools.find((t) => t.name === tc.toolName)
|
|
315
326
|
|
|
316
327
|
if (toolDef?.needsApproval) {
|
|
317
|
-
|
|
328
|
+
approvals.push(
|
|
329
|
+
new ToolApprovalRequired(tc.toolCallId, tc.toolName, tc.args)
|
|
330
|
+
)
|
|
331
|
+
continue
|
|
318
332
|
}
|
|
319
333
|
|
|
320
334
|
const tr = stepResult.toolResults.find(
|
|
@@ -332,22 +346,46 @@ function checkForApproval(
|
|
|
332
346
|
displayToolName?: string
|
|
333
347
|
displayArgs?: unknown
|
|
334
348
|
agentRunId?: string
|
|
349
|
+
subApprovals?: Array<{
|
|
350
|
+
toolCallId: string
|
|
351
|
+
toolName: string
|
|
352
|
+
args: unknown
|
|
353
|
+
runId: string
|
|
354
|
+
}>
|
|
355
|
+
}
|
|
356
|
+
if (r.subApprovals?.length) {
|
|
357
|
+
for (const sub of r.subApprovals) {
|
|
358
|
+
approvals.push(
|
|
359
|
+
new ToolApprovalRequired(
|
|
360
|
+
sub.toolCallId,
|
|
361
|
+
r.toolName,
|
|
362
|
+
r.args,
|
|
363
|
+
undefined,
|
|
364
|
+
sub.toolName,
|
|
365
|
+
sub.args,
|
|
366
|
+
r.agentRunId
|
|
367
|
+
)
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
approvals.push(
|
|
372
|
+
new ToolApprovalRequired(
|
|
373
|
+
tc.toolCallId,
|
|
374
|
+
r.toolName,
|
|
375
|
+
r.args,
|
|
376
|
+
r.reason,
|
|
377
|
+
r.displayToolName,
|
|
378
|
+
r.displayArgs,
|
|
379
|
+
r.agentRunId
|
|
380
|
+
)
|
|
381
|
+
)
|
|
335
382
|
}
|
|
336
|
-
return new ToolApprovalRequired(
|
|
337
|
-
tc.toolCallId,
|
|
338
|
-
r.toolName,
|
|
339
|
-
r.args,
|
|
340
|
-
r.reason,
|
|
341
|
-
r.displayToolName,
|
|
342
|
-
r.displayArgs,
|
|
343
|
-
r.agentRunId
|
|
344
|
-
)
|
|
345
383
|
}
|
|
346
384
|
}
|
|
347
|
-
return
|
|
385
|
+
return approvals
|
|
348
386
|
}
|
|
349
387
|
|
|
350
|
-
function appendStepMessages(
|
|
388
|
+
export function appendStepMessages(
|
|
351
389
|
runnerParams: AIAgentRunnerParams,
|
|
352
390
|
stepResult: AIAgentStepResult
|
|
353
391
|
): void {
|
|
@@ -383,8 +421,8 @@ function appendStepMessages(
|
|
|
383
421
|
}
|
|
384
422
|
}
|
|
385
423
|
|
|
386
|
-
function
|
|
387
|
-
|
|
424
|
+
function handleApprovals(
|
|
425
|
+
approvals: ToolApprovalRequired[],
|
|
388
426
|
runId: string,
|
|
389
427
|
channel: AIStreamChannel,
|
|
390
428
|
aiRunState: AIRunStateService,
|
|
@@ -393,37 +431,41 @@ function handleApproval(
|
|
|
393
431
|
return (async () => {
|
|
394
432
|
await persistingChannel.flush()
|
|
395
433
|
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
434
|
+
const pendingApprovals = approvals.map((err) =>
|
|
435
|
+
err.agentRunId
|
|
436
|
+
? {
|
|
437
|
+
type: 'agent-call' as const,
|
|
438
|
+
toolCallId: err.toolCallId,
|
|
439
|
+
agentName: err.toolName,
|
|
440
|
+
agentRunId: err.agentRunId,
|
|
441
|
+
displayToolName: err.displayToolName ?? err.toolName,
|
|
442
|
+
displayArgs: err.displayArgs ?? err.args,
|
|
443
|
+
}
|
|
444
|
+
: {
|
|
445
|
+
type: 'tool-call' as const,
|
|
446
|
+
toolCallId: err.toolCallId,
|
|
447
|
+
toolName: err.toolName,
|
|
448
|
+
args: err.args,
|
|
449
|
+
}
|
|
450
|
+
)
|
|
411
451
|
|
|
412
452
|
await aiRunState.updateRun(runId, {
|
|
413
453
|
status: 'suspended',
|
|
414
454
|
suspendReason: 'approval',
|
|
415
|
-
pendingApprovals
|
|
455
|
+
pendingApprovals,
|
|
416
456
|
})
|
|
417
457
|
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
458
|
+
for (const err of approvals) {
|
|
459
|
+
const approvalEvent = {
|
|
460
|
+
type: 'approval-request' as const,
|
|
461
|
+
toolCallId: err.toolCallId,
|
|
462
|
+
toolName: err.displayToolName ?? err.toolName,
|
|
463
|
+
args: err.displayArgs ?? err.args,
|
|
464
|
+
reason: err.reason,
|
|
465
|
+
runId,
|
|
466
|
+
}
|
|
467
|
+
channel.send(approvalEvent as any)
|
|
425
468
|
}
|
|
426
|
-
channel.send(approvalEvent as any)
|
|
427
469
|
channel.send({ type: 'done' })
|
|
428
470
|
channel.close()
|
|
429
471
|
})()
|
|
@@ -431,34 +473,24 @@ function handleApproval(
|
|
|
431
473
|
|
|
432
474
|
export async function streamAIAgent(
|
|
433
475
|
agentName: string,
|
|
434
|
-
input:
|
|
435
|
-
|
|
436
|
-
|
|
476
|
+
input: {
|
|
477
|
+
message: string
|
|
478
|
+
threadId: string
|
|
479
|
+
resourceId: string
|
|
480
|
+
model?: string
|
|
481
|
+
temperature?: number
|
|
482
|
+
},
|
|
437
483
|
channel: AIStreamChannel,
|
|
438
484
|
params: RunAIAgentParams,
|
|
439
485
|
agentSessionMap?: Map<string, string>,
|
|
440
486
|
options?: StreamAIAgentOptions
|
|
441
|
-
): Promise<
|
|
487
|
+
): Promise<string> {
|
|
442
488
|
const sessionMap = agentSessionMap ?? new Map<string, string>()
|
|
443
489
|
|
|
444
|
-
const
|
|
445
|
-
const inputRecord = input as Record<string, unknown>
|
|
446
|
-
const useUIMessageStream =
|
|
447
|
-
resolvedAgentForProtocol.protocol === 'ui-message-stream' ||
|
|
448
|
-
Array.isArray(inputRecord.messages)
|
|
449
|
-
let normalizedInput: { message: string; threadId: string; resourceId: string }
|
|
450
|
-
if (useUIMessageStream) {
|
|
451
|
-
normalizedInput = parseAssistantUIInput(inputRecord)
|
|
452
|
-
channel = createAssistantUIChannel(channel)
|
|
453
|
-
} else {
|
|
454
|
-
normalizedInput = input as {
|
|
455
|
-
message: string
|
|
456
|
-
threadId: string
|
|
457
|
-
resourceId: string
|
|
458
|
-
}
|
|
459
|
-
}
|
|
490
|
+
const normalizedInput = input
|
|
460
491
|
|
|
461
492
|
const streamContext: StreamContext = { channel, options }
|
|
493
|
+
// delegateState is attached after prepareAgentRun resolves the agent config
|
|
462
494
|
|
|
463
495
|
const {
|
|
464
496
|
agent,
|
|
@@ -501,7 +533,7 @@ export async function streamAIAgent(
|
|
|
501
533
|
})
|
|
502
534
|
channel.send({ type: 'suspended', reason: 'rpc-missing', missingRpcs })
|
|
503
535
|
channel.send({ type: 'done' })
|
|
504
|
-
return
|
|
536
|
+
return ''
|
|
505
537
|
}
|
|
506
538
|
|
|
507
539
|
const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
|
|
@@ -547,7 +579,12 @@ export async function streamAIAgent(
|
|
|
547
579
|
allEvents,
|
|
548
580
|
state,
|
|
549
581
|
})
|
|
550
|
-
if (result
|
|
582
|
+
if (result == null) return
|
|
583
|
+
if (Array.isArray(result)) {
|
|
584
|
+
for (const r of result) await next(r)
|
|
585
|
+
} else {
|
|
586
|
+
await next(result)
|
|
587
|
+
}
|
|
551
588
|
}
|
|
552
589
|
})
|
|
553
590
|
|
|
@@ -574,8 +611,32 @@ export async function streamAIAgent(
|
|
|
574
611
|
).channel as AIStreamChannel)
|
|
575
612
|
: channel
|
|
576
613
|
|
|
614
|
+
// In delegate mode (default), suppress parent's text from reaching the client
|
|
615
|
+
// AFTER a sub-agent has been called. If the parent responds directly (no delegation),
|
|
616
|
+
// its text goes through normally. Sub-agent text bypasses this path entirely
|
|
617
|
+
// (goes through subChannel → channel directly).
|
|
618
|
+
const isDelegateMode = agent.agentMode !== 'supervise' && meta.agents?.length
|
|
619
|
+
const delegateState = { delegated: false }
|
|
620
|
+
if (isDelegateMode) {
|
|
621
|
+
streamContext.delegateState = delegateState
|
|
622
|
+
}
|
|
623
|
+
const outputChannel = isDelegateMode
|
|
624
|
+
? {
|
|
625
|
+
...wrappedChannel,
|
|
626
|
+
send: (event: AIStreamEvent) => {
|
|
627
|
+
if (
|
|
628
|
+
delegateState.delegated &&
|
|
629
|
+
(event.type === 'text-delta' || event.type === 'reasoning-delta')
|
|
630
|
+
)
|
|
631
|
+
return
|
|
632
|
+
wrappedChannel.send(event)
|
|
633
|
+
},
|
|
634
|
+
delegateState,
|
|
635
|
+
}
|
|
636
|
+
: wrappedChannel
|
|
637
|
+
|
|
577
638
|
const persistingChannel = createPersistingChannel(
|
|
578
|
-
|
|
639
|
+
outputChannel,
|
|
579
640
|
storage,
|
|
580
641
|
threadId
|
|
581
642
|
)
|
|
@@ -593,14 +654,14 @@ export async function streamAIAgent(
|
|
|
593
654
|
})
|
|
594
655
|
|
|
595
656
|
if (loopResult.outcome === 'approval') {
|
|
596
|
-
await
|
|
597
|
-
loopResult.
|
|
657
|
+
await handleApprovals(
|
|
658
|
+
loopResult.approvals,
|
|
598
659
|
runId,
|
|
599
660
|
channel,
|
|
600
661
|
aiRunState,
|
|
601
662
|
persistingChannel
|
|
602
663
|
)
|
|
603
|
-
return
|
|
664
|
+
return persistingChannel.fullText
|
|
604
665
|
}
|
|
605
666
|
|
|
606
667
|
await postStreamCleanup(
|
|
@@ -618,6 +679,7 @@ export async function streamAIAgent(
|
|
|
618
679
|
|
|
619
680
|
channel.send({ type: 'done' })
|
|
620
681
|
channel.close()
|
|
682
|
+
return persistingChannel.fullText
|
|
621
683
|
} catch (err) {
|
|
622
684
|
for (const mw of aiMiddlewares) {
|
|
623
685
|
if (mw.onError) {
|
|
@@ -632,13 +694,17 @@ export async function streamAIAgent(
|
|
|
632
694
|
}
|
|
633
695
|
}
|
|
634
696
|
}
|
|
635
|
-
await aiRunState.updateRun(runId, {
|
|
697
|
+
await aiRunState.updateRun(runId, {
|
|
698
|
+
status: 'failed',
|
|
699
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
700
|
+
})
|
|
636
701
|
channel.send({
|
|
637
702
|
type: 'error',
|
|
638
703
|
message: err instanceof Error ? err.message : String(err),
|
|
639
704
|
})
|
|
640
705
|
channel.send({ type: 'done' })
|
|
641
706
|
channel.close()
|
|
707
|
+
return persistingChannel.fullText
|
|
642
708
|
}
|
|
643
709
|
}
|
|
644
710
|
|
|
@@ -690,7 +756,8 @@ export async function resumeAIAgent(
|
|
|
690
756
|
await aiRunState.updateRun(pending.agentRunId, { status: 'failed' })
|
|
691
757
|
}
|
|
692
758
|
|
|
693
|
-
const denialResult =
|
|
759
|
+
const denialResult =
|
|
760
|
+
'The user explicitly declined this action. Inform them that it was declined and do not retry.'
|
|
694
761
|
|
|
695
762
|
if (storage) {
|
|
696
763
|
await storage.saveMessages(run.threadId, [
|
|
@@ -712,6 +779,17 @@ export async function resumeAIAgent(
|
|
|
712
779
|
])
|
|
713
780
|
}
|
|
714
781
|
|
|
782
|
+
// Check remaining pending approvals
|
|
783
|
+
const updatedRun = await aiRunState.getRun(run.runId)
|
|
784
|
+
const remaining = updatedRun?.pendingApprovals ?? []
|
|
785
|
+
|
|
786
|
+
if (remaining.length > 0) {
|
|
787
|
+
// Still waiting for more approvals - don't continue step loop
|
|
788
|
+
channel.send({ type: 'done' })
|
|
789
|
+
channel.close()
|
|
790
|
+
return
|
|
791
|
+
}
|
|
792
|
+
|
|
715
793
|
await aiRunState.updateRun(run.runId, { status: 'running' })
|
|
716
794
|
|
|
717
795
|
await continueAfterToolResult(
|
|
@@ -735,7 +813,9 @@ export async function resumeAIAgent(
|
|
|
735
813
|
if (!subRun) {
|
|
736
814
|
throw new Error(`Sub-agent run not found: ${pending.agentRunId}`)
|
|
737
815
|
}
|
|
738
|
-
const subPending =
|
|
816
|
+
const subPending =
|
|
817
|
+
subRun.pendingApprovals?.find((p) => p.toolCallId === input.toolCallId) ??
|
|
818
|
+
subRun.pendingApprovals?.[0]
|
|
739
819
|
if (!subPending) {
|
|
740
820
|
throw new Error(
|
|
741
821
|
`No pending approval on sub-agent run ${pending.agentRunId}`
|
|
@@ -791,7 +871,7 @@ export async function resumeAIAgent(
|
|
|
791
871
|
}
|
|
792
872
|
const aiMiddlewaresForResume: PikkuAIMiddlewareHooks[] =
|
|
793
873
|
agent.aiMiddleware ?? []
|
|
794
|
-
const { tools } = buildToolDefs(
|
|
874
|
+
const { tools } = await buildToolDefs(
|
|
795
875
|
params,
|
|
796
876
|
new Map<string, string>(),
|
|
797
877
|
run.resourceId,
|
|
@@ -812,10 +892,12 @@ export async function resumeAIAgent(
|
|
|
812
892
|
typeof pending.args === 'string' ? JSON.parse(pending.args) : pending.args
|
|
813
893
|
|
|
814
894
|
let toolResult: unknown
|
|
895
|
+
let isError = false
|
|
815
896
|
try {
|
|
816
897
|
toolResult = await matchingTool.execute(toolArgs)
|
|
817
898
|
} catch (execErr) {
|
|
818
899
|
toolResult = `Error: ${execErr instanceof Error ? execErr.message : String(execErr)}`
|
|
900
|
+
isError = true
|
|
819
901
|
}
|
|
820
902
|
|
|
821
903
|
const resultStr =
|
|
@@ -842,9 +924,21 @@ export async function resumeAIAgent(
|
|
|
842
924
|
toolCallId: input.toolCallId,
|
|
843
925
|
toolName: pending.toolName,
|
|
844
926
|
result: toolResult,
|
|
927
|
+
...(isError ? { isError: true } : {}),
|
|
845
928
|
})
|
|
846
929
|
}
|
|
847
930
|
|
|
931
|
+
// Check remaining pending approvals after processing this one
|
|
932
|
+
const updatedRun = await aiRunState.getRun(run.runId)
|
|
933
|
+
const remaining = updatedRun?.pendingApprovals ?? []
|
|
934
|
+
|
|
935
|
+
if (remaining.length > 0) {
|
|
936
|
+
// Still waiting for more approvals - don't continue step loop
|
|
937
|
+
channel.send({ type: 'done' })
|
|
938
|
+
channel.close()
|
|
939
|
+
return
|
|
940
|
+
}
|
|
941
|
+
|
|
848
942
|
await aiRunState.updateRun(run.runId, { status: 'running' })
|
|
849
943
|
|
|
850
944
|
await continueAfterToolResult(
|
|
@@ -900,7 +994,7 @@ async function continueAfterToolResult(
|
|
|
900
994
|
const allMessages = [...contextMessages, ...messages]
|
|
901
995
|
const trimmedMessages = trimMessages(allMessages)
|
|
902
996
|
|
|
903
|
-
const instructions = buildInstructions(resolvedName, packageName)
|
|
997
|
+
const instructions = await buildInstructions(resolvedName, packageName)
|
|
904
998
|
|
|
905
999
|
const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
|
|
906
1000
|
let modifiedMessages = trimmedMessages
|
|
@@ -928,7 +1022,12 @@ async function continueAfterToolResult(
|
|
|
928
1022
|
allEvents,
|
|
929
1023
|
state,
|
|
930
1024
|
})
|
|
931
|
-
if (result
|
|
1025
|
+
if (result == null) return
|
|
1026
|
+
if (Array.isArray(result)) {
|
|
1027
|
+
for (const r of result) await next(r)
|
|
1028
|
+
} else {
|
|
1029
|
+
await next(result)
|
|
1030
|
+
}
|
|
932
1031
|
}
|
|
933
1032
|
})
|
|
934
1033
|
|
|
@@ -960,14 +1059,16 @@ async function continueAfterToolResult(
|
|
|
960
1059
|
)
|
|
961
1060
|
|
|
962
1061
|
const streamContext: StreamContext = { channel, options }
|
|
963
|
-
const resumeTools =
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1062
|
+
const resumeTools = (
|
|
1063
|
+
await buildToolDefs(
|
|
1064
|
+
params,
|
|
1065
|
+
new Map<string, string>(),
|
|
1066
|
+
run.resourceId,
|
|
1067
|
+
resolvedName,
|
|
1068
|
+
packageName,
|
|
1069
|
+
streamContext,
|
|
1070
|
+
aiMiddlewares
|
|
1071
|
+
)
|
|
971
1072
|
).tools
|
|
972
1073
|
|
|
973
1074
|
const resolved = resolveModelConfig(resolvedName, agent)
|
|
@@ -999,8 +1100,8 @@ async function continueAfterToolResult(
|
|
|
999
1100
|
})
|
|
1000
1101
|
|
|
1001
1102
|
if (loopResult.outcome === 'approval') {
|
|
1002
|
-
await
|
|
1003
|
-
loopResult.
|
|
1103
|
+
await handleApprovals(
|
|
1104
|
+
loopResult.approvals,
|
|
1004
1105
|
run.runId,
|
|
1005
1106
|
channel,
|
|
1006
1107
|
aiRunState,
|
|
@@ -1038,7 +1139,10 @@ async function continueAfterToolResult(
|
|
|
1038
1139
|
}
|
|
1039
1140
|
}
|
|
1040
1141
|
}
|
|
1041
|
-
await aiRunState.updateRun(run.runId, {
|
|
1142
|
+
await aiRunState.updateRun(run.runId, {
|
|
1143
|
+
status: 'failed',
|
|
1144
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
1145
|
+
})
|
|
1042
1146
|
channel.send({
|
|
1043
1147
|
type: 'error',
|
|
1044
1148
|
message: err instanceof Error ? err.message : String(err),
|
|
@@ -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,21 @@ 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[]
|
|
72
|
+
model?: string
|
|
73
|
+
temperature?: number
|
|
52
74
|
}
|
|
53
75
|
|
|
54
76
|
export interface AIAgentOutput {
|
|
@@ -58,6 +80,14 @@ export interface AIAgentOutput {
|
|
|
58
80
|
threadId: string
|
|
59
81
|
steps: AIAgentStep[]
|
|
60
82
|
usage: { inputTokens: number; outputTokens: number }
|
|
83
|
+
status?: 'completed' | 'suspended'
|
|
84
|
+
pendingApprovals?: Array<{
|
|
85
|
+
toolCallId: string
|
|
86
|
+
toolName: string
|
|
87
|
+
args: unknown
|
|
88
|
+
reason?: string
|
|
89
|
+
runId: string
|
|
90
|
+
}>
|
|
61
91
|
}
|
|
62
92
|
|
|
63
93
|
export interface AIAgentToolDef {
|
|
@@ -66,6 +96,7 @@ export interface AIAgentToolDef {
|
|
|
66
96
|
inputSchema: Record<string, unknown>
|
|
67
97
|
execute: (input: unknown) => Promise<unknown>
|
|
68
98
|
needsApproval?: boolean
|
|
99
|
+
approvalDescriptionFn?: (input: unknown) => Promise<string>
|
|
69
100
|
}
|
|
70
101
|
|
|
71
102
|
export interface PikkuAIMiddlewareHooks<
|
|
@@ -86,7 +117,11 @@ export interface PikkuAIMiddlewareHooks<
|
|
|
86
117
|
allEvents: readonly AIStreamEvent[]
|
|
87
118
|
state: State
|
|
88
119
|
}
|
|
89
|
-
) =>
|
|
120
|
+
) =>
|
|
121
|
+
| Promise<AIStreamEvent | AIStreamEvent[] | null>
|
|
122
|
+
| AIStreamEvent
|
|
123
|
+
| AIStreamEvent[]
|
|
124
|
+
| null
|
|
90
125
|
|
|
91
126
|
modifyOutput?: (
|
|
92
127
|
services: Services,
|
|
@@ -165,13 +200,14 @@ export type CoreAIAgent<
|
|
|
165
200
|
temperature?: number
|
|
166
201
|
tools?: unknown[]
|
|
167
202
|
agents?: unknown[]
|
|
203
|
+
agentMode?: 'delegate' | 'supervise'
|
|
168
204
|
memory?: AIAgentMemoryConfig
|
|
169
205
|
maxSteps?: number
|
|
170
206
|
toolChoice?: 'auto' | 'required' | 'none'
|
|
207
|
+
dynamicWorkflows?: 'read' | 'always' | 'ask'
|
|
171
208
|
input?: unknown
|
|
172
209
|
output?: unknown
|
|
173
210
|
tags?: string[]
|
|
174
|
-
protocol?: 'ui-message-stream'
|
|
175
211
|
prepareStep?: (ctx: {
|
|
176
212
|
stepNumber: number
|
|
177
213
|
messages: AIMessage[]
|
|
@@ -235,6 +271,21 @@ export type AIStreamEvent =
|
|
|
235
271
|
session?: string
|
|
236
272
|
}
|
|
237
273
|
| { type: 'error'; message: string; agent?: string; session?: string }
|
|
274
|
+
| {
|
|
275
|
+
type: 'audio-delta'
|
|
276
|
+
data: string
|
|
277
|
+
format: string
|
|
278
|
+
agent?: string
|
|
279
|
+
session?: string
|
|
280
|
+
}
|
|
281
|
+
| { type: 'audio-done'; agent?: string; session?: string }
|
|
282
|
+
| {
|
|
283
|
+
type: 'workflow-created'
|
|
284
|
+
workflowName: string
|
|
285
|
+
graph: any
|
|
286
|
+
agent?: string
|
|
287
|
+
session?: string
|
|
288
|
+
}
|
|
238
289
|
| {
|
|
239
290
|
type: 'suspended'
|
|
240
291
|
reason: 'rpc-missing'
|
|
@@ -266,6 +317,7 @@ export interface AgentRunState {
|
|
|
266
317
|
threadId: string
|
|
267
318
|
resourceId: string
|
|
268
319
|
status: 'running' | 'suspended' | 'completed' | 'failed'
|
|
320
|
+
errorMessage?: string
|
|
269
321
|
suspendReason?: 'approval' | 'rpc-missing'
|
|
270
322
|
missingRpcs?: string[]
|
|
271
323
|
pendingApprovals?: PendingApproval[]
|
|
@@ -280,6 +332,7 @@ export interface AgentRunRow {
|
|
|
280
332
|
threadId: string
|
|
281
333
|
resourceId: string
|
|
282
334
|
status: string
|
|
335
|
+
errorMessage?: string
|
|
283
336
|
suspendReason?: string
|
|
284
337
|
missingRpcs?: string[]
|
|
285
338
|
usageInputTokens: number
|
|
@@ -324,5 +377,6 @@ export type AIAgentMeta = Record<
|
|
|
324
377
|
channelMiddleware?: MiddlewareMetadata[]
|
|
325
378
|
aiMiddleware?: MiddlewareMetadata[]
|
|
326
379
|
permissions?: PermissionMetadata[]
|
|
380
|
+
dynamicWorkflows?: 'read' | 'always' | 'ask'
|
|
327
381
|
}
|
|
328
382
|
>
|
|
@@ -4,12 +4,8 @@ export {
|
|
|
4
4
|
agentResume,
|
|
5
5
|
agentApprove,
|
|
6
6
|
} from './ai-agent-helpers.js'
|
|
7
|
-
export { runAIAgent } from './ai-agent-runner.js'
|
|
7
|
+
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js'
|
|
8
8
|
export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js'
|
|
9
|
-
export {
|
|
10
|
-
createAssistantUIChannel,
|
|
11
|
-
parseAssistantUIInput,
|
|
12
|
-
} from './ai-agent-assistant-ui.js'
|
|
13
9
|
export {
|
|
14
10
|
type RunAIAgentParams,
|
|
15
11
|
type StreamAIAgentOptions,
|
|
@@ -23,9 +19,11 @@ export {
|
|
|
23
19
|
} from './ai-agent-registry.js'
|
|
24
20
|
export type {
|
|
25
21
|
AIAgentInput,
|
|
22
|
+
AIAgentInputAttachment,
|
|
26
23
|
AIAgentMeta,
|
|
27
24
|
AIAgentMemoryConfig,
|
|
28
25
|
AIAgentStep,
|
|
26
|
+
AIContentPart,
|
|
29
27
|
AgentRunRow,
|
|
30
28
|
AgentRunService,
|
|
31
29
|
AgentRunState,
|