@copilotkitnext/agent 0.0.0-max-changeset-20260109174803

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/dist/index.mjs ADDED
@@ -0,0 +1,606 @@
1
+ // src/index.ts
2
+ import {
3
+ AbstractAgent,
4
+ EventType
5
+ } from "@ag-ui/client";
6
+ import {
7
+ streamText,
8
+ tool as createVercelAISDKTool,
9
+ stepCountIs
10
+ } from "ai";
11
+ import { experimental_createMCPClient as createMCPClient } from "@ai-sdk/mcp";
12
+ import { Observable } from "rxjs";
13
+ import { createOpenAI } from "@ai-sdk/openai";
14
+ import { createAnthropic } from "@ai-sdk/anthropic";
15
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
16
+ import { randomUUID } from "crypto";
17
+ import { z } from "zod";
18
+ import {
19
+ StreamableHTTPClientTransport
20
+ } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
21
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
22
+ function resolveModel(spec) {
23
+ if (typeof spec !== "string") {
24
+ return spec;
25
+ }
26
+ const normalized = spec.replace("/", ":").trim();
27
+ const parts = normalized.split(":");
28
+ const rawProvider = parts[0];
29
+ const rest = parts.slice(1);
30
+ if (!rawProvider) {
31
+ throw new Error(
32
+ `Invalid model string "${spec}". Use "openai/gpt-5", "anthropic/claude-sonnet-4.5", or "google/gemini-2.5-pro".`
33
+ );
34
+ }
35
+ const provider = rawProvider.toLowerCase();
36
+ const model = rest.join(":").trim();
37
+ if (!model) {
38
+ throw new Error(
39
+ `Invalid model string "${spec}". Use "openai/gpt-5", "anthropic/claude-sonnet-4.5", or "google/gemini-2.5-pro".`
40
+ );
41
+ }
42
+ switch (provider) {
43
+ case "openai": {
44
+ const openai = createOpenAI({
45
+ apiKey: process.env.OPENAI_API_KEY
46
+ });
47
+ return openai(model);
48
+ }
49
+ case "anthropic": {
50
+ const anthropic = createAnthropic({
51
+ apiKey: process.env.ANTHROPIC_API_KEY
52
+ });
53
+ return anthropic(model);
54
+ }
55
+ case "google":
56
+ case "gemini":
57
+ case "google-gemini": {
58
+ const google = createGoogleGenerativeAI({
59
+ apiKey: process.env.GOOGLE_API_KEY
60
+ });
61
+ return google(model);
62
+ }
63
+ default:
64
+ throw new Error(`Unknown provider "${provider}" in "${spec}". Supported: openai, anthropic, google (gemini).`);
65
+ }
66
+ }
67
+ function defineTool(config) {
68
+ return {
69
+ name: config.name,
70
+ description: config.description,
71
+ parameters: config.parameters,
72
+ execute: config.execute
73
+ };
74
+ }
75
+ function flattenUserMessageContent(content) {
76
+ if (!content) {
77
+ return "";
78
+ }
79
+ if (typeof content === "string") {
80
+ return content;
81
+ }
82
+ return content.map((part) => {
83
+ if (part && typeof part === "object" && "type" in part && part.type === "text" && typeof part.text === "string") {
84
+ return part.text;
85
+ }
86
+ return "";
87
+ }).filter((text) => text.length > 0).join("\n");
88
+ }
89
+ function convertMessagesToVercelAISDKMessages(messages) {
90
+ const result = [];
91
+ for (const message of messages) {
92
+ if (message.role === "assistant") {
93
+ const parts = message.content ? [{ type: "text", text: message.content }] : [];
94
+ for (const toolCall of message.toolCalls ?? []) {
95
+ const toolCallPart = {
96
+ type: "tool-call",
97
+ toolCallId: toolCall.id,
98
+ toolName: toolCall.function.name,
99
+ input: JSON.parse(toolCall.function.arguments)
100
+ };
101
+ parts.push(toolCallPart);
102
+ }
103
+ const assistantMsg = {
104
+ role: "assistant",
105
+ content: parts
106
+ };
107
+ result.push(assistantMsg);
108
+ } else if (message.role === "user") {
109
+ const userMsg = {
110
+ role: "user",
111
+ content: flattenUserMessageContent(message.content)
112
+ };
113
+ result.push(userMsg);
114
+ } else if (message.role === "tool") {
115
+ let toolName = "unknown";
116
+ for (const msg of messages) {
117
+ if (msg.role === "assistant") {
118
+ for (const toolCall of msg.toolCalls ?? []) {
119
+ if (toolCall.id === message.toolCallId) {
120
+ toolName = toolCall.function.name;
121
+ break;
122
+ }
123
+ }
124
+ }
125
+ }
126
+ const toolResultPart = {
127
+ type: "tool-result",
128
+ toolCallId: message.toolCallId,
129
+ toolName,
130
+ output: {
131
+ type: "text",
132
+ value: message.content
133
+ }
134
+ };
135
+ const toolMsg = {
136
+ role: "tool",
137
+ content: [toolResultPart]
138
+ };
139
+ result.push(toolMsg);
140
+ }
141
+ }
142
+ return result;
143
+ }
144
+ function convertJsonSchemaToZodSchema(jsonSchema, required) {
145
+ if (jsonSchema.type === "object") {
146
+ const spec = {};
147
+ if (!jsonSchema.properties || !Object.keys(jsonSchema.properties).length) {
148
+ return !required ? z.object(spec).optional() : z.object(spec);
149
+ }
150
+ for (const [key, value] of Object.entries(jsonSchema.properties)) {
151
+ spec[key] = convertJsonSchemaToZodSchema(value, jsonSchema.required ? jsonSchema.required.includes(key) : false);
152
+ }
153
+ let schema = z.object(spec).describe(jsonSchema.description ?? "");
154
+ return required ? schema : schema.optional();
155
+ } else if (jsonSchema.type === "string") {
156
+ let schema = z.string().describe(jsonSchema.description ?? "");
157
+ return required ? schema : schema.optional();
158
+ } else if (jsonSchema.type === "number") {
159
+ let schema = z.number().describe(jsonSchema.description ?? "");
160
+ return required ? schema : schema.optional();
161
+ } else if (jsonSchema.type === "boolean") {
162
+ let schema = z.boolean().describe(jsonSchema.description ?? "");
163
+ return required ? schema : schema.optional();
164
+ } else if (jsonSchema.type === "array") {
165
+ if (!jsonSchema.items) {
166
+ throw new Error("Array type must have items property");
167
+ }
168
+ let itemSchema = convertJsonSchemaToZodSchema(jsonSchema.items, true);
169
+ let schema = z.array(itemSchema).describe(jsonSchema.description ?? "");
170
+ return required ? schema : schema.optional();
171
+ }
172
+ throw new Error("Invalid JSON schema");
173
+ }
174
+ function isJsonSchema(obj) {
175
+ if (typeof obj !== "object" || obj === null) return false;
176
+ const schema = obj;
177
+ return typeof schema.type === "string" && ["object", "string", "number", "boolean", "array"].includes(schema.type);
178
+ }
179
+ function convertToolsToVercelAITools(tools) {
180
+ const result = {};
181
+ for (const tool of tools) {
182
+ if (!isJsonSchema(tool.parameters)) {
183
+ throw new Error(`Invalid JSON schema for tool ${tool.name}`);
184
+ }
185
+ const zodSchema = convertJsonSchemaToZodSchema(tool.parameters, true);
186
+ result[tool.name] = createVercelAISDKTool({
187
+ description: tool.description,
188
+ inputSchema: zodSchema
189
+ });
190
+ }
191
+ return result;
192
+ }
193
+ function convertToolDefinitionsToVercelAITools(tools) {
194
+ const result = {};
195
+ for (const tool of tools) {
196
+ result[tool.name] = createVercelAISDKTool({
197
+ description: tool.description,
198
+ inputSchema: tool.parameters,
199
+ execute: tool.execute
200
+ });
201
+ }
202
+ return result;
203
+ }
204
+ var BuiltInAgent = class _BuiltInAgent extends AbstractAgent {
205
+ constructor(config) {
206
+ super();
207
+ this.config = config;
208
+ }
209
+ abortController;
210
+ /**
211
+ * Check if a property can be overridden by forwardedProps
212
+ */
213
+ canOverride(property) {
214
+ return this.config?.overridableProperties?.includes(property) ?? false;
215
+ }
216
+ run(input) {
217
+ return new Observable((subscriber) => {
218
+ const startEvent = {
219
+ type: EventType.RUN_STARTED,
220
+ threadId: input.threadId,
221
+ runId: input.runId
222
+ };
223
+ subscriber.next(startEvent);
224
+ const model = resolveModel(this.config.model);
225
+ let systemPrompt = void 0;
226
+ const hasPrompt = !!this.config.prompt;
227
+ const hasContext = input.context && input.context.length > 0;
228
+ const hasState = input.state !== void 0 && input.state !== null && !(typeof input.state === "object" && Object.keys(input.state).length === 0);
229
+ if (hasPrompt || hasContext || hasState) {
230
+ const parts = [];
231
+ if (hasPrompt) {
232
+ parts.push(this.config.prompt);
233
+ }
234
+ if (hasContext) {
235
+ parts.push("\n## Context from the application\n");
236
+ for (const ctx of input.context) {
237
+ parts.push(`${ctx.description}:
238
+ ${ctx.value}
239
+ `);
240
+ }
241
+ }
242
+ if (hasState) {
243
+ parts.push(
244
+ `
245
+ ## Application State
246
+ This is state from the application that you can edit by calling AGUISendStateSnapshot or AGUISendStateDelta.
247
+ \`\`\`json
248
+ ${JSON.stringify(input.state, null, 2)}
249
+ \`\`\`
250
+ `
251
+ );
252
+ }
253
+ systemPrompt = parts.join("");
254
+ }
255
+ const messages = convertMessagesToVercelAISDKMessages(input.messages);
256
+ if (systemPrompt) {
257
+ messages.unshift({
258
+ role: "system",
259
+ content: systemPrompt
260
+ });
261
+ }
262
+ let allTools = convertToolsToVercelAITools(input.tools);
263
+ if (this.config.tools && this.config.tools.length > 0) {
264
+ const configTools = convertToolDefinitionsToVercelAITools(this.config.tools);
265
+ allTools = { ...allTools, ...configTools };
266
+ }
267
+ const streamTextParams = {
268
+ model,
269
+ messages,
270
+ tools: allTools,
271
+ toolChoice: this.config.toolChoice,
272
+ stopWhen: this.config.maxSteps ? stepCountIs(this.config.maxSteps) : void 0,
273
+ maxOutputTokens: this.config.maxOutputTokens,
274
+ temperature: this.config.temperature,
275
+ topP: this.config.topP,
276
+ topK: this.config.topK,
277
+ presencePenalty: this.config.presencePenalty,
278
+ frequencyPenalty: this.config.frequencyPenalty,
279
+ stopSequences: this.config.stopSequences,
280
+ seed: this.config.seed,
281
+ maxRetries: this.config.maxRetries
282
+ };
283
+ if (input.forwardedProps && typeof input.forwardedProps === "object") {
284
+ const props = input.forwardedProps;
285
+ if (props.model !== void 0 && this.canOverride("model")) {
286
+ if (typeof props.model === "string" || typeof props.model === "object") {
287
+ streamTextParams.model = resolveModel(props.model);
288
+ }
289
+ }
290
+ if (props.toolChoice !== void 0 && this.canOverride("toolChoice")) {
291
+ const toolChoice = props.toolChoice;
292
+ if (toolChoice === "auto" || toolChoice === "required" || toolChoice === "none" || typeof toolChoice === "object" && toolChoice !== null && "type" in toolChoice && toolChoice.type === "tool") {
293
+ streamTextParams.toolChoice = toolChoice;
294
+ }
295
+ }
296
+ if (typeof props.maxOutputTokens === "number" && this.canOverride("maxOutputTokens")) {
297
+ streamTextParams.maxOutputTokens = props.maxOutputTokens;
298
+ }
299
+ if (typeof props.temperature === "number" && this.canOverride("temperature")) {
300
+ streamTextParams.temperature = props.temperature;
301
+ }
302
+ if (typeof props.topP === "number" && this.canOverride("topP")) {
303
+ streamTextParams.topP = props.topP;
304
+ }
305
+ if (typeof props.topK === "number" && this.canOverride("topK")) {
306
+ streamTextParams.topK = props.topK;
307
+ }
308
+ if (typeof props.presencePenalty === "number" && this.canOverride("presencePenalty")) {
309
+ streamTextParams.presencePenalty = props.presencePenalty;
310
+ }
311
+ if (typeof props.frequencyPenalty === "number" && this.canOverride("frequencyPenalty")) {
312
+ streamTextParams.frequencyPenalty = props.frequencyPenalty;
313
+ }
314
+ if (Array.isArray(props.stopSequences) && this.canOverride("stopSequences")) {
315
+ if (props.stopSequences.every((item) => typeof item === "string")) {
316
+ streamTextParams.stopSequences = props.stopSequences;
317
+ }
318
+ }
319
+ if (typeof props.seed === "number" && this.canOverride("seed")) {
320
+ streamTextParams.seed = props.seed;
321
+ }
322
+ if (typeof props.maxRetries === "number" && this.canOverride("maxRetries")) {
323
+ streamTextParams.maxRetries = props.maxRetries;
324
+ }
325
+ }
326
+ const mcpClients = [];
327
+ (async () => {
328
+ const abortController = new AbortController();
329
+ this.abortController = abortController;
330
+ let terminalEventEmitted = false;
331
+ try {
332
+ streamTextParams.tools = {
333
+ ...streamTextParams.tools,
334
+ AGUISendStateSnapshot: createVercelAISDKTool({
335
+ description: "Replace the entire application state with a new snapshot",
336
+ inputSchema: z.object({
337
+ snapshot: z.any().describe("The complete new state object")
338
+ }),
339
+ execute: async ({ snapshot }) => {
340
+ return { success: true, snapshot };
341
+ }
342
+ }),
343
+ AGUISendStateDelta: createVercelAISDKTool({
344
+ description: "Apply incremental updates to application state using JSON Patch operations",
345
+ inputSchema: z.object({
346
+ delta: z.array(
347
+ z.object({
348
+ op: z.enum(["add", "replace", "remove"]).describe("The operation to perform"),
349
+ path: z.string().describe("JSON Pointer path (e.g., '/foo/bar')"),
350
+ value: z.any().optional().describe(
351
+ "The value to set. Required for 'add' and 'replace' operations, ignored for 'remove'."
352
+ )
353
+ })
354
+ ).describe("Array of JSON Patch operations")
355
+ }),
356
+ execute: async ({ delta }) => {
357
+ return { success: true, delta };
358
+ }
359
+ })
360
+ };
361
+ if (this.config.mcpServers && this.config.mcpServers.length > 0) {
362
+ for (const serverConfig of this.config.mcpServers) {
363
+ let transport;
364
+ if (serverConfig.type === "http") {
365
+ const url = new URL(serverConfig.url);
366
+ transport = new StreamableHTTPClientTransport(url, serverConfig.options);
367
+ } else if (serverConfig.type === "sse") {
368
+ transport = new SSEClientTransport(new URL(serverConfig.url), serverConfig.headers);
369
+ }
370
+ if (transport) {
371
+ const mcpClient = await createMCPClient({ transport });
372
+ mcpClients.push(mcpClient);
373
+ const mcpTools = await mcpClient.tools();
374
+ streamTextParams.tools = { ...streamTextParams.tools, ...mcpTools };
375
+ }
376
+ }
377
+ }
378
+ const response = streamText({ ...streamTextParams, abortSignal: abortController.signal });
379
+ let messageId = randomUUID();
380
+ const toolCallStates = /* @__PURE__ */ new Map();
381
+ const ensureToolCallState = (toolCallId) => {
382
+ let state = toolCallStates.get(toolCallId);
383
+ if (!state) {
384
+ state = { started: false, hasArgsDelta: false, ended: false };
385
+ toolCallStates.set(toolCallId, state);
386
+ }
387
+ return state;
388
+ };
389
+ for await (const part of response.fullStream) {
390
+ switch (part.type) {
391
+ case "abort":
392
+ const abortEndEvent = {
393
+ type: EventType.RUN_FINISHED,
394
+ threadId: input.threadId,
395
+ runId: input.runId
396
+ };
397
+ subscriber.next(abortEndEvent);
398
+ terminalEventEmitted = true;
399
+ subscriber.complete();
400
+ break;
401
+ case "tool-input-start": {
402
+ const toolCallId = part.id;
403
+ const state = ensureToolCallState(toolCallId);
404
+ state.toolName = part.toolName;
405
+ if (!state.started) {
406
+ state.started = true;
407
+ const startEvent2 = {
408
+ type: EventType.TOOL_CALL_START,
409
+ parentMessageId: messageId,
410
+ toolCallId,
411
+ toolCallName: part.toolName
412
+ };
413
+ subscriber.next(startEvent2);
414
+ }
415
+ break;
416
+ }
417
+ case "tool-input-delta": {
418
+ const toolCallId = part.id;
419
+ const state = ensureToolCallState(toolCallId);
420
+ state.hasArgsDelta = true;
421
+ const argsEvent = {
422
+ type: EventType.TOOL_CALL_ARGS,
423
+ toolCallId,
424
+ delta: part.delta
425
+ };
426
+ subscriber.next(argsEvent);
427
+ break;
428
+ }
429
+ case "tool-input-end": {
430
+ break;
431
+ }
432
+ case "text-start": {
433
+ const providedId = "id" in part ? part.id : void 0;
434
+ messageId = providedId && providedId !== "0" ? providedId : randomUUID();
435
+ break;
436
+ }
437
+ case "text-delta": {
438
+ const textDelta = "text" in part ? part.text : "";
439
+ const textEvent = {
440
+ type: EventType.TEXT_MESSAGE_CHUNK,
441
+ role: "assistant",
442
+ messageId,
443
+ delta: textDelta
444
+ };
445
+ subscriber.next(textEvent);
446
+ break;
447
+ }
448
+ case "tool-call": {
449
+ const toolCallId = part.toolCallId;
450
+ const state = ensureToolCallState(toolCallId);
451
+ state.toolName = part.toolName ?? state.toolName;
452
+ if (!state.started) {
453
+ state.started = true;
454
+ const startEvent2 = {
455
+ type: EventType.TOOL_CALL_START,
456
+ parentMessageId: messageId,
457
+ toolCallId,
458
+ toolCallName: part.toolName
459
+ };
460
+ subscriber.next(startEvent2);
461
+ }
462
+ if (!state.hasArgsDelta && "input" in part && part.input !== void 0) {
463
+ let serializedInput = "";
464
+ if (typeof part.input === "string") {
465
+ serializedInput = part.input;
466
+ } else {
467
+ try {
468
+ serializedInput = JSON.stringify(part.input);
469
+ } catch {
470
+ serializedInput = String(part.input);
471
+ }
472
+ }
473
+ if (serializedInput.length > 0) {
474
+ const argsEvent = {
475
+ type: EventType.TOOL_CALL_ARGS,
476
+ toolCallId,
477
+ delta: serializedInput
478
+ };
479
+ subscriber.next(argsEvent);
480
+ state.hasArgsDelta = true;
481
+ }
482
+ }
483
+ if (!state.ended) {
484
+ state.ended = true;
485
+ const endEvent = {
486
+ type: EventType.TOOL_CALL_END,
487
+ toolCallId
488
+ };
489
+ subscriber.next(endEvent);
490
+ }
491
+ break;
492
+ }
493
+ case "tool-result": {
494
+ const toolResult = "output" in part ? part.output : null;
495
+ const toolName = "toolName" in part ? part.toolName : "";
496
+ toolCallStates.delete(part.toolCallId);
497
+ if (toolName === "AGUISendStateSnapshot" && toolResult && typeof toolResult === "object") {
498
+ const stateSnapshotEvent = {
499
+ type: EventType.STATE_SNAPSHOT,
500
+ snapshot: toolResult.snapshot
501
+ };
502
+ subscriber.next(stateSnapshotEvent);
503
+ } else if (toolName === "AGUISendStateDelta" && toolResult && typeof toolResult === "object") {
504
+ const stateDeltaEvent = {
505
+ type: EventType.STATE_DELTA,
506
+ delta: toolResult.delta
507
+ };
508
+ subscriber.next(stateDeltaEvent);
509
+ }
510
+ const resultEvent = {
511
+ type: EventType.TOOL_CALL_RESULT,
512
+ role: "tool",
513
+ messageId: randomUUID(),
514
+ toolCallId: part.toolCallId,
515
+ content: JSON.stringify(toolResult)
516
+ };
517
+ subscriber.next(resultEvent);
518
+ break;
519
+ }
520
+ case "finish":
521
+ const finishedEvent = {
522
+ type: EventType.RUN_FINISHED,
523
+ threadId: input.threadId,
524
+ runId: input.runId
525
+ };
526
+ subscriber.next(finishedEvent);
527
+ terminalEventEmitted = true;
528
+ subscriber.complete();
529
+ break;
530
+ case "error": {
531
+ if (abortController.signal.aborted) {
532
+ break;
533
+ }
534
+ const runErrorEvent = {
535
+ type: EventType.RUN_ERROR,
536
+ message: part.error + ""
537
+ };
538
+ subscriber.next(runErrorEvent);
539
+ terminalEventEmitted = true;
540
+ subscriber.error(part.error);
541
+ break;
542
+ }
543
+ }
544
+ }
545
+ if (!terminalEventEmitted) {
546
+ if (abortController.signal.aborted) {
547
+ } else {
548
+ const finishedEvent = {
549
+ type: EventType.RUN_FINISHED,
550
+ threadId: input.threadId,
551
+ runId: input.runId
552
+ };
553
+ subscriber.next(finishedEvent);
554
+ }
555
+ terminalEventEmitted = true;
556
+ subscriber.complete();
557
+ }
558
+ } catch (error) {
559
+ if (abortController.signal.aborted) {
560
+ subscriber.complete();
561
+ } else {
562
+ const runErrorEvent = {
563
+ type: EventType.RUN_ERROR,
564
+ message: error + ""
565
+ };
566
+ subscriber.next(runErrorEvent);
567
+ terminalEventEmitted = true;
568
+ subscriber.error(error);
569
+ }
570
+ } finally {
571
+ this.abortController = void 0;
572
+ await Promise.all(mcpClients.map((client) => client.close()));
573
+ }
574
+ })();
575
+ return () => {
576
+ Promise.all(mcpClients.map((client) => client.close())).catch(() => {
577
+ });
578
+ };
579
+ });
580
+ }
581
+ clone() {
582
+ const cloned = new _BuiltInAgent(this.config);
583
+ cloned.middlewares = [...this.middlewares];
584
+ return cloned;
585
+ }
586
+ abortRun() {
587
+ this.abortController?.abort();
588
+ }
589
+ };
590
+ var BasicAgent = class extends BuiltInAgent {
591
+ constructor(config) {
592
+ super(config);
593
+ console.warn("BasicAgent is deprecated, use BuiltInAgent instead");
594
+ }
595
+ };
596
+ export {
597
+ BasicAgent,
598
+ BuiltInAgent,
599
+ convertJsonSchemaToZodSchema,
600
+ convertMessagesToVercelAISDKMessages,
601
+ convertToolDefinitionsToVercelAITools,
602
+ convertToolsToVercelAITools,
603
+ defineTool,
604
+ resolveModel
605
+ };
606
+ //# sourceMappingURL=index.mjs.map