@mastra/acp 0.4.0 → 0.4.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,757 +1,705 @@
1
- 'use strict';
2
-
3
- var crypto = require('crypto');
4
- var web = require('stream/web');
5
- var messageList = require('@mastra/core/agent/message-list');
6
- var child_process = require('child_process');
7
- var process = require('process');
8
- var stream = require('stream');
9
- var sdk = require('@agentclientprotocol/sdk');
10
- var workspace = require('@mastra/core/workspace');
11
- var tools = require('@mastra/core/tools');
12
-
13
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
-
15
- var process__default = /*#__PURE__*/_interopDefault(process);
16
-
17
- // src/agent.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let crypto = require("crypto");
25
+ let stream_web = require("stream/web");
26
+ let _mastra_core_agent_message_list = require("@mastra/core/agent/message-list");
27
+ let child_process = require("child_process");
28
+ let process = require("process");
29
+ process = __toESM(process, 1);
30
+ let stream = require("stream");
31
+ let _agentclientprotocol_sdk = require("@agentclientprotocol/sdk");
32
+ let _mastra_core_workspace = require("@mastra/core/workspace");
33
+ let _mastra_core_tools = require("@mastra/core/tools");
34
+ //#region src/connection.ts
18
35
  var ACPClient = class {
19
- constructor(getPromptState, workspace, onPermissionRequest) {
20
- this.getPromptState = getPromptState;
21
- this.workspace = workspace;
22
- this.onPermissionRequest = onPermissionRequest;
23
- }
24
- getPromptState;
25
- workspace;
26
- onPermissionRequest;
27
- async sessionUpdate(notification) {
28
- const state = this.getPromptState();
29
- if (!state || notification.sessionId !== state.sessionId) {
30
- return;
31
- }
32
- const update = notification.update;
33
- if (update.sessionUpdate === "agent_message_chunk") {
34
- if (update.content.type === "text") {
35
- state.onEvent?.({ type: "text", text: update.content.text });
36
- }
37
- } else {
38
- state.onEvent?.({ type: "session-update", update });
39
- }
40
- }
41
- async requestPermission(request) {
42
- if (this.onPermissionRequest) {
43
- return this.onPermissionRequest(request);
44
- }
45
- const option = request.options[0];
46
- if (!option) {
47
- return { outcome: { outcome: "cancelled" } };
48
- }
49
- return { outcome: selectedPermissionOutcome(option) };
50
- }
51
- async readTextFile(params) {
52
- let content = await this.workspace.filesystem?.readFile(params.path);
53
- if (!(typeof content === "string")) {
54
- const decoder = new TextDecoder("utf-8");
55
- content = decoder.decode(content);
56
- }
57
- if (params.line != null || params.limit != null) {
58
- const lines = content.split("\n");
59
- const start = (params.line ?? 1) - 1;
60
- const end = params.limit != null ? start + params.limit : lines.length;
61
- return { content: lines.slice(start, end).join("\n") };
62
- }
63
- return { content };
64
- }
65
- async writeTextFile(params) {
66
- await this.workspace.filesystem?.writeFile(params.path, params.content);
67
- return {};
68
- }
36
+ getPromptState;
37
+ workspace;
38
+ onPermissionRequest;
39
+ constructor(getPromptState, workspace, onPermissionRequest) {
40
+ this.getPromptState = getPromptState;
41
+ this.workspace = workspace;
42
+ this.onPermissionRequest = onPermissionRequest;
43
+ }
44
+ async sessionUpdate(notification) {
45
+ const state = this.getPromptState();
46
+ if (!state || notification.sessionId !== state.sessionId) return;
47
+ const update = notification.update;
48
+ if (update.sessionUpdate === "agent_message_chunk") {
49
+ if (update.content.type === "text") state.onEvent?.({
50
+ type: "text",
51
+ text: update.content.text
52
+ });
53
+ } else state.onEvent?.({
54
+ type: "session-update",
55
+ update
56
+ });
57
+ }
58
+ async requestPermission(request) {
59
+ if (this.onPermissionRequest) return this.onPermissionRequest(request);
60
+ const option = request.options[0];
61
+ if (!option) return { outcome: { outcome: "cancelled" } };
62
+ return { outcome: selectedPermissionOutcome(option) };
63
+ }
64
+ async readTextFile(params) {
65
+ let content = await this.workspace.filesystem?.readFile(params.path);
66
+ if (!(typeof content === "string")) content = new TextDecoder("utf-8").decode(content);
67
+ if (params.line != null || params.limit != null) {
68
+ const lines = content.split("\n");
69
+ const start = (params.line ?? 1) - 1;
70
+ const end = params.limit != null ? start + params.limit : lines.length;
71
+ return { content: lines.slice(start, end).join("\n") };
72
+ }
73
+ return { content };
74
+ }
75
+ async writeTextFile(params) {
76
+ await this.workspace.filesystem?.writeFile(params.path, params.content);
77
+ return {};
78
+ }
69
79
  };
70
80
  var ACPConnection = class {
71
- options;
72
- agentProcess;
73
- connection;
74
- session;
75
- initializePromise;
76
- currentPrompt;
77
- stderr = "";
78
- constructor(options) {
79
- this.options = options;
80
- }
81
- get sessionId() {
82
- return this.session?.sessionId;
83
- }
84
- async getAvailableModels() {
85
- await this.ensureConnected();
86
- return this.session?.models?.availableModels ?? [];
87
- }
88
- async setModel(modelId) {
89
- await this.ensureConnected();
90
- const available = this.session?.models?.availableModels;
91
- if (available && !available.some((m) => m.modelId === modelId)) {
92
- const ids = available.map((m) => m.modelId).join(", ") || "(none)";
93
- throw new Error(`Model "${modelId}" is not available. Available models: ${ids}`);
94
- }
95
- await this.connection.unstable_setSessionModel({
96
- sessionId: this.session.sessionId,
97
- modelId
98
- });
99
- }
100
- async prompt(task, signal) {
101
- const parts = [];
102
- for await (const event of this.promptStream(task, signal)) {
103
- if (event.type === "text") {
104
- parts.push(event.text);
105
- }
106
- }
107
- return parts.join("");
108
- }
109
- async *promptStream(task, signal) {
110
- await this.ensureConnected();
111
- const sessionId = this.session?.sessionId;
112
- if (!this.connection || !sessionId) {
113
- throw new Error("ACP connection is not initialized");
114
- }
115
- if (signal?.aborted) {
116
- await this.cancel();
117
- throw signal.reason ?? new Error("ACP prompt aborted");
118
- }
119
- const queue = createAsyncQueue();
120
- const state = {
121
- sessionId,
122
- onEvent: (event) => queue.push(event)
123
- };
124
- this.currentPrompt = state;
125
- const abortHandler = () => {
126
- void this.cancel();
127
- queue.throw(signal?.reason ?? new Error("ACP prompt aborted"));
128
- };
129
- signal?.addEventListener("abort", abortHandler, { once: true });
130
- const responsePromise = this.connection.prompt({
131
- sessionId,
132
- prompt: [{ type: "text", text: task }]
133
- }).then(
134
- (response) => {
135
- this.throwIfPromptDidNotComplete(response);
136
- queue.close();
137
- },
138
- (error) => {
139
- queue.throw(this.withStderr(error));
140
- }
141
- );
142
- try {
143
- for await (const chunk of queue) {
144
- yield chunk;
145
- }
146
- await responsePromise;
147
- } catch (error) {
148
- await responsePromise.catch(() => void 0);
149
- throw error;
150
- } finally {
151
- signal?.removeEventListener("abort", abortHandler);
152
- if (this.currentPrompt === state) {
153
- this.currentPrompt = void 0;
154
- }
155
- if (this.options.persistSession === false) {
156
- this.disconnect();
157
- }
158
- }
159
- }
160
- async cancel() {
161
- const sessionId = this.session?.sessionId;
162
- if (!this.connection || !sessionId) {
163
- return;
164
- }
165
- await this.connection.cancel({ sessionId });
166
- }
167
- disconnect() {
168
- this.connection = void 0;
169
- this.session = void 0;
170
- this.initializePromise = void 0;
171
- this.currentPrompt = void 0;
172
- if (this.agentProcess && !this.agentProcess.killed) {
173
- this.agentProcess.kill();
174
- }
175
- this.agentProcess = void 0;
176
- }
177
- async ensureConnected() {
178
- if (this.connection && this.session) {
179
- return;
180
- }
181
- this.initializePromise ??= this.initialize();
182
- await this.initializePromise;
183
- }
184
- async initialize() {
185
- this.stderr = "";
186
- this.agentProcess = child_process.spawn(this.options.command, this.options.args ?? [], {
187
- cwd: this.options.cwd,
188
- env: { ...process__default.default.env, ...this.options.env },
189
- stdio: ["pipe", "pipe", "pipe"]
190
- });
191
- const processFailure = new Promise((_, reject) => {
192
- this.agentProcess.on("error", (error) => {
193
- reject(error instanceof Error ? error : new Error(String(error)));
194
- });
195
- this.agentProcess.on("exit", (code, signal) => {
196
- reject(new Error(`ACP agent process exited during initialization (code: ${code}, signal: ${signal})`));
197
- });
198
- });
199
- processFailure.catch(() => void 0);
200
- this.agentProcess.stderr.on("data", (chunk) => {
201
- this.stderr += String(chunk);
202
- });
203
- const stream$1 = sdk.ndJsonStream(
204
- stream.Writable.toWeb(this.agentProcess.stdin),
205
- stream.Readable.toWeb(this.agentProcess.stdout)
206
- );
207
- const workspace$1 = this.options.workspace ?? new workspace.Workspace({
208
- filesystem: new workspace.LocalFilesystem({ basePath: this.options.cwd ?? process__default.default.cwd() })
209
- });
210
- try {
211
- this.connection = new sdk.ClientSideConnection(() => {
212
- const defaultClient = new ACPClient(() => this.currentPrompt, workspace$1, this.options.onPermissionRequest);
213
- return this.options.createClient?.(defaultClient) ?? defaultClient;
214
- }, stream$1);
215
- await Promise.race([processFailure, this.initializeSession()]);
216
- } catch (error) {
217
- this.disconnect();
218
- throw this.withStderr(error);
219
- }
220
- }
221
- async initializeSession() {
222
- await this.connection.initialize(this.getInitializeRequest());
223
- if (this.options.authMethodId) {
224
- await this.connection.authenticate({ methodId: this.options.authMethodId });
225
- }
226
- this.session = await this.connection.newSession(this.getNewSessionRequest());
227
- if (this.options.model) {
228
- const available = this.session.models?.availableModels;
229
- if (available && !available.some((m) => m.modelId === this.options.model)) {
230
- const ids = available.map((m) => m.modelId).join(", ") || "(none)";
231
- throw new Error(`Model "${this.options.model}" is not available. Available models: ${ids}`);
232
- }
233
- await this.connection.unstable_setSessionModel({
234
- sessionId: this.session.sessionId,
235
- modelId: this.options.model
236
- });
237
- }
238
- }
239
- getInitializeRequest() {
240
- return {
241
- protocolVersion: sdk.PROTOCOL_VERSION,
242
- clientCapabilities: {
243
- fs: { readTextFile: true, writeTextFile: true }
244
- },
245
- clientInfo: {
246
- name: "@mastra/acp",
247
- version: "0.1.0"
248
- },
249
- ...this.options.initialize
250
- };
251
- }
252
- getNewSessionRequest() {
253
- return {
254
- cwd: this.options.cwd ?? process__default.default.cwd(),
255
- mcpServers: [],
256
- ...this.options.session
257
- };
258
- }
259
- throwIfPromptDidNotComplete(response) {
260
- if (response.stopReason === "end_turn") {
261
- return;
262
- }
263
- throw new Error(`ACP prompt stopped before completing: ${response.stopReason}`);
264
- }
265
- withStderr(error) {
266
- const stderr = this.stderr.trim();
267
- if (error instanceof Error) {
268
- if (stderr && !error.message.includes(stderr)) {
269
- error.message = `${error.message}
270
-
271
- ACP agent stderr:
272
- ${stderr}`;
273
- }
274
- return error;
275
- }
276
- return new Error(stderr ? `${String(error)}
277
-
278
- ACP agent stderr:
279
- ${stderr}` : String(error));
280
- }
81
+ options;
82
+ agentProcess;
83
+ connection;
84
+ session;
85
+ initializePromise;
86
+ currentPrompt;
87
+ stderr = "";
88
+ constructor(options) {
89
+ this.options = options;
90
+ }
91
+ get sessionId() {
92
+ return this.session?.sessionId;
93
+ }
94
+ async getAvailableModels() {
95
+ await this.ensureConnected();
96
+ return this.session?.models?.availableModels ?? [];
97
+ }
98
+ async setModel(modelId) {
99
+ await this.ensureConnected();
100
+ const available = this.session?.models?.availableModels;
101
+ if (available && !available.some((m) => m.modelId === modelId)) {
102
+ const ids = available.map((m) => m.modelId).join(", ") || "(none)";
103
+ throw new Error(`Model "${modelId}" is not available. Available models: ${ids}`);
104
+ }
105
+ await this.connection.unstable_setSessionModel({
106
+ sessionId: this.session.sessionId,
107
+ modelId
108
+ });
109
+ }
110
+ async prompt(task, signal) {
111
+ const parts = [];
112
+ for await (const event of this.promptStream(task, signal)) if (event.type === "text") parts.push(event.text);
113
+ return parts.join("");
114
+ }
115
+ async *promptStream(task, signal) {
116
+ await this.ensureConnected();
117
+ const sessionId = this.session?.sessionId;
118
+ if (!this.connection || !sessionId) throw new Error("ACP connection is not initialized");
119
+ if (signal?.aborted) {
120
+ await this.cancel();
121
+ throw signal.reason ?? /* @__PURE__ */ new Error("ACP prompt aborted");
122
+ }
123
+ const queue = createAsyncQueue();
124
+ const state = {
125
+ sessionId,
126
+ onEvent: (event) => queue.push(event)
127
+ };
128
+ this.currentPrompt = state;
129
+ const abortHandler = () => {
130
+ this.cancel();
131
+ queue.throw(signal?.reason ?? /* @__PURE__ */ new Error("ACP prompt aborted"));
132
+ };
133
+ signal?.addEventListener("abort", abortHandler, { once: true });
134
+ const responsePromise = this.connection.prompt({
135
+ sessionId,
136
+ prompt: [{
137
+ type: "text",
138
+ text: task
139
+ }]
140
+ }).then((response) => {
141
+ this.throwIfPromptDidNotComplete(response);
142
+ queue.close();
143
+ }, (error) => {
144
+ queue.throw(this.withStderr(error));
145
+ });
146
+ try {
147
+ for await (const chunk of queue) yield chunk;
148
+ await responsePromise;
149
+ } catch (error) {
150
+ await responsePromise.catch(() => void 0);
151
+ throw error;
152
+ } finally {
153
+ signal?.removeEventListener("abort", abortHandler);
154
+ if (this.currentPrompt === state) this.currentPrompt = void 0;
155
+ if (this.options.persistSession === false) this.disconnect();
156
+ }
157
+ }
158
+ async cancel() {
159
+ const sessionId = this.session?.sessionId;
160
+ if (!this.connection || !sessionId) return;
161
+ await this.connection.cancel({ sessionId });
162
+ }
163
+ disconnect() {
164
+ this.connection = void 0;
165
+ this.session = void 0;
166
+ this.initializePromise = void 0;
167
+ this.currentPrompt = void 0;
168
+ if (this.agentProcess && !this.agentProcess.killed) this.agentProcess.kill();
169
+ this.agentProcess = void 0;
170
+ }
171
+ async ensureConnected() {
172
+ if (this.connection && this.session) return;
173
+ this.initializePromise ??= this.initialize();
174
+ await this.initializePromise;
175
+ }
176
+ async initialize() {
177
+ this.stderr = "";
178
+ this.agentProcess = (0, child_process.spawn)(this.options.command, this.options.args ?? [], {
179
+ cwd: this.options.cwd,
180
+ env: {
181
+ ...process.default.env,
182
+ ...this.options.env
183
+ },
184
+ stdio: [
185
+ "pipe",
186
+ "pipe",
187
+ "pipe"
188
+ ]
189
+ });
190
+ const processFailure = new Promise((_, reject) => {
191
+ this.agentProcess.on("error", (error) => {
192
+ reject(error instanceof Error ? error : new Error(String(error)));
193
+ });
194
+ this.agentProcess.on("exit", (code, signal) => {
195
+ reject(/* @__PURE__ */ new Error(`ACP agent process exited during initialization (code: ${code}, signal: ${signal})`));
196
+ });
197
+ });
198
+ processFailure.catch(() => void 0);
199
+ this.agentProcess.stderr.on("data", (chunk) => {
200
+ this.stderr += String(chunk);
201
+ });
202
+ const stream$1 = (0, _agentclientprotocol_sdk.ndJsonStream)(stream.Writable.toWeb(this.agentProcess.stdin), stream.Readable.toWeb(this.agentProcess.stdout));
203
+ const workspace = this.options.workspace ?? new _mastra_core_workspace.Workspace({ filesystem: new _mastra_core_workspace.LocalFilesystem({ basePath: this.options.cwd ?? process.default.cwd() }) });
204
+ try {
205
+ this.connection = new _agentclientprotocol_sdk.ClientSideConnection(() => {
206
+ const defaultClient = new ACPClient(() => this.currentPrompt, workspace, this.options.onPermissionRequest);
207
+ return this.options.createClient?.(defaultClient) ?? defaultClient;
208
+ }, stream$1);
209
+ await Promise.race([processFailure, this.initializeSession()]);
210
+ } catch (error) {
211
+ this.disconnect();
212
+ throw this.withStderr(error);
213
+ }
214
+ }
215
+ async initializeSession() {
216
+ await this.connection.initialize(this.getInitializeRequest());
217
+ if (this.options.authMethodId) await this.connection.authenticate({ methodId: this.options.authMethodId });
218
+ this.session = await this.connection.newSession(this.getNewSessionRequest());
219
+ if (this.options.model) {
220
+ const available = this.session.models?.availableModels;
221
+ if (available && !available.some((m) => m.modelId === this.options.model)) {
222
+ const ids = available.map((m) => m.modelId).join(", ") || "(none)";
223
+ throw new Error(`Model "${this.options.model}" is not available. Available models: ${ids}`);
224
+ }
225
+ await this.connection.unstable_setSessionModel({
226
+ sessionId: this.session.sessionId,
227
+ modelId: this.options.model
228
+ });
229
+ }
230
+ }
231
+ getInitializeRequest() {
232
+ return {
233
+ protocolVersion: _agentclientprotocol_sdk.PROTOCOL_VERSION,
234
+ clientCapabilities: { fs: {
235
+ readTextFile: true,
236
+ writeTextFile: true
237
+ } },
238
+ clientInfo: {
239
+ name: "@mastra/acp",
240
+ version: "0.1.0"
241
+ },
242
+ ...this.options.initialize
243
+ };
244
+ }
245
+ getNewSessionRequest() {
246
+ return {
247
+ cwd: this.options.cwd ?? process.default.cwd(),
248
+ mcpServers: [],
249
+ ...this.options.session
250
+ };
251
+ }
252
+ throwIfPromptDidNotComplete(response) {
253
+ if (response.stopReason === "end_turn") return;
254
+ throw new Error(`ACP prompt stopped before completing: ${response.stopReason}`);
255
+ }
256
+ withStderr(error) {
257
+ const stderr = this.stderr.trim();
258
+ if (error instanceof Error) {
259
+ if (stderr && !error.message.includes(stderr)) error.message = `${error.message}\n\nACP agent stderr:\n${stderr}`;
260
+ return error;
261
+ }
262
+ return new Error(stderr ? `${String(error)}\n\nACP agent stderr:\n${stderr}` : String(error));
263
+ }
281
264
  };
282
265
  function createAsyncQueue() {
283
- const values = [];
284
- const waiters = [];
285
- let closed = false;
286
- let error;
287
- const next = () => {
288
- if (values.length > 0) {
289
- return Promise.resolve({ value: values.shift(), done: false });
290
- }
291
- if (error) {
292
- return Promise.reject(error);
293
- }
294
- if (closed) {
295
- return Promise.resolve({ value: void 0, done: true });
296
- }
297
- return new Promise((resolve, reject) => {
298
- waiters.push({ resolve, reject });
299
- });
300
- };
301
- return {
302
- push(value) {
303
- const waiter = waiters.shift();
304
- if (waiter) {
305
- waiter.resolve({ value, done: false });
306
- return;
307
- }
308
- values.push(value);
309
- },
310
- close() {
311
- closed = true;
312
- for (const waiter of waiters.splice(0)) {
313
- waiter.resolve({ value: void 0, done: true });
314
- }
315
- },
316
- throw(queueError) {
317
- error = queueError;
318
- for (const waiter of waiters.splice(0)) {
319
- waiter.reject(queueError);
320
- }
321
- },
322
- [Symbol.asyncIterator]() {
323
- return { next };
324
- }
325
- };
266
+ const values = [];
267
+ const waiters = [];
268
+ let closed = false;
269
+ let error;
270
+ const next = () => {
271
+ if (values.length > 0) return Promise.resolve({
272
+ value: values.shift(),
273
+ done: false
274
+ });
275
+ if (error) return Promise.reject(error);
276
+ if (closed) return Promise.resolve({
277
+ value: void 0,
278
+ done: true
279
+ });
280
+ return new Promise((resolve, reject) => {
281
+ waiters.push({
282
+ resolve,
283
+ reject
284
+ });
285
+ });
286
+ };
287
+ return {
288
+ push(value) {
289
+ const waiter = waiters.shift();
290
+ if (waiter) {
291
+ waiter.resolve({
292
+ value,
293
+ done: false
294
+ });
295
+ return;
296
+ }
297
+ values.push(value);
298
+ },
299
+ close() {
300
+ closed = true;
301
+ for (const waiter of waiters.splice(0)) waiter.resolve({
302
+ value: void 0,
303
+ done: true
304
+ });
305
+ },
306
+ throw(queueError) {
307
+ error = queueError;
308
+ for (const waiter of waiters.splice(0)) waiter.reject(queueError);
309
+ },
310
+ [Symbol.asyncIterator]() {
311
+ return { next };
312
+ }
313
+ };
326
314
  }
327
315
  function selectedPermissionOutcome(option) {
328
- return { outcome: "selected", optionId: option.optionId };
316
+ return {
317
+ outcome: "selected",
318
+ optionId: option.optionId
319
+ };
329
320
  }
330
-
331
- // src/agent.ts
332
- var CHUNK_FROM_AGENT = "AGENT";
333
- var model = {
334
- modelId: "acp-agent",
335
- provider: "@mastra/acp",
336
- specificationVersion: "v3",
337
- supportedUrls: {},
338
- doGenerate: async () => ({
339
- stream: new web.ReadableStream({
340
- start: async (controller) => {
341
- controller.close();
342
- }
343
- })
344
- }),
345
- doStream: async () => ({
346
- stream: new web.ReadableStream({
347
- start: async (controller) => {
348
- controller.close();
349
- }
350
- })
351
- })
321
+ //#endregion
322
+ //#region src/agent.ts
323
+ const CHUNK_FROM_AGENT = "AGENT";
324
+ const model = {
325
+ modelId: "acp-agent",
326
+ provider: "@mastra/acp",
327
+ specificationVersion: "v3",
328
+ supportedUrls: {},
329
+ doGenerate: async () => ({ stream: new stream_web.ReadableStream({ start: async (controller) => {
330
+ controller.close();
331
+ } }) }),
332
+ doStream: async () => ({ stream: new stream_web.ReadableStream({ start: async (controller) => {
333
+ controller.close();
334
+ } }) })
352
335
  };
353
336
  var AcpAgent = class {
354
- id;
355
- name;
356
- connection;
357
- description;
358
- constructor(options) {
359
- this.id = options.id;
360
- this.name = options.name ?? options.id;
361
- this.description = options.description;
362
- this.connection = new ACPConnection(options);
363
- }
364
- __registerMastra(_mastra) {
365
- }
366
- getDescription() {
367
- return this.description;
368
- }
369
- getModel() {
370
- return model;
371
- }
372
- hasOwnMemory() {
373
- return false;
374
- }
375
- __setMemory(_memory) {
376
- }
377
- getMemory() {
378
- return void 0;
379
- }
380
- getInstructions() {
381
- return "";
382
- }
383
- async getAvailableModels() {
384
- return this.connection.getAvailableModels();
385
- }
386
- async setModel(modelId) {
387
- return this.connection.setModel(modelId);
388
- }
389
- async generate(messages, options) {
390
- const prompt = this.getPrompt(messages, options?.instructions);
391
- const text = await this.connection.prompt(
392
- prompt,
393
- options?.abortSignal
394
- );
395
- const messageList = this.createMessageList(messages, text);
396
- return {
397
- text,
398
- response: {
399
- dbMessages: messageList.get.response.db()
400
- },
401
- toolResults: [],
402
- finishReason: "stop",
403
- runId: options?.runId ?? crypto.randomUUID()
404
- };
405
- }
406
- async resumeGenerate() {
407
- throw new Error("AcpAgent does not support resuming suspended generate calls");
408
- }
409
- async resumeStream() {
410
- throw new Error("AcpAgent does not support resuming suspended stream calls");
411
- }
412
- async stream(messages, options) {
413
- const runId = options?.runId ?? crypto.randomUUID();
414
- const prompt = this.getPrompt(messages, options?.instructions);
415
- const signal = options?.abortSignal;
416
- const messageList$1 = new messageList.MessageList();
417
- messageList$1.add(messages, "input");
418
- let resolveText;
419
- let rejectText;
420
- const textPromise = new Promise((resolve, reject) => {
421
- resolveText = resolve;
422
- rejectText = reject;
423
- });
424
- const fullStream = new web.ReadableStream({
425
- start: async (controller) => {
426
- const textId = crypto.randomUUID();
427
- const chunks = [];
428
- const toolNames = /* @__PURE__ */ new Map();
429
- const toolResults = [];
430
- try {
431
- controller.enqueue({ type: "text-start", runId, from: CHUNK_FROM_AGENT, payload: { id: textId } });
432
- for await (const event of this.connection.promptStream(prompt, signal)) {
433
- if (event.type === "text") {
434
- chunks.push(event.text);
435
- controller.enqueue({
436
- type: "text-delta",
437
- runId,
438
- from: CHUNK_FROM_AGENT,
439
- payload: { id: textId, text: event.text }
440
- });
441
- } else if (event.type === "session-update") {
442
- for (const chunk of getMastraChunksFromACPUpdate(event.update, runId, toolNames)) {
443
- if (chunk.type === "tool-result") {
444
- toolResults.push({ payload: chunk.payload });
445
- }
446
- controller.enqueue(chunk);
447
- }
448
- }
449
- }
450
- const text = chunks.join("");
451
- messageList$1.add([{ role: "assistant", content: text }], "response");
452
- controller.enqueue({ type: "text-end", runId, from: CHUNK_FROM_AGENT, payload: { id: textId } });
453
- controller.enqueue(createFinishChunk("step-finish", runId));
454
- controller.enqueue(createFinishChunk("finish", runId));
455
- await options?.onFinish?.(createOnFinishResult({ text, runId, messageList: messageList$1, toolResults }));
456
- resolveText(text);
457
- controller.close();
458
- } catch (error) {
459
- const text = chunks.join("");
460
- await options?.onFinish?.(createOnFinishResult({ text, runId, messageList: messageList$1, toolResults, error }));
461
- rejectText(error);
462
- controller.error(error);
463
- }
464
- }
465
- });
466
- return {
467
- fullStream,
468
- text: textPromise,
469
- messageList: messageList$1,
470
- toolResults: [],
471
- runId
472
- };
473
- }
474
- getPrompt(messages, instructions) {
475
- const prompt = extractText(messages);
476
- const instructionText = instructions ? extractInstructions(instructions) : "";
477
- if (!instructionText) {
478
- return prompt;
479
- }
480
- return `${instructionText}
481
-
482
- ${prompt}`;
483
- }
484
- createMessageList(messages, text) {
485
- const messageList$1 = new messageList.MessageList();
486
- messageList$1.add(messages, "input");
487
- messageList$1.add([{ role: "assistant", content: text }], "response");
488
- return messageList$1;
489
- }
337
+ id;
338
+ name;
339
+ connection;
340
+ description;
341
+ constructor(options) {
342
+ this.id = options.id;
343
+ this.name = options.name ?? options.id;
344
+ this.description = options.description;
345
+ this.connection = new ACPConnection(options);
346
+ }
347
+ __registerMastra(_mastra) {}
348
+ getDescription() {
349
+ return this.description;
350
+ }
351
+ getModel() {
352
+ return model;
353
+ }
354
+ hasOwnMemory() {
355
+ return false;
356
+ }
357
+ __setMemory(_memory) {}
358
+ getMemory() {}
359
+ getInstructions() {
360
+ return "";
361
+ }
362
+ async getAvailableModels() {
363
+ return this.connection.getAvailableModels();
364
+ }
365
+ async setModel(modelId) {
366
+ return this.connection.setModel(modelId);
367
+ }
368
+ async generate(messages, options) {
369
+ const prompt = this.getPrompt(messages, options?.instructions);
370
+ const text = await this.connection.prompt(prompt, options?.abortSignal);
371
+ return {
372
+ text,
373
+ response: { dbMessages: this.createMessageList(messages, text).get.response.db() },
374
+ toolResults: [],
375
+ finishReason: "stop",
376
+ runId: options?.runId ?? (0, crypto.randomUUID)()
377
+ };
378
+ }
379
+ async resumeGenerate() {
380
+ throw new Error("AcpAgent does not support resuming suspended generate calls");
381
+ }
382
+ async resumeStream() {
383
+ throw new Error("AcpAgent does not support resuming suspended stream calls");
384
+ }
385
+ async stream(messages, options) {
386
+ const runId = options?.runId ?? (0, crypto.randomUUID)();
387
+ const prompt = this.getPrompt(messages, options?.instructions);
388
+ const signal = options?.abortSignal;
389
+ const messageList = new _mastra_core_agent_message_list.MessageList();
390
+ messageList.add(messages, "input");
391
+ let resolveText;
392
+ let rejectText;
393
+ const textPromise = new Promise((resolve, reject) => {
394
+ resolveText = resolve;
395
+ rejectText = reject;
396
+ });
397
+ return {
398
+ fullStream: new stream_web.ReadableStream({ start: async (controller) => {
399
+ const textId = (0, crypto.randomUUID)();
400
+ const chunks = [];
401
+ const toolNames = /* @__PURE__ */ new Map();
402
+ const toolResults = [];
403
+ try {
404
+ controller.enqueue({
405
+ type: "text-start",
406
+ runId,
407
+ from: CHUNK_FROM_AGENT,
408
+ payload: { id: textId }
409
+ });
410
+ for await (const event of this.connection.promptStream(prompt, signal)) if (event.type === "text") {
411
+ chunks.push(event.text);
412
+ controller.enqueue({
413
+ type: "text-delta",
414
+ runId,
415
+ from: CHUNK_FROM_AGENT,
416
+ payload: {
417
+ id: textId,
418
+ text: event.text
419
+ }
420
+ });
421
+ } else if (event.type === "session-update") for (const chunk of getMastraChunksFromACPUpdate(event.update, runId, toolNames)) {
422
+ if (chunk.type === "tool-result") toolResults.push({ payload: chunk.payload });
423
+ controller.enqueue(chunk);
424
+ }
425
+ const text = chunks.join("");
426
+ messageList.add([{
427
+ role: "assistant",
428
+ content: text
429
+ }], "response");
430
+ controller.enqueue({
431
+ type: "text-end",
432
+ runId,
433
+ from: CHUNK_FROM_AGENT,
434
+ payload: { id: textId }
435
+ });
436
+ controller.enqueue(createFinishChunk("step-finish", runId));
437
+ controller.enqueue(createFinishChunk("finish", runId));
438
+ await options?.onFinish?.(createOnFinishResult({
439
+ text,
440
+ runId,
441
+ messageList,
442
+ toolResults
443
+ }));
444
+ resolveText(text);
445
+ controller.close();
446
+ } catch (error) {
447
+ const text = chunks.join("");
448
+ await options?.onFinish?.(createOnFinishResult({
449
+ text,
450
+ runId,
451
+ messageList,
452
+ toolResults,
453
+ error
454
+ }));
455
+ rejectText(error);
456
+ controller.error(error);
457
+ }
458
+ } }),
459
+ text: textPromise,
460
+ messageList,
461
+ toolResults: [],
462
+ runId
463
+ };
464
+ }
465
+ getPrompt(messages, instructions) {
466
+ const prompt = extractText(messages);
467
+ const instructionText = instructions ? extractInstructions(instructions) : "";
468
+ if (!instructionText) return prompt;
469
+ return `${instructionText}\n\n${prompt}`;
470
+ }
471
+ createMessageList(messages, text) {
472
+ const messageList = new _mastra_core_agent_message_list.MessageList();
473
+ messageList.add(messages, "input");
474
+ messageList.add([{
475
+ role: "assistant",
476
+ content: text
477
+ }], "response");
478
+ return messageList;
479
+ }
490
480
  };
491
481
  function extractText(messages) {
492
- if (typeof messages === "string") {
493
- return messages;
494
- }
495
- if (Array.isArray(messages) && messages.every((message) => typeof message === "string")) {
496
- return messages.join("\n");
497
- }
498
- const messageList$1 = new messageList.MessageList();
499
- messageList$1.add(messages, "input");
500
- return messageList$1.get.all.core().map((message) => messageList.coreContentToString(message.content)).filter(Boolean).join("\n");
482
+ if (typeof messages === "string") return messages;
483
+ if (Array.isArray(messages) && messages.every((message) => typeof message === "string")) return messages.join("\n");
484
+ const messageList = new _mastra_core_agent_message_list.MessageList();
485
+ messageList.add(messages, "input");
486
+ return messageList.get.all.core().map((message) => (0, _mastra_core_agent_message_list.coreContentToString)(message.content)).filter(Boolean).join("\n");
501
487
  }
502
488
  function extractInstructions(instructions) {
503
- if (typeof instructions === "string") {
504
- return instructions;
505
- }
506
- if (Array.isArray(instructions)) {
507
- return instructions.map((instruction) => extractInstructions(instruction)).join("\n");
508
- }
509
- return messageList.coreContentToString(instructions.content);
489
+ if (typeof instructions === "string") return instructions;
490
+ if (Array.isArray(instructions)) return instructions.map((instruction) => extractInstructions(instruction)).join("\n");
491
+ return (0, _mastra_core_agent_message_list.coreContentToString)(instructions.content);
510
492
  }
511
493
  function getMastraChunksFromACPUpdate(update, runId, toolNames) {
512
- switch (update.sessionUpdate) {
513
- case "tool_call": {
514
- const toolName = getToolName(update, toolNames);
515
- toolNames.set(update.toolCallId, toolName);
516
- return [
517
- {
518
- type: "tool-call",
519
- runId,
520
- from: CHUNK_FROM_AGENT,
521
- payload: {
522
- toolCallId: update.toolCallId,
523
- toolName,
524
- args: toRecord(update.rawInput)
525
- }
526
- }
527
- ];
528
- }
529
- case "tool_call_update": {
530
- const toolName = getToolName(update, toolNames);
531
- if (update.status === "completed" || update.status === "failed") {
532
- return [
533
- {
534
- type: "tool-result",
535
- runId,
536
- from: CHUNK_FROM_AGENT,
537
- payload: {
538
- toolCallId: update.toolCallId,
539
- toolName,
540
- result: update.rawOutput ?? update.content ?? { status: update.status, title: update.title },
541
- isError: update.status === "failed"
542
- }
543
- }
544
- ];
545
- }
546
- return [
547
- {
548
- type: "tool-call-delta",
549
- runId,
550
- from: CHUNK_FROM_AGENT,
551
- payload: {
552
- toolCallId: update.toolCallId,
553
- toolName,
554
- argsTextDelta: update.title ?? update.status ?? ""
555
- }
556
- }
557
- ];
558
- }
559
- default:
560
- return [];
561
- }
494
+ switch (update.sessionUpdate) {
495
+ case "tool_call": {
496
+ const toolName = getToolName(update, toolNames);
497
+ toolNames.set(update.toolCallId, toolName);
498
+ return [{
499
+ type: "tool-call",
500
+ runId,
501
+ from: CHUNK_FROM_AGENT,
502
+ payload: {
503
+ toolCallId: update.toolCallId,
504
+ toolName,
505
+ args: toRecord(update.rawInput)
506
+ }
507
+ }];
508
+ }
509
+ case "tool_call_update": {
510
+ const toolName = getToolName(update, toolNames);
511
+ if (update.status === "completed" || update.status === "failed") return [{
512
+ type: "tool-result",
513
+ runId,
514
+ from: CHUNK_FROM_AGENT,
515
+ payload: {
516
+ toolCallId: update.toolCallId,
517
+ toolName,
518
+ result: update.rawOutput ?? update.content ?? {
519
+ status: update.status,
520
+ title: update.title
521
+ },
522
+ isError: update.status === "failed"
523
+ }
524
+ }];
525
+ return [{
526
+ type: "tool-call-delta",
527
+ runId,
528
+ from: CHUNK_FROM_AGENT,
529
+ payload: {
530
+ toolCallId: update.toolCallId,
531
+ toolName,
532
+ argsTextDelta: update.title ?? update.status ?? ""
533
+ }
534
+ }];
535
+ }
536
+ default: return [];
537
+ }
562
538
  }
563
539
  function getToolName(update, toolNames) {
564
- return update.title ?? toolNames.get(update.toolCallId) ?? update.kind ?? "acp_tool";
540
+ return update.title ?? toolNames.get(update.toolCallId) ?? update.kind ?? "acp_tool";
565
541
  }
566
542
  function toRecord(value) {
567
- if (value && typeof value === "object" && !Array.isArray(value)) {
568
- return value;
569
- }
570
- if (value === void 0) {
571
- return {};
572
- }
573
- return { input: value };
543
+ if (value && typeof value === "object" && !Array.isArray(value)) return value;
544
+ if (value === void 0) return {};
545
+ return { input: value };
574
546
  }
575
- function createOnFinishResult({
576
- text,
577
- runId,
578
- messageList,
579
- toolResults,
580
- error
581
- }) {
582
- const usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
583
- return {
584
- text,
585
- finishReason: "stop",
586
- usage,
587
- totalUsage: usage,
588
- warnings: [],
589
- response: {
590
- messages: messageList.get.response.aiV5.model()
591
- },
592
- steps: [],
593
- toolResults,
594
- runId,
595
- ...error === void 0 ? {} : { error }
596
- };
547
+ function createOnFinishResult({ text, runId, messageList, toolResults, error }) {
548
+ const usage = {
549
+ inputTokens: 0,
550
+ outputTokens: 0,
551
+ totalTokens: 0
552
+ };
553
+ return {
554
+ text,
555
+ finishReason: "stop",
556
+ usage,
557
+ totalUsage: usage,
558
+ warnings: [],
559
+ response: { messages: messageList.get.response.aiV5.model() },
560
+ steps: [],
561
+ toolResults,
562
+ runId,
563
+ ...error === void 0 ? {} : { error }
564
+ };
597
565
  }
598
566
  function createFinishChunk(type, runId) {
599
- return {
600
- type,
601
- runId,
602
- from: CHUNK_FROM_AGENT,
603
- payload: {
604
- id: crypto.randomUUID(),
605
- output: {
606
- steps: [],
607
- usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
608
- },
609
- stepResult: {
610
- reason: "stop",
611
- warnings: [],
612
- isContinued: false
613
- },
614
- metadata: {},
615
- messages: { nonUser: [], all: [] }
616
- }
617
- };
567
+ return {
568
+ type,
569
+ runId,
570
+ from: CHUNK_FROM_AGENT,
571
+ payload: {
572
+ id: (0, crypto.randomUUID)(),
573
+ output: {
574
+ steps: [],
575
+ usage: {
576
+ inputTokens: 0,
577
+ outputTokens: 0,
578
+ totalTokens: 0
579
+ }
580
+ },
581
+ stepResult: {
582
+ reason: "stop",
583
+ warnings: [],
584
+ isContinued: false
585
+ },
586
+ metadata: {},
587
+ messages: {
588
+ nonUser: [],
589
+ all: []
590
+ }
591
+ }
592
+ };
618
593
  }
619
-
620
- // src/session.ts
594
+ //#endregion
595
+ //#region src/session.ts
621
596
  var ACPToolSession = class {
622
- constructor(options) {
623
- this.options = options;
624
- }
625
- options;
626
- connection;
627
- getConnection(workspace) {
628
- if (this.options.persistSession === false) {
629
- return this.createConnection(workspace);
630
- }
631
- this.connection ??= this.createConnection(workspace);
632
- return this.connection;
633
- }
634
- createConnection(workspace) {
635
- return new ACPConnection({
636
- ...this.options,
637
- workspace: workspace ?? this.options.workspace
638
- });
639
- }
597
+ options;
598
+ connection;
599
+ constructor(options) {
600
+ this.options = options;
601
+ }
602
+ getConnection(workspace) {
603
+ if (this.options.persistSession === false) return this.createConnection(workspace);
604
+ this.connection ??= this.createConnection(workspace);
605
+ return this.connection;
606
+ }
607
+ createConnection(workspace) {
608
+ return new ACPConnection({
609
+ ...this.options,
610
+ workspace: workspace ?? this.options.workspace
611
+ });
612
+ }
640
613
  };
641
-
642
- // src/tool.ts
614
+ //#endregion
615
+ //#region src/tool.ts
643
616
  function createACPTool(options) {
644
- const session = new ACPToolSession(options);
645
- return tools.createTool({
646
- id: options.id,
647
- description: options.description,
648
- inputSchema: {
649
- "$schema": "https://json-schema.org/draft/2020-12/schema",
650
- "type": "object",
651
- "properties": {
652
- "task": {
653
- "type": "string",
654
- "description": "The task to send to the ACP agent"
655
- }
656
- },
657
- "required": [
658
- "task"
659
- ]
660
- },
661
- outputSchema: {
662
- "$schema": "https://json-schema.org/draft/2020-12/schema",
663
- "type": "object",
664
- "properties": {
665
- "output": {
666
- "type": "string",
667
- "description": "The output of the ACP agent"
668
- }
669
- },
670
- "required": [
671
- "output"
672
- ]
673
- },
674
- suspendSchema: {
675
- "$schema": "https://json-schema.org/draft/2020-12/schema",
676
- "type": "object",
677
- "properties": {
678
- "permissionRequest": {
679
- "type": "object",
680
- "properties": {
681
- "title": {
682
- "type": "string",
683
- "description": "The title of the permission request"
684
- },
685
- "options": {
686
- "type": "array",
687
- "items": {
688
- "type": "object",
689
- "properties": {
690
- "optionId": {
691
- "type": "string",
692
- "description": "The option id to select"
693
- },
694
- "name": {
695
- "type": "string",
696
- "description": "The title of the permission request"
697
- }
698
- },
699
- "required": [
700
- "optionId",
701
- "name"
702
- ]
703
- }
704
- }
705
- },
706
- "required": [
707
- "title",
708
- "options"
709
- ]
710
- }
711
- },
712
- "required": [
713
- "permissionRequest"
714
- ]
715
- },
716
- resumeSchema: {
717
- "$schema": "https://json-schema.org/draft/2020-12/schema",
718
- "anyOf": [
719
- {
720
- "type": "object",
721
- "properties": {
722
- "optionId": {
723
- "description": "The option id to select",
724
- "type": "string"
725
- },
726
- "outcome": {
727
- "description": "The outcome of the permission request",
728
- "type": "string",
729
- "const": "selected"
730
- }
731
- }
732
- },
733
- {
734
- "type": "object",
735
- "properties": {
736
- "outcome": {
737
- "description": "The outcome of the permission request",
738
- "type": "string",
739
- "const": "cancelled"
740
- }
741
- }
742
- }
743
- ]
744
- },
745
- execute: async ({ task }, context) => {
746
- const workspace = await context?.mastra?.getWorkspace();
747
- const connection = session.getConnection(workspace);
748
- const output = await connection.prompt(task, context?.abortSignal);
749
- return { output };
750
- }
751
- });
617
+ const session = new ACPToolSession(options);
618
+ return (0, _mastra_core_tools.createTool)({
619
+ id: options.id,
620
+ description: options.description,
621
+ inputSchema: {
622
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
623
+ "type": "object",
624
+ "properties": { "task": {
625
+ "type": "string",
626
+ "description": "The task to send to the ACP agent"
627
+ } },
628
+ "required": ["task"]
629
+ },
630
+ outputSchema: {
631
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
632
+ "type": "object",
633
+ "properties": { "output": {
634
+ "type": "string",
635
+ "description": "The output of the ACP agent"
636
+ } },
637
+ "required": ["output"]
638
+ },
639
+ suspendSchema: {
640
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
641
+ "type": "object",
642
+ "properties": { "permissionRequest": {
643
+ "type": "object",
644
+ "properties": {
645
+ "title": {
646
+ "type": "string",
647
+ "description": "The title of the permission request"
648
+ },
649
+ "options": {
650
+ "type": "array",
651
+ "items": {
652
+ "type": "object",
653
+ "properties": {
654
+ "optionId": {
655
+ "type": "string",
656
+ "description": "The option id to select"
657
+ },
658
+ "name": {
659
+ "type": "string",
660
+ "description": "The title of the permission request"
661
+ }
662
+ },
663
+ "required": ["optionId", "name"]
664
+ }
665
+ }
666
+ },
667
+ "required": ["title", "options"]
668
+ } },
669
+ "required": ["permissionRequest"]
670
+ },
671
+ resumeSchema: {
672
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
673
+ "anyOf": [{
674
+ "type": "object",
675
+ "properties": {
676
+ "optionId": {
677
+ "description": "The option id to select",
678
+ "type": "string"
679
+ },
680
+ "outcome": {
681
+ "description": "The outcome of the permission request",
682
+ "type": "string",
683
+ "const": "selected"
684
+ }
685
+ }
686
+ }, {
687
+ "type": "object",
688
+ "properties": { "outcome": {
689
+ "description": "The outcome of the permission request",
690
+ "type": "string",
691
+ "const": "cancelled"
692
+ } }
693
+ }]
694
+ },
695
+ execute: async ({ task }, context) => {
696
+ const workspace = await context?.mastra?.getWorkspace();
697
+ return { output: await session.getConnection(workspace).prompt(task, context?.abortSignal) };
698
+ }
699
+ });
752
700
  }
753
-
701
+ //#endregion
754
702
  exports.AcpAgent = AcpAgent;
755
703
  exports.createACPTool = createACPTool;
756
- //# sourceMappingURL=index.cjs.map
704
+
757
705
  //# sourceMappingURL=index.cjs.map