@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.
- package/CHANGELOG.md +24 -0
- package/dist/errors/errors.d.ts +6 -0
- package/dist/errors/errors.js +10 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/function/function-runner.d.ts +3 -3
- package/dist/function/function-runner.js +66 -44
- package/dist/function/functions.types.d.ts +1 -0
- package/dist/handle-error.d.ts +2 -2
- package/dist/handle-error.js +2 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -1
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +2 -0
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.d.ts +2 -2
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/cors.d.ts +2 -2
- package/dist/middleware/cors.js +45 -37
- package/dist/middleware-runner.d.ts +1 -1
- package/dist/permissions.d.ts +2 -2
- package/dist/pikku-state.d.ts +9 -8
- package/dist/pikku-state.js +30 -17
- package/dist/schema.d.ts +4 -4
- package/dist/schema.js +9 -5
- package/dist/services/ai-agent-runner-service.d.ts +22 -3
- package/dist/services/ai-run-state-service.d.ts +1 -1
- package/dist/services/ai-storage-service.d.ts +1 -1
- package/dist/services/content-service.d.ts +6 -0
- package/dist/services/gopass-secrets.d.ts +1 -1
- package/dist/services/gopass-secrets.js +3 -0
- package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
- package/dist/services/in-memory-ai-run-state-service.js +44 -0
- package/dist/services/in-memory-trigger-service.d.ts +0 -1
- package/dist/services/in-memory-trigger-service.js +6 -8
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +1 -0
- package/dist/services/local-content.d.ts +2 -1
- package/dist/services/local-content.js +6 -1
- package/dist/services/local-secrets.d.ts +2 -2
- package/dist/services/local-variables.d.ts +1 -1
- package/dist/services/logger-console.d.ts +2 -1
- package/dist/services/scheduler-service.d.ts +0 -12
- package/dist/services/scheduler-service.js +0 -6
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/trigger-service.d.ts +0 -7
- package/dist/services/user-session-service.d.ts +3 -3
- package/dist/services/workflow-service.d.ts +2 -3
- package/dist/types/core.types.d.ts +24 -18
- package/dist/types/state.types.d.ts +17 -15
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +12 -9
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
- package/dist/wirings/ai-agent/ai-agent-prepare.js +66 -30
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +1 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +107 -8
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +246 -87
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +61 -2
- package/dist/wirings/ai-agent/index.d.ts +3 -1
- package/dist/wirings/ai-agent/index.js +2 -0
- package/dist/wirings/channel/channel-common.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.d.ts +3 -3
- package/dist/wirings/channel/channel-handler.js +4 -4
- package/dist/wirings/channel/channel-runner.d.ts +5 -5
- package/dist/wirings/channel/channel-runner.js +3 -2
- package/dist/wirings/channel/channel-store.d.ts +1 -1
- package/dist/wirings/channel/channel.types.d.ts +4 -6
- package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
- package/dist/wirings/channel/local/local-channel-runner.js +4 -3
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
- package/dist/wirings/channel/log-channels.d.ts +1 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +25 -19
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +2 -2
- package/dist/wirings/cli/cli.types.d.ts +3 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -1
- package/dist/wirings/http/http-runner.d.ts +9 -9
- package/dist/wirings/http/http-runner.js +33 -14
- package/dist/wirings/http/http.types.d.ts +2 -6
- package/dist/wirings/http/log-http-routes.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
- package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
- package/dist/wirings/http/routers/http-router.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +0 -3
- package/dist/wirings/mcp/mcp-runner.js +4 -2
- package/dist/wirings/mcp/mcp.types.d.ts +2 -2
- package/dist/wirings/oauth2/oauth2-client.d.ts +3 -3
- package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +1 -1
- package/dist/wirings/queue/index.d.ts +1 -1
- package/dist/wirings/queue/index.js +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +1 -12
- package/dist/wirings/queue/queue-runner.js +4 -12
- package/dist/wirings/queue/queue.types.d.ts +3 -9
- package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
- package/dist/wirings/queue/register-queue-helper.js +1 -1
- package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +2 -0
- package/dist/wirings/rpc/index.js +1 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +36 -14
- package/dist/wirings/rpc/rpc-runner.js +56 -28
- package/dist/wirings/rpc/rpc-types.d.ts +14 -2
- package/dist/wirings/rpc/wire-addon.d.ts +10 -0
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/scheduler/index.js +1 -1
- package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -10
- package/dist/wirings/scheduler/scheduler-runner.js +4 -25
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +2 -6
- package/dist/wirings/trigger/pikku-trigger-service.js +11 -16
- package/dist/wirings/trigger/trigger-runner.d.ts +1 -5
- package/dist/wirings/trigger/trigger-runner.js +4 -3
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +20 -29
- package/dist/wirings/workflow/workflow.types.d.ts +2 -2
- package/package.json +2 -1
- package/src/crypto-utils.test.ts +116 -0
- package/src/errors/error.test.ts +143 -2
- package/src/errors/errors.ts +10 -0
- package/src/errors/index.ts +1 -0
- package/src/function/function-runner.test.ts +2 -2
- package/src/function/function-runner.ts +72 -49
- package/src/function/functions.types.ts +1 -0
- package/src/handle-error.test.ts +361 -0
- package/src/handle-error.ts +4 -4
- package/src/index.ts +3 -10
- package/src/internal.ts +6 -0
- package/src/middleware/auth-apikey.test.ts +1 -1
- package/src/middleware/auth-bearer.test.ts +1 -1
- package/src/middleware/auth-bearer.ts +2 -5
- package/src/middleware/auth-cookie.test.ts +1 -1
- package/src/middleware/auth-cookie.ts +3 -5
- package/src/middleware/cors.test.ts +424 -0
- package/src/middleware/cors.ts +14 -6
- package/src/middleware/remote-auth.test.ts +488 -0
- package/src/middleware-runner.test.ts +1 -1
- package/src/middleware-runner.ts +1 -1
- package/src/permissions.test.ts +2 -2
- package/src/permissions.ts +2 -2
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +40 -28
- package/src/schema.test.ts +198 -6
- package/src/schema.ts +11 -7
- package/src/services/ai-agent-runner-service.ts +15 -3
- package/src/services/ai-run-state-service.ts +1 -1
- package/src/services/ai-storage-service.ts +1 -1
- package/src/services/content-service.ts +7 -0
- package/src/services/gopass-secrets.ts +4 -1
- package/src/services/in-memory-ai-run-state-service.ts +73 -0
- package/src/services/in-memory-trigger-service.ts +6 -10
- package/src/services/in-memory-workflow-service.test.ts +351 -0
- package/src/services/index.ts +2 -1
- package/src/services/local-content.ts +9 -3
- package/src/services/local-secrets.test.ts +80 -0
- package/src/services/local-secrets.ts +2 -2
- package/src/services/local-variables.test.ts +61 -0
- package/src/services/local-variables.ts +1 -1
- package/src/services/logger-console.test.ts +118 -0
- package/src/services/logger-console.ts +2 -1
- package/src/services/scheduler-service.ts +0 -18
- package/src/services/scoped-secret-service.test.ts +74 -0
- package/src/services/scoped-secret-service.ts +1 -1
- package/src/services/trigger-service.ts +0 -21
- package/src/services/typed-secret-service.test.ts +93 -0
- package/src/services/typed-variables-service.test.ts +73 -0
- package/src/services/user-session-service.test.ts +113 -0
- package/src/services/user-session-service.ts +3 -3
- package/src/services/workflow-service.ts +2 -12
- package/src/time-utils.test.ts +1 -1
- package/src/types/core.types.ts +25 -19
- package/src/types/state.types.ts +24 -15
- package/src/utils.test.ts +350 -0
- package/src/utils.ts +14 -13
- package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
- package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
- package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
- package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +79 -45
- package/src/wirings/ai-agent/ai-agent-registry.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +245 -3
- package/src/wirings/ai-agent/ai-agent-runner.ts +121 -7
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +430 -24
- package/src/wirings/ai-agent/ai-agent-stream.ts +377 -102
- package/src/wirings/ai-agent/ai-agent.types.ts +57 -2
- package/src/wirings/ai-agent/index.ts +11 -0
- package/src/wirings/channel/channel-common.ts +2 -2
- package/src/wirings/channel/channel-handler.ts +13 -9
- package/src/wirings/channel/channel-runner.ts +6 -6
- package/src/wirings/channel/channel-store.ts +1 -1
- package/src/wirings/channel/channel.types.ts +4 -8
- package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
- package/src/wirings/channel/local/local-channel-runner.ts +18 -13
- package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +37 -32
- package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
- package/src/wirings/cli/cli-runner.test.ts +1 -1
- package/src/wirings/cli/cli-runner.ts +11 -4
- package/src/wirings/cli/cli.types.ts +3 -3
- package/src/wirings/cli/command-parser.test.ts +1 -1
- package/src/wirings/cli/command-parser.ts +1 -1
- package/src/wirings/http/http-routes.test.ts +1 -1
- package/src/wirings/http/http-runner.test.ts +9 -17
- package/src/wirings/http/http-runner.ts +43 -27
- package/src/wirings/http/http.types.ts +1 -14
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
- package/src/wirings/http/routers/http-router.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.ts +4 -3
- package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- package/src/wirings/mcp/mcp.types.ts +2 -2
- package/src/wirings/oauth2/oauth2-client.ts +3 -3
- package/src/wirings/oauth2/wire-oauth2-credential.ts +1 -1
- package/src/wirings/queue/index.ts +0 -1
- package/src/wirings/queue/queue-runner.test.ts +52 -25
- package/src/wirings/queue/queue-runner.ts +8 -30
- package/src/wirings/queue/queue.types.ts +3 -13
- package/src/wirings/queue/register-queue-helper.ts +3 -5
- package/src/wirings/queue/validate-worker-config.test.ts +108 -0
- package/src/wirings/queue/validate-worker-config.ts +4 -1
- package/src/wirings/rpc/index.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +92 -49
- package/src/wirings/rpc/rpc-types.ts +17 -2
- package/src/wirings/rpc/wire-addon.ts +20 -0
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +49 -60
- package/src/wirings/scheduler/scheduler-runner.ts +9 -56
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
- package/src/wirings/trigger/pikku-trigger-service.ts +17 -39
- package/src/wirings/trigger/trigger-runner.test.ts +79 -0
- package/src/wirings/trigger/trigger-runner.ts +8 -11
- package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +14 -22
- package/src/wirings/workflow/graph/template.test.ts +49 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -27
- package/src/wirings/workflow/pikku-workflow-service.ts +29 -45
- package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
- package/src/wirings/workflow/workflow.types.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-utils.d.ts +0 -1
- package/dist/wirings/workflow/workflow-utils.js +0 -1
- package/src/wirings/workflow/workflow-utils.ts +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { saveMessages } from './ai-agent-memory.js';
|
|
2
2
|
import { prepareAgentRun } from './ai-agent-prepare.js';
|
|
3
|
+
import { getSingletonServices } from '../../pikku-state.js';
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
3
5
|
export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
4
6
|
const sessionMap = agentSessionMap ?? new Map();
|
|
5
|
-
const { agent, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, missingRpcs, workingMemoryJsonSchema, workingMemorySchemaName, } = await prepareAgentRun(agentName, input, params, sessionMap);
|
|
6
|
-
const
|
|
7
|
+
const { agent, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, maxSteps, missingRpcs, workingMemoryJsonSchema, workingMemorySchemaName, } = await prepareAgentRun(agentName, input, params, sessionMap);
|
|
8
|
+
const singletonServices = getSingletonServices();
|
|
7
9
|
const { aiRunState } = singletonServices;
|
|
8
10
|
if (!aiRunState) {
|
|
9
11
|
throw new Error('AIRunStateService not available in singletonServices');
|
|
@@ -53,7 +55,90 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
53
55
|
updatedAt: new Date(),
|
|
54
56
|
});
|
|
55
57
|
try {
|
|
56
|
-
const
|
|
58
|
+
const accumulatedSteps = [];
|
|
59
|
+
const totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
60
|
+
let lastStepResult = null;
|
|
61
|
+
for (let step = 0; step < maxSteps; step++) {
|
|
62
|
+
if (agent.prepareStep) {
|
|
63
|
+
let stopped = false;
|
|
64
|
+
await agent.prepareStep({
|
|
65
|
+
stepNumber: step,
|
|
66
|
+
messages: runnerParams.messages,
|
|
67
|
+
tools: runnerParams.tools,
|
|
68
|
+
toolChoice: runnerParams.toolChoice,
|
|
69
|
+
model: runnerParams.model,
|
|
70
|
+
stop: () => {
|
|
71
|
+
stopped = true;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (stopped)
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
const stepResult = await agentRunner.run(runnerParams);
|
|
78
|
+
lastStepResult = stepResult;
|
|
79
|
+
totalUsage.inputTokens += stepResult.usage.inputTokens;
|
|
80
|
+
totalUsage.outputTokens += stepResult.usage.outputTokens;
|
|
81
|
+
for (const mw of aiMiddlewares) {
|
|
82
|
+
if (mw.afterStep) {
|
|
83
|
+
await mw.afterStep(singletonServices, {
|
|
84
|
+
stepNumber: step,
|
|
85
|
+
text: stepResult.text,
|
|
86
|
+
toolCalls: stepResult.toolCalls,
|
|
87
|
+
toolResults: stepResult.toolResults,
|
|
88
|
+
usage: stepResult.usage,
|
|
89
|
+
finishReason: stepResult.finishReason,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
accumulatedSteps.push({
|
|
94
|
+
usage: stepResult.usage,
|
|
95
|
+
toolCalls: stepResult.toolCalls.map((tc) => {
|
|
96
|
+
const tr = stepResult.toolResults.find((r) => r.toolCallId === tc.toolCallId);
|
|
97
|
+
return {
|
|
98
|
+
name: tc.toolName,
|
|
99
|
+
args: tc.args,
|
|
100
|
+
result: typeof tr?.result === 'string'
|
|
101
|
+
? tr.result
|
|
102
|
+
: JSON.stringify(tr?.result ?? ''),
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
if (stepResult.toolCalls.length === 0)
|
|
107
|
+
break;
|
|
108
|
+
const assistantMsg = {
|
|
109
|
+
id: randomUUID(),
|
|
110
|
+
role: 'assistant',
|
|
111
|
+
content: stepResult.text || undefined,
|
|
112
|
+
toolCalls: stepResult.toolCalls.map((tc) => ({
|
|
113
|
+
id: tc.toolCallId,
|
|
114
|
+
name: tc.toolName,
|
|
115
|
+
args: tc.args,
|
|
116
|
+
})),
|
|
117
|
+
createdAt: new Date(),
|
|
118
|
+
};
|
|
119
|
+
runnerParams.messages.push(assistantMsg);
|
|
120
|
+
if (stepResult.toolResults.length > 0) {
|
|
121
|
+
const toolMsg = {
|
|
122
|
+
id: randomUUID(),
|
|
123
|
+
role: 'tool',
|
|
124
|
+
toolResults: stepResult.toolResults.map((tr) => ({
|
|
125
|
+
id: tr.toolCallId,
|
|
126
|
+
name: tr.toolName,
|
|
127
|
+
result: typeof tr.result === 'string'
|
|
128
|
+
? tr.result
|
|
129
|
+
: JSON.stringify(tr.result),
|
|
130
|
+
})),
|
|
131
|
+
createdAt: new Date(),
|
|
132
|
+
};
|
|
133
|
+
runnerParams.messages.push(toolMsg);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const finalText = lastStepResult?.text ?? '';
|
|
137
|
+
const finalObject = lastStepResult?.object;
|
|
138
|
+
const result = {
|
|
139
|
+
text: finalText,
|
|
140
|
+
steps: accumulatedSteps,
|
|
141
|
+
};
|
|
57
142
|
const responseText = await saveMessages(storage, threadId, input.resourceId, memoryConfig, userMessage, result, {
|
|
58
143
|
workingMemoryJsonSchema,
|
|
59
144
|
workingMemorySchemaName,
|
|
@@ -68,7 +153,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
68
153
|
const modResult = await mw.modifyOutput(singletonServices, {
|
|
69
154
|
text: outputText,
|
|
70
155
|
messages: outputMessages,
|
|
71
|
-
usage:
|
|
156
|
+
usage: totalUsage,
|
|
72
157
|
});
|
|
73
158
|
outputText = modResult.text;
|
|
74
159
|
outputMessages = modResult.messages;
|
|
@@ -76,18 +161,32 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
76
161
|
}
|
|
77
162
|
await aiRunState.updateRun(runId, {
|
|
78
163
|
status: 'completed',
|
|
79
|
-
usage: { ...
|
|
164
|
+
usage: { ...totalUsage, model: agent.model },
|
|
80
165
|
});
|
|
81
166
|
return {
|
|
82
167
|
runId,
|
|
83
168
|
text: outputText,
|
|
84
|
-
object:
|
|
169
|
+
object: finalObject,
|
|
85
170
|
threadId,
|
|
86
|
-
steps:
|
|
87
|
-
usage:
|
|
171
|
+
steps: accumulatedSteps,
|
|
172
|
+
usage: totalUsage,
|
|
88
173
|
};
|
|
89
174
|
}
|
|
90
175
|
catch (error) {
|
|
176
|
+
for (const mw of aiMiddlewares) {
|
|
177
|
+
if (mw.onError) {
|
|
178
|
+
try {
|
|
179
|
+
await mw.onError(singletonServices, {
|
|
180
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
181
|
+
stepNumber: -1,
|
|
182
|
+
messages: runnerParams.messages,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// onError hooks must not affect error flow
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
91
190
|
await aiRunState.updateRun(runId, {
|
|
92
191
|
status: 'failed',
|
|
93
192
|
});
|
|
@@ -4,8 +4,9 @@ export declare function streamAIAgent(agentName: string, input: {
|
|
|
4
4
|
message: string;
|
|
5
5
|
threadId: string;
|
|
6
6
|
resourceId: string;
|
|
7
|
-
}, channel: AIStreamChannel, params: RunAIAgentParams, agentSessionMap?: Map<string, string>, options?: StreamAIAgentOptions): Promise<void>;
|
|
7
|
+
} | Record<string, unknown>, channel: AIStreamChannel, params: RunAIAgentParams, agentSessionMap?: Map<string, string>, options?: StreamAIAgentOptions): Promise<void>;
|
|
8
8
|
export declare function resumeAIAgent(input: {
|
|
9
|
+
runId: string;
|
|
9
10
|
toolCallId: string;
|
|
10
11
|
approved: boolean;
|
|
11
12
|
}, channel: AIStreamChannel, params: RunAIAgentParams, options?: StreamAIAgentOptions): Promise<void>;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import { pikkuState } from '../../pikku-state.js';
|
|
1
|
+
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
2
2
|
import { combineChannelMiddleware, wrapChannelWithMiddleware, } from '../channel/channel-middleware-runner.js';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
import { parseWorkingMemory, deepMergeWorkingMemory, resolveMemoryServices, loadContextMessages, trimMessages, } from './ai-agent-memory.js';
|
|
5
5
|
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, createScopedChannel, ToolApprovalRequired, } from './ai-agent-prepare.js';
|
|
6
|
+
import { createAssistantUIChannel, parseAssistantUIInput, } from './ai-agent-assistant-ui.js';
|
|
6
7
|
import { resolveModelConfig } from './ai-agent-model-config.js';
|
|
7
8
|
function createPersistingChannel(parent, storage, threadId) {
|
|
8
9
|
let fullText = '';
|
|
9
10
|
let stepText = '';
|
|
10
11
|
let stepToolCalls = [];
|
|
11
12
|
let stepToolResults = [];
|
|
13
|
+
const totalUsage = {
|
|
14
|
+
inputTokens: 0,
|
|
15
|
+
outputTokens: 0,
|
|
16
|
+
};
|
|
12
17
|
const flushStep = async () => {
|
|
13
18
|
if (!storage)
|
|
14
19
|
return;
|
|
@@ -47,6 +52,9 @@ function createPersistingChannel(parent, storage, threadId) {
|
|
|
47
52
|
get fullText() {
|
|
48
53
|
return fullText;
|
|
49
54
|
},
|
|
55
|
+
get totalUsage() {
|
|
56
|
+
return totalUsage;
|
|
57
|
+
},
|
|
50
58
|
flush: flushStep,
|
|
51
59
|
close: () => parent.close(),
|
|
52
60
|
send: (event) => {
|
|
@@ -73,6 +81,10 @@ function createPersistingChannel(parent, storage, threadId) {
|
|
|
73
81
|
});
|
|
74
82
|
break;
|
|
75
83
|
case 'usage':
|
|
84
|
+
totalUsage.inputTokens += event.tokens.input;
|
|
85
|
+
totalUsage.outputTokens += event.tokens.output;
|
|
86
|
+
if (event.model)
|
|
87
|
+
totalUsage.model = event.model;
|
|
76
88
|
flushStep();
|
|
77
89
|
break;
|
|
78
90
|
case 'done':
|
|
@@ -86,6 +98,7 @@ function createPersistingChannel(parent, storage, threadId) {
|
|
|
86
98
|
return channel;
|
|
87
99
|
}
|
|
88
100
|
async function postStreamCleanup(persistingChannel, aiMiddlewares, singletonServices, storage, memoryConfig, threadId, workingMemorySchemaName, messages, aiRunState, runId) {
|
|
101
|
+
const usage = persistingChannel.totalUsage;
|
|
89
102
|
let outputText = persistingChannel.fullText;
|
|
90
103
|
let outputMessages = messages;
|
|
91
104
|
for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
|
|
@@ -94,7 +107,10 @@ async function postStreamCleanup(persistingChannel, aiMiddlewares, singletonServ
|
|
|
94
107
|
const result = await mw.modifyOutput(singletonServices, {
|
|
95
108
|
text: outputText,
|
|
96
109
|
messages: outputMessages,
|
|
97
|
-
usage: {
|
|
110
|
+
usage: {
|
|
111
|
+
inputTokens: usage.inputTokens,
|
|
112
|
+
outputTokens: usage.outputTokens,
|
|
113
|
+
},
|
|
98
114
|
});
|
|
99
115
|
outputText = result.text;
|
|
100
116
|
outputMessages = result.messages;
|
|
@@ -116,13 +132,160 @@ async function postStreamCleanup(persistingChannel, aiMiddlewares, singletonServ
|
|
|
116
132
|
await storage.saveWorkingMemory(threadId, 'thread', merged);
|
|
117
133
|
}
|
|
118
134
|
}
|
|
119
|
-
await aiRunState.updateRun(runId, {
|
|
135
|
+
await aiRunState.updateRun(runId, {
|
|
136
|
+
status: 'completed',
|
|
137
|
+
...(usage.model
|
|
138
|
+
? {
|
|
139
|
+
usage: {
|
|
140
|
+
inputTokens: usage.inputTokens,
|
|
141
|
+
outputTokens: usage.outputTokens,
|
|
142
|
+
model: usage.model,
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
: {}),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async function runStreamStepLoop(params) {
|
|
149
|
+
const { agent, runnerParams, maxSteps, agentRunner, persistingChannel, channel, runId, aiMiddlewares, } = params;
|
|
150
|
+
const singletonServices = getSingletonServices();
|
|
151
|
+
for (let step = 0; step < maxSteps; step++) {
|
|
152
|
+
if (agent.prepareStep) {
|
|
153
|
+
let stopped = false;
|
|
154
|
+
await agent.prepareStep({
|
|
155
|
+
stepNumber: step,
|
|
156
|
+
messages: runnerParams.messages,
|
|
157
|
+
tools: runnerParams.tools,
|
|
158
|
+
toolChoice: runnerParams.toolChoice,
|
|
159
|
+
model: runnerParams.model,
|
|
160
|
+
stop: () => {
|
|
161
|
+
stopped = true;
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
if (stopped)
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
channel.send({ type: 'step-start', stepNumber: step });
|
|
168
|
+
const stepResult = await agentRunner.stream(runnerParams, persistingChannel);
|
|
169
|
+
for (const mw of aiMiddlewares) {
|
|
170
|
+
if (mw.afterStep) {
|
|
171
|
+
await mw.afterStep(singletonServices, {
|
|
172
|
+
stepNumber: step,
|
|
173
|
+
text: stepResult.text,
|
|
174
|
+
toolCalls: stepResult.toolCalls,
|
|
175
|
+
toolResults: stepResult.toolResults,
|
|
176
|
+
usage: stepResult.usage,
|
|
177
|
+
finishReason: stepResult.finishReason,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (stepResult.toolCalls.length === 0)
|
|
182
|
+
break;
|
|
183
|
+
const approvalNeeded = checkForApproval(stepResult, runnerParams.tools, runId);
|
|
184
|
+
if (approvalNeeded) {
|
|
185
|
+
return { outcome: 'approval', approval: approvalNeeded };
|
|
186
|
+
}
|
|
187
|
+
appendStepMessages(runnerParams, stepResult);
|
|
188
|
+
}
|
|
189
|
+
return { outcome: 'done' };
|
|
190
|
+
}
|
|
191
|
+
function checkForApproval(stepResult, tools, runId) {
|
|
192
|
+
for (const tc of stepResult.toolCalls) {
|
|
193
|
+
const toolDef = tools.find((t) => t.name === tc.toolName);
|
|
194
|
+
if (toolDef?.needsApproval) {
|
|
195
|
+
return new ToolApprovalRequired(tc.toolCallId, tc.toolName, tc.args);
|
|
196
|
+
}
|
|
197
|
+
const tr = stepResult.toolResults.find((r) => r.toolCallId === tc.toolCallId);
|
|
198
|
+
if (tr?.result &&
|
|
199
|
+
typeof tr.result === 'object' &&
|
|
200
|
+
'__approvalRequired' in tr.result) {
|
|
201
|
+
const r = tr.result;
|
|
202
|
+
return new ToolApprovalRequired(tc.toolCallId, r.toolName, r.args, r.reason, r.displayToolName, r.displayArgs, r.agentRunId);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
function appendStepMessages(runnerParams, stepResult) {
|
|
208
|
+
const assistantMsg = {
|
|
209
|
+
id: randomUUID(),
|
|
210
|
+
role: 'assistant',
|
|
211
|
+
content: stepResult.text || undefined,
|
|
212
|
+
toolCalls: stepResult.toolCalls.length > 0
|
|
213
|
+
? stepResult.toolCalls.map((tc) => ({
|
|
214
|
+
id: tc.toolCallId,
|
|
215
|
+
name: tc.toolName,
|
|
216
|
+
args: tc.args,
|
|
217
|
+
}))
|
|
218
|
+
: undefined,
|
|
219
|
+
createdAt: new Date(),
|
|
220
|
+
};
|
|
221
|
+
runnerParams.messages.push(assistantMsg);
|
|
222
|
+
if (stepResult.toolResults.length > 0) {
|
|
223
|
+
const toolMsg = {
|
|
224
|
+
id: randomUUID(),
|
|
225
|
+
role: 'tool',
|
|
226
|
+
toolResults: stepResult.toolResults.map((tr) => ({
|
|
227
|
+
id: tr.toolCallId,
|
|
228
|
+
name: tr.toolName,
|
|
229
|
+
result: typeof tr.result === 'string' ? tr.result : JSON.stringify(tr.result),
|
|
230
|
+
})),
|
|
231
|
+
createdAt: new Date(),
|
|
232
|
+
};
|
|
233
|
+
runnerParams.messages.push(toolMsg);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function handleApproval(err, runId, channel, aiRunState, persistingChannel) {
|
|
237
|
+
return (async () => {
|
|
238
|
+
await persistingChannel.flush();
|
|
239
|
+
const pendingApproval = err.agentRunId
|
|
240
|
+
? {
|
|
241
|
+
type: 'agent-call',
|
|
242
|
+
toolCallId: err.toolCallId,
|
|
243
|
+
agentName: err.toolName,
|
|
244
|
+
agentRunId: err.agentRunId,
|
|
245
|
+
displayToolName: err.displayToolName ?? err.toolName,
|
|
246
|
+
displayArgs: err.displayArgs ?? err.args,
|
|
247
|
+
}
|
|
248
|
+
: {
|
|
249
|
+
type: 'tool-call',
|
|
250
|
+
toolCallId: err.toolCallId,
|
|
251
|
+
toolName: err.toolName,
|
|
252
|
+
args: err.args,
|
|
253
|
+
};
|
|
254
|
+
await aiRunState.updateRun(runId, {
|
|
255
|
+
status: 'suspended',
|
|
256
|
+
suspendReason: 'approval',
|
|
257
|
+
pendingApprovals: [pendingApproval],
|
|
258
|
+
});
|
|
259
|
+
const approvalEvent = {
|
|
260
|
+
type: 'approval-request',
|
|
261
|
+
toolCallId: err.toolCallId,
|
|
262
|
+
toolName: err.displayToolName ?? err.toolName,
|
|
263
|
+
args: err.displayArgs ?? err.args,
|
|
264
|
+
reason: err.reason,
|
|
265
|
+
runId,
|
|
266
|
+
};
|
|
267
|
+
channel.send(approvalEvent);
|
|
268
|
+
channel.send({ type: 'done' });
|
|
269
|
+
channel.close();
|
|
270
|
+
})();
|
|
120
271
|
}
|
|
121
272
|
export async function streamAIAgent(agentName, input, channel, params, agentSessionMap, options) {
|
|
122
273
|
const sessionMap = agentSessionMap ?? new Map();
|
|
274
|
+
const { agent: resolvedAgentForProtocol } = resolveAgent(agentName);
|
|
275
|
+
const inputRecord = input;
|
|
276
|
+
const useUIMessageStream = resolvedAgentForProtocol.protocol === 'ui-message-stream' ||
|
|
277
|
+
Array.isArray(inputRecord.messages);
|
|
278
|
+
let normalizedInput;
|
|
279
|
+
if (useUIMessageStream) {
|
|
280
|
+
normalizedInput = parseAssistantUIInput(inputRecord);
|
|
281
|
+
channel = createAssistantUIChannel(channel);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
normalizedInput = input;
|
|
285
|
+
}
|
|
123
286
|
const streamContext = { channel, options };
|
|
124
|
-
const { agent, packageName, resolvedName, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, missingRpcs, workingMemorySchemaName, } = await prepareAgentRun(agentName,
|
|
125
|
-
const
|
|
287
|
+
const { agent, packageName, resolvedName, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, maxSteps, missingRpcs, workingMemorySchemaName, } = await prepareAgentRun(agentName, normalizedInput, params, sessionMap, streamContext);
|
|
288
|
+
const singletonServices = getSingletonServices();
|
|
126
289
|
const { aiRunState } = singletonServices;
|
|
127
290
|
if (!aiRunState) {
|
|
128
291
|
throw new Error('AIRunStateService not available in singletonServices');
|
|
@@ -131,7 +294,7 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
131
294
|
await aiRunState.createRun({
|
|
132
295
|
agentName,
|
|
133
296
|
threadId,
|
|
134
|
-
resourceId:
|
|
297
|
+
resourceId: normalizedInput.resourceId,
|
|
135
298
|
status: 'suspended',
|
|
136
299
|
suspendReason: 'rpc-missing',
|
|
137
300
|
missingRpcs,
|
|
@@ -161,7 +324,7 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
161
324
|
const runId = await aiRunState.createRun({
|
|
162
325
|
agentName,
|
|
163
326
|
threadId,
|
|
164
|
-
resourceId:
|
|
327
|
+
resourceId: normalizedInput.resourceId,
|
|
165
328
|
status: 'running',
|
|
166
329
|
usage: { inputTokens: 0, outputTokens: 0, model: agent.model },
|
|
167
330
|
createdAt: new Date(),
|
|
@@ -200,44 +363,38 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
200
363
|
: channel;
|
|
201
364
|
const persistingChannel = createPersistingChannel(wrappedChannel, storage, threadId);
|
|
202
365
|
try {
|
|
203
|
-
await
|
|
366
|
+
const loopResult = await runStreamStepLoop({
|
|
367
|
+
agent,
|
|
368
|
+
runnerParams,
|
|
369
|
+
maxSteps,
|
|
370
|
+
agentRunner,
|
|
371
|
+
persistingChannel,
|
|
372
|
+
channel,
|
|
373
|
+
runId,
|
|
374
|
+
aiMiddlewares,
|
|
375
|
+
});
|
|
376
|
+
if (loopResult.outcome === 'approval') {
|
|
377
|
+
await handleApproval(loopResult.approval, runId, channel, aiRunState, persistingChannel);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
204
380
|
await postStreamCleanup(persistingChannel, aiMiddlewares, singletonServices, storage, memoryConfig, threadId, workingMemorySchemaName, runnerParams.messages, aiRunState, runId);
|
|
381
|
+
channel.send({ type: 'done' });
|
|
382
|
+
channel.close();
|
|
205
383
|
}
|
|
206
384
|
catch (err) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
displayToolName: err.displayToolName ?? err.toolName,
|
|
216
|
-
displayArgs: err.displayArgs ?? err.args,
|
|
385
|
+
for (const mw of aiMiddlewares) {
|
|
386
|
+
if (mw.onError) {
|
|
387
|
+
try {
|
|
388
|
+
await mw.onError(singletonServices, {
|
|
389
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
390
|
+
stepNumber: -1,
|
|
391
|
+
messages: runnerParams.messages,
|
|
392
|
+
});
|
|
217
393
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
args: err.args,
|
|
223
|
-
};
|
|
224
|
-
await aiRunState.updateRun(runId, {
|
|
225
|
-
status: 'suspended',
|
|
226
|
-
suspendReason: 'approval',
|
|
227
|
-
pendingApprovals: [pendingApproval],
|
|
228
|
-
});
|
|
229
|
-
const approvalEvent = {
|
|
230
|
-
type: 'approval-request',
|
|
231
|
-
toolCallId: err.toolCallId,
|
|
232
|
-
toolName: err.displayToolName ?? err.toolName,
|
|
233
|
-
args: err.displayArgs ?? err.args,
|
|
234
|
-
reason: err.reason,
|
|
235
|
-
runId,
|
|
236
|
-
};
|
|
237
|
-
channel.send(approvalEvent);
|
|
238
|
-
channel.send({ type: 'done' });
|
|
239
|
-
channel.close();
|
|
240
|
-
return;
|
|
394
|
+
catch {
|
|
395
|
+
// onError hooks must not affect error flow
|
|
396
|
+
}
|
|
397
|
+
}
|
|
241
398
|
}
|
|
242
399
|
await aiRunState.updateRun(runId, { status: 'failed' });
|
|
243
400
|
channel.send({
|
|
@@ -249,16 +406,19 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
249
406
|
}
|
|
250
407
|
}
|
|
251
408
|
export async function resumeAIAgent(input, channel, params, options) {
|
|
252
|
-
const
|
|
409
|
+
const singletonServices = getSingletonServices();
|
|
253
410
|
const { aiRunState } = singletonServices;
|
|
254
411
|
if (!aiRunState) {
|
|
255
412
|
throw new Error('AIRunStateService not available in singletonServices');
|
|
256
413
|
}
|
|
257
|
-
const
|
|
258
|
-
if (!
|
|
259
|
-
throw new Error(`No
|
|
414
|
+
const run = await aiRunState.getRun(input.runId);
|
|
415
|
+
if (!run) {
|
|
416
|
+
throw new Error(`No run found for runId ${input.runId}`);
|
|
417
|
+
}
|
|
418
|
+
const pending = run.pendingApprovals?.find((p) => p.toolCallId === input.toolCallId);
|
|
419
|
+
if (!pending) {
|
|
420
|
+
throw new Error(`No pending approval for toolCallId ${input.toolCallId} on run ${input.runId}`);
|
|
260
421
|
}
|
|
261
|
-
const { run, approval: pending } = found;
|
|
262
422
|
await aiRunState.resolveApproval(input.toolCallId, input.approved ? 'approved' : 'denied');
|
|
263
423
|
const { agent, packageName, resolvedName } = resolveAgent(run.agentName);
|
|
264
424
|
const { storage } = resolveMemoryServices(agent, singletonServices);
|
|
@@ -310,7 +470,11 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
310
470
|
session: 'resume',
|
|
311
471
|
input: null,
|
|
312
472
|
});
|
|
313
|
-
await resumeAIAgent({
|
|
473
|
+
await resumeAIAgent({
|
|
474
|
+
runId: pending.agentRunId,
|
|
475
|
+
toolCallId: subPending.toolCallId,
|
|
476
|
+
approved: true,
|
|
477
|
+
}, subChannel, params, options);
|
|
314
478
|
channel.send({
|
|
315
479
|
type: 'agent-result',
|
|
316
480
|
agentName: subRun.agentName,
|
|
@@ -339,16 +503,16 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
339
503
|
channel,
|
|
340
504
|
options: { ...options, requiresToolApproval: false },
|
|
341
505
|
};
|
|
342
|
-
const
|
|
506
|
+
const aiMiddlewaresForResume = agent.aiMiddleware ?? [];
|
|
507
|
+
const { tools } = buildToolDefs(params, new Map(), run.resourceId, resolvedName, packageName, streamContext, aiMiddlewaresForResume);
|
|
343
508
|
const matchingTool = tools.find((t) => t.name === pending.toolName);
|
|
344
509
|
if (!matchingTool) {
|
|
345
510
|
throw new Error(`Tool "${pending.toolName}" not found in agent definition`);
|
|
346
511
|
}
|
|
347
512
|
const toolArgs = typeof pending.args === 'string' ? JSON.parse(pending.args) : pending.args;
|
|
348
|
-
const { toolApprovalReason: _ignored, ...cleanArgs } = toolArgs;
|
|
349
513
|
let toolResult;
|
|
350
514
|
try {
|
|
351
|
-
toolResult = await matchingTool.execute(
|
|
515
|
+
toolResult = await matchingTool.execute(toolArgs);
|
|
352
516
|
}
|
|
353
517
|
catch (execErr) {
|
|
354
518
|
toolResult = `Error: ${execErr instanceof Error ? execErr.message : String(execErr)}`;
|
|
@@ -381,7 +545,7 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
381
545
|
await continueAfterToolResult(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, channel, params, aiRunState, options);
|
|
382
546
|
}
|
|
383
547
|
async function continueAfterToolResult(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, channel, params, aiRunState, options) {
|
|
384
|
-
const
|
|
548
|
+
const singletonServices = getSingletonServices();
|
|
385
549
|
const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta');
|
|
386
550
|
const meta = agentsMeta[resolvedName];
|
|
387
551
|
const workingMemorySchemaName = meta?.workingMemorySchema ?? null;
|
|
@@ -438,59 +602,54 @@ async function continueAfterToolResult(run, agent, packageName, resolvedName, st
|
|
|
438
602
|
: channel;
|
|
439
603
|
const persistingChannel = createPersistingChannel(wrappedChannel, storage, run.threadId);
|
|
440
604
|
const streamContext = { channel, options };
|
|
441
|
-
const resumeTools = buildToolDefs(
|
|
605
|
+
const resumeTools = buildToolDefs(params, new Map(), run.resourceId, resolvedName, packageName, streamContext, aiMiddlewares).tools;
|
|
442
606
|
const resolved = resolveModelConfig(resolvedName, agent);
|
|
607
|
+
const maxSteps = resolved.maxSteps ?? 10;
|
|
443
608
|
const runnerParams = {
|
|
444
609
|
model: resolved.model,
|
|
445
610
|
temperature: resolved.temperature,
|
|
446
611
|
instructions: modifiedInstructions,
|
|
447
612
|
messages: modifiedMessages,
|
|
448
613
|
tools: resumeTools,
|
|
449
|
-
maxSteps:
|
|
614
|
+
maxSteps: 1,
|
|
450
615
|
toolChoice: (agent.toolChoice ?? 'auto'),
|
|
451
616
|
outputSchema: meta?.outputSchema
|
|
452
617
|
? pikkuState(packageName, 'misc', 'schemas').get(meta.outputSchema)
|
|
453
618
|
: undefined,
|
|
454
619
|
};
|
|
455
620
|
try {
|
|
456
|
-
await
|
|
621
|
+
const loopResult = await runStreamStepLoop({
|
|
622
|
+
agent,
|
|
623
|
+
runnerParams,
|
|
624
|
+
maxSteps,
|
|
625
|
+
agentRunner,
|
|
626
|
+
persistingChannel,
|
|
627
|
+
channel,
|
|
628
|
+
runId: run.runId,
|
|
629
|
+
aiMiddlewares,
|
|
630
|
+
});
|
|
631
|
+
if (loopResult.outcome === 'approval') {
|
|
632
|
+
await handleApproval(loopResult.approval, run.runId, channel, aiRunState, persistingChannel);
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
457
635
|
await postStreamCleanup(persistingChannel, aiMiddlewares, singletonServices, storage, memoryConfig, run.threadId, workingMemorySchemaName, runnerParams.messages, aiRunState, run.runId);
|
|
636
|
+
channel.send({ type: 'done' });
|
|
637
|
+
channel.close();
|
|
458
638
|
}
|
|
459
639
|
catch (err) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
displayToolName: err.displayToolName ?? err.toolName,
|
|
469
|
-
displayArgs: err.displayArgs ?? err.args,
|
|
640
|
+
for (const mw of aiMiddlewares) {
|
|
641
|
+
if (mw.onError) {
|
|
642
|
+
try {
|
|
643
|
+
await mw.onError(singletonServices, {
|
|
644
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
645
|
+
stepNumber: -1,
|
|
646
|
+
messages: runnerParams.messages,
|
|
647
|
+
});
|
|
470
648
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
args: err.args,
|
|
476
|
-
};
|
|
477
|
-
await aiRunState.updateRun(run.runId, {
|
|
478
|
-
status: 'suspended',
|
|
479
|
-
suspendReason: 'approval',
|
|
480
|
-
pendingApprovals: [pendingApproval],
|
|
481
|
-
});
|
|
482
|
-
const approvalEvent = {
|
|
483
|
-
type: 'approval-request',
|
|
484
|
-
toolCallId: err.toolCallId,
|
|
485
|
-
toolName: err.displayToolName ?? err.toolName,
|
|
486
|
-
args: err.displayArgs ?? err.args,
|
|
487
|
-
reason: err.reason,
|
|
488
|
-
runId: run.runId,
|
|
489
|
-
};
|
|
490
|
-
channel.send(approvalEvent);
|
|
491
|
-
channel.send({ type: 'done' });
|
|
492
|
-
channel.close();
|
|
493
|
-
return;
|
|
649
|
+
catch {
|
|
650
|
+
// onError hooks must not affect error flow
|
|
651
|
+
}
|
|
652
|
+
}
|
|
494
653
|
}
|
|
495
654
|
await aiRunState.updateRun(run.runId, { status: 'failed' });
|
|
496
655
|
channel.send({
|