@mastra/client-js 0.1.20-alpha.5 → 0.1.20-alpha.6

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @mastra/client-js@0.1.20-alpha.5 build /home/runner/work/mastra/mastra/client-sdks/client-js
2
+ > @mastra/client-js@0.1.20-alpha.6 build /home/runner/work/mastra/mastra/client-sdks/client-js
3
3
  > tsup src/index.ts --format esm,cjs --dts --clean --treeshake=smallest --splitting
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -9,11 +9,11 @@
9
9
  CLI Cleaning output folder
10
10
  ESM Build start
11
11
  CJS Build start
12
- ESM dist/index.js 29.18 KB
13
- ESM ⚡️ Build success in 499ms
14
- CJS dist/index.cjs 29.36 KB
15
- CJS ⚡️ Build success in 502ms
12
+ CJS dist/index.cjs 34.65 KB
13
+ CJS ⚡️ Build success in 1594ms
14
+ ESM dist/index.js 34.43 KB
15
+ ESM ⚡️ Build success in 1595ms
16
16
  DTS Build start
17
- DTS ⚡️ Build success in 14118ms
18
- DTS dist/index.d.ts 24.97 KB
19
- DTS dist/index.d.cts 24.97 KB
17
+ DTS ⚡️ Build success in 14306ms
18
+ DTS dist/index.d.ts 25.12 KB
19
+ DTS dist/index.d.cts 25.12 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @mastra/client-js
2
2
 
3
+ ## 0.1.20-alpha.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 2e4f8e9: Agui client integration
8
+ - Updated dependencies [6052aa6]
9
+ - Updated dependencies [7d8b7c7]
10
+ - Updated dependencies [3a5f1e1]
11
+ - Updated dependencies [8398d89]
12
+ - @mastra/core@0.9.2-alpha.6
13
+
3
14
  ## 0.1.20-alpha.5
4
15
 
5
16
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -1,10 +1,175 @@
1
1
  'use strict';
2
2
 
3
+ var client = require('@ag-ui/client');
4
+ var rxjs = require('rxjs');
3
5
  var uiUtils = require('@ai-sdk/ui-utils');
4
6
  var zod = require('zod');
5
7
  var zodToJsonSchema = require('zod-to-json-schema');
6
8
 
7
- // src/resources/agent.ts
9
+ // src/adapters/agui.ts
10
+ var AGUIAdapter = class extends client.AbstractAgent {
11
+ agent;
12
+ resourceId;
13
+ constructor({ agent, agentId, resourceId, ...rest }) {
14
+ super({
15
+ agentId,
16
+ ...rest
17
+ });
18
+ this.agent = agent;
19
+ this.resourceId = resourceId;
20
+ }
21
+ run(input) {
22
+ return new rxjs.Observable((subscriber) => {
23
+ const convertedMessages = convertMessagesToMastraMessages(input.messages);
24
+ subscriber.next({
25
+ type: client.EventType.RUN_STARTED,
26
+ threadId: input.threadId,
27
+ runId: input.runId
28
+ });
29
+ this.agent.stream({
30
+ threadId: input.threadId,
31
+ resourceId: this.resourceId ?? "",
32
+ runId: input.runId,
33
+ messages: convertedMessages,
34
+ clientTools: input.tools.reduce(
35
+ (acc, tool) => {
36
+ acc[tool.name] = {
37
+ id: tool.name,
38
+ description: tool.description,
39
+ inputSchema: tool.parameters
40
+ };
41
+ return acc;
42
+ },
43
+ {}
44
+ )
45
+ }).then((response) => {
46
+ let currentMessageId = void 0;
47
+ return response.processDataStream({
48
+ onTextPart: (text) => {
49
+ if (currentMessageId === void 0) {
50
+ currentMessageId = generateUUID();
51
+ const message2 = {
52
+ type: client.EventType.TEXT_MESSAGE_START,
53
+ messageId: currentMessageId,
54
+ role: "assistant"
55
+ };
56
+ subscriber.next(message2);
57
+ }
58
+ const message = {
59
+ type: client.EventType.TEXT_MESSAGE_CONTENT,
60
+ messageId: currentMessageId,
61
+ delta: text
62
+ };
63
+ subscriber.next(message);
64
+ },
65
+ onFinishMessagePart: (message) => {
66
+ console.log("onFinishMessagePart", message);
67
+ if (currentMessageId !== void 0) {
68
+ const message2 = {
69
+ type: client.EventType.TEXT_MESSAGE_END,
70
+ messageId: currentMessageId
71
+ };
72
+ subscriber.next(message2);
73
+ }
74
+ subscriber.next({
75
+ type: client.EventType.RUN_FINISHED,
76
+ threadId: input.threadId,
77
+ runId: input.runId
78
+ });
79
+ subscriber.complete();
80
+ },
81
+ onToolCallPart(streamPart) {
82
+ const parentMessageId = currentMessageId || generateUUID();
83
+ subscriber.next({
84
+ type: client.EventType.TOOL_CALL_START,
85
+ toolCallId: streamPart.toolCallId,
86
+ toolCallName: streamPart.toolName,
87
+ parentMessageId
88
+ });
89
+ subscriber.next({
90
+ type: client.EventType.TOOL_CALL_ARGS,
91
+ toolCallId: streamPart.toolCallId,
92
+ delta: JSON.stringify(streamPart.args),
93
+ parentMessageId
94
+ });
95
+ subscriber.next({
96
+ type: client.EventType.TOOL_CALL_END,
97
+ toolCallId: streamPart.toolCallId,
98
+ parentMessageId
99
+ });
100
+ }
101
+ });
102
+ }).catch((error) => {
103
+ console.log("error", error);
104
+ subscriber.error(error);
105
+ });
106
+ return () => {
107
+ };
108
+ });
109
+ }
110
+ };
111
+ function generateUUID() {
112
+ if (typeof crypto !== "undefined") {
113
+ if (typeof crypto.randomUUID === "function") {
114
+ return crypto.randomUUID();
115
+ }
116
+ if (typeof crypto.getRandomValues === "function") {
117
+ const buffer = new Uint8Array(16);
118
+ crypto.getRandomValues(buffer);
119
+ buffer[6] = buffer[6] & 15 | 64;
120
+ buffer[8] = buffer[8] & 63 | 128;
121
+ let hex = "";
122
+ for (let i = 0; i < 16; i++) {
123
+ hex += buffer[i].toString(16).padStart(2, "0");
124
+ if (i === 3 || i === 5 || i === 7 || i === 9) hex += "-";
125
+ }
126
+ return hex;
127
+ }
128
+ }
129
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
130
+ const r = Math.random() * 16 | 0;
131
+ const v = c === "x" ? r : r & 3 | 8;
132
+ return v.toString(16);
133
+ });
134
+ }
135
+ function convertMessagesToMastraMessages(messages) {
136
+ const result = [];
137
+ for (const message of messages) {
138
+ if (message.role === "assistant") {
139
+ const parts = message.content ? [{ type: "text", text: message.content }] : [];
140
+ for (const toolCall of message.toolCalls ?? []) {
141
+ parts.push({
142
+ type: "tool-call",
143
+ toolCallId: toolCall.id,
144
+ toolName: toolCall.function.name,
145
+ args: JSON.parse(toolCall.function.arguments)
146
+ });
147
+ }
148
+ result.push({
149
+ role: "assistant",
150
+ content: parts
151
+ });
152
+ } else if (message.role === "user") {
153
+ result.push({
154
+ role: "user",
155
+ content: message.content || ""
156
+ });
157
+ } else if (message.role === "tool") {
158
+ result.push({
159
+ role: "tool",
160
+ content: [
161
+ {
162
+ type: "tool-result",
163
+ toolCallId: message.toolCallId,
164
+ toolName: "unknown",
165
+ result: message.content
166
+ }
167
+ ]
168
+ });
169
+ }
170
+ }
171
+ return result;
172
+ }
8
173
 
9
174
  // src/resources/base.ts
10
175
  var BaseResource = class {
@@ -778,6 +943,21 @@ var MastraClient = class extends BaseResource {
778
943
  getAgents() {
779
944
  return this.request("/api/agents");
780
945
  }
946
+ async getAGUI({ resourceId }) {
947
+ const agents = await this.getAgents();
948
+ return Object.entries(agents).reduce(
949
+ (acc, [agentId]) => {
950
+ const agent = this.getAgent(agentId);
951
+ acc[agentId] = new AGUIAdapter({
952
+ agentId,
953
+ agent,
954
+ resourceId
955
+ });
956
+ return acc;
957
+ },
958
+ {}
959
+ );
960
+ }
781
961
  /**
782
962
  * Gets an agent instance by ID
783
963
  * @param agentId - ID of the agent to retrieve
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import { AbstractAgent } from '@ag-ui/client';
1
2
  import { processDataStream } from '@ai-sdk/ui-utils';
2
3
  import { CoreMessage, AiMessageType, StorageThreadType, MessageType, StepAction, StepGraph, WorkflowRuns, WorkflowRunResult as WorkflowRunResult$1, QueryResult, BaseLogMessage, GenerateReturn } from '@mastra/core';
3
4
  import { JSONSchema7 } from 'json-schema';
@@ -609,6 +610,9 @@ declare class MastraClient extends BaseResource {
609
610
  * @returns Promise containing map of agent IDs to agent details
610
611
  */
611
612
  getAgents(): Promise<Record<string, GetAgentResponse>>;
613
+ getAGUI({ resourceId }: {
614
+ resourceId: string;
615
+ }): Promise<Record<string, AbstractAgent>>;
612
616
  /**
613
617
  * Gets an agent instance by ID
614
618
  * @param agentId - ID of the agent to retrieve
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { AbstractAgent } from '@ag-ui/client';
1
2
  import { processDataStream } from '@ai-sdk/ui-utils';
2
3
  import { CoreMessage, AiMessageType, StorageThreadType, MessageType, StepAction, StepGraph, WorkflowRuns, WorkflowRunResult as WorkflowRunResult$1, QueryResult, BaseLogMessage, GenerateReturn } from '@mastra/core';
3
4
  import { JSONSchema7 } from 'json-schema';
@@ -609,6 +610,9 @@ declare class MastraClient extends BaseResource {
609
610
  * @returns Promise containing map of agent IDs to agent details
610
611
  */
611
612
  getAgents(): Promise<Record<string, GetAgentResponse>>;
613
+ getAGUI({ resourceId }: {
614
+ resourceId: string;
615
+ }): Promise<Record<string, AbstractAgent>>;
612
616
  /**
613
617
  * Gets an agent instance by ID
614
618
  * @param agentId - ID of the agent to retrieve
package/dist/index.js CHANGED
@@ -1,8 +1,173 @@
1
+ import { AbstractAgent, EventType } from '@ag-ui/client';
2
+ import { Observable } from 'rxjs';
1
3
  import { processDataStream } from '@ai-sdk/ui-utils';
2
4
  import { ZodSchema } from 'zod';
3
5
  import { zodToJsonSchema } from 'zod-to-json-schema';
4
6
 
5
- // src/resources/agent.ts
7
+ // src/adapters/agui.ts
8
+ var AGUIAdapter = class extends AbstractAgent {
9
+ agent;
10
+ resourceId;
11
+ constructor({ agent, agentId, resourceId, ...rest }) {
12
+ super({
13
+ agentId,
14
+ ...rest
15
+ });
16
+ this.agent = agent;
17
+ this.resourceId = resourceId;
18
+ }
19
+ run(input) {
20
+ return new Observable((subscriber) => {
21
+ const convertedMessages = convertMessagesToMastraMessages(input.messages);
22
+ subscriber.next({
23
+ type: EventType.RUN_STARTED,
24
+ threadId: input.threadId,
25
+ runId: input.runId
26
+ });
27
+ this.agent.stream({
28
+ threadId: input.threadId,
29
+ resourceId: this.resourceId ?? "",
30
+ runId: input.runId,
31
+ messages: convertedMessages,
32
+ clientTools: input.tools.reduce(
33
+ (acc, tool) => {
34
+ acc[tool.name] = {
35
+ id: tool.name,
36
+ description: tool.description,
37
+ inputSchema: tool.parameters
38
+ };
39
+ return acc;
40
+ },
41
+ {}
42
+ )
43
+ }).then((response) => {
44
+ let currentMessageId = void 0;
45
+ return response.processDataStream({
46
+ onTextPart: (text) => {
47
+ if (currentMessageId === void 0) {
48
+ currentMessageId = generateUUID();
49
+ const message2 = {
50
+ type: EventType.TEXT_MESSAGE_START,
51
+ messageId: currentMessageId,
52
+ role: "assistant"
53
+ };
54
+ subscriber.next(message2);
55
+ }
56
+ const message = {
57
+ type: EventType.TEXT_MESSAGE_CONTENT,
58
+ messageId: currentMessageId,
59
+ delta: text
60
+ };
61
+ subscriber.next(message);
62
+ },
63
+ onFinishMessagePart: (message) => {
64
+ console.log("onFinishMessagePart", message);
65
+ if (currentMessageId !== void 0) {
66
+ const message2 = {
67
+ type: EventType.TEXT_MESSAGE_END,
68
+ messageId: currentMessageId
69
+ };
70
+ subscriber.next(message2);
71
+ }
72
+ subscriber.next({
73
+ type: EventType.RUN_FINISHED,
74
+ threadId: input.threadId,
75
+ runId: input.runId
76
+ });
77
+ subscriber.complete();
78
+ },
79
+ onToolCallPart(streamPart) {
80
+ const parentMessageId = currentMessageId || generateUUID();
81
+ subscriber.next({
82
+ type: EventType.TOOL_CALL_START,
83
+ toolCallId: streamPart.toolCallId,
84
+ toolCallName: streamPart.toolName,
85
+ parentMessageId
86
+ });
87
+ subscriber.next({
88
+ type: EventType.TOOL_CALL_ARGS,
89
+ toolCallId: streamPart.toolCallId,
90
+ delta: JSON.stringify(streamPart.args),
91
+ parentMessageId
92
+ });
93
+ subscriber.next({
94
+ type: EventType.TOOL_CALL_END,
95
+ toolCallId: streamPart.toolCallId,
96
+ parentMessageId
97
+ });
98
+ }
99
+ });
100
+ }).catch((error) => {
101
+ console.log("error", error);
102
+ subscriber.error(error);
103
+ });
104
+ return () => {
105
+ };
106
+ });
107
+ }
108
+ };
109
+ function generateUUID() {
110
+ if (typeof crypto !== "undefined") {
111
+ if (typeof crypto.randomUUID === "function") {
112
+ return crypto.randomUUID();
113
+ }
114
+ if (typeof crypto.getRandomValues === "function") {
115
+ const buffer = new Uint8Array(16);
116
+ crypto.getRandomValues(buffer);
117
+ buffer[6] = buffer[6] & 15 | 64;
118
+ buffer[8] = buffer[8] & 63 | 128;
119
+ let hex = "";
120
+ for (let i = 0; i < 16; i++) {
121
+ hex += buffer[i].toString(16).padStart(2, "0");
122
+ if (i === 3 || i === 5 || i === 7 || i === 9) hex += "-";
123
+ }
124
+ return hex;
125
+ }
126
+ }
127
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
128
+ const r = Math.random() * 16 | 0;
129
+ const v = c === "x" ? r : r & 3 | 8;
130
+ return v.toString(16);
131
+ });
132
+ }
133
+ function convertMessagesToMastraMessages(messages) {
134
+ const result = [];
135
+ for (const message of messages) {
136
+ if (message.role === "assistant") {
137
+ const parts = message.content ? [{ type: "text", text: message.content }] : [];
138
+ for (const toolCall of message.toolCalls ?? []) {
139
+ parts.push({
140
+ type: "tool-call",
141
+ toolCallId: toolCall.id,
142
+ toolName: toolCall.function.name,
143
+ args: JSON.parse(toolCall.function.arguments)
144
+ });
145
+ }
146
+ result.push({
147
+ role: "assistant",
148
+ content: parts
149
+ });
150
+ } else if (message.role === "user") {
151
+ result.push({
152
+ role: "user",
153
+ content: message.content || ""
154
+ });
155
+ } else if (message.role === "tool") {
156
+ result.push({
157
+ role: "tool",
158
+ content: [
159
+ {
160
+ type: "tool-result",
161
+ toolCallId: message.toolCallId,
162
+ toolName: "unknown",
163
+ result: message.content
164
+ }
165
+ ]
166
+ });
167
+ }
168
+ }
169
+ return result;
170
+ }
6
171
 
7
172
  // src/resources/base.ts
8
173
  var BaseResource = class {
@@ -776,6 +941,21 @@ var MastraClient = class extends BaseResource {
776
941
  getAgents() {
777
942
  return this.request("/api/agents");
778
943
  }
944
+ async getAGUI({ resourceId }) {
945
+ const agents = await this.getAgents();
946
+ return Object.entries(agents).reduce(
947
+ (acc, [agentId]) => {
948
+ const agent = this.getAgent(agentId);
949
+ acc[agentId] = new AGUIAdapter({
950
+ agentId,
951
+ agent,
952
+ resourceId
953
+ });
954
+ return acc;
955
+ },
956
+ {}
957
+ );
958
+ }
779
959
  /**
780
960
  * Gets an agent instance by ID
781
961
  * @param agentId - ID of the agent to retrieve
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/client-js",
3
- "version": "0.1.20-alpha.5",
3
+ "version": "0.1.20-alpha.6",
4
4
  "description": "The official TypeScript library for the Mastra Client API",
5
5
  "author": "",
6
6
  "type": "module",
@@ -22,11 +22,13 @@
22
22
  "repository": "github:mastra-ai/client-js",
23
23
  "license": "Elastic-2.0",
24
24
  "dependencies": {
25
+ "@ag-ui/client": "^0.0.27",
25
26
  "@ai-sdk/ui-utils": "^1.1.19",
26
27
  "json-schema": "^0.4.0",
28
+ "rxjs": "7.8.1",
27
29
  "zod": "^3.24.2",
28
30
  "zod-to-json-schema": "^3.24.3",
29
- "@mastra/core": "^0.9.2-alpha.5"
31
+ "@mastra/core": "^0.9.2-alpha.6"
30
32
  },
31
33
  "peerDependencies": {
32
34
  "zod": "^3.24.2"
@@ -0,0 +1,167 @@
1
+ import type { Message } from '@ag-ui/client';
2
+ import { describe, it, expect } from 'vitest';
3
+ import { generateUUID, convertMessagesToMastraMessages } from './agui';
4
+
5
+ describe('generateUUID', () => {
6
+ it('should generate a valid UUID v4 string', () => {
7
+ const uuid = generateUUID();
8
+ // Check UUID format (8-4-4-4-12 hex digits)
9
+ expect(uuid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
10
+ });
11
+
12
+ it('should generate unique UUIDs', () => {
13
+ const uuids = new Set();
14
+ for (let i = 0; i < 100; i++) {
15
+ uuids.add(generateUUID());
16
+ }
17
+ // All UUIDs should be unique
18
+ expect(uuids.size).toBe(100);
19
+ });
20
+ });
21
+
22
+ describe('convertMessagesToMastraMessages', () => {
23
+ it('should convert user messages correctly', () => {
24
+ const messages: Message[] = [
25
+ {
26
+ id: '1',
27
+ role: 'user',
28
+ content: 'Hello, world!',
29
+ },
30
+ ];
31
+
32
+ const result = convertMessagesToMastraMessages(messages);
33
+
34
+ expect(result).toEqual([
35
+ {
36
+ role: 'user',
37
+ content: 'Hello, world!',
38
+ },
39
+ ]);
40
+ });
41
+
42
+ it('should convert assistant messages correctly', () => {
43
+ const messages: Message[] = [
44
+ {
45
+ id: '1',
46
+ role: 'assistant',
47
+ content: 'Hello, I am an assistant',
48
+ },
49
+ ];
50
+
51
+ const result = convertMessagesToMastraMessages(messages);
52
+
53
+ expect(result).toEqual([
54
+ {
55
+ role: 'assistant',
56
+ content: [{ type: 'text', text: 'Hello, I am an assistant' }],
57
+ },
58
+ ]);
59
+ });
60
+
61
+ it('should convert assistant messages with tool calls correctly', () => {
62
+ const messages: Message[] = [
63
+ {
64
+ id: '1',
65
+ role: 'assistant',
66
+ content: undefined,
67
+ toolCalls: [
68
+ {
69
+ id: 'tool-call-1',
70
+ type: 'function',
71
+ function: {
72
+ name: 'getWeather',
73
+ arguments: '{"location":"San Francisco"}',
74
+ },
75
+ },
76
+ ],
77
+ },
78
+ ];
79
+
80
+ const result = convertMessagesToMastraMessages(messages);
81
+
82
+ expect(result).toEqual([
83
+ {
84
+ role: 'assistant',
85
+ content: [
86
+ {
87
+ type: 'tool-call',
88
+ toolCallId: 'tool-call-1',
89
+ toolName: 'getWeather',
90
+ args: { location: 'San Francisco' },
91
+ },
92
+ ],
93
+ },
94
+ ]);
95
+ });
96
+
97
+ it('should convert tool messages correctly', () => {
98
+ const messages: Message[] = [
99
+ {
100
+ id: '1',
101
+ role: 'tool',
102
+ toolCallId: 'tool-call-1',
103
+ content: '{"temperature":72,"unit":"F"}',
104
+ },
105
+ ];
106
+
107
+ const result = convertMessagesToMastraMessages(messages);
108
+
109
+ expect(result).toEqual([
110
+ {
111
+ role: 'tool',
112
+ content: [
113
+ {
114
+ type: 'tool-result',
115
+ toolCallId: 'tool-call-1',
116
+ toolName: 'unknown',
117
+ result: '{"temperature":72,"unit":"F"}',
118
+ },
119
+ ],
120
+ },
121
+ ]);
122
+ });
123
+
124
+ it('should convert a complex conversation correctly', () => {
125
+ const messages: Message[] = [
126
+ {
127
+ id: '1',
128
+ role: 'user',
129
+ content: "What's the weather in San Francisco?",
130
+ },
131
+ {
132
+ id: '2',
133
+ role: 'assistant',
134
+ content: undefined,
135
+ toolCalls: [
136
+ {
137
+ id: 'tool-call-1',
138
+ type: 'function',
139
+ function: {
140
+ name: 'getWeather',
141
+ arguments: '{"location":"San Francisco"}',
142
+ },
143
+ },
144
+ ],
145
+ },
146
+ {
147
+ id: '3',
148
+ role: 'tool',
149
+ toolCallId: 'tool-call-1',
150
+ content: '{"temperature":72,"unit":"F"}',
151
+ },
152
+ {
153
+ id: '4',
154
+ role: 'assistant',
155
+ content: 'The weather in San Francisco is 72°F.',
156
+ },
157
+ ];
158
+
159
+ const result = convertMessagesToMastraMessages(messages);
160
+
161
+ expect(result).toHaveLength(4);
162
+ expect(result[0].role).toBe('user');
163
+ expect(result[1].role).toBe('assistant');
164
+ expect(result[2].role).toBe('tool');
165
+ expect(result[3].role).toBe('assistant');
166
+ });
167
+ });
@@ -0,0 +1,219 @@
1
+ // Cross-platform UUID generation function
2
+ import { AbstractAgent, EventType } from '@ag-ui/client';
3
+ import type {
4
+ BaseEvent,
5
+ RunAgentInput,
6
+ AgentConfig,
7
+ RunStartedEvent,
8
+ RunFinishedEvent,
9
+ TextMessageStartEvent,
10
+ TextMessageContentEvent,
11
+ TextMessageEndEvent,
12
+ Message,
13
+ ToolCallStartEvent,
14
+ ToolCallArgsEvent,
15
+ ToolCallEndEvent,
16
+ } from '@ag-ui/client';
17
+ import type { CoreMessage } from '@mastra/core';
18
+ import { Observable } from 'rxjs';
19
+ import type { Agent } from '../resources/agent';
20
+
21
+ interface MastraAgentConfig extends AgentConfig {
22
+ agent: Agent;
23
+ agentId: string;
24
+ resourceId?: string;
25
+ }
26
+
27
+ export class AGUIAdapter extends AbstractAgent {
28
+ agent: Agent;
29
+ resourceId?: string;
30
+ constructor({ agent, agentId, resourceId, ...rest }: MastraAgentConfig) {
31
+ super({
32
+ agentId,
33
+ ...rest,
34
+ });
35
+ this.agent = agent;
36
+ this.resourceId = resourceId;
37
+ }
38
+
39
+ protected run(input: RunAgentInput): Observable<BaseEvent> {
40
+ return new Observable<BaseEvent>(subscriber => {
41
+ const convertedMessages = convertMessagesToMastraMessages(input.messages);
42
+
43
+ subscriber.next({
44
+ type: EventType.RUN_STARTED,
45
+ threadId: input.threadId,
46
+ runId: input.runId,
47
+ } as RunStartedEvent);
48
+
49
+ this.agent
50
+ .stream({
51
+ threadId: input.threadId,
52
+ resourceId: this.resourceId ?? '',
53
+ runId: input.runId,
54
+ messages: convertedMessages,
55
+ clientTools: input.tools.reduce(
56
+ (acc, tool) => {
57
+ acc[tool.name as string] = {
58
+ id: tool.name,
59
+ description: tool.description,
60
+ inputSchema: tool.parameters,
61
+ };
62
+ return acc;
63
+ },
64
+ {} as Record<string, any>,
65
+ ),
66
+ })
67
+ .then(response => {
68
+ let currentMessageId: string | undefined = undefined;
69
+ return response.processDataStream({
70
+ onTextPart: text => {
71
+ if (currentMessageId === undefined) {
72
+ currentMessageId = generateUUID();
73
+
74
+ const message: TextMessageStartEvent = {
75
+ type: EventType.TEXT_MESSAGE_START,
76
+ messageId: currentMessageId,
77
+ role: 'assistant',
78
+ };
79
+ subscriber.next(message);
80
+ }
81
+
82
+ const message: TextMessageContentEvent = {
83
+ type: EventType.TEXT_MESSAGE_CONTENT,
84
+ messageId: currentMessageId,
85
+ delta: text,
86
+ };
87
+ subscriber.next(message);
88
+ },
89
+ onFinishMessagePart: message => {
90
+ console.log('onFinishMessagePart', message);
91
+ if (currentMessageId !== undefined) {
92
+ const message: TextMessageEndEvent = {
93
+ type: EventType.TEXT_MESSAGE_END,
94
+ messageId: currentMessageId,
95
+ };
96
+ subscriber.next(message);
97
+ }
98
+ // Emit run finished event
99
+ subscriber.next({
100
+ type: EventType.RUN_FINISHED,
101
+ threadId: input.threadId,
102
+ runId: input.runId,
103
+ } as RunFinishedEvent);
104
+
105
+ // Complete the observable
106
+ subscriber.complete();
107
+ },
108
+ onToolCallPart(streamPart) {
109
+ const parentMessageId = currentMessageId || generateUUID();
110
+ subscriber.next({
111
+ type: EventType.TOOL_CALL_START,
112
+ toolCallId: streamPart.toolCallId,
113
+ toolCallName: streamPart.toolName,
114
+ parentMessageId,
115
+ } as ToolCallStartEvent);
116
+
117
+ subscriber.next({
118
+ type: EventType.TOOL_CALL_ARGS,
119
+ toolCallId: streamPart.toolCallId,
120
+ delta: JSON.stringify(streamPart.args),
121
+ parentMessageId,
122
+ } as ToolCallArgsEvent);
123
+
124
+ subscriber.next({
125
+ type: EventType.TOOL_CALL_END,
126
+ toolCallId: streamPart.toolCallId,
127
+ parentMessageId,
128
+ } as ToolCallEndEvent);
129
+ },
130
+ });
131
+ })
132
+ .catch(error => {
133
+ console.log('error', error);
134
+ // Handle error
135
+ subscriber.error(error);
136
+ });
137
+
138
+ return () => {};
139
+ });
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Generates a UUID v4 that works in both browser and Node.js environments
145
+ */
146
+ export function generateUUID(): string {
147
+ // Use crypto.randomUUID() if available (Node.js environment or modern browsers)
148
+ if (typeof crypto !== 'undefined') {
149
+ // Browser crypto API or Node.js crypto global
150
+ if (typeof crypto.randomUUID === 'function') {
151
+ return crypto.randomUUID();
152
+ }
153
+ // Fallback for older browsers
154
+ if (typeof crypto.getRandomValues === 'function') {
155
+ const buffer = new Uint8Array(16);
156
+ crypto.getRandomValues(buffer);
157
+ // Set version (4) and variant (8, 9, A, or B)
158
+ buffer[6] = (buffer[6]! & 0x0f) | 0x40; // version 4
159
+ buffer[8] = (buffer[8]! & 0x3f) | 0x80; // variant
160
+
161
+ // Convert to hex string in UUID format
162
+ let hex = '';
163
+ for (let i = 0; i < 16; i++) {
164
+ hex += buffer[i]!.toString(16).padStart(2, '0');
165
+ // Add hyphens at standard positions
166
+ if (i === 3 || i === 5 || i === 7 || i === 9) hex += '-';
167
+ }
168
+ return hex;
169
+ }
170
+ }
171
+
172
+ // Last resort fallback (less secure but works everywhere)
173
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
174
+ const r = (Math.random() * 16) | 0;
175
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
176
+ return v.toString(16);
177
+ });
178
+ }
179
+
180
+ export function convertMessagesToMastraMessages(messages: Message[]): CoreMessage[] {
181
+ const result: CoreMessage[] = [];
182
+
183
+ for (const message of messages) {
184
+ if (message.role === 'assistant') {
185
+ const parts: any[] = message.content ? [{ type: 'text', text: message.content }] : [];
186
+ for (const toolCall of message.toolCalls ?? []) {
187
+ parts.push({
188
+ type: 'tool-call',
189
+ toolCallId: toolCall.id,
190
+ toolName: toolCall.function.name,
191
+ args: JSON.parse(toolCall.function.arguments),
192
+ });
193
+ }
194
+ result.push({
195
+ role: 'assistant',
196
+ content: parts,
197
+ });
198
+ } else if (message.role === 'user') {
199
+ result.push({
200
+ role: 'user',
201
+ content: message.content || '',
202
+ });
203
+ } else if (message.role === 'tool') {
204
+ result.push({
205
+ role: 'tool',
206
+ content: [
207
+ {
208
+ type: 'tool-result',
209
+ toolCallId: message.toolCallId,
210
+ toolName: 'unknown',
211
+ result: message.content,
212
+ },
213
+ ],
214
+ });
215
+ }
216
+ }
217
+
218
+ return result;
219
+ }
package/src/client.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { AbstractAgent } from '@ag-ui/client';
2
+ import { AGUIAdapter } from './adapters/agui';
1
3
  import { Agent, MemoryThread, Tool, Workflow, Vector, BaseResource, Network, VNextWorkflow } from './resources';
2
4
  import type {
3
5
  ClientOptions,
@@ -32,6 +34,25 @@ export class MastraClient extends BaseResource {
32
34
  return this.request('/api/agents');
33
35
  }
34
36
 
37
+ public async getAGUI({ resourceId }: { resourceId: string }): Promise<Record<string, AbstractAgent>> {
38
+ const agents = await this.getAgents();
39
+
40
+ return Object.entries(agents).reduce(
41
+ (acc, [agentId]) => {
42
+ const agent = this.getAgent(agentId);
43
+
44
+ acc[agentId] = new AGUIAdapter({
45
+ agentId,
46
+ agent,
47
+ resourceId,
48
+ });
49
+
50
+ return acc;
51
+ },
52
+ {} as Record<string, AbstractAgent>,
53
+ );
54
+ }
55
+
35
56
  /**
36
57
  * Gets an agent instance by ID
37
58
  * @param agentId - ID of the agent to retrieve