@mastra/client-js 0.11.3-alpha.3 → 0.11.3-alpha.5
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 +25 -0
- package/dist/client.d.ts +12 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/index.cjs +398 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +398 -4
- package/dist/index.js.map +1 -1
- package/dist/resources/agent-builder.d.ts +148 -0
- package/dist/resources/agent-builder.d.ts.map +1 -0
- package/dist/resources/agent.d.ts +25 -0
- package/dist/resources/agent.d.ts.map +1 -1
- package/dist/resources/index.d.ts +1 -0
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -8
- package/.turbo/turbo-build.log +0 -18
- package/eslint.config.js +0 -11
- package/integration-tests/agui-adapter.test.ts +0 -122
- package/integration-tests/package.json +0 -18
- package/integration-tests/src/mastra/index.ts +0 -35
- package/integration-tests/vitest.config.ts +0 -9
- package/src/adapters/agui.test.ts +0 -293
- package/src/adapters/agui.ts +0 -257
- package/src/client.ts +0 -644
- package/src/example.ts +0 -95
- package/src/index.test.ts +0 -1253
- package/src/index.ts +0 -3
- package/src/resources/a2a.ts +0 -98
- package/src/resources/agent.ts +0 -1460
- package/src/resources/base.ts +0 -77
- package/src/resources/index.ts +0 -11
- package/src/resources/legacy-workflow.ts +0 -242
- package/src/resources/mcp-tool.ts +0 -48
- package/src/resources/memory-thread.test.ts +0 -285
- package/src/resources/memory-thread.ts +0 -99
- package/src/resources/network-memory-thread.test.ts +0 -269
- package/src/resources/network-memory-thread.ts +0 -81
- package/src/resources/network.ts +0 -86
- package/src/resources/observability.ts +0 -53
- package/src/resources/tool.ts +0 -45
- package/src/resources/vNextNetwork.ts +0 -194
- package/src/resources/vector.ts +0 -83
- package/src/resources/workflow.ts +0 -410
- package/src/types.ts +0 -534
- package/src/utils/index.ts +0 -11
- package/src/utils/process-client-tools.ts +0 -32
- package/src/utils/process-mastra-stream.test.ts +0 -353
- package/src/utils/process-mastra-stream.ts +0 -49
- package/src/utils/zod-to-json-schema.ts +0 -30
- package/src/v2-messages.test.ts +0 -180
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -17
- package/vitest.config.js +0 -8
package/src/resources/agent.ts
DELETED
|
@@ -1,1460 +0,0 @@
|
|
|
1
|
-
import { parsePartialJson, processDataStream } from '@ai-sdk/ui-utils';
|
|
2
|
-
import type {
|
|
3
|
-
JSONValue,
|
|
4
|
-
ReasoningUIPart,
|
|
5
|
-
TextUIPart,
|
|
6
|
-
ToolInvocation,
|
|
7
|
-
ToolInvocationUIPart,
|
|
8
|
-
UIMessage,
|
|
9
|
-
UseChatOptions,
|
|
10
|
-
} from '@ai-sdk/ui-utils';
|
|
11
|
-
import { v4 as uuid } from '@lukeed/uuid';
|
|
12
|
-
import type { MessageListInput } from '@mastra/core/agent/message-list';
|
|
13
|
-
import type { GenerateReturn, CoreMessage } from '@mastra/core/llm';
|
|
14
|
-
import type { RuntimeContext } from '@mastra/core/runtime-context';
|
|
15
|
-
import type { OutputSchema, MastraModelOutput } from '@mastra/core/stream';
|
|
16
|
-
import type { Tool } from '@mastra/core/tools';
|
|
17
|
-
import type { JSONSchema7 } from 'json-schema';
|
|
18
|
-
import type { ZodType } from 'zod';
|
|
19
|
-
|
|
20
|
-
import type {
|
|
21
|
-
GenerateParams,
|
|
22
|
-
GetAgentResponse,
|
|
23
|
-
GetEvalsByAgentIdResponse,
|
|
24
|
-
GetToolResponse,
|
|
25
|
-
ClientOptions,
|
|
26
|
-
StreamParams,
|
|
27
|
-
UpdateModelParams,
|
|
28
|
-
StreamVNextParams,
|
|
29
|
-
} from '../types';
|
|
30
|
-
|
|
31
|
-
import { parseClientRuntimeContext } from '../utils';
|
|
32
|
-
import { processClientTools } from '../utils/process-client-tools';
|
|
33
|
-
import { processMastraStream } from '../utils/process-mastra-stream';
|
|
34
|
-
import { zodToJsonSchema } from '../utils/zod-to-json-schema';
|
|
35
|
-
import { BaseResource } from './base';
|
|
36
|
-
|
|
37
|
-
async function executeToolCallAndRespond({
|
|
38
|
-
response,
|
|
39
|
-
params,
|
|
40
|
-
runId,
|
|
41
|
-
resourceId,
|
|
42
|
-
threadId,
|
|
43
|
-
runtimeContext,
|
|
44
|
-
respondFn,
|
|
45
|
-
}: {
|
|
46
|
-
params: StreamVNextParams<any>;
|
|
47
|
-
response: Awaited<ReturnType<MastraModelOutput['getFullOutput']>>;
|
|
48
|
-
runId?: string;
|
|
49
|
-
resourceId?: string;
|
|
50
|
-
threadId?: string;
|
|
51
|
-
runtimeContext?: RuntimeContext<any>;
|
|
52
|
-
respondFn: Agent['generateVNext'];
|
|
53
|
-
}) {
|
|
54
|
-
if (response.finishReason === 'tool-calls') {
|
|
55
|
-
const toolCalls = (
|
|
56
|
-
response as unknown as {
|
|
57
|
-
toolCalls: { toolName: string; args: any; toolCallId: string }[];
|
|
58
|
-
messages: CoreMessage[];
|
|
59
|
-
}
|
|
60
|
-
).toolCalls;
|
|
61
|
-
|
|
62
|
-
if (!toolCalls || !Array.isArray(toolCalls)) {
|
|
63
|
-
return response;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
for (const toolCall of toolCalls) {
|
|
67
|
-
const clientTool = params.clientTools?.[toolCall.toolName] as Tool;
|
|
68
|
-
|
|
69
|
-
if (clientTool && clientTool.execute) {
|
|
70
|
-
const result = await clientTool.execute(
|
|
71
|
-
{
|
|
72
|
-
context: toolCall?.args,
|
|
73
|
-
runId,
|
|
74
|
-
resourceId,
|
|
75
|
-
threadId,
|
|
76
|
-
runtimeContext: runtimeContext as RuntimeContext,
|
|
77
|
-
tracingContext: { currentSpan: undefined },
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
messages: (response as unknown as { messages: CoreMessage[] }).messages,
|
|
81
|
-
toolCallId: toolCall?.toolCallId,
|
|
82
|
-
},
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const updatedMessages = [
|
|
86
|
-
{
|
|
87
|
-
role: 'user',
|
|
88
|
-
content: params.messages,
|
|
89
|
-
},
|
|
90
|
-
...(response.response as unknown as { messages: CoreMessage[] }).messages,
|
|
91
|
-
{
|
|
92
|
-
role: 'tool',
|
|
93
|
-
content: [
|
|
94
|
-
{
|
|
95
|
-
type: 'tool-result',
|
|
96
|
-
toolCallId: toolCall.toolCallId,
|
|
97
|
-
toolName: toolCall.toolName,
|
|
98
|
-
result,
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
] as MessageListInput;
|
|
103
|
-
|
|
104
|
-
// @ts-ignore
|
|
105
|
-
return respondFn({
|
|
106
|
-
...params,
|
|
107
|
-
messages: updatedMessages,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export class AgentVoice extends BaseResource {
|
|
115
|
-
constructor(
|
|
116
|
-
options: ClientOptions,
|
|
117
|
-
private agentId: string,
|
|
118
|
-
) {
|
|
119
|
-
super(options);
|
|
120
|
-
this.agentId = agentId;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Convert text to speech using the agent's voice provider
|
|
125
|
-
* @param text - Text to convert to speech
|
|
126
|
-
* @param options - Optional provider-specific options for speech generation
|
|
127
|
-
* @returns Promise containing the audio data
|
|
128
|
-
*/
|
|
129
|
-
async speak(text: string, options?: { speaker?: string; [key: string]: any }): Promise<Response> {
|
|
130
|
-
return this.request<Response>(`/api/agents/${this.agentId}/voice/speak`, {
|
|
131
|
-
method: 'POST',
|
|
132
|
-
headers: {
|
|
133
|
-
'Content-Type': 'application/json',
|
|
134
|
-
},
|
|
135
|
-
body: { input: text, options },
|
|
136
|
-
stream: true,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Convert speech to text using the agent's voice provider
|
|
142
|
-
* @param audio - Audio data to transcribe
|
|
143
|
-
* @param options - Optional provider-specific options
|
|
144
|
-
* @returns Promise containing the transcribed text
|
|
145
|
-
*/
|
|
146
|
-
listen(audio: Blob, options?: Record<string, any>): Promise<{ text: string }> {
|
|
147
|
-
const formData = new FormData();
|
|
148
|
-
formData.append('audio', audio);
|
|
149
|
-
|
|
150
|
-
if (options) {
|
|
151
|
-
formData.append('options', JSON.stringify(options));
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return this.request(`/api/agents/${this.agentId}/voice/listen`, {
|
|
155
|
-
method: 'POST',
|
|
156
|
-
body: formData,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get available speakers for the agent's voice provider
|
|
162
|
-
* @returns Promise containing list of available speakers
|
|
163
|
-
*/
|
|
164
|
-
getSpeakers(): Promise<Array<{ voiceId: string; [key: string]: any }>> {
|
|
165
|
-
return this.request(`/api/agents/${this.agentId}/voice/speakers`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Get the listener configuration for the agent's voice provider
|
|
170
|
-
* @returns Promise containing a check if the agent has listening capabilities
|
|
171
|
-
*/
|
|
172
|
-
getListener(): Promise<{ enabled: boolean }> {
|
|
173
|
-
return this.request(`/api/agents/${this.agentId}/voice/listener`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export class Agent extends BaseResource {
|
|
178
|
-
public readonly voice: AgentVoice;
|
|
179
|
-
|
|
180
|
-
constructor(
|
|
181
|
-
options: ClientOptions,
|
|
182
|
-
private agentId: string,
|
|
183
|
-
) {
|
|
184
|
-
super(options);
|
|
185
|
-
this.voice = new AgentVoice(options, this.agentId);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Retrieves details about the agent
|
|
190
|
-
* @returns Promise containing agent details including model and instructions
|
|
191
|
-
*/
|
|
192
|
-
details(): Promise<GetAgentResponse> {
|
|
193
|
-
return this.request(`/api/agents/${this.agentId}`);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Generates a response from the agent
|
|
198
|
-
* @param params - Generation parameters including prompt
|
|
199
|
-
* @returns Promise containing the generated response
|
|
200
|
-
*/
|
|
201
|
-
async generate(
|
|
202
|
-
params: GenerateParams<undefined> & { output?: never; experimental_output?: never },
|
|
203
|
-
): Promise<GenerateReturn<any, undefined, undefined>>;
|
|
204
|
-
async generate<Output extends JSONSchema7 | ZodType>(
|
|
205
|
-
params: GenerateParams<Output> & { output: Output; experimental_output?: never },
|
|
206
|
-
): Promise<GenerateReturn<any, Output, undefined>>;
|
|
207
|
-
async generate<StructuredOutput extends JSONSchema7 | ZodType>(
|
|
208
|
-
params: GenerateParams<StructuredOutput> & { output?: never; experimental_output: StructuredOutput },
|
|
209
|
-
): Promise<GenerateReturn<any, undefined, StructuredOutput>>;
|
|
210
|
-
async generate<
|
|
211
|
-
Output extends JSONSchema7 | ZodType | undefined = undefined,
|
|
212
|
-
StructuredOutput extends JSONSchema7 | ZodType | undefined = undefined,
|
|
213
|
-
>(params: GenerateParams<Output>): Promise<GenerateReturn<any, Output, StructuredOutput>> {
|
|
214
|
-
const processedParams = {
|
|
215
|
-
...params,
|
|
216
|
-
output: params.output ? zodToJsonSchema(params.output) : undefined,
|
|
217
|
-
experimental_output: params.experimental_output ? zodToJsonSchema(params.experimental_output) : undefined,
|
|
218
|
-
runtimeContext: parseClientRuntimeContext(params.runtimeContext),
|
|
219
|
-
clientTools: processClientTools(params.clientTools),
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
const { runId, resourceId, threadId, runtimeContext } = processedParams as GenerateParams;
|
|
223
|
-
|
|
224
|
-
const response: GenerateReturn<any, Output, StructuredOutput> = await this.request(
|
|
225
|
-
`/api/agents/${this.agentId}/generate`,
|
|
226
|
-
{
|
|
227
|
-
method: 'POST',
|
|
228
|
-
body: processedParams,
|
|
229
|
-
},
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
if (response.finishReason === 'tool-calls') {
|
|
233
|
-
const toolCalls = (
|
|
234
|
-
response as unknown as {
|
|
235
|
-
toolCalls: { toolName: string; args: any; toolCallId: string }[];
|
|
236
|
-
messages: CoreMessage[];
|
|
237
|
-
}
|
|
238
|
-
).toolCalls;
|
|
239
|
-
|
|
240
|
-
if (!toolCalls || !Array.isArray(toolCalls)) {
|
|
241
|
-
return response;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
for (const toolCall of toolCalls) {
|
|
245
|
-
const clientTool = params.clientTools?.[toolCall.toolName] as Tool;
|
|
246
|
-
|
|
247
|
-
if (clientTool && clientTool.execute) {
|
|
248
|
-
const result = await clientTool.execute(
|
|
249
|
-
{
|
|
250
|
-
context: toolCall?.args,
|
|
251
|
-
runId,
|
|
252
|
-
resourceId,
|
|
253
|
-
threadId,
|
|
254
|
-
runtimeContext: runtimeContext as RuntimeContext,
|
|
255
|
-
tracingContext: { currentSpan: undefined },
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
messages: (response as unknown as { messages: CoreMessage[] }).messages,
|
|
259
|
-
toolCallId: toolCall?.toolCallId,
|
|
260
|
-
},
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
const updatedMessages = [
|
|
264
|
-
{
|
|
265
|
-
role: 'user',
|
|
266
|
-
content: params.messages,
|
|
267
|
-
},
|
|
268
|
-
...(response.response as unknown as { messages: CoreMessage[] }).messages,
|
|
269
|
-
{
|
|
270
|
-
role: 'tool',
|
|
271
|
-
content: [
|
|
272
|
-
{
|
|
273
|
-
type: 'tool-result',
|
|
274
|
-
toolCallId: toolCall.toolCallId,
|
|
275
|
-
toolName: toolCall.toolName,
|
|
276
|
-
result,
|
|
277
|
-
},
|
|
278
|
-
],
|
|
279
|
-
},
|
|
280
|
-
];
|
|
281
|
-
// @ts-ignore
|
|
282
|
-
return this.generate({
|
|
283
|
-
...params,
|
|
284
|
-
messages: updatedMessages,
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return response;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async generateVNext<T extends OutputSchema | undefined = undefined>(
|
|
294
|
-
params: StreamVNextParams<T>,
|
|
295
|
-
): Promise<ReturnType<MastraModelOutput['getFullOutput']>> {
|
|
296
|
-
const processedParams = {
|
|
297
|
-
...params,
|
|
298
|
-
output: params.output ? zodToJsonSchema(params.output) : undefined,
|
|
299
|
-
runtimeContext: parseClientRuntimeContext(params.runtimeContext),
|
|
300
|
-
clientTools: processClientTools(params.clientTools),
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
const { runId, resourceId, threadId, runtimeContext } = processedParams as StreamVNextParams;
|
|
304
|
-
|
|
305
|
-
const response = await this.request<ReturnType<MastraModelOutput['getFullOutput']>>(
|
|
306
|
-
`/api/agents/${this.agentId}/generate/vnext`,
|
|
307
|
-
{
|
|
308
|
-
method: 'POST',
|
|
309
|
-
body: processedParams,
|
|
310
|
-
},
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
if (response.finishReason === 'tool-calls') {
|
|
314
|
-
return executeToolCallAndRespond({
|
|
315
|
-
response,
|
|
316
|
-
params,
|
|
317
|
-
runId,
|
|
318
|
-
resourceId,
|
|
319
|
-
threadId,
|
|
320
|
-
runtimeContext: runtimeContext as RuntimeContext<any>,
|
|
321
|
-
respondFn: this.generateVNext.bind(this),
|
|
322
|
-
}) as unknown as Awaited<ReturnType<MastraModelOutput['getFullOutput']>>;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return response;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
private async processChatResponse({
|
|
329
|
-
stream,
|
|
330
|
-
update,
|
|
331
|
-
onToolCall,
|
|
332
|
-
onFinish,
|
|
333
|
-
getCurrentDate = () => new Date(),
|
|
334
|
-
lastMessage,
|
|
335
|
-
}: {
|
|
336
|
-
stream: ReadableStream<Uint8Array>;
|
|
337
|
-
update: (options: { message: UIMessage; data: JSONValue[] | undefined; replaceLastMessage: boolean }) => void;
|
|
338
|
-
onToolCall?: UseChatOptions['onToolCall'];
|
|
339
|
-
onFinish?: (options: { message: UIMessage | undefined; finishReason: string; usage: string }) => void;
|
|
340
|
-
generateId?: () => string;
|
|
341
|
-
getCurrentDate?: () => Date;
|
|
342
|
-
lastMessage: UIMessage | undefined;
|
|
343
|
-
}) {
|
|
344
|
-
const replaceLastMessage = lastMessage?.role === 'assistant';
|
|
345
|
-
let step = replaceLastMessage
|
|
346
|
-
? 1 +
|
|
347
|
-
// find max step in existing tool invocations:
|
|
348
|
-
(lastMessage.toolInvocations?.reduce((max, toolInvocation) => {
|
|
349
|
-
return Math.max(max, toolInvocation.step ?? 0);
|
|
350
|
-
}, 0) ?? 0)
|
|
351
|
-
: 0;
|
|
352
|
-
|
|
353
|
-
const message: UIMessage = replaceLastMessage
|
|
354
|
-
? structuredClone(lastMessage)
|
|
355
|
-
: {
|
|
356
|
-
id: uuid(),
|
|
357
|
-
createdAt: getCurrentDate(),
|
|
358
|
-
role: 'assistant',
|
|
359
|
-
content: '',
|
|
360
|
-
parts: [],
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
let currentTextPart: TextUIPart | undefined = undefined;
|
|
364
|
-
let currentReasoningPart: ReasoningUIPart | undefined = undefined;
|
|
365
|
-
let currentReasoningTextDetail: { type: 'text'; text: string; signature?: string } | undefined = undefined;
|
|
366
|
-
|
|
367
|
-
function updateToolInvocationPart(toolCallId: string, invocation: ToolInvocation) {
|
|
368
|
-
const part = message.parts.find(
|
|
369
|
-
part => part.type === 'tool-invocation' && part.toolInvocation.toolCallId === toolCallId,
|
|
370
|
-
) as ToolInvocationUIPart | undefined;
|
|
371
|
-
|
|
372
|
-
if (part != null) {
|
|
373
|
-
part.toolInvocation = invocation;
|
|
374
|
-
} else {
|
|
375
|
-
message.parts.push({
|
|
376
|
-
type: 'tool-invocation',
|
|
377
|
-
toolInvocation: invocation,
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const data: JSONValue[] = [];
|
|
383
|
-
|
|
384
|
-
// keep list of current message annotations for message
|
|
385
|
-
let messageAnnotations: JSONValue[] | undefined = replaceLastMessage ? lastMessage?.annotations : undefined;
|
|
386
|
-
|
|
387
|
-
// keep track of partial tool calls
|
|
388
|
-
const partialToolCalls: Record<string, { text: string; step: number; index: number; toolName: string }> = {};
|
|
389
|
-
|
|
390
|
-
let usage: any = {
|
|
391
|
-
completionTokens: NaN,
|
|
392
|
-
promptTokens: NaN,
|
|
393
|
-
totalTokens: NaN,
|
|
394
|
-
};
|
|
395
|
-
let finishReason: string = 'unknown';
|
|
396
|
-
|
|
397
|
-
function execUpdate() {
|
|
398
|
-
// make a copy of the data array to ensure UI is updated (SWR)
|
|
399
|
-
const copiedData = [...data];
|
|
400
|
-
|
|
401
|
-
// keeps the currentMessage up to date with the latest annotations,
|
|
402
|
-
// even if annotations preceded the message creation
|
|
403
|
-
if (messageAnnotations?.length) {
|
|
404
|
-
message.annotations = messageAnnotations;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const copiedMessage = {
|
|
408
|
-
// deep copy the message to ensure that deep changes (msg attachments) are updated
|
|
409
|
-
// with SolidJS. SolidJS uses referential integration of sub-objects to detect changes.
|
|
410
|
-
...structuredClone(message),
|
|
411
|
-
// add a revision id to ensure that the message is updated with SWR. SWR uses a
|
|
412
|
-
// hashing approach by default to detect changes, but it only works for shallow
|
|
413
|
-
// changes. This is why we need to add a revision id to ensure that the message
|
|
414
|
-
// is updated with SWR (without it, the changes get stuck in SWR and are not
|
|
415
|
-
// forwarded to rendering):
|
|
416
|
-
revisionId: uuid(),
|
|
417
|
-
} as UIMessage;
|
|
418
|
-
|
|
419
|
-
update({
|
|
420
|
-
message: copiedMessage,
|
|
421
|
-
data: copiedData,
|
|
422
|
-
replaceLastMessage,
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
await processDataStream({
|
|
427
|
-
stream,
|
|
428
|
-
onTextPart(value) {
|
|
429
|
-
if (currentTextPart == null) {
|
|
430
|
-
currentTextPart = {
|
|
431
|
-
type: 'text',
|
|
432
|
-
text: value,
|
|
433
|
-
};
|
|
434
|
-
message.parts.push(currentTextPart);
|
|
435
|
-
} else {
|
|
436
|
-
currentTextPart.text += value;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
message.content += value;
|
|
440
|
-
execUpdate();
|
|
441
|
-
},
|
|
442
|
-
onReasoningPart(value) {
|
|
443
|
-
if (currentReasoningTextDetail == null) {
|
|
444
|
-
currentReasoningTextDetail = { type: 'text', text: value };
|
|
445
|
-
if (currentReasoningPart != null) {
|
|
446
|
-
currentReasoningPart.details.push(currentReasoningTextDetail);
|
|
447
|
-
}
|
|
448
|
-
} else {
|
|
449
|
-
currentReasoningTextDetail.text += value;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (currentReasoningPart == null) {
|
|
453
|
-
currentReasoningPart = {
|
|
454
|
-
type: 'reasoning',
|
|
455
|
-
reasoning: value,
|
|
456
|
-
details: [currentReasoningTextDetail],
|
|
457
|
-
};
|
|
458
|
-
message.parts.push(currentReasoningPart);
|
|
459
|
-
} else {
|
|
460
|
-
currentReasoningPart.reasoning += value;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
message.reasoning = (message.reasoning ?? '') + value;
|
|
464
|
-
|
|
465
|
-
execUpdate();
|
|
466
|
-
},
|
|
467
|
-
onReasoningSignaturePart(value) {
|
|
468
|
-
if (currentReasoningTextDetail != null) {
|
|
469
|
-
currentReasoningTextDetail.signature = value.signature;
|
|
470
|
-
}
|
|
471
|
-
},
|
|
472
|
-
onRedactedReasoningPart(value) {
|
|
473
|
-
if (currentReasoningPart == null) {
|
|
474
|
-
currentReasoningPart = {
|
|
475
|
-
type: 'reasoning',
|
|
476
|
-
reasoning: '',
|
|
477
|
-
details: [],
|
|
478
|
-
};
|
|
479
|
-
message.parts.push(currentReasoningPart);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
currentReasoningPart.details.push({
|
|
483
|
-
type: 'redacted',
|
|
484
|
-
data: value.data,
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
currentReasoningTextDetail = undefined;
|
|
488
|
-
|
|
489
|
-
execUpdate();
|
|
490
|
-
},
|
|
491
|
-
onFilePart(value) {
|
|
492
|
-
message.parts.push({
|
|
493
|
-
type: 'file',
|
|
494
|
-
mimeType: value.mimeType,
|
|
495
|
-
data: value.data,
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
execUpdate();
|
|
499
|
-
},
|
|
500
|
-
onSourcePart(value) {
|
|
501
|
-
message.parts.push({
|
|
502
|
-
type: 'source',
|
|
503
|
-
source: value,
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
execUpdate();
|
|
507
|
-
},
|
|
508
|
-
onToolCallStreamingStartPart(value) {
|
|
509
|
-
if (message.toolInvocations == null) {
|
|
510
|
-
message.toolInvocations = [];
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// add the partial tool call to the map
|
|
514
|
-
partialToolCalls[value.toolCallId] = {
|
|
515
|
-
text: '',
|
|
516
|
-
step,
|
|
517
|
-
toolName: value.toolName,
|
|
518
|
-
index: message.toolInvocations.length,
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
const invocation = {
|
|
522
|
-
state: 'partial-call',
|
|
523
|
-
step,
|
|
524
|
-
toolCallId: value.toolCallId,
|
|
525
|
-
toolName: value.toolName,
|
|
526
|
-
args: undefined,
|
|
527
|
-
} as const;
|
|
528
|
-
|
|
529
|
-
message.toolInvocations.push(invocation);
|
|
530
|
-
|
|
531
|
-
updateToolInvocationPart(value.toolCallId, invocation);
|
|
532
|
-
|
|
533
|
-
execUpdate();
|
|
534
|
-
},
|
|
535
|
-
onToolCallDeltaPart(value) {
|
|
536
|
-
const partialToolCall = partialToolCalls[value.toolCallId];
|
|
537
|
-
|
|
538
|
-
partialToolCall!.text += value.argsTextDelta;
|
|
539
|
-
|
|
540
|
-
const { value: partialArgs } = parsePartialJson(partialToolCall!.text);
|
|
541
|
-
|
|
542
|
-
const invocation = {
|
|
543
|
-
state: 'partial-call',
|
|
544
|
-
step: partialToolCall!.step,
|
|
545
|
-
toolCallId: value.toolCallId,
|
|
546
|
-
toolName: partialToolCall!.toolName,
|
|
547
|
-
args: partialArgs,
|
|
548
|
-
} as const;
|
|
549
|
-
|
|
550
|
-
message.toolInvocations![partialToolCall!.index] = invocation;
|
|
551
|
-
|
|
552
|
-
updateToolInvocationPart(value.toolCallId, invocation);
|
|
553
|
-
|
|
554
|
-
execUpdate();
|
|
555
|
-
},
|
|
556
|
-
async onToolCallPart(value) {
|
|
557
|
-
const invocation = {
|
|
558
|
-
state: 'call',
|
|
559
|
-
step,
|
|
560
|
-
...value,
|
|
561
|
-
} as const;
|
|
562
|
-
|
|
563
|
-
if (partialToolCalls[value.toolCallId] != null) {
|
|
564
|
-
// change the partial tool call to a full tool call
|
|
565
|
-
message.toolInvocations![partialToolCalls[value.toolCallId]!.index] = invocation;
|
|
566
|
-
} else {
|
|
567
|
-
if (message.toolInvocations == null) {
|
|
568
|
-
message.toolInvocations = [];
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
message.toolInvocations.push(invocation);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
updateToolInvocationPart(value.toolCallId, invocation);
|
|
575
|
-
|
|
576
|
-
execUpdate();
|
|
577
|
-
|
|
578
|
-
// invoke the onToolCall callback if it exists. This is blocking.
|
|
579
|
-
// In the future we should make this non-blocking, which
|
|
580
|
-
// requires additional state management for error handling etc.
|
|
581
|
-
if (onToolCall) {
|
|
582
|
-
const result = await onToolCall({ toolCall: value });
|
|
583
|
-
if (result != null) {
|
|
584
|
-
const invocation = {
|
|
585
|
-
state: 'result',
|
|
586
|
-
step,
|
|
587
|
-
...value,
|
|
588
|
-
result,
|
|
589
|
-
} as const;
|
|
590
|
-
|
|
591
|
-
// store the result in the tool invocation
|
|
592
|
-
message.toolInvocations![message.toolInvocations!.length - 1] = invocation;
|
|
593
|
-
|
|
594
|
-
updateToolInvocationPart(value.toolCallId, invocation);
|
|
595
|
-
|
|
596
|
-
execUpdate();
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
},
|
|
600
|
-
onToolResultPart(value) {
|
|
601
|
-
const toolInvocations = message.toolInvocations;
|
|
602
|
-
|
|
603
|
-
if (toolInvocations == null) {
|
|
604
|
-
throw new Error('tool_result must be preceded by a tool_call');
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
// find if there is any tool invocation with the same toolCallId
|
|
608
|
-
// and replace it with the result
|
|
609
|
-
const toolInvocationIndex = toolInvocations.findIndex(invocation => invocation.toolCallId === value.toolCallId);
|
|
610
|
-
|
|
611
|
-
if (toolInvocationIndex === -1) {
|
|
612
|
-
throw new Error('tool_result must be preceded by a tool_call with the same toolCallId');
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
const invocation = {
|
|
616
|
-
...toolInvocations[toolInvocationIndex],
|
|
617
|
-
state: 'result' as const,
|
|
618
|
-
...value,
|
|
619
|
-
} as const;
|
|
620
|
-
|
|
621
|
-
toolInvocations[toolInvocationIndex] = invocation as ToolInvocation;
|
|
622
|
-
|
|
623
|
-
updateToolInvocationPart(value.toolCallId, invocation as ToolInvocation);
|
|
624
|
-
|
|
625
|
-
execUpdate();
|
|
626
|
-
},
|
|
627
|
-
onDataPart(value) {
|
|
628
|
-
data.push(...value);
|
|
629
|
-
execUpdate();
|
|
630
|
-
},
|
|
631
|
-
onMessageAnnotationsPart(value) {
|
|
632
|
-
if (messageAnnotations == null) {
|
|
633
|
-
messageAnnotations = [...value];
|
|
634
|
-
} else {
|
|
635
|
-
messageAnnotations.push(...value);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
execUpdate();
|
|
639
|
-
},
|
|
640
|
-
onFinishStepPart(value) {
|
|
641
|
-
step += 1;
|
|
642
|
-
|
|
643
|
-
// reset the current text and reasoning parts
|
|
644
|
-
currentTextPart = value.isContinued ? currentTextPart : undefined;
|
|
645
|
-
currentReasoningPart = undefined;
|
|
646
|
-
currentReasoningTextDetail = undefined;
|
|
647
|
-
},
|
|
648
|
-
onStartStepPart(value) {
|
|
649
|
-
// keep message id stable when we are updating an existing message:
|
|
650
|
-
if (!replaceLastMessage) {
|
|
651
|
-
message.id = value.messageId;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// add a step boundary part to the message
|
|
655
|
-
message.parts.push({ type: 'step-start' });
|
|
656
|
-
execUpdate();
|
|
657
|
-
},
|
|
658
|
-
onFinishMessagePart(value) {
|
|
659
|
-
finishReason = value.finishReason;
|
|
660
|
-
if (value.usage != null) {
|
|
661
|
-
// usage = calculateLanguageModelUsage(value.usage);
|
|
662
|
-
usage = value.usage;
|
|
663
|
-
}
|
|
664
|
-
},
|
|
665
|
-
onErrorPart(error) {
|
|
666
|
-
throw new Error(error);
|
|
667
|
-
},
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
onFinish?.({ message, finishReason, usage });
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Streams a response from the agent
|
|
675
|
-
* @param params - Stream parameters including prompt
|
|
676
|
-
* @returns Promise containing the enhanced Response object with processDataStream method
|
|
677
|
-
*/
|
|
678
|
-
async stream<T extends JSONSchema7 | ZodType | undefined = undefined>(
|
|
679
|
-
params: StreamParams<T>,
|
|
680
|
-
): Promise<
|
|
681
|
-
Response & {
|
|
682
|
-
processDataStream: (options?: Omit<Parameters<typeof processDataStream>[0], 'stream'>) => Promise<void>;
|
|
683
|
-
}
|
|
684
|
-
> {
|
|
685
|
-
const processedParams = {
|
|
686
|
-
...params,
|
|
687
|
-
output: params.output ? zodToJsonSchema(params.output) : undefined,
|
|
688
|
-
experimental_output: params.experimental_output ? zodToJsonSchema(params.experimental_output) : undefined,
|
|
689
|
-
runtimeContext: parseClientRuntimeContext(params.runtimeContext),
|
|
690
|
-
clientTools: processClientTools(params.clientTools),
|
|
691
|
-
};
|
|
692
|
-
|
|
693
|
-
// Create a readable stream that will handle the response processing
|
|
694
|
-
const { readable, writable } = new TransformStream<Uint8Array, Uint8Array>();
|
|
695
|
-
|
|
696
|
-
// Start processing the response in the background
|
|
697
|
-
const response = await this.processStreamResponse(processedParams, writable);
|
|
698
|
-
|
|
699
|
-
// Create a new response with the readable stream
|
|
700
|
-
const streamResponse = new Response(readable, {
|
|
701
|
-
status: response.status,
|
|
702
|
-
statusText: response.statusText,
|
|
703
|
-
headers: response.headers,
|
|
704
|
-
}) as Response & {
|
|
705
|
-
processDataStream: (options?: Omit<Parameters<typeof processDataStream>[0], 'stream'>) => Promise<void>;
|
|
706
|
-
};
|
|
707
|
-
|
|
708
|
-
// Add the processDataStream method to the response
|
|
709
|
-
streamResponse.processDataStream = async (options = {}) => {
|
|
710
|
-
await processDataStream({
|
|
711
|
-
stream: streamResponse.body as ReadableStream<Uint8Array>,
|
|
712
|
-
...options,
|
|
713
|
-
});
|
|
714
|
-
};
|
|
715
|
-
|
|
716
|
-
return streamResponse;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
private async processChatResponse_vNext({
|
|
720
|
-
stream,
|
|
721
|
-
update,
|
|
722
|
-
onToolCall,
|
|
723
|
-
onFinish,
|
|
724
|
-
getCurrentDate = () => new Date(),
|
|
725
|
-
lastMessage,
|
|
726
|
-
}: {
|
|
727
|
-
stream: ReadableStream<Uint8Array>;
|
|
728
|
-
update: (options: { message: UIMessage; data: JSONValue[] | undefined; replaceLastMessage: boolean }) => void;
|
|
729
|
-
onToolCall?: UseChatOptions['onToolCall'];
|
|
730
|
-
onFinish?: (options: { message: UIMessage | undefined; finishReason: string; usage: string }) => void;
|
|
731
|
-
generateId?: () => string;
|
|
732
|
-
getCurrentDate?: () => Date;
|
|
733
|
-
lastMessage: UIMessage | undefined;
|
|
734
|
-
}) {
|
|
735
|
-
const replaceLastMessage = lastMessage?.role === 'assistant';
|
|
736
|
-
let step = replaceLastMessage
|
|
737
|
-
? 1 +
|
|
738
|
-
// find max step in existing tool invocations:
|
|
739
|
-
(lastMessage.toolInvocations?.reduce((max, toolInvocation) => {
|
|
740
|
-
return Math.max(max, toolInvocation.step ?? 0);
|
|
741
|
-
}, 0) ?? 0)
|
|
742
|
-
: 0;
|
|
743
|
-
|
|
744
|
-
const message: UIMessage = replaceLastMessage
|
|
745
|
-
? structuredClone(lastMessage)
|
|
746
|
-
: {
|
|
747
|
-
id: uuid(),
|
|
748
|
-
createdAt: getCurrentDate(),
|
|
749
|
-
role: 'assistant',
|
|
750
|
-
content: '',
|
|
751
|
-
parts: [],
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
let currentTextPart: TextUIPart | undefined = undefined;
|
|
755
|
-
let currentReasoningPart: ReasoningUIPart | undefined = undefined;
|
|
756
|
-
let currentReasoningTextDetail: { type: 'text'; text: string; signature?: string } | undefined = undefined;
|
|
757
|
-
|
|
758
|
-
function updateToolInvocationPart(toolCallId: string, invocation: ToolInvocation) {
|
|
759
|
-
const part = message.parts.find(
|
|
760
|
-
part => part.type === 'tool-invocation' && part.toolInvocation.toolCallId === toolCallId,
|
|
761
|
-
) as ToolInvocationUIPart | undefined;
|
|
762
|
-
|
|
763
|
-
if (part != null) {
|
|
764
|
-
part.toolInvocation = invocation;
|
|
765
|
-
} else {
|
|
766
|
-
message.parts.push({
|
|
767
|
-
type: 'tool-invocation',
|
|
768
|
-
toolInvocation: invocation,
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
const data: JSONValue[] = [];
|
|
774
|
-
|
|
775
|
-
// keep list of current message annotations for message
|
|
776
|
-
let messageAnnotations: JSONValue[] | undefined = replaceLastMessage ? lastMessage?.annotations : undefined;
|
|
777
|
-
|
|
778
|
-
// keep track of partial tool calls
|
|
779
|
-
const partialToolCalls: Record<string, { text: string; step: number; index: number; toolName: string }> = {};
|
|
780
|
-
|
|
781
|
-
let usage: any = {
|
|
782
|
-
completionTokens: NaN,
|
|
783
|
-
promptTokens: NaN,
|
|
784
|
-
totalTokens: NaN,
|
|
785
|
-
};
|
|
786
|
-
let finishReason: string = 'unknown';
|
|
787
|
-
|
|
788
|
-
function execUpdate() {
|
|
789
|
-
// make a copy of the data array to ensure UI is updated (SWR)
|
|
790
|
-
const copiedData = [...data];
|
|
791
|
-
|
|
792
|
-
// keeps the currentMessage up to date with the latest annotations,
|
|
793
|
-
// even if annotations preceded the message creation
|
|
794
|
-
if (messageAnnotations?.length) {
|
|
795
|
-
message.annotations = messageAnnotations;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
const copiedMessage = {
|
|
799
|
-
// deep copy the message to ensure that deep changes (msg attachments) are updated
|
|
800
|
-
// with SolidJS. SolidJS uses referential integration of sub-objects to detect changes.
|
|
801
|
-
...structuredClone(message),
|
|
802
|
-
// add a revision id to ensure that the message is updated with SWR. SWR uses a
|
|
803
|
-
// hashing approach by default to detect changes, but it only works for shallow
|
|
804
|
-
// changes. This is why we need to add a revision id to ensure that the message
|
|
805
|
-
// is updated with SWR (without it, the changes get stuck in SWR and are not
|
|
806
|
-
// forwarded to rendering):
|
|
807
|
-
revisionId: uuid(),
|
|
808
|
-
} as UIMessage;
|
|
809
|
-
|
|
810
|
-
update({
|
|
811
|
-
message: copiedMessage,
|
|
812
|
-
data: copiedData,
|
|
813
|
-
replaceLastMessage,
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
await processMastraStream({
|
|
818
|
-
stream,
|
|
819
|
-
// TODO: casting as any here because the stream types were all typed as any before in core.
|
|
820
|
-
// but this is completely wrong and this fn is probably broken. Remove ":any" and you'll see a bunch of type errors
|
|
821
|
-
onChunk: async (chunk: any) => {
|
|
822
|
-
switch (chunk.type) {
|
|
823
|
-
case 'step-start': {
|
|
824
|
-
// keep message id stable when we are updating an existing message:
|
|
825
|
-
if (!replaceLastMessage) {
|
|
826
|
-
message.id = chunk.payload.messageId;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// add a step boundary part to the message
|
|
830
|
-
message.parts.push({ type: 'step-start' });
|
|
831
|
-
execUpdate();
|
|
832
|
-
break;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
case 'text-delta': {
|
|
836
|
-
if (currentTextPart == null) {
|
|
837
|
-
currentTextPart = {
|
|
838
|
-
type: 'text',
|
|
839
|
-
text: chunk.payload.text,
|
|
840
|
-
};
|
|
841
|
-
message.parts.push(currentTextPart);
|
|
842
|
-
} else {
|
|
843
|
-
currentTextPart.text += chunk.payload.text;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
message.content += chunk.payload.text;
|
|
847
|
-
execUpdate();
|
|
848
|
-
break;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
case 'reasoning-delta': {
|
|
852
|
-
if (currentReasoningTextDetail == null) {
|
|
853
|
-
currentReasoningTextDetail = { type: 'text', text: chunk.payload.text };
|
|
854
|
-
if (currentReasoningPart != null) {
|
|
855
|
-
currentReasoningPart.details.push(currentReasoningTextDetail);
|
|
856
|
-
}
|
|
857
|
-
} else {
|
|
858
|
-
currentReasoningTextDetail.text += chunk.payload.text;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
if (currentReasoningPart == null) {
|
|
862
|
-
currentReasoningPart = {
|
|
863
|
-
type: 'reasoning',
|
|
864
|
-
reasoning: chunk.payload.text,
|
|
865
|
-
details: [currentReasoningTextDetail],
|
|
866
|
-
};
|
|
867
|
-
message.parts.push(currentReasoningPart);
|
|
868
|
-
} else {
|
|
869
|
-
currentReasoningPart.reasoning += chunk.payload.text;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
message.reasoning = (message.reasoning ?? '') + chunk.payload.text;
|
|
873
|
-
|
|
874
|
-
execUpdate();
|
|
875
|
-
break;
|
|
876
|
-
}
|
|
877
|
-
case 'file': {
|
|
878
|
-
message.parts.push({
|
|
879
|
-
type: 'file',
|
|
880
|
-
mimeType: chunk.payload.mimeType,
|
|
881
|
-
data: chunk.payload.data,
|
|
882
|
-
});
|
|
883
|
-
|
|
884
|
-
execUpdate();
|
|
885
|
-
break;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
case 'source': {
|
|
889
|
-
message.parts.push({
|
|
890
|
-
type: 'source',
|
|
891
|
-
source: chunk.payload.source,
|
|
892
|
-
});
|
|
893
|
-
execUpdate();
|
|
894
|
-
break;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
case 'tool-call': {
|
|
898
|
-
const invocation = {
|
|
899
|
-
state: 'call',
|
|
900
|
-
step,
|
|
901
|
-
...chunk.payload,
|
|
902
|
-
} as const;
|
|
903
|
-
|
|
904
|
-
if (partialToolCalls[chunk.payload.toolCallId] != null) {
|
|
905
|
-
// change the partial tool call to a full tool call
|
|
906
|
-
message.toolInvocations![partialToolCalls[chunk.payload.toolCallId]!.index] =
|
|
907
|
-
invocation as ToolInvocation;
|
|
908
|
-
} else {
|
|
909
|
-
if (message.toolInvocations == null) {
|
|
910
|
-
message.toolInvocations = [];
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
message.toolInvocations.push(invocation as ToolInvocation);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
updateToolInvocationPart(chunk.payload.toolCallId, invocation as ToolInvocation);
|
|
917
|
-
|
|
918
|
-
execUpdate();
|
|
919
|
-
|
|
920
|
-
// invoke the onToolCall callback if it exists. This is blocking.
|
|
921
|
-
// In the future we should make this non-blocking, which
|
|
922
|
-
// requires additional state management for error handling etc.
|
|
923
|
-
if (onToolCall) {
|
|
924
|
-
const result = await onToolCall({ toolCall: chunk.payload as any });
|
|
925
|
-
if (result != null) {
|
|
926
|
-
const invocation = {
|
|
927
|
-
state: 'result',
|
|
928
|
-
step,
|
|
929
|
-
...chunk.payload,
|
|
930
|
-
result,
|
|
931
|
-
} as const;
|
|
932
|
-
|
|
933
|
-
// store the result in the tool invocation
|
|
934
|
-
message.toolInvocations![message.toolInvocations!.length - 1] = invocation as ToolInvocation;
|
|
935
|
-
|
|
936
|
-
updateToolInvocationPart(chunk.payload.toolCallId, invocation as ToolInvocation);
|
|
937
|
-
|
|
938
|
-
execUpdate();
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
case 'tool-call-input-streaming-start': {
|
|
944
|
-
if (message.toolInvocations == null) {
|
|
945
|
-
message.toolInvocations = [];
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
// add the partial tool call to the map
|
|
949
|
-
partialToolCalls[chunk.payload.toolCallId] = {
|
|
950
|
-
text: '',
|
|
951
|
-
step,
|
|
952
|
-
toolName: chunk.payload.toolName,
|
|
953
|
-
index: message.toolInvocations.length,
|
|
954
|
-
};
|
|
955
|
-
|
|
956
|
-
const invocation = {
|
|
957
|
-
state: 'partial-call',
|
|
958
|
-
step,
|
|
959
|
-
toolCallId: chunk.payload.toolCallId,
|
|
960
|
-
toolName: chunk.payload.toolName,
|
|
961
|
-
args: undefined,
|
|
962
|
-
} as const;
|
|
963
|
-
|
|
964
|
-
message.toolInvocations.push(invocation as ToolInvocation);
|
|
965
|
-
|
|
966
|
-
updateToolInvocationPart(chunk.payload.toolCallId, invocation);
|
|
967
|
-
|
|
968
|
-
execUpdate();
|
|
969
|
-
break;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
case 'tool-call-delta': {
|
|
973
|
-
const partialToolCall = partialToolCalls[chunk.payload.toolCallId];
|
|
974
|
-
|
|
975
|
-
partialToolCall!.text += chunk.payload.argsTextDelta;
|
|
976
|
-
|
|
977
|
-
const { value: partialArgs } = parsePartialJson(partialToolCall!.text);
|
|
978
|
-
|
|
979
|
-
const invocation = {
|
|
980
|
-
state: 'partial-call',
|
|
981
|
-
step: partialToolCall!.step,
|
|
982
|
-
toolCallId: chunk.payload.toolCallId,
|
|
983
|
-
toolName: partialToolCall!.toolName,
|
|
984
|
-
args: partialArgs,
|
|
985
|
-
} as const;
|
|
986
|
-
|
|
987
|
-
message.toolInvocations![partialToolCall!.index] = invocation as ToolInvocation;
|
|
988
|
-
|
|
989
|
-
updateToolInvocationPart(chunk.payload.toolCallId, invocation);
|
|
990
|
-
|
|
991
|
-
execUpdate();
|
|
992
|
-
break;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
case 'tool-result': {
|
|
996
|
-
const toolInvocations = message.toolInvocations;
|
|
997
|
-
|
|
998
|
-
if (toolInvocations == null) {
|
|
999
|
-
throw new Error('tool_result must be preceded by a tool_call');
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
// find if there is any tool invocation with the same toolCallId
|
|
1003
|
-
// and replace it with the result
|
|
1004
|
-
const toolInvocationIndex = toolInvocations.findIndex(
|
|
1005
|
-
invocation => invocation.toolCallId === chunk.payload.toolCallId,
|
|
1006
|
-
);
|
|
1007
|
-
|
|
1008
|
-
if (toolInvocationIndex === -1) {
|
|
1009
|
-
throw new Error('tool_result must be preceded by a tool_call with the same toolCallId');
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
const invocation = {
|
|
1013
|
-
...toolInvocations[toolInvocationIndex],
|
|
1014
|
-
state: 'result' as const,
|
|
1015
|
-
...chunk.payload,
|
|
1016
|
-
} as const;
|
|
1017
|
-
|
|
1018
|
-
toolInvocations[toolInvocationIndex] = invocation as ToolInvocation;
|
|
1019
|
-
|
|
1020
|
-
updateToolInvocationPart(chunk.payload.toolCallId, invocation as ToolInvocation);
|
|
1021
|
-
|
|
1022
|
-
execUpdate();
|
|
1023
|
-
break;
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
case 'error': {
|
|
1027
|
-
throw new Error(chunk.payload.error);
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
case 'data': {
|
|
1031
|
-
data.push(...chunk.payload.data);
|
|
1032
|
-
execUpdate();
|
|
1033
|
-
break;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
case 'step-finish': {
|
|
1037
|
-
step += 1;
|
|
1038
|
-
|
|
1039
|
-
// reset the current text and reasoning parts
|
|
1040
|
-
currentTextPart = chunk.payload.isContinued ? currentTextPart : undefined;
|
|
1041
|
-
currentReasoningPart = undefined;
|
|
1042
|
-
currentReasoningTextDetail = undefined;
|
|
1043
|
-
|
|
1044
|
-
execUpdate();
|
|
1045
|
-
break;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
case 'finish': {
|
|
1049
|
-
finishReason = chunk.payload.finishReason;
|
|
1050
|
-
if (chunk.payload.usage != null) {
|
|
1051
|
-
// usage = calculateLanguageModelUsage(value.usage);
|
|
1052
|
-
usage = chunk.payload.usage;
|
|
1053
|
-
}
|
|
1054
|
-
break;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
},
|
|
1058
|
-
});
|
|
1059
|
-
|
|
1060
|
-
onFinish?.({ message, finishReason, usage });
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
async processStreamResponse_vNext(processedParams: any, writable: any) {
|
|
1064
|
-
const response: Response = await this.request(`/api/agents/${this.agentId}/stream/vnext`, {
|
|
1065
|
-
method: 'POST',
|
|
1066
|
-
body: processedParams,
|
|
1067
|
-
stream: true,
|
|
1068
|
-
});
|
|
1069
|
-
|
|
1070
|
-
if (!response.body) {
|
|
1071
|
-
throw new Error('No response body');
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
try {
|
|
1075
|
-
let toolCalls: ToolInvocation[] = [];
|
|
1076
|
-
let messages: UIMessage[] = [];
|
|
1077
|
-
|
|
1078
|
-
// Use tee() to split the stream into two branches
|
|
1079
|
-
const [streamForWritable, streamForProcessing] = response.body.tee();
|
|
1080
|
-
|
|
1081
|
-
// Pipe one branch to the writable stream
|
|
1082
|
-
streamForWritable
|
|
1083
|
-
.pipeTo(writable, {
|
|
1084
|
-
preventClose: true,
|
|
1085
|
-
})
|
|
1086
|
-
.catch(error => {
|
|
1087
|
-
console.error('Error piping to writable stream:', error);
|
|
1088
|
-
});
|
|
1089
|
-
|
|
1090
|
-
// Process the other branch for chat response handling
|
|
1091
|
-
this.processChatResponse_vNext({
|
|
1092
|
-
stream: streamForProcessing,
|
|
1093
|
-
update: ({ message }) => {
|
|
1094
|
-
const existingIndex = messages.findIndex(m => m.id === message.id);
|
|
1095
|
-
|
|
1096
|
-
if (existingIndex !== -1) {
|
|
1097
|
-
messages[existingIndex] = message;
|
|
1098
|
-
} else {
|
|
1099
|
-
messages.push(message);
|
|
1100
|
-
}
|
|
1101
|
-
},
|
|
1102
|
-
onFinish: async ({ finishReason, message }) => {
|
|
1103
|
-
if (finishReason === 'tool-calls') {
|
|
1104
|
-
const toolCall = [...(message?.parts ?? [])]
|
|
1105
|
-
.reverse()
|
|
1106
|
-
.find(part => part.type === 'tool-invocation')?.toolInvocation;
|
|
1107
|
-
if (toolCall) {
|
|
1108
|
-
toolCalls.push(toolCall);
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
// Handle tool calls if needed
|
|
1112
|
-
for (const toolCall of toolCalls) {
|
|
1113
|
-
const clientTool = processedParams.clientTools?.[toolCall.toolName] as Tool;
|
|
1114
|
-
if (clientTool && clientTool.execute) {
|
|
1115
|
-
const result = await clientTool.execute(
|
|
1116
|
-
{
|
|
1117
|
-
context: toolCall?.args,
|
|
1118
|
-
runId: processedParams.runId,
|
|
1119
|
-
resourceId: processedParams.resourceId,
|
|
1120
|
-
threadId: processedParams.threadId,
|
|
1121
|
-
runtimeContext: processedParams.runtimeContext as RuntimeContext,
|
|
1122
|
-
// TODO: Pass proper tracing context when client-js supports tracing
|
|
1123
|
-
tracingContext: { currentSpan: undefined },
|
|
1124
|
-
},
|
|
1125
|
-
{
|
|
1126
|
-
messages: (response as unknown as { messages: CoreMessage[] }).messages,
|
|
1127
|
-
toolCallId: toolCall?.toolCallId,
|
|
1128
|
-
},
|
|
1129
|
-
);
|
|
1130
|
-
|
|
1131
|
-
const lastMessage: UIMessage = JSON.parse(JSON.stringify(messages[messages.length - 1]));
|
|
1132
|
-
|
|
1133
|
-
const toolInvocationPart = lastMessage?.parts?.find(
|
|
1134
|
-
part => part.type === 'tool-invocation' && part.toolInvocation?.toolCallId === toolCall.toolCallId,
|
|
1135
|
-
) as ToolInvocationUIPart | undefined;
|
|
1136
|
-
|
|
1137
|
-
if (toolInvocationPart) {
|
|
1138
|
-
toolInvocationPart.toolInvocation = {
|
|
1139
|
-
...toolInvocationPart.toolInvocation,
|
|
1140
|
-
state: 'result',
|
|
1141
|
-
result,
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
const toolInvocation = lastMessage?.toolInvocations?.find(
|
|
1146
|
-
toolInvocation => toolInvocation.toolCallId === toolCall.toolCallId,
|
|
1147
|
-
) as ToolInvocation | undefined;
|
|
1148
|
-
|
|
1149
|
-
if (toolInvocation) {
|
|
1150
|
-
toolInvocation.state = 'result';
|
|
1151
|
-
// @ts-ignore
|
|
1152
|
-
toolInvocation.result = result;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
// write the tool result part to the stream
|
|
1156
|
-
const writer = writable.getWriter();
|
|
1157
|
-
|
|
1158
|
-
try {
|
|
1159
|
-
await writer.write(
|
|
1160
|
-
new TextEncoder().encode(
|
|
1161
|
-
'a:' +
|
|
1162
|
-
JSON.stringify({
|
|
1163
|
-
toolCallId: toolCall.toolCallId,
|
|
1164
|
-
result,
|
|
1165
|
-
}) +
|
|
1166
|
-
'\n',
|
|
1167
|
-
),
|
|
1168
|
-
);
|
|
1169
|
-
} finally {
|
|
1170
|
-
writer.releaseLock();
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
// Convert messages to the correct format for the recursive call
|
|
1174
|
-
const originalMessages = processedParams.messages;
|
|
1175
|
-
const messageArray = Array.isArray(originalMessages) ? originalMessages : [originalMessages];
|
|
1176
|
-
|
|
1177
|
-
// Recursively call stream with updated messages
|
|
1178
|
-
this.processStreamResponse_vNext(
|
|
1179
|
-
{
|
|
1180
|
-
...processedParams,
|
|
1181
|
-
messages: [...messageArray, ...messages.filter(m => m.id !== lastMessage.id), lastMessage],
|
|
1182
|
-
},
|
|
1183
|
-
writable,
|
|
1184
|
-
).catch(error => {
|
|
1185
|
-
console.error('Error processing stream response:', error);
|
|
1186
|
-
});
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
} else {
|
|
1190
|
-
setTimeout(() => {
|
|
1191
|
-
writable.close();
|
|
1192
|
-
}, 0);
|
|
1193
|
-
}
|
|
1194
|
-
},
|
|
1195
|
-
lastMessage: undefined,
|
|
1196
|
-
}).catch(error => {
|
|
1197
|
-
console.error('Error processing stream response:', error);
|
|
1198
|
-
});
|
|
1199
|
-
} catch (error) {
|
|
1200
|
-
console.error('Error processing stream response:', error);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
return response;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
async streamVNext<T extends OutputSchema | undefined = undefined>(
|
|
1207
|
-
params: StreamVNextParams<T>,
|
|
1208
|
-
): Promise<
|
|
1209
|
-
Response & {
|
|
1210
|
-
processDataStream: ({
|
|
1211
|
-
onChunk,
|
|
1212
|
-
}: {
|
|
1213
|
-
onChunk: Parameters<typeof processMastraStream>[0]['onChunk'];
|
|
1214
|
-
}) => Promise<void>;
|
|
1215
|
-
}
|
|
1216
|
-
> {
|
|
1217
|
-
const processedParams = {
|
|
1218
|
-
...params,
|
|
1219
|
-
output: params.output ? zodToJsonSchema(params.output) : undefined,
|
|
1220
|
-
runtimeContext: parseClientRuntimeContext(params.runtimeContext),
|
|
1221
|
-
clientTools: processClientTools(params.clientTools),
|
|
1222
|
-
};
|
|
1223
|
-
|
|
1224
|
-
// Create a readable stream that will handle the response processing
|
|
1225
|
-
const { readable, writable } = new TransformStream<Uint8Array, Uint8Array>();
|
|
1226
|
-
|
|
1227
|
-
// Start processing the response in the background
|
|
1228
|
-
const response = await this.processStreamResponse_vNext(processedParams, writable);
|
|
1229
|
-
|
|
1230
|
-
// Create a new response with the readable stream
|
|
1231
|
-
const streamResponse = new Response(readable, {
|
|
1232
|
-
status: response.status,
|
|
1233
|
-
statusText: response.statusText,
|
|
1234
|
-
headers: response.headers,
|
|
1235
|
-
}) as Response & {
|
|
1236
|
-
processDataStream: ({
|
|
1237
|
-
onChunk,
|
|
1238
|
-
}: {
|
|
1239
|
-
onChunk: Parameters<typeof processMastraStream>[0]['onChunk'];
|
|
1240
|
-
}) => Promise<void>;
|
|
1241
|
-
};
|
|
1242
|
-
|
|
1243
|
-
// Add the processDataStream method to the response
|
|
1244
|
-
streamResponse.processDataStream = async ({
|
|
1245
|
-
onChunk,
|
|
1246
|
-
}: {
|
|
1247
|
-
onChunk: Parameters<typeof processMastraStream>[0]['onChunk'];
|
|
1248
|
-
}) => {
|
|
1249
|
-
await processMastraStream({
|
|
1250
|
-
stream: streamResponse.body as ReadableStream<Uint8Array>,
|
|
1251
|
-
onChunk,
|
|
1252
|
-
});
|
|
1253
|
-
};
|
|
1254
|
-
|
|
1255
|
-
return streamResponse;
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
/**
|
|
1259
|
-
* Processes the stream response and handles tool calls
|
|
1260
|
-
*/
|
|
1261
|
-
private async processStreamResponse(processedParams: any, writable: WritableStream<Uint8Array>) {
|
|
1262
|
-
const response: Response & {
|
|
1263
|
-
processDataStream: (options?: Omit<Parameters<typeof processDataStream>[0], 'stream'>) => Promise<void>;
|
|
1264
|
-
} = await this.request(`/api/agents/${this.agentId}/stream`, {
|
|
1265
|
-
method: 'POST',
|
|
1266
|
-
body: processedParams,
|
|
1267
|
-
stream: true,
|
|
1268
|
-
});
|
|
1269
|
-
|
|
1270
|
-
if (!response.body) {
|
|
1271
|
-
throw new Error('No response body');
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
try {
|
|
1275
|
-
let toolCalls: ToolInvocation[] = [];
|
|
1276
|
-
let messages: UIMessage[] = [];
|
|
1277
|
-
|
|
1278
|
-
// Use tee() to split the stream into two branches
|
|
1279
|
-
const [streamForWritable, streamForProcessing] = response.body.tee();
|
|
1280
|
-
|
|
1281
|
-
// Pipe one branch to the writable stream
|
|
1282
|
-
streamForWritable
|
|
1283
|
-
.pipeTo(writable, {
|
|
1284
|
-
preventClose: true,
|
|
1285
|
-
})
|
|
1286
|
-
.catch(error => {
|
|
1287
|
-
console.error('Error piping to writable stream:', error);
|
|
1288
|
-
});
|
|
1289
|
-
|
|
1290
|
-
// Process the other branch for chat response handling
|
|
1291
|
-
this.processChatResponse({
|
|
1292
|
-
stream: streamForProcessing,
|
|
1293
|
-
update: ({ message }) => {
|
|
1294
|
-
const existingIndex = messages.findIndex(m => m.id === message.id);
|
|
1295
|
-
|
|
1296
|
-
if (existingIndex !== -1) {
|
|
1297
|
-
messages[existingIndex] = message;
|
|
1298
|
-
} else {
|
|
1299
|
-
messages.push(message);
|
|
1300
|
-
}
|
|
1301
|
-
},
|
|
1302
|
-
onFinish: async ({ finishReason, message }) => {
|
|
1303
|
-
if (finishReason === 'tool-calls') {
|
|
1304
|
-
const toolCall = [...(message?.parts ?? [])]
|
|
1305
|
-
.reverse()
|
|
1306
|
-
.find(part => part.type === 'tool-invocation')?.toolInvocation;
|
|
1307
|
-
if (toolCall) {
|
|
1308
|
-
toolCalls.push(toolCall);
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
// Handle tool calls if needed
|
|
1312
|
-
for (const toolCall of toolCalls) {
|
|
1313
|
-
const clientTool = processedParams.clientTools?.[toolCall.toolName] as Tool;
|
|
1314
|
-
if (clientTool && clientTool.execute) {
|
|
1315
|
-
const result = await clientTool.execute(
|
|
1316
|
-
{
|
|
1317
|
-
context: toolCall?.args,
|
|
1318
|
-
runId: processedParams.runId,
|
|
1319
|
-
resourceId: processedParams.resourceId,
|
|
1320
|
-
threadId: processedParams.threadId,
|
|
1321
|
-
runtimeContext: processedParams.runtimeContext as RuntimeContext,
|
|
1322
|
-
// TODO: Pass proper tracing context when client-js supports tracing
|
|
1323
|
-
tracingContext: { currentSpan: undefined },
|
|
1324
|
-
},
|
|
1325
|
-
{
|
|
1326
|
-
messages: (response as unknown as { messages: CoreMessage[] }).messages,
|
|
1327
|
-
toolCallId: toolCall?.toolCallId,
|
|
1328
|
-
},
|
|
1329
|
-
);
|
|
1330
|
-
|
|
1331
|
-
const lastMessage: UIMessage = JSON.parse(JSON.stringify(messages[messages.length - 1]));
|
|
1332
|
-
|
|
1333
|
-
const toolInvocationPart = lastMessage?.parts?.find(
|
|
1334
|
-
part => part.type === 'tool-invocation' && part.toolInvocation?.toolCallId === toolCall.toolCallId,
|
|
1335
|
-
) as ToolInvocationUIPart | undefined;
|
|
1336
|
-
|
|
1337
|
-
if (toolInvocationPart) {
|
|
1338
|
-
toolInvocationPart.toolInvocation = {
|
|
1339
|
-
...toolInvocationPart.toolInvocation,
|
|
1340
|
-
state: 'result',
|
|
1341
|
-
result,
|
|
1342
|
-
};
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
const toolInvocation = lastMessage?.toolInvocations?.find(
|
|
1346
|
-
toolInvocation => toolInvocation.toolCallId === toolCall.toolCallId,
|
|
1347
|
-
) as ToolInvocation | undefined;
|
|
1348
|
-
|
|
1349
|
-
if (toolInvocation) {
|
|
1350
|
-
toolInvocation.state = 'result';
|
|
1351
|
-
// @ts-ignore
|
|
1352
|
-
toolInvocation.result = result;
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
// write the tool result part to the stream
|
|
1356
|
-
const writer = writable.getWriter();
|
|
1357
|
-
|
|
1358
|
-
try {
|
|
1359
|
-
await writer.write(
|
|
1360
|
-
new TextEncoder().encode(
|
|
1361
|
-
'a:' +
|
|
1362
|
-
JSON.stringify({
|
|
1363
|
-
toolCallId: toolCall.toolCallId,
|
|
1364
|
-
result,
|
|
1365
|
-
}) +
|
|
1366
|
-
'\n',
|
|
1367
|
-
),
|
|
1368
|
-
);
|
|
1369
|
-
} finally {
|
|
1370
|
-
writer.releaseLock();
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
// Convert messages to the correct format for the recursive call
|
|
1374
|
-
const originalMessages = processedParams.messages;
|
|
1375
|
-
const messageArray = Array.isArray(originalMessages) ? originalMessages : [originalMessages];
|
|
1376
|
-
|
|
1377
|
-
// Recursively call stream with updated messages
|
|
1378
|
-
this.processStreamResponse(
|
|
1379
|
-
{
|
|
1380
|
-
...processedParams,
|
|
1381
|
-
messages: [...messageArray, ...messages.filter(m => m.id !== lastMessage.id), lastMessage],
|
|
1382
|
-
},
|
|
1383
|
-
writable,
|
|
1384
|
-
).catch(error => {
|
|
1385
|
-
console.error('Error processing stream response:', error);
|
|
1386
|
-
});
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
} else {
|
|
1390
|
-
setTimeout(() => {
|
|
1391
|
-
// We can't close the stream in this function, we have to wait until it's done
|
|
1392
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1393
|
-
writable.close();
|
|
1394
|
-
}, 0);
|
|
1395
|
-
}
|
|
1396
|
-
},
|
|
1397
|
-
lastMessage: undefined,
|
|
1398
|
-
}).catch(error => {
|
|
1399
|
-
console.error('Error processing stream response:', error);
|
|
1400
|
-
});
|
|
1401
|
-
} catch (error) {
|
|
1402
|
-
console.error('Error processing stream response:', error);
|
|
1403
|
-
}
|
|
1404
|
-
return response;
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
/**
|
|
1408
|
-
* Gets details about a specific tool available to the agent
|
|
1409
|
-
* @param toolId - ID of the tool to retrieve
|
|
1410
|
-
* @returns Promise containing tool details
|
|
1411
|
-
*/
|
|
1412
|
-
getTool(toolId: string): Promise<GetToolResponse> {
|
|
1413
|
-
return this.request(`/api/agents/${this.agentId}/tools/${toolId}`);
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
/**
|
|
1417
|
-
* Executes a tool for the agent
|
|
1418
|
-
* @param toolId - ID of the tool to execute
|
|
1419
|
-
* @param params - Parameters required for tool execution
|
|
1420
|
-
* @returns Promise containing the tool execution results
|
|
1421
|
-
*/
|
|
1422
|
-
executeTool(toolId: string, params: { data: any; runtimeContext?: RuntimeContext }): Promise<any> {
|
|
1423
|
-
const body = {
|
|
1424
|
-
data: params.data,
|
|
1425
|
-
runtimeContext: params.runtimeContext ? Object.fromEntries(params.runtimeContext.entries()) : undefined,
|
|
1426
|
-
};
|
|
1427
|
-
return this.request(`/api/agents/${this.agentId}/tools/${toolId}/execute`, {
|
|
1428
|
-
method: 'POST',
|
|
1429
|
-
body,
|
|
1430
|
-
});
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
/**
|
|
1434
|
-
* Retrieves evaluation results for the agent
|
|
1435
|
-
* @returns Promise containing agent evaluations
|
|
1436
|
-
*/
|
|
1437
|
-
evals(): Promise<GetEvalsByAgentIdResponse> {
|
|
1438
|
-
return this.request(`/api/agents/${this.agentId}/evals/ci`);
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
/**
|
|
1442
|
-
* Retrieves live evaluation results for the agent
|
|
1443
|
-
* @returns Promise containing live agent evaluations
|
|
1444
|
-
*/
|
|
1445
|
-
liveEvals(): Promise<GetEvalsByAgentIdResponse> {
|
|
1446
|
-
return this.request(`/api/agents/${this.agentId}/evals/live`);
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
/**
|
|
1450
|
-
* Updates the model for the agent
|
|
1451
|
-
* @param params - Parameters for updating the model
|
|
1452
|
-
* @returns Promise containing the updated model
|
|
1453
|
-
*/
|
|
1454
|
-
updateModel(params: UpdateModelParams): Promise<{ message: string }> {
|
|
1455
|
-
return this.request(`/api/agents/${this.agentId}/model`, {
|
|
1456
|
-
method: 'POST',
|
|
1457
|
-
body: params,
|
|
1458
|
-
});
|
|
1459
|
-
}
|
|
1460
|
-
}
|