@witqq/agent-sdk 0.6.1 → 0.7.0

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.
Files changed (122) hide show
  1. package/README.md +433 -6
  2. package/dist/auth/index.cjs +188 -1
  3. package/dist/auth/index.cjs.map +1 -1
  4. package/dist/auth/index.d.cts +154 -138
  5. package/dist/auth/index.d.ts +154 -138
  6. package/dist/auth/index.js +188 -2
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/backends/claude.cjs +315 -21
  9. package/dist/backends/claude.cjs.map +1 -1
  10. package/dist/backends/claude.d.cts +2 -1
  11. package/dist/backends/claude.d.ts +2 -1
  12. package/dist/backends/claude.js +315 -21
  13. package/dist/backends/claude.js.map +1 -1
  14. package/dist/backends/copilot.cjs +132 -24
  15. package/dist/backends/copilot.cjs.map +1 -1
  16. package/dist/backends/copilot.d.cts +2 -1
  17. package/dist/backends/copilot.d.ts +2 -1
  18. package/dist/backends/copilot.js +132 -24
  19. package/dist/backends/copilot.js.map +1 -1
  20. package/dist/backends/vercel-ai.cjs +56 -17
  21. package/dist/backends/vercel-ai.cjs.map +1 -1
  22. package/dist/backends/vercel-ai.d.cts +1 -1
  23. package/dist/backends/vercel-ai.d.ts +1 -1
  24. package/dist/backends/vercel-ai.js +56 -17
  25. package/dist/backends/vercel-ai.js.map +1 -1
  26. package/dist/chat/accumulator.cjs +147 -0
  27. package/dist/chat/accumulator.cjs.map +1 -0
  28. package/dist/chat/accumulator.d.cts +61 -0
  29. package/dist/chat/accumulator.d.ts +61 -0
  30. package/dist/chat/accumulator.js +145 -0
  31. package/dist/chat/accumulator.js.map +1 -0
  32. package/dist/chat/backends.cjs +3534 -0
  33. package/dist/chat/backends.cjs.map +1 -0
  34. package/dist/chat/backends.d.cts +62 -0
  35. package/dist/chat/backends.d.ts +62 -0
  36. package/dist/chat/backends.js +3501 -0
  37. package/dist/chat/backends.js.map +1 -0
  38. package/dist/chat/context.cjs +230 -0
  39. package/dist/chat/context.cjs.map +1 -0
  40. package/dist/chat/context.d.cts +167 -0
  41. package/dist/chat/context.d.ts +167 -0
  42. package/dist/chat/context.js +227 -0
  43. package/dist/chat/context.js.map +1 -0
  44. package/dist/chat/core.cjs +282 -0
  45. package/dist/chat/core.cjs.map +1 -0
  46. package/dist/chat/core.d.cts +435 -0
  47. package/dist/chat/core.d.ts +435 -0
  48. package/dist/chat/core.js +261 -0
  49. package/dist/chat/core.js.map +1 -0
  50. package/dist/chat/errors.cjs +251 -0
  51. package/dist/chat/errors.cjs.map +1 -0
  52. package/dist/chat/errors.d.cts +122 -0
  53. package/dist/chat/errors.d.ts +122 -0
  54. package/dist/chat/errors.js +243 -0
  55. package/dist/chat/errors.js.map +1 -0
  56. package/dist/chat/events.cjs +203 -0
  57. package/dist/chat/events.cjs.map +1 -0
  58. package/dist/chat/events.d.cts +241 -0
  59. package/dist/chat/events.d.ts +241 -0
  60. package/dist/chat/events.js +196 -0
  61. package/dist/chat/events.js.map +1 -0
  62. package/dist/chat/index.cjs +5359 -0
  63. package/dist/chat/index.cjs.map +1 -0
  64. package/dist/chat/index.d.cts +52 -0
  65. package/dist/chat/index.d.ts +52 -0
  66. package/dist/chat/index.js +5296 -0
  67. package/dist/chat/index.js.map +1 -0
  68. package/dist/chat/react.cjs +2739 -0
  69. package/dist/chat/react.cjs.map +1 -0
  70. package/dist/chat/react.d.cts +619 -0
  71. package/dist/chat/react.d.ts +619 -0
  72. package/dist/chat/react.js +2714 -0
  73. package/dist/chat/react.js.map +1 -0
  74. package/dist/chat/runtime.cjs +1030 -0
  75. package/dist/chat/runtime.cjs.map +1 -0
  76. package/dist/chat/runtime.d.cts +118 -0
  77. package/dist/chat/runtime.d.ts +118 -0
  78. package/dist/chat/runtime.js +1028 -0
  79. package/dist/chat/runtime.js.map +1 -0
  80. package/dist/chat/server.cjs +643 -0
  81. package/dist/chat/server.cjs.map +1 -0
  82. package/dist/chat/server.d.cts +287 -0
  83. package/dist/chat/server.d.ts +287 -0
  84. package/dist/chat/server.js +617 -0
  85. package/dist/chat/server.js.map +1 -0
  86. package/dist/chat/sessions.cjs +398 -0
  87. package/dist/chat/sessions.cjs.map +1 -0
  88. package/dist/chat/sessions.d.cts +239 -0
  89. package/dist/chat/sessions.d.ts +239 -0
  90. package/dist/chat/sessions.js +394 -0
  91. package/dist/chat/sessions.js.map +1 -0
  92. package/dist/chat/state.cjs +177 -0
  93. package/dist/chat/state.cjs.map +1 -0
  94. package/dist/chat/state.d.cts +92 -0
  95. package/dist/chat/state.d.ts +92 -0
  96. package/dist/chat/state.js +167 -0
  97. package/dist/chat/state.js.map +1 -0
  98. package/dist/chat/storage.cjs +240 -0
  99. package/dist/chat/storage.cjs.map +1 -0
  100. package/dist/chat/storage.d.cts +191 -0
  101. package/dist/chat/storage.d.ts +191 -0
  102. package/dist/chat/storage.js +236 -0
  103. package/dist/chat/storage.js.map +1 -0
  104. package/dist/errors-BDLbNu9w.d.cts +13 -0
  105. package/dist/errors-BDLbNu9w.d.ts +13 -0
  106. package/dist/in-process-transport-C2oPTYs6.d.ts +223 -0
  107. package/dist/in-process-transport-DG-w5G6k.d.cts +223 -0
  108. package/dist/index.cjs +25 -13
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.cts +32 -4
  111. package/dist/index.d.ts +32 -4
  112. package/dist/index.js +25 -13
  113. package/dist/index.js.map +1 -1
  114. package/dist/transport-D1OaUgRk.d.ts +67 -0
  115. package/dist/transport-DX1Nhm4N.d.cts +67 -0
  116. package/dist/types-Bh5AhqD-.d.ts +141 -0
  117. package/dist/types-CGF7AEX1.d.cts +141 -0
  118. package/dist/{types-BvwNzZCj.d.cts → types-CqvUAYxt.d.cts} +21 -3
  119. package/dist/{types-BvwNzZCj.d.ts → types-CqvUAYxt.d.ts} +21 -3
  120. package/dist/types-DLZzlJxt.d.ts +39 -0
  121. package/dist/types-tE0CXwBl.d.cts +39 -0
  122. package/package.json +149 -2
@@ -0,0 +1,3501 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // src/errors.ts
27
+ var AgentSDKError, ReentrancyError, DisposedError, BackendNotFoundError, BackendAlreadyRegisteredError, SubprocessError, DependencyError, AbortError, ToolExecutionError, StructuredOutputError;
28
+ var init_errors = __esm({
29
+ "src/errors.ts"() {
30
+ AgentSDKError = class extends Error {
31
+ /** @internal Marker for cross-bundle identity checks */
32
+ _agentSDKError = true;
33
+ constructor(message, options) {
34
+ super(message, options);
35
+ this.name = "AgentSDKError";
36
+ }
37
+ /** Check if an error is an AgentSDKError (works across bundled copies) */
38
+ static is(error) {
39
+ return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
40
+ }
41
+ };
42
+ ReentrancyError = class extends AgentSDKError {
43
+ constructor() {
44
+ super("Agent is already running. Await the current run before starting another.");
45
+ this.name = "ReentrancyError";
46
+ }
47
+ };
48
+ DisposedError = class extends AgentSDKError {
49
+ constructor(entity) {
50
+ super(`${entity} has been disposed and cannot be used.`);
51
+ this.name = "DisposedError";
52
+ }
53
+ };
54
+ BackendNotFoundError = class extends AgentSDKError {
55
+ constructor(backend) {
56
+ super(
57
+ `Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`
58
+ );
59
+ this.name = "BackendNotFoundError";
60
+ }
61
+ };
62
+ BackendAlreadyRegisteredError = class extends AgentSDKError {
63
+ constructor(backend) {
64
+ super(`Backend "${backend}" is already registered. Use a different name or unregister first.`);
65
+ this.name = "BackendAlreadyRegisteredError";
66
+ }
67
+ };
68
+ SubprocessError = class extends AgentSDKError {
69
+ constructor(message, options) {
70
+ super(message, options);
71
+ this.name = "SubprocessError";
72
+ }
73
+ };
74
+ DependencyError = class extends AgentSDKError {
75
+ packageName;
76
+ constructor(packageName) {
77
+ super(`${packageName} is not installed. Install it: npm install ${packageName}`);
78
+ this.name = "DependencyError";
79
+ this.packageName = packageName;
80
+ }
81
+ };
82
+ AbortError = class extends AgentSDKError {
83
+ constructor() {
84
+ super("Agent run was aborted.");
85
+ this.name = "AbortError";
86
+ }
87
+ };
88
+ ToolExecutionError = class extends AgentSDKError {
89
+ toolName;
90
+ constructor(toolName, message, options) {
91
+ super(`Tool "${toolName}" failed: ${message}`, options);
92
+ this.name = "ToolExecutionError";
93
+ this.toolName = toolName;
94
+ }
95
+ };
96
+ StructuredOutputError = class extends AgentSDKError {
97
+ constructor(message, options) {
98
+ super(`Structured output error: ${message}`, options);
99
+ this.name = "StructuredOutputError";
100
+ }
101
+ };
102
+ }
103
+ });
104
+
105
+ // src/types.ts
106
+ function isToolDefinition(tool) {
107
+ return "execute" in tool && typeof tool.execute === "function";
108
+ }
109
+ function isTextContent(content) {
110
+ return typeof content === "string";
111
+ }
112
+ function isMultiPartContent(content) {
113
+ return Array.isArray(content);
114
+ }
115
+ function getTextContent(content) {
116
+ if (typeof content === "string") return content;
117
+ return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
118
+ }
119
+ var init_types = __esm({
120
+ "src/types.ts"() {
121
+ }
122
+ });
123
+
124
+ // src/base-agent.ts
125
+ var BaseAgent;
126
+ var init_base_agent = __esm({
127
+ "src/base-agent.ts"() {
128
+ init_errors();
129
+ BaseAgent = class {
130
+ state = "idle";
131
+ abortController = null;
132
+ config;
133
+ _cleanupExternalSignal = null;
134
+ /** CLI session ID for persistent mode. Override in backends that support it. */
135
+ get sessionId() {
136
+ return void 0;
137
+ }
138
+ constructor(config) {
139
+ this.config = Object.freeze({ ...config });
140
+ }
141
+ // ─── Public Interface ─────────────────────────────────────────
142
+ async run(prompt, options) {
143
+ this.guardReentrancy();
144
+ this.guardDisposed();
145
+ const ac = this.createAbortController(options?.signal);
146
+ this.state = "running";
147
+ try {
148
+ const messages = [{ role: "user", content: prompt }];
149
+ const result = await this.executeRun(messages, options, ac.signal);
150
+ this.enrichAndNotifyUsage(result);
151
+ return result;
152
+ } finally {
153
+ this.cleanupRun();
154
+ }
155
+ }
156
+ async runWithContext(messages, options) {
157
+ this.guardReentrancy();
158
+ this.guardDisposed();
159
+ const ac = this.createAbortController(options?.signal);
160
+ this.state = "running";
161
+ try {
162
+ const result = await this.executeRun(messages, options, ac.signal);
163
+ this.enrichAndNotifyUsage(result);
164
+ return result;
165
+ } finally {
166
+ this.cleanupRun();
167
+ }
168
+ }
169
+ async runStructured(prompt, schema, options) {
170
+ this.guardReentrancy();
171
+ this.guardDisposed();
172
+ const ac = this.createAbortController(options?.signal);
173
+ this.state = "running";
174
+ try {
175
+ const messages = [{ role: "user", content: prompt }];
176
+ const result = await this.executeRunStructured(
177
+ messages,
178
+ schema,
179
+ options,
180
+ ac.signal
181
+ );
182
+ this.enrichAndNotifyUsage(result);
183
+ return result;
184
+ } finally {
185
+ this.cleanupRun();
186
+ }
187
+ }
188
+ async *stream(prompt, options) {
189
+ this.guardReentrancy();
190
+ this.guardDisposed();
191
+ const ac = this.createAbortController(options?.signal);
192
+ this.state = "streaming";
193
+ try {
194
+ const messages = [{ role: "user", content: prompt }];
195
+ const enriched = this.enrichStream(this.executeStream(messages, options, ac.signal));
196
+ yield* this.heartbeatStream(enriched);
197
+ } finally {
198
+ this.cleanupRun();
199
+ }
200
+ }
201
+ async *streamWithContext(messages, options) {
202
+ this.guardReentrancy();
203
+ this.guardDisposed();
204
+ const ac = this.createAbortController(options?.signal);
205
+ this.state = "streaming";
206
+ try {
207
+ const enriched = this.enrichStream(this.executeStream(messages, options, ac.signal));
208
+ yield* this.heartbeatStream(enriched);
209
+ } finally {
210
+ this.cleanupRun();
211
+ }
212
+ }
213
+ abort() {
214
+ if (this.abortController) {
215
+ this.abortController.abort();
216
+ }
217
+ }
218
+ /** Default interrupt — falls back to abort(). Backends may override with graceful shutdown. */
219
+ async interrupt() {
220
+ this.abort();
221
+ }
222
+ getState() {
223
+ return this.state;
224
+ }
225
+ getConfig() {
226
+ return this.config;
227
+ }
228
+ /** Mark agent as disposed. Override to add cleanup. */
229
+ dispose() {
230
+ this._cleanupExternalSignal?.();
231
+ this._cleanupExternalSignal = null;
232
+ this.abort();
233
+ this.state = "disposed";
234
+ }
235
+ // ─── Usage Enrichment ───────────────────────────────────────────
236
+ /** Enrich result usage with model/backend and fire onUsage callback */
237
+ enrichAndNotifyUsage(result) {
238
+ if (result.usage) {
239
+ result.usage = {
240
+ ...result.usage,
241
+ model: this.config.model,
242
+ backend: this.backendName
243
+ };
244
+ this.callOnUsage(result.usage);
245
+ }
246
+ }
247
+ /** Wrap a stream to enrich usage_update events and fire onUsage callback */
248
+ async *enrichStream(source) {
249
+ for await (const event of source) {
250
+ if (event.type === "usage_update") {
251
+ const usage = {
252
+ promptTokens: event.promptTokens,
253
+ completionTokens: event.completionTokens,
254
+ model: this.config.model,
255
+ backend: this.backendName
256
+ };
257
+ this.callOnUsage(usage);
258
+ yield { type: "usage_update", ...usage };
259
+ } else {
260
+ yield event;
261
+ }
262
+ }
263
+ }
264
+ /** Fire onUsage callback (fire-and-forget: errors logged, not propagated) */
265
+ callOnUsage(usage) {
266
+ if (!this.config.onUsage) return;
267
+ try {
268
+ this.config.onUsage(usage);
269
+ } catch (e) {
270
+ console.warn(
271
+ "[agent-sdk] onUsage callback error:",
272
+ e instanceof Error ? e.message : String(e)
273
+ );
274
+ }
275
+ }
276
+ // ─── Heartbeat ───────────────────────────────────────────────
277
+ /** Wrap a stream to emit heartbeat events at configured intervals.
278
+ * When heartbeatInterval is not set, passes through directly. */
279
+ async *heartbeatStream(source) {
280
+ const interval = this.config.heartbeatInterval;
281
+ if (!interval || interval <= 0) {
282
+ yield* source;
283
+ return;
284
+ }
285
+ const iterator = source[Symbol.asyncIterator]();
286
+ let pendingEvent = null;
287
+ let heartbeatResolve = null;
288
+ const timer = setInterval(() => {
289
+ if (heartbeatResolve) {
290
+ const resolve2 = heartbeatResolve;
291
+ heartbeatResolve = null;
292
+ resolve2();
293
+ }
294
+ }, interval);
295
+ try {
296
+ while (true) {
297
+ if (!pendingEvent) {
298
+ pendingEvent = iterator.next();
299
+ }
300
+ const heartbeatPromise = new Promise((resolve2) => {
301
+ heartbeatResolve = resolve2;
302
+ });
303
+ const eventDone = pendingEvent.then(
304
+ (r) => ({ kind: "event", result: r })
305
+ );
306
+ const heartbeatDone = heartbeatPromise.then(
307
+ () => ({ kind: "heartbeat" })
308
+ );
309
+ const winner = await Promise.race([eventDone, heartbeatDone]);
310
+ if (winner.kind === "heartbeat") {
311
+ yield { type: "heartbeat" };
312
+ } else {
313
+ pendingEvent = null;
314
+ heartbeatResolve = null;
315
+ if (winner.result.done) break;
316
+ yield winner.result.value;
317
+ }
318
+ }
319
+ } finally {
320
+ clearInterval(timer);
321
+ heartbeatResolve = null;
322
+ }
323
+ }
324
+ // ─── Guards ───────────────────────────────────────────────────
325
+ guardReentrancy() {
326
+ if (this.state === "running" || this.state === "streaming") {
327
+ throw new ReentrancyError();
328
+ }
329
+ }
330
+ guardDisposed() {
331
+ if (this.state === "disposed") {
332
+ throw new DisposedError("Agent");
333
+ }
334
+ }
335
+ /** Throw AbortError if signal is already aborted */
336
+ checkAbort(signal) {
337
+ if (signal.aborted) {
338
+ throw new AbortError();
339
+ }
340
+ }
341
+ // ─── Internal Helpers ─────────────────────────────────────────
342
+ /** Clean up after a run completes (success, error, or abort). */
343
+ cleanupRun() {
344
+ this._cleanupExternalSignal?.();
345
+ this._cleanupExternalSignal = null;
346
+ this.state = "idle";
347
+ this.abortController = null;
348
+ }
349
+ createAbortController(externalSignal) {
350
+ const ac = new AbortController();
351
+ this.abortController = ac;
352
+ this._cleanupExternalSignal = null;
353
+ if (externalSignal) {
354
+ if (externalSignal.aborted) {
355
+ ac.abort();
356
+ } else {
357
+ const listener = () => ac.abort();
358
+ externalSignal.addEventListener("abort", listener, { once: true });
359
+ this._cleanupExternalSignal = () => externalSignal.removeEventListener("abort", listener);
360
+ }
361
+ }
362
+ return ac;
363
+ }
364
+ };
365
+ }
366
+ });
367
+
368
+ // src/utils/schema.ts
369
+ function zodToJsonSchema(schema) {
370
+ const schemaAny = schema;
371
+ if ("toJSONSchema" in schema && typeof schemaAny.toJSONSchema === "function") {
372
+ return schemaAny.toJSONSchema();
373
+ }
374
+ if ("jsonSchema" in schema && typeof schemaAny.jsonSchema === "function") {
375
+ return schemaAny.jsonSchema();
376
+ }
377
+ return extractSchemaFromDef(schema);
378
+ }
379
+ function extractSchemaFromDef(schema) {
380
+ const def = schema._def;
381
+ const typeName = def.typeName;
382
+ switch (typeName) {
383
+ case "ZodString":
384
+ return { type: "string" };
385
+ case "ZodNumber":
386
+ return { type: "number" };
387
+ case "ZodBoolean":
388
+ return { type: "boolean" };
389
+ case "ZodNull":
390
+ return { type: "null" };
391
+ case "ZodArray":
392
+ return {
393
+ type: "array",
394
+ items: extractSchemaFromDef(def.type)
395
+ };
396
+ case "ZodObject": {
397
+ const shape = schema.shape;
398
+ const properties = {};
399
+ const required = [];
400
+ for (const [key, value] of Object.entries(shape)) {
401
+ const valueDef = value._def;
402
+ if (valueDef.typeName === "ZodOptional") {
403
+ properties[key] = extractSchemaFromDef(valueDef.innerType);
404
+ } else {
405
+ properties[key] = extractSchemaFromDef(value);
406
+ required.push(key);
407
+ }
408
+ }
409
+ return {
410
+ type: "object",
411
+ properties,
412
+ ...required.length > 0 ? { required } : {}
413
+ };
414
+ }
415
+ case "ZodOptional":
416
+ return extractSchemaFromDef(def.innerType);
417
+ case "ZodEnum":
418
+ return { type: "string", enum: def.values };
419
+ default:
420
+ return {};
421
+ }
422
+ }
423
+ var init_schema = __esm({
424
+ "src/utils/schema.ts"() {
425
+ }
426
+ });
427
+
428
+ // src/backends/copilot.ts
429
+ var copilot_exports = {};
430
+ __export(copilot_exports, {
431
+ _injectSDK: () => _injectSDK,
432
+ _resetSDK: () => _resetSDK,
433
+ createCopilotService: () => createCopilotService
434
+ });
435
+ async function loadSDK() {
436
+ if (sdkModule) return sdkModule;
437
+ try {
438
+ sdkModule = await import('@github/copilot-sdk');
439
+ return sdkModule;
440
+ } catch {
441
+ throw new SubprocessError(
442
+ "@github/copilot-sdk is not installed. Install it: npm install @github/copilot-sdk"
443
+ );
444
+ }
445
+ }
446
+ function _injectSDK(mock) {
447
+ sdkModule = mock;
448
+ }
449
+ function _resetSDK() {
450
+ sdkModule = null;
451
+ }
452
+ function mapToolsToSDK(tools) {
453
+ return tools.map((tool) => ({
454
+ name: tool.name,
455
+ description: tool.description,
456
+ parameters: convertParameters(tool.parameters),
457
+ handler: async (args) => {
458
+ const result = await tool.execute(args);
459
+ return typeof result === "string" ? result : JSON.stringify(result);
460
+ }
461
+ }));
462
+ }
463
+ function convertParameters(params) {
464
+ if (!params) return void 0;
465
+ if (params && typeof params === "object" && "_def" in params) {
466
+ return zodToJsonSchema(params);
467
+ }
468
+ return params;
469
+ }
470
+ async function mapToolsToSDKAsync(tools) {
471
+ return tools.map((tool) => ({
472
+ name: tool.name,
473
+ description: tool.description,
474
+ parameters: convertParameters(tool.parameters),
475
+ handler: async (args) => {
476
+ const result = await tool.execute(args);
477
+ return typeof result === "string" ? result : JSON.stringify(result);
478
+ }
479
+ }));
480
+ }
481
+ function buildPermissionHandler(config) {
482
+ const onPermission = config.supervisor?.onPermission;
483
+ if (!onPermission) {
484
+ return async () => ({ kind: "approved" });
485
+ }
486
+ const permissionStore = config.permissionStore;
487
+ return async (request) => {
488
+ const toolName = String(request.kind);
489
+ if (permissionStore && await permissionStore.isApproved(toolName)) {
490
+ return { kind: "approved" };
491
+ }
492
+ const unifiedRequest = {
493
+ toolName,
494
+ toolArgs: { ...request },
495
+ rawSDKRequest: request
496
+ };
497
+ const ac = new AbortController();
498
+ const decision = await onPermission(unifiedRequest, ac.signal);
499
+ if (decision.allowed) {
500
+ if (permissionStore && decision.scope) {
501
+ await permissionStore.approve(toolName, decision.scope);
502
+ }
503
+ return { kind: "approved" };
504
+ }
505
+ return { kind: "denied-interactively-by-user" };
506
+ };
507
+ }
508
+ function buildUserInputHandler(config) {
509
+ const onAskUser = config.supervisor?.onAskUser;
510
+ if (!onAskUser) {
511
+ return async () => ({
512
+ answer: "Complete the task autonomously without asking questions.",
513
+ wasFreeform: true
514
+ });
515
+ }
516
+ return async (request) => {
517
+ const ac = new AbortController();
518
+ const response = await onAskUser(
519
+ {
520
+ question: request.question,
521
+ choices: request.choices,
522
+ allowFreeform: request.allowFreeform
523
+ },
524
+ ac.signal
525
+ );
526
+ return { answer: response.answer, wasFreeform: response.wasFreeform };
527
+ };
528
+ }
529
+ function mapSessionEvent(event, tracker, thinkingTracker) {
530
+ const data = event.data;
531
+ switch (event.type) {
532
+ case "assistant.message_delta": {
533
+ const textEvent = {
534
+ type: "text_delta",
535
+ text: String(data.deltaContent ?? "")
536
+ };
537
+ if (thinkingTracker.endThinking()) {
538
+ return [{ type: "thinking_end" }, textEvent];
539
+ }
540
+ return textEvent;
541
+ }
542
+ case "assistant.reasoning":
543
+ case "assistant.reasoning_delta": {
544
+ if (thinkingTracker.isCompleted()) return null;
545
+ const events = [];
546
+ if (!thinkingTracker.isActive()) {
547
+ thinkingTracker.startThinking();
548
+ events.push({ type: "thinking_start" });
549
+ }
550
+ const reasoningText = String(data.deltaContent ?? data.content ?? "");
551
+ if (reasoningText) {
552
+ events.push({ type: "thinking_delta", text: reasoningText });
553
+ }
554
+ return events.length === 1 ? events[0] : events.length > 1 ? events : null;
555
+ }
556
+ case "tool.execution_start": {
557
+ const toolCallId = String(data.toolCallId ?? "");
558
+ const toolName = String(data.toolName ?? "unknown");
559
+ let args = {};
560
+ if (typeof data.arguments === "string") {
561
+ try {
562
+ args = JSON.parse(data.arguments);
563
+ } catch {
564
+ args = data.arguments;
565
+ }
566
+ } else if (data.arguments != null) {
567
+ args = data.arguments;
568
+ }
569
+ tracker.trackStart(toolCallId, toolName, args);
570
+ const toolStartEvent = { type: "tool_call_start", toolCallId, toolName, args };
571
+ const events = [];
572
+ if (thinkingTracker.endThinking()) {
573
+ events.push({ type: "thinking_end" });
574
+ }
575
+ thinkingTracker.reset();
576
+ events.push(toolStartEvent);
577
+ return events.length === 1 ? events[0] : events;
578
+ }
579
+ case "tool.execution_complete": {
580
+ const toolCallId = String(data.toolCallId ?? "");
581
+ const info = tracker.getInfo(toolCallId);
582
+ const rawResult = data.result;
583
+ const result = (rawResult && typeof rawResult === "object" && "content" in rawResult ? rawResult.content : rawResult) ?? null;
584
+ return {
585
+ type: "tool_call_end",
586
+ toolCallId,
587
+ toolName: info?.toolName ?? "unknown",
588
+ result
589
+ };
590
+ }
591
+ case "assistant.usage":
592
+ return {
593
+ type: "usage_update",
594
+ promptTokens: Number(data.inputTokens ?? 0),
595
+ completionTokens: Number(data.outputTokens ?? 0)
596
+ };
597
+ case "session.error":
598
+ console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
599
+ return {
600
+ type: "error",
601
+ error: String(data.message ?? "Unknown error"),
602
+ recoverable: false
603
+ };
604
+ case "assistant.message": {
605
+ const doneEvent = {
606
+ type: "done",
607
+ finalOutput: data.content ? String(data.content) : null
608
+ };
609
+ if (thinkingTracker.endThinking()) {
610
+ return [{ type: "thinking_end" }, doneEvent];
611
+ }
612
+ return doneEvent;
613
+ }
614
+ default:
615
+ return null;
616
+ }
617
+ }
618
+ function extractLastUserPrompt(messages) {
619
+ for (let i = messages.length - 1; i >= 0; i--) {
620
+ const msg = messages[i];
621
+ if (msg.role === "user") {
622
+ return getTextContent(msg.content);
623
+ }
624
+ }
625
+ return "";
626
+ }
627
+ function serializeToolCall(tc) {
628
+ const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
629
+ return ` Tool call: ${tc.name}(${args})`;
630
+ }
631
+ function serializeToolResult(tr) {
632
+ const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
633
+ const prefix = tr.isError ? "[ERROR] " : "";
634
+ return ` ${tr.name} \u2192 ${prefix}${result}`;
635
+ }
636
+ function buildContextualPrompt(messages) {
637
+ if (messages.length <= 1) {
638
+ return extractLastUserPrompt(messages);
639
+ }
640
+ const history = messages.slice(0, -1).map((msg) => {
641
+ if (msg.role === "user") {
642
+ return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
643
+ }
644
+ if (msg.role === "tool" && msg.toolResults) {
645
+ const results = msg.toolResults.map(serializeToolResult).join("\n");
646
+ return `Tool results:
647
+ ${results}`;
648
+ }
649
+ if (msg.role === "assistant") {
650
+ const parts = [];
651
+ const thinking = msg.thinking;
652
+ if (thinking) {
653
+ parts.push(`[reasoning: ${thinking}]`);
654
+ }
655
+ const text2 = msg.content ? getTextContent(msg.content) : "";
656
+ if (text2) parts.push(text2);
657
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
658
+ parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
659
+ }
660
+ return `Assistant: ${parts.join("\n")}`;
661
+ }
662
+ const text = msg.content ? getTextContent(msg.content) : "";
663
+ return `${msg.role}: ${text}`;
664
+ }).join("\n");
665
+ const lastPrompt = extractLastUserPrompt(messages);
666
+ return `Conversation history:
667
+ ${history}
668
+
669
+ User: ${lastPrompt}`;
670
+ }
671
+ function withTimeout(promise, ms, message) {
672
+ return new Promise((resolve2, reject) => {
673
+ const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
674
+ promise.then(
675
+ (val) => {
676
+ clearTimeout(timer);
677
+ resolve2(val);
678
+ },
679
+ (err) => {
680
+ clearTimeout(timer);
681
+ reject(err);
682
+ }
683
+ );
684
+ });
685
+ }
686
+ function createCopilotService(options) {
687
+ return new CopilotAgentService(options);
688
+ }
689
+ var sdkModule, ToolCallTracker, ThinkingTracker, CopilotAgent, CopilotAgentService;
690
+ var init_copilot = __esm({
691
+ "src/backends/copilot.ts"() {
692
+ init_types();
693
+ init_base_agent();
694
+ init_errors();
695
+ init_schema();
696
+ sdkModule = null;
697
+ ToolCallTracker = class {
698
+ map = /* @__PURE__ */ new Map();
699
+ trackStart(toolCallId, toolName, args) {
700
+ this.map.set(toolCallId, { toolName, args });
701
+ }
702
+ getInfo(toolCallId) {
703
+ return this.map.get(toolCallId);
704
+ }
705
+ clear() {
706
+ this.map.clear();
707
+ }
708
+ };
709
+ ThinkingTracker = class {
710
+ active = false;
711
+ completed = false;
712
+ isActive() {
713
+ return this.active;
714
+ }
715
+ /** Returns true if thinking already completed (should ignore further reasoning events). */
716
+ isCompleted() {
717
+ return this.completed;
718
+ }
719
+ startThinking() {
720
+ this.active = true;
721
+ }
722
+ /** Returns true if thinking was active and is now ended. */
723
+ endThinking() {
724
+ if (!this.active) return false;
725
+ this.active = false;
726
+ this.completed = true;
727
+ return true;
728
+ }
729
+ /** Reset for next turn (e.g. after done event). */
730
+ reset() {
731
+ this.active = false;
732
+ this.completed = false;
733
+ }
734
+ };
735
+ CopilotAgent = class extends BaseAgent {
736
+ backendName = "copilot";
737
+ getClient;
738
+ sdkTools;
739
+ sessionConfig;
740
+ sendAndWaitTimeout;
741
+ isPersistent;
742
+ persistentSession = null;
743
+ _sessionId;
744
+ activeSession = null;
745
+ _resumeSessionId;
746
+ _toolsReady = null;
747
+ constructor(config, getClient, sendAndWaitTimeout, resumeSessionId) {
748
+ super(config);
749
+ this.getClient = getClient;
750
+ this.sendAndWaitTimeout = sendAndWaitTimeout;
751
+ this.isPersistent = config.sessionMode === "persistent";
752
+ this.sdkTools = mapToolsToSDK(config.tools ?? []);
753
+ this.sessionConfig = {
754
+ model: config.model,
755
+ tools: this.sdkTools,
756
+ systemMessage: {
757
+ mode: config.systemMessageMode ?? "append",
758
+ content: config.systemPrompt
759
+ },
760
+ onPermissionRequest: buildPermissionHandler(config),
761
+ onUserInputRequest: buildUserInputHandler(config),
762
+ ...config.availableTools?.length ? { availableTools: config.availableTools } : {}
763
+ };
764
+ this._toolsReady = this._initToolsAsync(config);
765
+ this._resumeSessionId = resumeSessionId;
766
+ }
767
+ /** Pre-convert Zod schemas to JSON Schema asynchronously.
768
+ * Updates sdkTools and sessionConfig.tools before first session creation. */
769
+ async _initToolsAsync(config) {
770
+ this.sdkTools = await mapToolsToSDKAsync(config.tools ?? []);
771
+ this.sessionConfig.tools = this.sdkTools;
772
+ }
773
+ get sessionId() {
774
+ return this._sessionId;
775
+ }
776
+ async interrupt() {
777
+ if (this.activeSession) {
778
+ this.activeSession.abort().catch(() => {
779
+ });
780
+ }
781
+ this.abort();
782
+ }
783
+ emitSessionInfo(sessionId) {
784
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
785
+ const transcriptPath = home ? `${home}/.copilot/session-state/${sessionId}/events.jsonl` : void 0;
786
+ return { type: "session_info", sessionId, transcriptPath, backend: "copilot" };
787
+ }
788
+ clearPersistentSession() {
789
+ if (this.isPersistent) {
790
+ this.persistentSession?.destroy().catch(() => {
791
+ });
792
+ this.persistentSession = null;
793
+ this._sessionId = void 0;
794
+ }
795
+ }
796
+ async getOrCreateSession(streaming) {
797
+ if (this.isPersistent && this.persistentSession) {
798
+ return { session: this.persistentSession, isNew: false };
799
+ }
800
+ if (this._toolsReady) {
801
+ await this._toolsReady;
802
+ this._toolsReady = null;
803
+ }
804
+ const client = await this.getClient();
805
+ if (this._resumeSessionId) {
806
+ const storedId = this._resumeSessionId;
807
+ this._resumeSessionId = void 0;
808
+ try {
809
+ const session2 = await client.resumeSession(storedId, {
810
+ ...this.sessionConfig,
811
+ streaming: this.isPersistent ? true : streaming
812
+ });
813
+ if (this.isPersistent) {
814
+ this.persistentSession = session2;
815
+ this._sessionId = session2.sessionId;
816
+ }
817
+ return { session: session2, isNew: false };
818
+ } catch {
819
+ }
820
+ }
821
+ const session = await client.createSession({
822
+ ...this.sessionConfig,
823
+ streaming: this.isPersistent ? true : streaming
824
+ });
825
+ if (this.isPersistent) {
826
+ this.persistentSession = session;
827
+ this._sessionId = session.sessionId;
828
+ }
829
+ return { session, isNew: true };
830
+ }
831
+ // ─── executeRun ─────────────────────────────────────────────────
832
+ async executeRun(messages, _options, signal) {
833
+ this.checkAbort(signal);
834
+ const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
835
+ this.activeSession = session;
836
+ const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
837
+ const tracker = new ToolCallTracker();
838
+ const toolCalls = [];
839
+ let usage;
840
+ const unsubscribe = session.on((event) => {
841
+ if (event.type === "tool.execution_start") {
842
+ tracker.trackStart(
843
+ String(event.data.toolCallId ?? ""),
844
+ String(event.data.toolName ?? "unknown"),
845
+ event.data.arguments ?? {}
846
+ );
847
+ }
848
+ if (event.type === "tool.execution_complete") {
849
+ const info = tracker.getInfo(String(event.data.toolCallId ?? ""));
850
+ const resultContent = event.data.result?.content;
851
+ toolCalls.push({
852
+ toolName: info?.toolName ?? "unknown",
853
+ args: info?.args ?? {},
854
+ result: resultContent ?? null,
855
+ approved: Boolean(event.data.success ?? true)
856
+ });
857
+ }
858
+ if (event.type === "assistant.usage") {
859
+ usage = {
860
+ promptTokens: Number(event.data.inputTokens ?? 0),
861
+ completionTokens: Number(event.data.outputTokens ?? 0)
862
+ };
863
+ }
864
+ });
865
+ const onAbort = () => {
866
+ session.abort().catch(() => {
867
+ });
868
+ };
869
+ signal.addEventListener("abort", onAbort, { once: true });
870
+ try {
871
+ const response = this.sendAndWaitTimeout !== void 0 ? await session.sendAndWait({ prompt }, this.sendAndWaitTimeout) : await session.sendAndWait({ prompt });
872
+ const output = response?.data?.content ?? null;
873
+ return {
874
+ output,
875
+ structuredOutput: void 0,
876
+ toolCalls,
877
+ messages: [
878
+ ...messages,
879
+ ...output !== null ? [{ role: "assistant", content: output }] : []
880
+ ],
881
+ usage
882
+ };
883
+ } catch (error) {
884
+ this.clearPersistentSession();
885
+ throw error;
886
+ } finally {
887
+ this.activeSession = null;
888
+ signal.removeEventListener("abort", onAbort);
889
+ unsubscribe();
890
+ tracker.clear();
891
+ if (!this.isPersistent) {
892
+ session.destroy().catch(() => {
893
+ });
894
+ }
895
+ }
896
+ }
897
+ // ─── executeRunStructured ───────────────────────────────────────
898
+ async executeRunStructured(messages, schema, options, signal) {
899
+ const jsonSchema = zodToJsonSchema(schema.schema);
900
+ const instruction = `
901
+
902
+ You MUST respond with ONLY valid JSON matching this schema:
903
+ ` + JSON.stringify(jsonSchema, null, 2);
904
+ const augmented = [...messages];
905
+ const lastIdx = augmented.length - 1;
906
+ if (lastIdx >= 0 && augmented[lastIdx].role === "user") {
907
+ const orig = augmented[lastIdx];
908
+ augmented[lastIdx] = {
909
+ role: "user",
910
+ content: getTextContent(orig.content) + instruction
911
+ };
912
+ }
913
+ const result = await this.executeRun(augmented, options, signal);
914
+ let structuredOutput;
915
+ if (result.output) {
916
+ try {
917
+ const jsonMatch = result.output.match(
918
+ /```(?:json)?\s*([\s\S]*?)```/
919
+ );
920
+ const raw = jsonMatch ? jsonMatch[1].trim() : result.output.trim();
921
+ structuredOutput = schema.schema.parse(JSON.parse(raw));
922
+ } catch {
923
+ }
924
+ }
925
+ return {
926
+ ...result,
927
+ structuredOutput
928
+ };
929
+ }
930
+ // ─── executeStream ──────────────────────────────────────────────
931
+ async *executeStream(messages, _options, signal) {
932
+ this.checkAbort(signal);
933
+ const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
934
+ this.activeSession = session;
935
+ if (isNewSession) {
936
+ yield this.emitSessionInfo(session.sessionId);
937
+ }
938
+ const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
939
+ const tracker = new ToolCallTracker();
940
+ const thinkingTracker = new ThinkingTracker();
941
+ const queue = [];
942
+ let notify = null;
943
+ const push = (item) => {
944
+ queue.push(item);
945
+ if (notify) {
946
+ notify();
947
+ notify = null;
948
+ }
949
+ };
950
+ const waitForItem = () => new Promise((resolve2) => {
951
+ notify = resolve2;
952
+ });
953
+ const unsubscribe = session.on((event) => {
954
+ const mapped = mapSessionEvent(event, tracker, thinkingTracker);
955
+ if (mapped) {
956
+ if (Array.isArray(mapped)) {
957
+ for (const e of mapped) push({ event: e });
958
+ } else {
959
+ push({ event: mapped });
960
+ }
961
+ }
962
+ if (event.type === "session.idle") {
963
+ if (thinkingTracker.endThinking()) {
964
+ push({ event: { type: "thinking_end" } });
965
+ }
966
+ push({ done: true });
967
+ } else if (event.type === "session.error") {
968
+ console.error("[copilot] session.error:", JSON.stringify(event.data));
969
+ push({
970
+ error: new Error(
971
+ String(event.data.message ?? "Session error")
972
+ )
973
+ });
974
+ }
975
+ });
976
+ const onAbort = () => {
977
+ session.abort().catch(() => {
978
+ });
979
+ push({ error: new AbortError() });
980
+ };
981
+ signal.addEventListener("abort", onAbort, { once: true });
982
+ try {
983
+ await session.send({ prompt });
984
+ while (true) {
985
+ while (queue.length === 0) await waitForItem();
986
+ const item = queue.shift();
987
+ if ("done" in item) break;
988
+ if ("error" in item) {
989
+ this.clearPersistentSession();
990
+ throw item.error;
991
+ }
992
+ yield item.event;
993
+ }
994
+ } catch (error) {
995
+ this.clearPersistentSession();
996
+ throw error;
997
+ } finally {
998
+ this.activeSession = null;
999
+ signal.removeEventListener("abort", onAbort);
1000
+ unsubscribe();
1001
+ tracker.clear();
1002
+ if (!this.isPersistent) {
1003
+ session.destroy().catch(() => {
1004
+ });
1005
+ }
1006
+ }
1007
+ }
1008
+ // ─── dispose ────────────────────────────────────────────────────
1009
+ dispose() {
1010
+ if (this.persistentSession) {
1011
+ this.persistentSession.destroy().catch(() => {
1012
+ });
1013
+ this.persistentSession = null;
1014
+ this._sessionId = void 0;
1015
+ }
1016
+ super.dispose();
1017
+ }
1018
+ };
1019
+ CopilotAgentService = class {
1020
+ name = "copilot";
1021
+ client = null;
1022
+ clientPromise = null;
1023
+ disposed = false;
1024
+ options;
1025
+ constructor(options) {
1026
+ this.options = options;
1027
+ }
1028
+ async ensureClient() {
1029
+ if (this.disposed) throw new DisposedError("CopilotAgentService");
1030
+ if (this.client) return this.client;
1031
+ if (this.clientPromise) return this.clientPromise;
1032
+ this.clientPromise = (async () => {
1033
+ try {
1034
+ const sdk = await loadSDK();
1035
+ const client = new sdk.CopilotClient({
1036
+ cliPath: this.options.cliPath,
1037
+ cwd: this.options.workingDirectory,
1038
+ useStdio: true,
1039
+ autoStart: false,
1040
+ autoRestart: true,
1041
+ logLevel: "error",
1042
+ githubToken: this.options.githubToken,
1043
+ useLoggedInUser: this.options.useLoggedInUser ?? !this.options.githubToken,
1044
+ ...this.options.cliArgs ? { cliArgs: this.options.cliArgs } : {},
1045
+ ...this.options.env ? { env: { ...process.env, ...this.options.env } } : {}
1046
+ });
1047
+ const startupTimeout = this.options.startupTimeoutMs ?? 3e4;
1048
+ await withTimeout(client.start(), startupTimeout, "CLI startup timed out");
1049
+ const auth = await withTimeout(
1050
+ client.getAuthStatus(),
1051
+ startupTimeout,
1052
+ "Auth status check timed out \u2014 token may be expired"
1053
+ );
1054
+ if (!auth.isAuthenticated) {
1055
+ await client.stop();
1056
+ throw new SubprocessError(
1057
+ "Not authenticated with GitHub Copilot. Run 'copilot auth login' or set GITHUB_TOKEN."
1058
+ );
1059
+ }
1060
+ this.client = client;
1061
+ return client;
1062
+ } catch (e) {
1063
+ this.clientPromise = null;
1064
+ throw e;
1065
+ }
1066
+ })();
1067
+ return this.clientPromise;
1068
+ }
1069
+ createAgent(config) {
1070
+ if (this.disposed) throw new DisposedError("CopilotAgentService");
1071
+ return new CopilotAgent(config, () => this.ensureClient(), this.options.timeout, this.options.resumeSessionId);
1072
+ }
1073
+ async listModels() {
1074
+ const client = await this.ensureClient();
1075
+ const models = await client.listModels();
1076
+ return models.map((m) => ({
1077
+ id: m.id,
1078
+ name: m.name,
1079
+ provider: "copilot"
1080
+ }));
1081
+ }
1082
+ async validate() {
1083
+ const errors = [];
1084
+ try {
1085
+ const client = await this.ensureClient();
1086
+ const auth = await client.getAuthStatus();
1087
+ if (!auth.isAuthenticated) {
1088
+ errors.push(
1089
+ "Not authenticated with GitHub Copilot. Run 'copilot auth login'."
1090
+ );
1091
+ }
1092
+ } catch (e) {
1093
+ errors.push(
1094
+ `Failed to connect to Copilot CLI: ${e instanceof Error ? e.message : String(e)}`
1095
+ );
1096
+ }
1097
+ return { valid: errors.length === 0, errors };
1098
+ }
1099
+ async dispose() {
1100
+ if (this.disposed) return;
1101
+ this.disposed = true;
1102
+ if (this.clientPromise) {
1103
+ try {
1104
+ await this.clientPromise;
1105
+ } catch {
1106
+ }
1107
+ }
1108
+ if (this.client) {
1109
+ await this.client.stop();
1110
+ this.client = null;
1111
+ }
1112
+ this.clientPromise = null;
1113
+ }
1114
+ };
1115
+ }
1116
+ });
1117
+
1118
+ // src/backends/claude.ts
1119
+ var claude_exports = {};
1120
+ __export(claude_exports, {
1121
+ _injectSDK: () => _injectSDK2,
1122
+ _resetSDK: () => _resetSDK2,
1123
+ createClaudeService: () => createClaudeService
1124
+ });
1125
+ function mcpToolName(toolName) {
1126
+ return `${MCP_TOOL_PREFIX}${toolName}`;
1127
+ }
1128
+ function stripMcpPrefix(name) {
1129
+ return name.startsWith(MCP_TOOL_PREFIX) ? name.slice(MCP_TOOL_PREFIX.length) : name;
1130
+ }
1131
+ async function loadSDK2() {
1132
+ if (sdkModule2) return sdkModule2;
1133
+ try {
1134
+ sdkModule2 = await import('@anthropic-ai/claude-agent-sdk');
1135
+ return sdkModule2;
1136
+ } catch {
1137
+ throw new SubprocessError(
1138
+ "@anthropic-ai/claude-agent-sdk is not installed. Install it: npm install @anthropic-ai/claude-agent-sdk"
1139
+ );
1140
+ }
1141
+ }
1142
+ function _injectSDK2(mock) {
1143
+ sdkModule2 = mock;
1144
+ }
1145
+ function _resetSDK2() {
1146
+ sdkModule2 = null;
1147
+ }
1148
+ function buildMcpServer(sdk, tools, toolResultCapture) {
1149
+ if (tools.length === 0) return void 0;
1150
+ const mcpTools = tools.map((tool) => {
1151
+ const zodSchema = tool.parameters;
1152
+ const inputSchema = zodSchema.shape ?? zodToJsonSchema(tool.parameters);
1153
+ return sdk.tool(
1154
+ tool.name,
1155
+ tool.description ?? "",
1156
+ inputSchema,
1157
+ async (args) => {
1158
+ const result = await tool.execute(args);
1159
+ if (toolResultCapture) {
1160
+ toolResultCapture.set(tool.name, result);
1161
+ }
1162
+ return {
1163
+ content: [
1164
+ {
1165
+ type: "text",
1166
+ text: typeof result === "string" ? result : JSON.stringify(result)
1167
+ }
1168
+ ]
1169
+ };
1170
+ }
1171
+ );
1172
+ });
1173
+ return sdk.createSdkMcpServer({
1174
+ name: MCP_SERVER_NAME,
1175
+ version: "1.0.0",
1176
+ tools: mcpTools
1177
+ });
1178
+ }
1179
+ function scopeToDestination(scope) {
1180
+ switch (scope) {
1181
+ case "once":
1182
+ return "session";
1183
+ case "session":
1184
+ return "session";
1185
+ case "project":
1186
+ return "projectSettings";
1187
+ case "always":
1188
+ return "userSettings";
1189
+ }
1190
+ }
1191
+ function destinationToScope(dest) {
1192
+ switch (dest) {
1193
+ case "session":
1194
+ case "cliArg":
1195
+ return "session";
1196
+ case "projectSettings":
1197
+ case "localSettings":
1198
+ return "project";
1199
+ case "userSettings":
1200
+ return "always";
1201
+ }
1202
+ }
1203
+ function extractSuggestedScope(suggestions) {
1204
+ if (!suggestions || suggestions.length === 0) return void 0;
1205
+ return destinationToScope(suggestions[0].destination);
1206
+ }
1207
+ function buildCanUseTool(config) {
1208
+ const onPermission = config.supervisor?.onPermission;
1209
+ if (!onPermission) return void 0;
1210
+ const permissionStore = config.permissionStore;
1211
+ return async (rawToolName, input, options) => {
1212
+ const toolName = stripMcpPrefix(rawToolName);
1213
+ if (permissionStore && await permissionStore.isApproved(toolName)) {
1214
+ return {
1215
+ behavior: "allow",
1216
+ toolUseID: options.toolUseID
1217
+ };
1218
+ }
1219
+ const unifiedRequest = {
1220
+ toolName,
1221
+ toolArgs: input,
1222
+ suggestedScope: extractSuggestedScope(options.suggestions),
1223
+ rawSDKRequest: { toolName, input, ...options }
1224
+ };
1225
+ const decision = await onPermission(
1226
+ unifiedRequest,
1227
+ options.signal
1228
+ );
1229
+ if (decision.allowed) {
1230
+ if (permissionStore && decision.scope) {
1231
+ await permissionStore.approve(toolName, decision.scope);
1232
+ }
1233
+ const result = {
1234
+ behavior: "allow",
1235
+ toolUseID: options.toolUseID
1236
+ };
1237
+ if (decision.modifiedInput) {
1238
+ result.updatedInput = decision.modifiedInput;
1239
+ }
1240
+ if (decision.scope && decision.scope !== "once" && options.suggestions) {
1241
+ result.updatedPermissions = options.suggestions.map((s) => ({
1242
+ ...s,
1243
+ destination: scopeToDestination(decision.scope)
1244
+ }));
1245
+ }
1246
+ return result;
1247
+ }
1248
+ return {
1249
+ behavior: "deny",
1250
+ message: decision.reason ?? "Permission denied",
1251
+ toolUseID: options.toolUseID
1252
+ };
1253
+ };
1254
+ }
1255
+ function aggregateUsage(modelUsage) {
1256
+ let promptTokens = 0;
1257
+ let completionTokens = 0;
1258
+ for (const u of Object.values(modelUsage ?? {})) {
1259
+ promptTokens += u.inputTokens ?? 0;
1260
+ completionTokens += u.outputTokens ?? 0;
1261
+ }
1262
+ return { promptTokens, completionTokens };
1263
+ }
1264
+ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
1265
+ switch (msg.type) {
1266
+ case "assistant": {
1267
+ const betaMessage = msg.message;
1268
+ if (!betaMessage?.content) return null;
1269
+ const events = [];
1270
+ for (const block of betaMessage.content) {
1271
+ if (block.type === "tool_use") {
1272
+ const toolCallId = String(block.id ?? "");
1273
+ const toolName = stripMcpPrefix(block.name ?? "unknown");
1274
+ if (toolCallTracker) {
1275
+ toolCallTracker.trackStart(toolCallId, toolName);
1276
+ }
1277
+ events.push({
1278
+ type: "tool_call_start",
1279
+ toolCallId,
1280
+ toolName,
1281
+ args: block.input ?? {}
1282
+ });
1283
+ }
1284
+ }
1285
+ return events.length > 0 ? events : null;
1286
+ }
1287
+ case "user": {
1288
+ const toolResult = msg.tool_use_result;
1289
+ if (toolResult !== void 0) {
1290
+ return null;
1291
+ }
1292
+ return null;
1293
+ }
1294
+ case "tool_use_summary": {
1295
+ const summary = msg.summary;
1296
+ const toolName = stripMcpPrefix(msg.tool_name ?? "unknown");
1297
+ const precedingIds = msg.preceding_tool_use_ids;
1298
+ let toolCallId = "";
1299
+ if (precedingIds && precedingIds.length > 0) {
1300
+ toolCallId = precedingIds[0];
1301
+ if (toolCallTracker) toolCallTracker.consumeToolCallId(toolName);
1302
+ } else if (toolCallTracker) {
1303
+ toolCallId = toolCallTracker.consumeToolCallId(toolName);
1304
+ }
1305
+ return {
1306
+ type: "tool_call_end",
1307
+ toolCallId,
1308
+ toolName,
1309
+ result: summary ?? null
1310
+ };
1311
+ }
1312
+ case "stream_event": {
1313
+ const event = msg.event;
1314
+ if (!event) return null;
1315
+ if (event.type === "content_block_delta" && event.index !== void 0 && thinkingBlockIndices?.has(event.index)) {
1316
+ const thinkingText = String(event.delta?.thinking ?? event.delta?.text ?? "");
1317
+ if (thinkingText) {
1318
+ return { type: "thinking_delta", text: thinkingText };
1319
+ }
1320
+ return null;
1321
+ }
1322
+ if (event.type === "content_block_delta" && event.delta?.type === "text_delta" && event.delta.text) {
1323
+ return { type: "text_delta", text: event.delta.text };
1324
+ }
1325
+ if (event.type === "content_block_start" && event.content_block?.type === "thinking") {
1326
+ if (thinkingBlockIndices && event.index !== void 0) {
1327
+ thinkingBlockIndices.add(event.index);
1328
+ }
1329
+ return { type: "thinking_start" };
1330
+ }
1331
+ if (event.type === "content_block_stop" && event.index !== void 0 && thinkingBlockIndices?.has(event.index)) {
1332
+ thinkingBlockIndices.delete(event.index);
1333
+ return { type: "thinking_end" };
1334
+ }
1335
+ return null;
1336
+ }
1337
+ case "tool_progress": {
1338
+ return null;
1339
+ }
1340
+ case "result": {
1341
+ if (msg.subtype === "success") {
1342
+ const r = msg;
1343
+ return {
1344
+ type: "usage_update",
1345
+ ...aggregateUsage(r.modelUsage)
1346
+ };
1347
+ }
1348
+ if (msg.is_error) {
1349
+ const r = msg;
1350
+ return {
1351
+ type: "error",
1352
+ error: r.errors?.join("; ") ?? "Unknown error",
1353
+ recoverable: false
1354
+ };
1355
+ }
1356
+ return null;
1357
+ }
1358
+ default:
1359
+ return null;
1360
+ }
1361
+ }
1362
+ function extractLastUserPrompt2(messages) {
1363
+ for (let i = messages.length - 1; i >= 0; i--) {
1364
+ const msg = messages[i];
1365
+ if (msg.role === "user") {
1366
+ return getTextContent(msg.content);
1367
+ }
1368
+ }
1369
+ return "";
1370
+ }
1371
+ function serializeToolCall2(tc) {
1372
+ const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
1373
+ return ` Tool call: ${tc.name}(${args})`;
1374
+ }
1375
+ function serializeToolResult2(tr) {
1376
+ const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
1377
+ const prefix = tr.isError ? "[ERROR] " : "";
1378
+ return ` ${tr.name} \u2192 ${prefix}${result}`;
1379
+ }
1380
+ function buildContextualPrompt2(messages) {
1381
+ if (messages.length <= 1) {
1382
+ return extractLastUserPrompt2(messages);
1383
+ }
1384
+ const history = messages.slice(0, -1).map((msg) => {
1385
+ if (msg.role === "user") {
1386
+ return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
1387
+ }
1388
+ if (msg.role === "tool" && msg.toolResults) {
1389
+ const results = msg.toolResults.map(serializeToolResult2).join("\n");
1390
+ return `Tool results:
1391
+ ${results}`;
1392
+ }
1393
+ if (msg.role === "assistant") {
1394
+ const parts = [];
1395
+ const thinking = msg.thinking;
1396
+ if (thinking) {
1397
+ parts.push(`[reasoning: ${thinking}]`);
1398
+ }
1399
+ const text2 = msg.content ? getTextContent(msg.content) : "";
1400
+ if (text2) parts.push(text2);
1401
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
1402
+ parts.push(msg.toolCalls.map(serializeToolCall2).join("\n"));
1403
+ }
1404
+ return `Assistant: ${parts.join("\n")}`;
1405
+ }
1406
+ const text = msg.content ? getTextContent(msg.content) : "";
1407
+ return `${msg.role}: ${text}`;
1408
+ }).join("\n");
1409
+ const lastPrompt = extractLastUserPrompt2(messages);
1410
+ return `Conversation history:
1411
+ ${history}
1412
+
1413
+ User: ${lastPrompt}`;
1414
+ }
1415
+ function createClaudeService(options) {
1416
+ return new ClaudeAgentService(options);
1417
+ }
1418
+ var MCP_SERVER_NAME, MCP_TOOL_PREFIX, sdkModule2, ANTHROPIC_MODELS_URL, ANTHROPIC_API_VERSION, ANTHROPIC_OAUTH_BETA, ClaudeToolCallTracker, ClaudeAgent, ClaudeAgentService;
1419
+ var init_claude = __esm({
1420
+ "src/backends/claude.ts"() {
1421
+ init_types();
1422
+ init_base_agent();
1423
+ init_errors();
1424
+ init_schema();
1425
+ MCP_SERVER_NAME = "agent-sdk-tools";
1426
+ MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
1427
+ sdkModule2 = null;
1428
+ ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
1429
+ ANTHROPIC_API_VERSION = "2023-06-01";
1430
+ ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
1431
+ ClaudeToolCallTracker = class {
1432
+ queues = /* @__PURE__ */ new Map();
1433
+ trackStart(toolCallId, toolName) {
1434
+ if (!this.queues.has(toolName)) {
1435
+ this.queues.set(toolName, []);
1436
+ }
1437
+ this.queues.get(toolName).push(toolCallId);
1438
+ }
1439
+ /** Peek at the current tool call ID for a tool name (does not consume) */
1440
+ peekToolCallId(toolName) {
1441
+ const queue = this.queues.get(toolName);
1442
+ if (!queue || queue.length === 0) return "";
1443
+ return queue[0];
1444
+ }
1445
+ /** Consume and return the first tool call ID for a tool name */
1446
+ consumeToolCallId(toolName) {
1447
+ const queue = this.queues.get(toolName);
1448
+ if (!queue || queue.length === 0) return "";
1449
+ return queue.shift();
1450
+ }
1451
+ clear() {
1452
+ this.queues.clear();
1453
+ }
1454
+ };
1455
+ ClaudeAgent = class extends BaseAgent {
1456
+ backendName = "claude";
1457
+ options;
1458
+ tools;
1459
+ canUseTool;
1460
+ isPersistent;
1461
+ _sessionId;
1462
+ activeQuery = null;
1463
+ constructor(config, options) {
1464
+ super(config);
1465
+ this.options = options;
1466
+ this.tools = config.tools ?? [];
1467
+ this.canUseTool = buildCanUseTool(config);
1468
+ this.isPersistent = config.sessionMode === "persistent";
1469
+ if (options.resumeSessionId) {
1470
+ this._sessionId = options.resumeSessionId;
1471
+ }
1472
+ if (config.supervisor?.onAskUser) {
1473
+ console.warn(
1474
+ "[agent-sdk/claude] supervisor.onAskUser is not supported by the Claude CLI backend. User interaction requests from the model will not be forwarded."
1475
+ );
1476
+ }
1477
+ }
1478
+ get sessionId() {
1479
+ return this._sessionId;
1480
+ }
1481
+ async interrupt() {
1482
+ try {
1483
+ if (this.activeQuery) {
1484
+ await this.activeQuery.interrupt();
1485
+ }
1486
+ } catch {
1487
+ } finally {
1488
+ this.abort();
1489
+ }
1490
+ }
1491
+ /** Clear persistent session state after an error so next call starts fresh */
1492
+ clearPersistentSession() {
1493
+ this._sessionId = void 0;
1494
+ }
1495
+ emitSessionInfo(sessionId) {
1496
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
1497
+ const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
1498
+ return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
1499
+ }
1500
+ buildQueryOptions(signal) {
1501
+ const ac = new AbortController();
1502
+ signal.addEventListener("abort", () => ac.abort(), { once: true });
1503
+ const opts = {
1504
+ abortController: ac,
1505
+ model: this.config.model,
1506
+ maxTurns: this.options.maxTurns,
1507
+ cwd: this.options.workingDirectory,
1508
+ pathToClaudeCodeExecutable: this.options.cliPath,
1509
+ persistSession: this.isPersistent,
1510
+ includePartialMessages: true,
1511
+ canUseTool: this.canUseTool
1512
+ };
1513
+ if (this.isPersistent && this._sessionId) {
1514
+ opts.resume = this._sessionId;
1515
+ }
1516
+ if (this.config.systemPrompt) {
1517
+ opts.systemPrompt = this.config.systemPrompt;
1518
+ }
1519
+ if (this.options.oauthToken || this.options.env) {
1520
+ opts.env = {
1521
+ ...process.env,
1522
+ ...this.options.env ?? {},
1523
+ ...this.options.oauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: this.options.oauthToken } : {}
1524
+ };
1525
+ }
1526
+ if (opts.canUseTool && !opts.permissionMode) {
1527
+ opts.permissionMode = "default";
1528
+ }
1529
+ if (this.config.availableTools) {
1530
+ opts.tools = [...this.config.availableTools];
1531
+ }
1532
+ return opts;
1533
+ }
1534
+ async buildMcpConfig(opts, toolResultCapture) {
1535
+ if (this.tools.length === 0) return opts;
1536
+ const sdk = await loadSDK2();
1537
+ const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture);
1538
+ if (mcpServer) {
1539
+ opts.mcpServers = {
1540
+ [MCP_SERVER_NAME]: mcpServer
1541
+ };
1542
+ const mcpToolNames = this.tools.map((t) => mcpToolName(t.name));
1543
+ opts.allowedTools = [...opts.allowedTools ?? [], ...mcpToolNames];
1544
+ }
1545
+ return opts;
1546
+ }
1547
+ // ─── executeRun ─────────────────────────────────────────────────
1548
+ async executeRun(messages, _options, signal) {
1549
+ this.checkAbort(signal);
1550
+ const sdk = await loadSDK2();
1551
+ const isResuming = this.isPersistent && this._sessionId !== void 0;
1552
+ const prompt = isResuming ? extractLastUserPrompt2(messages) : buildContextualPrompt2(messages);
1553
+ let opts = this.buildQueryOptions(signal);
1554
+ const toolResultCapture = /* @__PURE__ */ new Map();
1555
+ opts = await this.buildMcpConfig(opts, toolResultCapture);
1556
+ const q = sdk.query({ prompt, options: opts });
1557
+ this.activeQuery = q;
1558
+ const toolCalls = [];
1559
+ let output = null;
1560
+ let usage;
1561
+ try {
1562
+ for await (const msg of q) {
1563
+ if (msg.type === "assistant") {
1564
+ const betaMessage = msg.message;
1565
+ if (betaMessage?.content) {
1566
+ for (const block of betaMessage.content) {
1567
+ if (block.type === "tool_use") {
1568
+ const toolName = stripMcpPrefix(block.name ?? "unknown");
1569
+ toolCalls.push({
1570
+ toolName,
1571
+ args: block.input ?? {},
1572
+ result: toolResultCapture.get(toolName) ?? null,
1573
+ approved: true
1574
+ });
1575
+ }
1576
+ }
1577
+ }
1578
+ }
1579
+ if (msg.type === "tool_use_summary" || msg.type === "result") {
1580
+ for (const tc of toolCalls) {
1581
+ if (tc.result === null) {
1582
+ const captured = toolResultCapture.get(tc.toolName);
1583
+ if (captured !== void 0) tc.result = captured;
1584
+ }
1585
+ }
1586
+ }
1587
+ if (msg.type === "result") {
1588
+ if (msg.subtype === "success") {
1589
+ const r = msg;
1590
+ output = r.result;
1591
+ usage = aggregateUsage(r.modelUsage);
1592
+ if (this.isPersistent && r.session_id) {
1593
+ this._sessionId = r.session_id;
1594
+ }
1595
+ } else if (msg.is_error) {
1596
+ const r = msg;
1597
+ throw new Error(
1598
+ `Claude query failed: ${r.errors?.join("; ") ?? "unknown error"}`
1599
+ );
1600
+ }
1601
+ }
1602
+ }
1603
+ } catch (e) {
1604
+ if (signal.aborted) throw new AbortError();
1605
+ if (isResuming && this.isPersistent) {
1606
+ this.clearPersistentSession();
1607
+ const retryPrompt = buildContextualPrompt2(messages);
1608
+ let retryOpts = this.buildQueryOptions(signal);
1609
+ toolResultCapture.clear();
1610
+ retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
1611
+ const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
1612
+ this.activeQuery = retryQ;
1613
+ toolCalls.length = 0;
1614
+ output = null;
1615
+ try {
1616
+ for await (const msg of retryQ) {
1617
+ if (msg.type === "assistant") {
1618
+ const betaMessage = msg.message;
1619
+ if (betaMessage?.content) {
1620
+ for (const block of betaMessage.content) {
1621
+ if (block.type === "tool_use") {
1622
+ const toolName = stripMcpPrefix(block.name ?? "unknown");
1623
+ toolCalls.push({
1624
+ toolName,
1625
+ args: block.input ?? {},
1626
+ result: toolResultCapture.get(toolName) ?? null,
1627
+ approved: true
1628
+ });
1629
+ }
1630
+ }
1631
+ }
1632
+ }
1633
+ if (msg.type === "tool_use_summary" || msg.type === "result") {
1634
+ for (const tc of toolCalls) {
1635
+ if (tc.result === null) {
1636
+ const captured = toolResultCapture.get(tc.toolName);
1637
+ if (captured !== void 0) tc.result = captured;
1638
+ }
1639
+ }
1640
+ }
1641
+ if (msg.type === "result") {
1642
+ if (msg.subtype === "success") {
1643
+ const r = msg;
1644
+ output = r.result;
1645
+ usage = aggregateUsage(r.modelUsage);
1646
+ if (this.isPersistent && r.session_id) {
1647
+ this._sessionId = r.session_id;
1648
+ }
1649
+ } else if (msg.is_error) {
1650
+ const r = msg;
1651
+ throw new Error(
1652
+ `Claude query failed: ${r.errors?.join("; ") ?? "unknown error"}`
1653
+ );
1654
+ }
1655
+ }
1656
+ }
1657
+ } catch (retryError) {
1658
+ if (this.isPersistent) this.clearPersistentSession();
1659
+ if (signal.aborted) throw new AbortError();
1660
+ throw retryError;
1661
+ } finally {
1662
+ this.activeQuery = null;
1663
+ }
1664
+ return {
1665
+ output,
1666
+ structuredOutput: void 0,
1667
+ toolCalls,
1668
+ messages: [
1669
+ ...messages,
1670
+ ...output !== null ? [{ role: "assistant", content: output }] : []
1671
+ ],
1672
+ usage
1673
+ };
1674
+ }
1675
+ if (this.isPersistent) this.clearPersistentSession();
1676
+ throw e;
1677
+ } finally {
1678
+ this.activeQuery = null;
1679
+ }
1680
+ return {
1681
+ output,
1682
+ structuredOutput: void 0,
1683
+ toolCalls,
1684
+ messages: [
1685
+ ...messages,
1686
+ ...output !== null ? [{ role: "assistant", content: output }] : []
1687
+ ],
1688
+ usage
1689
+ };
1690
+ }
1691
+ // ─── executeRunStructured ───────────────────────────────────────
1692
+ async executeRunStructured(messages, schema, _options, signal) {
1693
+ this.checkAbort(signal);
1694
+ const sdk = await loadSDK2();
1695
+ const isResuming = this.isPersistent && this._sessionId !== void 0;
1696
+ const prompt = isResuming ? extractLastUserPrompt2(messages) : buildContextualPrompt2(messages);
1697
+ let opts = this.buildQueryOptions(signal);
1698
+ const toolResultCapture = /* @__PURE__ */ new Map();
1699
+ opts = await this.buildMcpConfig(opts, toolResultCapture);
1700
+ const jsonSchema = zodToJsonSchema(schema.schema);
1701
+ opts.outputFormat = {
1702
+ type: "json_schema",
1703
+ schema: jsonSchema
1704
+ };
1705
+ const q = sdk.query({ prompt, options: opts });
1706
+ this.activeQuery = q;
1707
+ const toolCalls = [];
1708
+ let output = null;
1709
+ let structuredOutput;
1710
+ let usage;
1711
+ try {
1712
+ for await (const msg of q) {
1713
+ if (msg.type === "assistant") {
1714
+ const betaMessage = msg.message;
1715
+ if (betaMessage?.content) {
1716
+ for (const block of betaMessage.content) {
1717
+ if (block.type === "tool_use") {
1718
+ const toolName = stripMcpPrefix(block.name ?? "unknown");
1719
+ toolCalls.push({
1720
+ toolName,
1721
+ args: block.input ?? {},
1722
+ result: toolResultCapture.get(toolName) ?? null,
1723
+ approved: true
1724
+ });
1725
+ }
1726
+ }
1727
+ }
1728
+ }
1729
+ if (msg.type === "tool_use_summary" || msg.type === "result") {
1730
+ for (const tc of toolCalls) {
1731
+ if (tc.result === null) {
1732
+ const captured = toolResultCapture.get(tc.toolName);
1733
+ if (captured !== void 0) tc.result = captured;
1734
+ }
1735
+ }
1736
+ }
1737
+ if (msg.type === "result" && msg.subtype === "success") {
1738
+ const r = msg;
1739
+ output = r.result;
1740
+ if (r.structured_output !== void 0) {
1741
+ try {
1742
+ structuredOutput = schema.schema.parse(r.structured_output);
1743
+ } catch {
1744
+ try {
1745
+ structuredOutput = schema.schema.parse(JSON.parse(r.result));
1746
+ } catch {
1747
+ }
1748
+ }
1749
+ } else if (r.result) {
1750
+ try {
1751
+ const jsonMatch = r.result.match(/```(?:json)?\s*([\s\S]*?)```/);
1752
+ const raw = jsonMatch ? jsonMatch[1].trim() : r.result.trim();
1753
+ structuredOutput = schema.schema.parse(JSON.parse(raw));
1754
+ } catch {
1755
+ }
1756
+ }
1757
+ usage = aggregateUsage(r.modelUsage);
1758
+ if (this.isPersistent && r.session_id) {
1759
+ this._sessionId = r.session_id;
1760
+ }
1761
+ } else if (msg.type === "result" && msg.is_error) {
1762
+ const r = msg;
1763
+ throw new Error(
1764
+ `Claude query failed: ${r.errors?.join("; ") ?? "unknown error"}`
1765
+ );
1766
+ }
1767
+ }
1768
+ } catch (e) {
1769
+ if (signal.aborted) throw new AbortError();
1770
+ if (isResuming && this.isPersistent) {
1771
+ this.clearPersistentSession();
1772
+ const retryPrompt = buildContextualPrompt2(messages);
1773
+ let retryOpts = this.buildQueryOptions(signal);
1774
+ toolResultCapture.clear();
1775
+ retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
1776
+ retryOpts.outputFormat = {
1777
+ type: "json_schema",
1778
+ schema: jsonSchema
1779
+ };
1780
+ const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
1781
+ this.activeQuery = retryQ;
1782
+ toolCalls.length = 0;
1783
+ output = null;
1784
+ structuredOutput = void 0;
1785
+ try {
1786
+ for await (const msg of retryQ) {
1787
+ if (msg.type === "assistant") {
1788
+ const betaMessage = msg.message;
1789
+ if (betaMessage?.content) {
1790
+ for (const block of betaMessage.content) {
1791
+ if (block.type === "tool_use") {
1792
+ const toolName = stripMcpPrefix(block.name ?? "unknown");
1793
+ toolCalls.push({
1794
+ toolName,
1795
+ args: block.input ?? {},
1796
+ result: toolResultCapture.get(toolName) ?? null,
1797
+ approved: true
1798
+ });
1799
+ }
1800
+ }
1801
+ }
1802
+ }
1803
+ if (msg.type === "tool_use_summary" || msg.type === "result") {
1804
+ for (const tc of toolCalls) {
1805
+ if (tc.result === null) {
1806
+ const captured = toolResultCapture.get(tc.toolName);
1807
+ if (captured !== void 0) tc.result = captured;
1808
+ }
1809
+ }
1810
+ }
1811
+ if (msg.type === "result" && msg.subtype === "success") {
1812
+ const r = msg;
1813
+ output = r.result;
1814
+ if (r.structured_output !== void 0) {
1815
+ try {
1816
+ structuredOutput = schema.schema.parse(r.structured_output);
1817
+ } catch {
1818
+ try {
1819
+ structuredOutput = schema.schema.parse(JSON.parse(r.result));
1820
+ } catch {
1821
+ }
1822
+ }
1823
+ } else if (r.result) {
1824
+ try {
1825
+ const jsonMatch = r.result.match(/```(?:json)?\s*([\s\S]*?)```/);
1826
+ const raw = jsonMatch ? jsonMatch[1].trim() : r.result.trim();
1827
+ structuredOutput = schema.schema.parse(JSON.parse(raw));
1828
+ } catch {
1829
+ }
1830
+ }
1831
+ usage = aggregateUsage(r.modelUsage);
1832
+ if (this.isPersistent && r.session_id) {
1833
+ this._sessionId = r.session_id;
1834
+ }
1835
+ } else if (msg.type === "result" && msg.is_error) {
1836
+ const r = msg;
1837
+ throw new Error(
1838
+ `Claude query failed: ${r.errors?.join("; ") ?? "unknown error"}`
1839
+ );
1840
+ }
1841
+ }
1842
+ } catch (retryError) {
1843
+ if (this.isPersistent) this.clearPersistentSession();
1844
+ if (signal.aborted) throw new AbortError();
1845
+ throw retryError;
1846
+ } finally {
1847
+ this.activeQuery = null;
1848
+ }
1849
+ return {
1850
+ output,
1851
+ structuredOutput,
1852
+ toolCalls,
1853
+ messages: [
1854
+ ...messages,
1855
+ ...output !== null ? [{ role: "assistant", content: output }] : []
1856
+ ],
1857
+ usage
1858
+ };
1859
+ }
1860
+ if (this.isPersistent) this.clearPersistentSession();
1861
+ throw e;
1862
+ } finally {
1863
+ this.activeQuery = null;
1864
+ }
1865
+ return {
1866
+ output,
1867
+ structuredOutput,
1868
+ toolCalls,
1869
+ messages: [
1870
+ ...messages,
1871
+ ...output !== null ? [{ role: "assistant", content: output }] : []
1872
+ ],
1873
+ usage
1874
+ };
1875
+ }
1876
+ // ─── executeStream ──────────────────────────────────────────────
1877
+ async *executeStream(messages, _options, signal) {
1878
+ this.checkAbort(signal);
1879
+ const sdk = await loadSDK2();
1880
+ const isResuming = this.isPersistent && this._sessionId !== void 0;
1881
+ const prompt = isResuming ? extractLastUserPrompt2(messages) : buildContextualPrompt2(messages);
1882
+ let opts = this.buildQueryOptions(signal);
1883
+ const toolResultCapture = /* @__PURE__ */ new Map();
1884
+ opts = await this.buildMcpConfig(opts, toolResultCapture);
1885
+ const q = sdk.query({ prompt, options: opts });
1886
+ this.activeQuery = q;
1887
+ const thinkingBlockIndices = /* @__PURE__ */ new Set();
1888
+ const toolCallTracker = new ClaudeToolCallTracker();
1889
+ const pendingStreamToolCalls = /* @__PURE__ */ new Map();
1890
+ try {
1891
+ for await (const msg of q) {
1892
+ if (signal.aborted) throw new AbortError();
1893
+ const events = mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker);
1894
+ if (events) {
1895
+ const mapped = Array.isArray(events) ? events : [events];
1896
+ for (const e of mapped) {
1897
+ if (e.type === "tool_call_start") {
1898
+ pendingStreamToolCalls.set(e.toolCallId, e.toolName);
1899
+ }
1900
+ if (e.type === "tool_call_end" && toolResultCapture.has(e.toolName)) {
1901
+ e.result = toolResultCapture.get(e.toolName);
1902
+ toolResultCapture.delete(e.toolName);
1903
+ pendingStreamToolCalls.delete(e.toolCallId);
1904
+ } else if (e.type === "tool_call_end") {
1905
+ pendingStreamToolCalls.delete(e.toolCallId);
1906
+ }
1907
+ yield e;
1908
+ }
1909
+ }
1910
+ if (msg.type === "result" && msg.subtype === "success") {
1911
+ const r = msg;
1912
+ for (const [toolCallId, toolName] of pendingStreamToolCalls) {
1913
+ if (toolResultCapture.has(toolName)) {
1914
+ yield {
1915
+ type: "tool_call_end",
1916
+ toolCallId,
1917
+ toolName,
1918
+ result: toolResultCapture.get(toolName)
1919
+ };
1920
+ toolResultCapture.delete(toolName);
1921
+ }
1922
+ }
1923
+ pendingStreamToolCalls.clear();
1924
+ if (r.session_id) {
1925
+ if (this.isPersistent) {
1926
+ this._sessionId = r.session_id;
1927
+ }
1928
+ yield this.emitSessionInfo(r.session_id);
1929
+ }
1930
+ yield { type: "done", finalOutput: r.result };
1931
+ }
1932
+ }
1933
+ } catch (e) {
1934
+ if (signal.aborted) throw new AbortError();
1935
+ if (isResuming && this.isPersistent) {
1936
+ this.clearPersistentSession();
1937
+ const retryPrompt = buildContextualPrompt2(messages);
1938
+ let retryOpts = this.buildQueryOptions(signal);
1939
+ toolResultCapture.clear();
1940
+ retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
1941
+ const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
1942
+ this.activeQuery = retryQ;
1943
+ const retryThinkingBlockIndices = /* @__PURE__ */ new Set();
1944
+ const retryToolCallTracker = new ClaudeToolCallTracker();
1945
+ const retryPendingToolCalls = /* @__PURE__ */ new Map();
1946
+ try {
1947
+ for await (const msg of retryQ) {
1948
+ if (signal.aborted) throw new AbortError();
1949
+ const retryEvents = mapSDKMessage(msg, retryThinkingBlockIndices, retryToolCallTracker);
1950
+ if (retryEvents) {
1951
+ const mapped = Array.isArray(retryEvents) ? retryEvents : [retryEvents];
1952
+ for (const ev of mapped) {
1953
+ if (ev.type === "tool_call_start") {
1954
+ retryPendingToolCalls.set(ev.toolCallId, ev.toolName);
1955
+ }
1956
+ if (ev.type === "tool_call_end" && toolResultCapture.has(ev.toolName)) {
1957
+ ev.result = toolResultCapture.get(ev.toolName);
1958
+ toolResultCapture.delete(ev.toolName);
1959
+ retryPendingToolCalls.delete(ev.toolCallId);
1960
+ } else if (ev.type === "tool_call_end") {
1961
+ retryPendingToolCalls.delete(ev.toolCallId);
1962
+ }
1963
+ yield ev;
1964
+ }
1965
+ }
1966
+ if (msg.type === "result" && msg.subtype === "success") {
1967
+ const r = msg;
1968
+ for (const [toolCallId, toolName] of retryPendingToolCalls) {
1969
+ if (toolResultCapture.has(toolName)) {
1970
+ yield {
1971
+ type: "tool_call_end",
1972
+ toolCallId,
1973
+ toolName,
1974
+ result: toolResultCapture.get(toolName)
1975
+ };
1976
+ toolResultCapture.delete(toolName);
1977
+ }
1978
+ }
1979
+ retryPendingToolCalls.clear();
1980
+ if (r.session_id) {
1981
+ if (this.isPersistent) {
1982
+ this._sessionId = r.session_id;
1983
+ }
1984
+ yield this.emitSessionInfo(r.session_id);
1985
+ }
1986
+ yield { type: "done", finalOutput: r.result };
1987
+ }
1988
+ }
1989
+ } catch (retryError) {
1990
+ if (this.isPersistent) this.clearPersistentSession();
1991
+ if (signal.aborted) throw new AbortError();
1992
+ throw retryError;
1993
+ } finally {
1994
+ this.activeQuery = null;
1995
+ }
1996
+ return;
1997
+ }
1998
+ if (this.isPersistent) this.clearPersistentSession();
1999
+ throw e;
2000
+ } finally {
2001
+ this.activeQuery = null;
2002
+ }
2003
+ }
2004
+ dispose() {
2005
+ this._sessionId = void 0;
2006
+ super.dispose();
2007
+ }
2008
+ };
2009
+ ClaudeAgentService = class {
2010
+ name = "claude";
2011
+ disposed = false;
2012
+ options;
2013
+ cachedModels = null;
2014
+ constructor(options) {
2015
+ this.options = options;
2016
+ }
2017
+ createAgent(config) {
2018
+ if (this.disposed) throw new DisposedError("ClaudeAgentService");
2019
+ return new ClaudeAgent(config, this.options);
2020
+ }
2021
+ async listModels() {
2022
+ if (this.disposed) throw new DisposedError("ClaudeAgentService");
2023
+ if (this.cachedModels) return this.cachedModels;
2024
+ const token = this.options.oauthToken;
2025
+ if (!token) {
2026
+ return [];
2027
+ }
2028
+ const res = await globalThis.fetch(
2029
+ `${ANTHROPIC_MODELS_URL}?limit=100`,
2030
+ {
2031
+ headers: {
2032
+ Authorization: `Bearer ${token}`,
2033
+ "anthropic-version": ANTHROPIC_API_VERSION,
2034
+ "anthropic-beta": ANTHROPIC_OAUTH_BETA
2035
+ }
2036
+ }
2037
+ );
2038
+ if (!res.ok) {
2039
+ return [];
2040
+ }
2041
+ const body = await res.json();
2042
+ if (!body.data || body.data.length === 0) {
2043
+ return [];
2044
+ }
2045
+ this.cachedModels = body.data.map((m) => ({
2046
+ id: m.id,
2047
+ name: m.display_name,
2048
+ provider: "claude"
2049
+ }));
2050
+ return this.cachedModels;
2051
+ }
2052
+ async validate() {
2053
+ if (this.disposed) throw new DisposedError("ClaudeAgentService");
2054
+ const errors = [];
2055
+ try {
2056
+ await loadSDK2();
2057
+ } catch (e) {
2058
+ errors.push(
2059
+ e instanceof Error ? e.message : String(e)
2060
+ );
2061
+ return { valid: false, errors };
2062
+ }
2063
+ try {
2064
+ const sdk = await loadSDK2();
2065
+ const q = sdk.query({
2066
+ prompt: "echo test",
2067
+ options: {
2068
+ model: "claude-sonnet-4-20250514",
2069
+ pathToClaudeCodeExecutable: this.options.cliPath,
2070
+ cwd: this.options.workingDirectory,
2071
+ persistSession: false,
2072
+ maxTurns: 1,
2073
+ permissionMode: "plan"
2074
+ }
2075
+ });
2076
+ const first = await q.next();
2077
+ q.close();
2078
+ if (first.done) {
2079
+ errors.push("Claude CLI returned no messages \u2014 may not be authenticated.");
2080
+ }
2081
+ } catch (e) {
2082
+ errors.push(
2083
+ `Failed to connect to Claude CLI: ${e instanceof Error ? e.message : String(e)}`
2084
+ );
2085
+ }
2086
+ return { valid: errors.length === 0, errors };
2087
+ }
2088
+ async dispose() {
2089
+ if (this.disposed) return;
2090
+ this.disposed = true;
2091
+ this.cachedModels = null;
2092
+ }
2093
+ };
2094
+ }
2095
+ });
2096
+
2097
+ // src/backends/vercel-ai.ts
2098
+ var vercel_ai_exports = {};
2099
+ __export(vercel_ai_exports, {
2100
+ _injectCompat: () => _injectCompat,
2101
+ _injectSDK: () => _injectSDK3,
2102
+ _resetSDK: () => _resetSDK3,
2103
+ createVercelAIService: () => createVercelAIService
2104
+ });
2105
+ async function loadSDK3() {
2106
+ if (sdkModule3) return sdkModule3;
2107
+ try {
2108
+ sdkModule3 = await import('ai');
2109
+ return sdkModule3;
2110
+ } catch {
2111
+ throw new DependencyError("ai");
2112
+ }
2113
+ }
2114
+ async function loadCompat() {
2115
+ if (compatModule) return compatModule;
2116
+ try {
2117
+ compatModule = await import('@ai-sdk/openai-compatible');
2118
+ return compatModule;
2119
+ } catch {
2120
+ throw new DependencyError("@ai-sdk/openai-compatible");
2121
+ }
2122
+ }
2123
+ function _injectSDK3(mock) {
2124
+ sdkModule3 = mock;
2125
+ }
2126
+ function _injectCompat(mock) {
2127
+ compatModule = mock;
2128
+ }
2129
+ function _resetSDK3() {
2130
+ sdkModule3 = null;
2131
+ compatModule = null;
2132
+ }
2133
+ function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, signal) {
2134
+ const toolMap = {};
2135
+ const supervisor = config.supervisor;
2136
+ for (const ourTool of tools) {
2137
+ const jsonSchema = zodToJsonSchema(ourTool.parameters);
2138
+ toolMap[ourTool.name] = sdk.tool({
2139
+ description: ourTool.description,
2140
+ inputSchema: sdk.jsonSchema(jsonSchema),
2141
+ execute: wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal),
2142
+ ...ourTool.needsApproval && supervisor?.onPermission ? {
2143
+ needsApproval: async (_input) => {
2144
+ if (permissionStore && await permissionStore.isApproved(ourTool.name)) return false;
2145
+ if (sessionApprovals.has(ourTool.name)) return false;
2146
+ return true;
2147
+ }
2148
+ } : {}
2149
+ });
2150
+ }
2151
+ if (supervisor?.onAskUser) {
2152
+ const onAskUser = supervisor.onAskUser;
2153
+ toolMap["ask_user"] = sdk.tool({
2154
+ description: "Ask the user a question and wait for their response",
2155
+ inputSchema: sdk.jsonSchema({
2156
+ type: "object",
2157
+ properties: {
2158
+ question: { type: "string", description: "The question to ask the user" }
2159
+ },
2160
+ required: ["question"]
2161
+ }),
2162
+ execute: async (args) => {
2163
+ const response = await onAskUser(
2164
+ { question: args.question, allowFreeform: true },
2165
+ signal
2166
+ );
2167
+ return response.answer;
2168
+ }
2169
+ });
2170
+ }
2171
+ return toolMap;
2172
+ }
2173
+ function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
2174
+ return async (args) => {
2175
+ if (ourTool.needsApproval && supervisor?.onPermission) {
2176
+ const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
2177
+ if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
2178
+ const request = {
2179
+ toolName: ourTool.name,
2180
+ toolArgs: args ?? {}
2181
+ };
2182
+ const decision = await supervisor.onPermission(
2183
+ request,
2184
+ signal
2185
+ );
2186
+ if (!decision.allowed) {
2187
+ throw new ToolExecutionError(
2188
+ ourTool.name,
2189
+ decision.reason ?? "Permission denied"
2190
+ );
2191
+ }
2192
+ if (permissionStore && decision.scope) {
2193
+ await permissionStore.approve(ourTool.name, decision.scope);
2194
+ }
2195
+ if (decision.scope === "session" || decision.scope === "always" || decision.scope === "project") {
2196
+ sessionApprovals.add(ourTool.name);
2197
+ }
2198
+ if (decision.modifiedInput) {
2199
+ args = decision.modifiedInput;
2200
+ }
2201
+ }
2202
+ }
2203
+ try {
2204
+ const result = await ourTool.execute(args);
2205
+ return result;
2206
+ } catch (e) {
2207
+ if (e instanceof ToolExecutionError) throw e;
2208
+ throw new ToolExecutionError(
2209
+ ourTool.name,
2210
+ e instanceof Error ? e.message : String(e)
2211
+ );
2212
+ }
2213
+ };
2214
+ }
2215
+ function messagesToSDK(messages) {
2216
+ return messages.map((msg) => {
2217
+ switch (msg.role) {
2218
+ case "user":
2219
+ return { role: "user", content: getTextContent(msg.content) };
2220
+ case "assistant": {
2221
+ let content = getTextContent(msg.content);
2222
+ const thinking = msg.thinking;
2223
+ if (thinking) {
2224
+ content = `[reasoning: ${thinking}]
2225
+ ${content}`;
2226
+ }
2227
+ const mapped = { role: "assistant", content };
2228
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
2229
+ mapped.toolCalls = msg.toolCalls.map((tc) => ({
2230
+ id: tc.id,
2231
+ name: tc.name,
2232
+ args: tc.args
2233
+ }));
2234
+ }
2235
+ return mapped;
2236
+ }
2237
+ case "system":
2238
+ return { role: "system", content: msg.content };
2239
+ case "tool": {
2240
+ if (msg.toolResults && msg.toolResults.length > 0) {
2241
+ return {
2242
+ role: "tool",
2243
+ toolResults: msg.toolResults.map((tr) => ({
2244
+ toolCallId: tr.toolCallId,
2245
+ name: tr.name,
2246
+ result: tr.result,
2247
+ isError: tr.isError ?? false
2248
+ }))
2249
+ };
2250
+ }
2251
+ return { role: "tool", content: msg.content ?? "" };
2252
+ }
2253
+ default:
2254
+ return { role: "user", content: "" };
2255
+ }
2256
+ });
2257
+ }
2258
+ function mapStreamPart(part) {
2259
+ switch (part.type) {
2260
+ case "text-delta": {
2261
+ const p = part;
2262
+ return { type: "text_delta", text: p.text ?? "" };
2263
+ }
2264
+ case "tool-call": {
2265
+ const p = part;
2266
+ return {
2267
+ type: "tool_call_start",
2268
+ toolCallId: String(p.toolCallId ?? ""),
2269
+ toolName: p.toolName ?? "unknown",
2270
+ args: p.input ?? {}
2271
+ };
2272
+ }
2273
+ case "tool-result": {
2274
+ const p = part;
2275
+ return {
2276
+ type: "tool_call_end",
2277
+ toolCallId: String(p.toolCallId ?? ""),
2278
+ toolName: p.toolName ?? "unknown",
2279
+ result: p.output ?? null
2280
+ };
2281
+ }
2282
+ case "tool-error": {
2283
+ const p = part;
2284
+ return {
2285
+ type: "error",
2286
+ error: p.error instanceof Error ? p.error.message : String(p.error ?? "Tool execution failed"),
2287
+ recoverable: true
2288
+ };
2289
+ }
2290
+ case "reasoning-start":
2291
+ return { type: "thinking_start" };
2292
+ case "reasoning-end":
2293
+ return { type: "thinking_end" };
2294
+ case "reasoning-delta": {
2295
+ const p = part;
2296
+ return { type: "thinking_delta", text: p.text ?? "" };
2297
+ }
2298
+ case "finish-step": {
2299
+ const p = part;
2300
+ return {
2301
+ type: "usage_update",
2302
+ promptTokens: Number(p.usage?.inputTokens ?? 0),
2303
+ completionTokens: Number(p.usage?.outputTokens ?? 0)
2304
+ };
2305
+ }
2306
+ case "error": {
2307
+ const p = part;
2308
+ return {
2309
+ type: "error",
2310
+ error: p.error instanceof Error ? p.error.message : String(p.error ?? "Unknown error"),
2311
+ recoverable: false
2312
+ };
2313
+ }
2314
+ default:
2315
+ return null;
2316
+ }
2317
+ }
2318
+ function createVercelAIService(options) {
2319
+ return new VercelAIAgentService(options);
2320
+ }
2321
+ var sdkModule3, compatModule, DEFAULT_BASE_URL, DEFAULT_PROVIDER, DEFAULT_MAX_TURNS, VercelAIAgent, VercelAIAgentService;
2322
+ var init_vercel_ai = __esm({
2323
+ "src/backends/vercel-ai.ts"() {
2324
+ init_types();
2325
+ init_base_agent();
2326
+ init_errors();
2327
+ init_schema();
2328
+ sdkModule3 = null;
2329
+ compatModule = null;
2330
+ DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
2331
+ DEFAULT_PROVIDER = "openrouter";
2332
+ DEFAULT_MAX_TURNS = 10;
2333
+ VercelAIAgent = class extends BaseAgent {
2334
+ backendName = "vercel-ai";
2335
+ backendOptions;
2336
+ sessionApprovals = /* @__PURE__ */ new Set();
2337
+ model = null;
2338
+ constructor(config, backendOptions) {
2339
+ super(config);
2340
+ this.backendOptions = backendOptions;
2341
+ }
2342
+ async getModel() {
2343
+ if (this.model) return this.model;
2344
+ const compat = await loadCompat();
2345
+ const provider = compat.createOpenAICompatible({
2346
+ name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
2347
+ baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
2348
+ apiKey: this.backendOptions.apiKey
2349
+ });
2350
+ const modelId = this.config.model ?? "anthropic/claude-sonnet-4-5";
2351
+ this.model = provider.chatModel(modelId);
2352
+ return this.model;
2353
+ }
2354
+ async getSDKTools(signal) {
2355
+ const sdk = await loadSDK3();
2356
+ return mapToolsToSDK2(sdk, this.config.tools ?? [], this.config, this.sessionApprovals, this.config.permissionStore, signal);
2357
+ }
2358
+ // ─── executeRun ─────────────────────────────────────────────────
2359
+ async executeRun(messages, _options, signal) {
2360
+ this.checkAbort(signal);
2361
+ const sdk = await loadSDK3();
2362
+ const model = await this.getModel();
2363
+ const tools = await this.getSDKTools(signal);
2364
+ const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
2365
+ const sdkMessages = messagesToSDK(messages);
2366
+ const hasTools = Object.keys(tools).length > 0;
2367
+ const result = await sdk.generateText({
2368
+ model,
2369
+ system: this.config.systemPrompt,
2370
+ messages: sdkMessages,
2371
+ tools: hasTools ? tools : void 0,
2372
+ stopWhen: sdk.stepCountIs(maxTurns),
2373
+ abortSignal: signal,
2374
+ ...this.config.modelParams?.temperature !== void 0 && {
2375
+ temperature: this.config.modelParams.temperature
2376
+ },
2377
+ ...this.config.modelParams?.maxTokens !== void 0 && {
2378
+ maxTokens: this.config.modelParams.maxTokens
2379
+ },
2380
+ ...this.config.modelParams?.topP !== void 0 && {
2381
+ topP: this.config.modelParams.topP
2382
+ },
2383
+ ...this.config.providerOptions && {
2384
+ providerOptions: this.config.providerOptions
2385
+ }
2386
+ });
2387
+ const toolCalls = [];
2388
+ for (const step of result.steps) {
2389
+ for (const tc of step.toolCalls) {
2390
+ const matchingResult = step.toolResults.find(
2391
+ (tr) => tr.toolCallId === tc.toolCallId
2392
+ );
2393
+ toolCalls.push({
2394
+ toolName: tc.toolName,
2395
+ args: tc.input ?? {},
2396
+ result: matchingResult?.output ?? null,
2397
+ approved: true
2398
+ });
2399
+ }
2400
+ }
2401
+ const usage = {
2402
+ promptTokens: Number(result.totalUsage?.inputTokens ?? 0),
2403
+ completionTokens: Number(result.totalUsage?.outputTokens ?? 0)
2404
+ };
2405
+ const lastStep = result.steps.length > 0 ? result.steps[result.steps.length - 1] : null;
2406
+ const outputText = lastStep?.text || null;
2407
+ return {
2408
+ output: outputText,
2409
+ structuredOutput: void 0,
2410
+ toolCalls,
2411
+ messages: [
2412
+ ...messages,
2413
+ ...outputText ? [{ role: "assistant", content: outputText }] : []
2414
+ ],
2415
+ usage
2416
+ };
2417
+ }
2418
+ // ─── executeRunStructured ───────────────────────────────────────
2419
+ async executeRunStructured(messages, schema, _options, signal) {
2420
+ this.checkAbort(signal);
2421
+ const sdk = await loadSDK3();
2422
+ const model = await this.getModel();
2423
+ const sdkMessages = messagesToSDK(messages);
2424
+ const jsonSchema = zodToJsonSchema(schema.schema);
2425
+ const result = await sdk.generateObject({
2426
+ model,
2427
+ system: this.config.systemPrompt,
2428
+ messages: sdkMessages,
2429
+ schema: sdk.jsonSchema(jsonSchema),
2430
+ schemaName: schema.name,
2431
+ schemaDescription: schema.description,
2432
+ abortSignal: signal,
2433
+ ...this.config.modelParams?.temperature !== void 0 && {
2434
+ temperature: this.config.modelParams.temperature
2435
+ },
2436
+ ...this.config.modelParams?.maxTokens !== void 0 && {
2437
+ maxTokens: this.config.modelParams.maxTokens
2438
+ },
2439
+ ...this.config.providerOptions && {
2440
+ providerOptions: this.config.providerOptions
2441
+ }
2442
+ });
2443
+ let structuredOutput;
2444
+ try {
2445
+ structuredOutput = schema.schema.parse(result.object);
2446
+ } catch {
2447
+ }
2448
+ const usage = {
2449
+ promptTokens: Number(result.usage?.inputTokens ?? 0),
2450
+ completionTokens: Number(result.usage?.outputTokens ?? 0)
2451
+ };
2452
+ return {
2453
+ output: JSON.stringify(result.object),
2454
+ structuredOutput,
2455
+ toolCalls: [],
2456
+ messages: [
2457
+ ...messages,
2458
+ ...result.object != null ? [{ role: "assistant", content: JSON.stringify(result.object) }] : []
2459
+ ],
2460
+ usage
2461
+ };
2462
+ }
2463
+ // ─── executeStream ──────────────────────────────────────────────
2464
+ async *executeStream(messages, _options, signal) {
2465
+ this.checkAbort(signal);
2466
+ const sdk = await loadSDK3();
2467
+ const model = await this.getModel();
2468
+ const tools = await this.getSDKTools(signal);
2469
+ const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
2470
+ const sdkMessages = messagesToSDK(messages);
2471
+ const hasTools = Object.keys(tools).length > 0;
2472
+ const result = sdk.streamText({
2473
+ model,
2474
+ system: this.config.systemPrompt,
2475
+ messages: sdkMessages,
2476
+ tools: hasTools ? tools : void 0,
2477
+ stopWhen: sdk.stepCountIs(maxTurns),
2478
+ abortSignal: signal,
2479
+ ...this.config.modelParams?.temperature !== void 0 && {
2480
+ temperature: this.config.modelParams.temperature
2481
+ },
2482
+ ...this.config.modelParams?.maxTokens !== void 0 && {
2483
+ maxTokens: this.config.modelParams.maxTokens
2484
+ },
2485
+ ...this.config.modelParams?.topP !== void 0 && {
2486
+ topP: this.config.modelParams.topP
2487
+ },
2488
+ ...this.config.providerOptions && {
2489
+ providerOptions: this.config.providerOptions
2490
+ }
2491
+ });
2492
+ let finalText = "";
2493
+ try {
2494
+ for await (const part of result.fullStream) {
2495
+ if (signal.aborted) throw new AbortError();
2496
+ const event = mapStreamPart(part);
2497
+ if (event) yield event;
2498
+ if (part.type === "text-delta") {
2499
+ finalText += part.text ?? "";
2500
+ }
2501
+ if (part.type === "finish-step") {
2502
+ const p = part;
2503
+ if (p.finishReason === "tool-calls") {
2504
+ finalText = "";
2505
+ }
2506
+ }
2507
+ }
2508
+ const totalUsage = await result.totalUsage;
2509
+ yield {
2510
+ type: "usage_update",
2511
+ promptTokens: Number(totalUsage?.inputTokens ?? 0),
2512
+ completionTokens: Number(totalUsage?.outputTokens ?? 0)
2513
+ };
2514
+ yield {
2515
+ type: "done",
2516
+ finalOutput: finalText || null
2517
+ };
2518
+ } catch (e) {
2519
+ if (signal.aborted) throw new AbortError();
2520
+ throw e;
2521
+ }
2522
+ }
2523
+ dispose() {
2524
+ this.sessionApprovals.clear();
2525
+ this.model = null;
2526
+ super.dispose();
2527
+ }
2528
+ };
2529
+ VercelAIAgentService = class {
2530
+ name = "vercel-ai";
2531
+ disposed = false;
2532
+ options;
2533
+ constructor(options) {
2534
+ this.options = options;
2535
+ }
2536
+ createAgent(config) {
2537
+ if (this.disposed) throw new DisposedError("VercelAIAgentService");
2538
+ return new VercelAIAgent(config, this.options);
2539
+ }
2540
+ async listModels() {
2541
+ if (this.disposed) throw new DisposedError("VercelAIAgentService");
2542
+ const baseUrl = (this.options.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, "");
2543
+ try {
2544
+ const res = await globalThis.fetch(`${baseUrl}/models`, {
2545
+ headers: { Authorization: `Bearer ${this.options.apiKey}` }
2546
+ });
2547
+ if (!res.ok) {
2548
+ return [];
2549
+ }
2550
+ const body = await res.json();
2551
+ if (!body.data || body.data.length === 0) {
2552
+ return [];
2553
+ }
2554
+ return body.data.map((m) => ({ id: m.id }));
2555
+ } catch {
2556
+ return [];
2557
+ }
2558
+ }
2559
+ async validate() {
2560
+ if (this.disposed) throw new DisposedError("VercelAIAgentService");
2561
+ const errors = [];
2562
+ if (!this.options.apiKey) {
2563
+ errors.push("apiKey is required for Vercel AI backend.");
2564
+ }
2565
+ try {
2566
+ await loadSDK3();
2567
+ } catch (e) {
2568
+ errors.push(e instanceof Error ? e.message : String(e));
2569
+ }
2570
+ try {
2571
+ await loadCompat();
2572
+ } catch (e) {
2573
+ errors.push(e instanceof Error ? e.message : String(e));
2574
+ }
2575
+ return { valid: errors.length === 0, errors };
2576
+ }
2577
+ async dispose() {
2578
+ if (this.disposed) return;
2579
+ this.disposed = true;
2580
+ }
2581
+ };
2582
+ }
2583
+ });
2584
+
2585
+ // src/registry.ts
2586
+ function registerBackend(name, factory) {
2587
+ if (registry.has(name)) {
2588
+ throw new BackendAlreadyRegisteredError(name);
2589
+ }
2590
+ registry.set(name, { factory, builtin: false });
2591
+ }
2592
+ function unregisterBackend(name) {
2593
+ return registry.delete(name);
2594
+ }
2595
+ function hasBackend(name) {
2596
+ return registry.has(name) || isBuiltinName(name);
2597
+ }
2598
+ function listBackends() {
2599
+ const names = new Set(registry.keys());
2600
+ for (const builtin of BUILTIN_BACKENDS) {
2601
+ names.add(builtin);
2602
+ }
2603
+ return [...names];
2604
+ }
2605
+ function resetRegistry() {
2606
+ registry.clear();
2607
+ }
2608
+ function isBuiltinName(name) {
2609
+ return BUILTIN_BACKENDS.has(name);
2610
+ }
2611
+ async function loadBuiltinFactory(name) {
2612
+ switch (name) {
2613
+ case "copilot": {
2614
+ const mod = await Promise.resolve().then(() => (init_copilot(), copilot_exports));
2615
+ return (opts) => mod.createCopilotService(opts);
2616
+ }
2617
+ case "claude": {
2618
+ const mod = await Promise.resolve().then(() => (init_claude(), claude_exports));
2619
+ return (opts) => mod.createClaudeService(opts);
2620
+ }
2621
+ case "vercel-ai": {
2622
+ const mod = await Promise.resolve().then(() => (init_vercel_ai(), vercel_ai_exports));
2623
+ return (opts) => mod.createVercelAIService(opts);
2624
+ }
2625
+ }
2626
+ }
2627
+ async function createAgentService(name, options) {
2628
+ const entry = registry.get(name);
2629
+ if (entry) {
2630
+ return entry.factory(options);
2631
+ }
2632
+ if (isBuiltinName(name)) {
2633
+ const factory = await loadBuiltinFactory(name);
2634
+ registry.set(name, { factory, builtin: true });
2635
+ return factory(options);
2636
+ }
2637
+ throw new BackendNotFoundError(name);
2638
+ }
2639
+ var registry, BUILTIN_BACKENDS;
2640
+ var init_registry = __esm({
2641
+ "src/registry.ts"() {
2642
+ init_errors();
2643
+ registry = /* @__PURE__ */ new Map();
2644
+ BUILTIN_BACKENDS = /* @__PURE__ */ new Set([
2645
+ "copilot",
2646
+ "claude",
2647
+ "vercel-ai"
2648
+ ]);
2649
+ }
2650
+ });
2651
+
2652
+ // src/utils/messages.ts
2653
+ function messagesToPrompt(messages) {
2654
+ return messages.map((msg) => {
2655
+ switch (msg.role) {
2656
+ case "user":
2657
+ return contentToText(msg.content);
2658
+ case "assistant":
2659
+ return contentToText(msg.content);
2660
+ case "system":
2661
+ return msg.content;
2662
+ case "tool":
2663
+ return msg.content ?? "";
2664
+ }
2665
+ }).filter(Boolean).join("\n\n");
2666
+ }
2667
+ function contentToText(content) {
2668
+ return getTextContent(content);
2669
+ }
2670
+ function buildSystemPrompt(base, schemaInstruction) {
2671
+ if (!schemaInstruction) return base;
2672
+ return `${base}
2673
+
2674
+ ${schemaInstruction}`;
2675
+ }
2676
+ var init_messages = __esm({
2677
+ "src/utils/messages.ts"() {
2678
+ init_types();
2679
+ }
2680
+ });
2681
+ function createDefaultPermissionStore(projectDir) {
2682
+ const sessionStore = new InMemoryPermissionStore();
2683
+ const projectPath = projectDir ? path.join(projectDir, ".agent-sdk", "permissions.json") : path.join(process.cwd(), ".agent-sdk", "permissions.json");
2684
+ const userPath = path.join(os.homedir(), ".agent-sdk", "permissions.json");
2685
+ const projectStore = new FilePermissionStore(projectPath);
2686
+ const userStore = new FilePermissionStore(userPath);
2687
+ return new CompositePermissionStore(sessionStore, projectStore, userStore);
2688
+ }
2689
+ var InMemoryPermissionStore, FilePermissionStore, CompositePermissionStore;
2690
+ var init_permission_store = __esm({
2691
+ "src/permission-store.ts"() {
2692
+ InMemoryPermissionStore = class {
2693
+ approvals = /* @__PURE__ */ new Map();
2694
+ async isApproved(toolName) {
2695
+ return this.approvals.has(toolName);
2696
+ }
2697
+ async approve(toolName, scope) {
2698
+ if (scope === "once") return;
2699
+ this.approvals.set(toolName, scope);
2700
+ }
2701
+ async revoke(toolName) {
2702
+ this.approvals.delete(toolName);
2703
+ }
2704
+ async clear() {
2705
+ this.approvals.clear();
2706
+ }
2707
+ async dispose() {
2708
+ this.approvals.clear();
2709
+ }
2710
+ };
2711
+ FilePermissionStore = class {
2712
+ filePath;
2713
+ constructor(filePath) {
2714
+ this.filePath = path.resolve(filePath);
2715
+ }
2716
+ async isApproved(toolName) {
2717
+ const data = this.readFile();
2718
+ return toolName in data.approvals;
2719
+ }
2720
+ async approve(toolName, scope) {
2721
+ if (scope === "once") return;
2722
+ const data = this.readFile();
2723
+ data.approvals[toolName] = { scope, timestamp: Date.now() };
2724
+ this.writeFileAtomic(data);
2725
+ }
2726
+ async revoke(toolName) {
2727
+ const data = this.readFile();
2728
+ delete data.approvals[toolName];
2729
+ this.writeFileAtomic(data);
2730
+ }
2731
+ async clear() {
2732
+ this.writeFileAtomic({ approvals: {} });
2733
+ }
2734
+ async dispose() {
2735
+ }
2736
+ readFile() {
2737
+ try {
2738
+ const raw = fs.readFileSync(this.filePath, "utf-8");
2739
+ const parsed = JSON.parse(raw);
2740
+ if (parsed && typeof parsed.approvals === "object") return parsed;
2741
+ } catch {
2742
+ }
2743
+ return { approvals: {} };
2744
+ }
2745
+ writeFileAtomic(data) {
2746
+ const dir = path.dirname(this.filePath);
2747
+ fs.mkdirSync(dir, { recursive: true });
2748
+ const tmpPath = this.filePath + `.tmp.${process.pid}.${Date.now()}`;
2749
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
2750
+ fs.renameSync(tmpPath, this.filePath);
2751
+ }
2752
+ };
2753
+ CompositePermissionStore = class {
2754
+ sessionStore;
2755
+ projectStore;
2756
+ userStore;
2757
+ constructor(sessionStore, projectStore, userStore) {
2758
+ this.sessionStore = sessionStore;
2759
+ this.projectStore = projectStore;
2760
+ this.userStore = userStore ?? projectStore;
2761
+ }
2762
+ async isApproved(toolName) {
2763
+ return await this.sessionStore.isApproved(toolName) || await this.projectStore.isApproved(toolName) || await this.userStore.isApproved(toolName);
2764
+ }
2765
+ async approve(toolName, scope) {
2766
+ if (scope === "once") return;
2767
+ if (scope === "session") {
2768
+ await this.sessionStore.approve(toolName, scope);
2769
+ } else if (scope === "project") {
2770
+ await this.projectStore.approve(toolName, scope);
2771
+ } else {
2772
+ await this.userStore.approve(toolName, scope);
2773
+ }
2774
+ }
2775
+ async revoke(toolName) {
2776
+ await this.sessionStore.revoke(toolName);
2777
+ await this.projectStore.revoke(toolName);
2778
+ await this.userStore.revoke(toolName);
2779
+ }
2780
+ async clear() {
2781
+ await this.sessionStore.clear();
2782
+ await this.projectStore.clear();
2783
+ await this.userStore.clear();
2784
+ }
2785
+ async dispose() {
2786
+ await this.sessionStore.dispose();
2787
+ await this.projectStore.dispose();
2788
+ if (this.userStore !== this.projectStore) {
2789
+ await this.userStore.dispose();
2790
+ }
2791
+ }
2792
+ };
2793
+ }
2794
+ });
2795
+
2796
+ // src/index.ts
2797
+ var src_exports = {};
2798
+ __export(src_exports, {
2799
+ AbortError: () => AbortError,
2800
+ AgentSDKError: () => AgentSDKError,
2801
+ BackendAlreadyRegisteredError: () => BackendAlreadyRegisteredError,
2802
+ BackendNotFoundError: () => BackendNotFoundError,
2803
+ BaseAgent: () => BaseAgent,
2804
+ CompositePermissionStore: () => CompositePermissionStore,
2805
+ DependencyError: () => DependencyError,
2806
+ DisposedError: () => DisposedError,
2807
+ FilePermissionStore: () => FilePermissionStore,
2808
+ InMemoryPermissionStore: () => InMemoryPermissionStore,
2809
+ ReentrancyError: () => ReentrancyError,
2810
+ StructuredOutputError: () => StructuredOutputError,
2811
+ SubprocessError: () => SubprocessError,
2812
+ ToolExecutionError: () => ToolExecutionError,
2813
+ buildSystemPrompt: () => buildSystemPrompt,
2814
+ contentToText: () => contentToText,
2815
+ createAgentService: () => createAgentService,
2816
+ createDefaultPermissionStore: () => createDefaultPermissionStore,
2817
+ getTextContent: () => getTextContent,
2818
+ hasBackend: () => hasBackend,
2819
+ isMultiPartContent: () => isMultiPartContent,
2820
+ isTextContent: () => isTextContent,
2821
+ isToolDefinition: () => isToolDefinition,
2822
+ listBackends: () => listBackends,
2823
+ messagesToPrompt: () => messagesToPrompt,
2824
+ registerBackend: () => registerBackend,
2825
+ resetRegistry: () => resetRegistry,
2826
+ unregisterBackend: () => unregisterBackend,
2827
+ zodToJsonSchema: () => zodToJsonSchema
2828
+ });
2829
+ var init_src = __esm({
2830
+ "src/index.ts"() {
2831
+ init_types();
2832
+ init_errors();
2833
+ init_registry();
2834
+ init_base_agent();
2835
+ init_schema();
2836
+ init_messages();
2837
+ init_permission_store();
2838
+ }
2839
+ });
2840
+
2841
+ // src/chat/core.ts
2842
+ function createChatId() {
2843
+ return crypto.randomUUID();
2844
+ }
2845
+ function getMessageText(message) {
2846
+ return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
2847
+ }
2848
+ function getMessageToolCalls(message) {
2849
+ return message.parts.filter((p) => p.type === "tool_call");
2850
+ }
2851
+ function agentEventToChatEvent(event, messageId) {
2852
+ switch (event.type) {
2853
+ case "text_delta":
2854
+ return { type: "message:delta", messageId, text: event.text };
2855
+ case "thinking_start":
2856
+ return { type: "thinking:start", messageId };
2857
+ case "thinking_delta":
2858
+ return { type: "thinking:delta", messageId, text: event.text };
2859
+ case "thinking_end":
2860
+ return { type: "thinking:end", messageId };
2861
+ case "tool_call_start":
2862
+ return {
2863
+ type: "tool:start",
2864
+ messageId,
2865
+ toolCallId: event.toolCallId,
2866
+ toolName: event.toolName,
2867
+ args: event.args
2868
+ };
2869
+ case "tool_call_end":
2870
+ return {
2871
+ type: "tool:complete",
2872
+ messageId,
2873
+ toolCallId: event.toolCallId,
2874
+ toolName: event.toolName,
2875
+ result: event.result
2876
+ };
2877
+ case "permission_request":
2878
+ return {
2879
+ type: "permission:request",
2880
+ messageId,
2881
+ toolName: event.request.toolName,
2882
+ toolArgs: event.request.toolArgs
2883
+ };
2884
+ case "permission_response":
2885
+ return {
2886
+ type: "permission:response",
2887
+ messageId,
2888
+ toolName: event.toolName,
2889
+ allowed: event.decision.allowed
2890
+ };
2891
+ case "usage_update":
2892
+ return {
2893
+ type: "usage",
2894
+ promptTokens: event.promptTokens,
2895
+ completionTokens: event.completionTokens,
2896
+ model: event.model
2897
+ };
2898
+ case "error":
2899
+ return {
2900
+ type: "error",
2901
+ error: event.error,
2902
+ recoverable: event.recoverable,
2903
+ messageId
2904
+ };
2905
+ case "heartbeat":
2906
+ return { type: "heartbeat" };
2907
+ case "ask_user":
2908
+ case "ask_user_response":
2909
+ case "session_info":
2910
+ case "done":
2911
+ return null;
2912
+ default:
2913
+ return null;
2914
+ }
2915
+ }
2916
+ async function* adaptAgentEvents(events, messageId) {
2917
+ for await (const event of events) {
2918
+ const chatEvent = agentEventToChatEvent(event, messageId);
2919
+ if (chatEvent !== null) {
2920
+ yield chatEvent;
2921
+ }
2922
+ }
2923
+ }
2924
+ function toAgentMessage(message) {
2925
+ const textContent = getMessageText(message);
2926
+ const toolCallParts = getMessageToolCalls(message);
2927
+ switch (message.role) {
2928
+ case "user":
2929
+ return { role: "user", content: textContent };
2930
+ case "assistant": {
2931
+ const toolCalls = toolCallParts.length > 0 ? toolCallParts.map((p) => ({ id: p.toolCallId, name: p.name, args: p.args })) : void 0;
2932
+ return {
2933
+ role: "assistant",
2934
+ content: textContent,
2935
+ toolCalls
2936
+ };
2937
+ }
2938
+ case "system":
2939
+ return { role: "system", content: textContent };
2940
+ }
2941
+ }
2942
+
2943
+ // src/chat/errors.ts
2944
+ init_errors();
2945
+ var ChatError = class extends AgentSDKError {
2946
+ code;
2947
+ retryable;
2948
+ retryAfter;
2949
+ timestamp;
2950
+ constructor(message, options) {
2951
+ super(message, { cause: options.cause });
2952
+ this.name = "ChatError";
2953
+ this.code = options.code;
2954
+ this.retryable = options.retryable ?? false;
2955
+ this.retryAfter = options.retryAfter;
2956
+ this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
2957
+ }
2958
+ };
2959
+
2960
+ // src/chat/backends/base.ts
2961
+ var BaseBackendAdapter = class {
2962
+ name;
2963
+ _agentService;
2964
+ _agent = null;
2965
+ _disposed = false;
2966
+ _agentConfig;
2967
+ _ownsService;
2968
+ constructor(name, options) {
2969
+ this.name = name;
2970
+ this._agentConfig = options.agentConfig;
2971
+ if (options.agentService) {
2972
+ this._agentService = options.agentService;
2973
+ this._ownsService = false;
2974
+ } else {
2975
+ this._agentService = this.createService();
2976
+ this._ownsService = true;
2977
+ }
2978
+ }
2979
+ get agentService() {
2980
+ return this._agentService;
2981
+ }
2982
+ async sendMessage(session, message, options) {
2983
+ this.assertNotDisposed();
2984
+ const events = this.streamMessage(session, message, options);
2985
+ let text = "";
2986
+ let lastMessage;
2987
+ for await (const event of events) {
2988
+ if (event.type === "message:delta") {
2989
+ text += event.text;
2990
+ }
2991
+ if (event.type === "message:complete") {
2992
+ lastMessage = event.message;
2993
+ }
2994
+ }
2995
+ if (lastMessage) return lastMessage;
2996
+ const messageId = createChatId();
2997
+ return {
2998
+ id: messageId,
2999
+ role: "assistant",
3000
+ parts: [{ type: "text", text, status: "complete" }],
3001
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3002
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3003
+ status: "complete"
3004
+ };
3005
+ }
3006
+ async *streamMessage(session, message, options) {
3007
+ this.assertNotDisposed();
3008
+ const agent = this.getOrCreateAgent(options);
3009
+ const messages = session.messages.map(toAgentMessage);
3010
+ messages.push({ role: "user", content: message });
3011
+ yield* this.streamAgentEvents(agent, messages, options);
3012
+ }
3013
+ /**
3014
+ * Shared streaming helper: bridges agent events to chat events.
3015
+ * Used by both streamMessage() and resume() to avoid duplication.
3016
+ */
3017
+ async *streamAgentEvents(agent, messages, options) {
3018
+ const messageId = createChatId();
3019
+ const agentEvents = agent.streamWithContext(messages, {
3020
+ signal: options?.signal,
3021
+ context: options?.context
3022
+ });
3023
+ yield { type: "message:start", messageId, role: "assistant" };
3024
+ let text = "";
3025
+ for await (const chatEvent of adaptAgentEvents(agentEvents, messageId)) {
3026
+ if (chatEvent.type === "message:delta") {
3027
+ text += chatEvent.text;
3028
+ }
3029
+ yield chatEvent;
3030
+ }
3031
+ this.captureSessionId(agent);
3032
+ yield {
3033
+ type: "message:complete",
3034
+ messageId,
3035
+ message: {
3036
+ id: messageId,
3037
+ role: "assistant",
3038
+ parts: [{ type: "text", text, status: "complete" }],
3039
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3040
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3041
+ status: "complete"
3042
+ }
3043
+ };
3044
+ }
3045
+ async listModels() {
3046
+ this.assertNotDisposed();
3047
+ return this._agentService.listModels();
3048
+ }
3049
+ async validate() {
3050
+ this.assertNotDisposed();
3051
+ return this._agentService.validate();
3052
+ }
3053
+ async dispose() {
3054
+ if (this._disposed) return;
3055
+ this._disposed = true;
3056
+ this._agent?.dispose();
3057
+ this._agent = null;
3058
+ if (this._ownsService) {
3059
+ await this._agentService.dispose();
3060
+ }
3061
+ }
3062
+ /** Get or create an agent, applying model override from options */
3063
+ getOrCreateAgent(options) {
3064
+ const config = options?.model ? { ...this._agentConfig, model: options.model } : this._agentConfig;
3065
+ if (this._agentConfig.sessionMode === "persistent" && this._agent) {
3066
+ return this._agent;
3067
+ }
3068
+ const agent = this._agentService.createAgent(config);
3069
+ if (this._agentConfig.sessionMode === "persistent") {
3070
+ this._agent = agent;
3071
+ }
3072
+ return agent;
3073
+ }
3074
+ assertNotDisposed() {
3075
+ if (this._disposed) {
3076
+ throw new ChatError("Adapter is disposed", {
3077
+ code: "DISPOSED" /* DISPOSED */
3078
+ });
3079
+ }
3080
+ }
3081
+ };
3082
+
3083
+ // src/chat/backends/copilot.ts
3084
+ var CopilotChatAdapter = class extends BaseBackendAdapter {
3085
+ _backendSessionId = null;
3086
+ _copilotOptions;
3087
+ constructor(options) {
3088
+ const agentConfig = {
3089
+ ...options.agentConfig,
3090
+ sessionMode: "persistent"
3091
+ };
3092
+ super("copilot", { ...options, agentConfig });
3093
+ this._copilotOptions = options.copilotOptions;
3094
+ }
3095
+ createService() {
3096
+ const { createAgentService: createAgentService2 } = (init_src(), __toCommonJS(src_exports));
3097
+ return createAgentService2("copilot", this._copilotOptions);
3098
+ }
3099
+ get backendSessionId() {
3100
+ return this._backendSessionId;
3101
+ }
3102
+ canResume() {
3103
+ return this._backendSessionId !== null;
3104
+ }
3105
+ async *resume(session, backendSessionId, options) {
3106
+ this.assertNotDisposed();
3107
+ if (!backendSessionId) {
3108
+ throw new ChatError("Backend session ID is required for resume", {
3109
+ code: "INVALID_INPUT" /* INVALID_INPUT */
3110
+ });
3111
+ }
3112
+ const agent = this.getOrCreateAgent(options);
3113
+ const currentSessionId = agent.sessionId;
3114
+ if (!currentSessionId) {
3115
+ throw new ChatError(
3116
+ `No active session to resume (requested: ${backendSessionId})`,
3117
+ { code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
3118
+ );
3119
+ }
3120
+ if (currentSessionId !== backendSessionId) {
3121
+ throw new ChatError(
3122
+ `Session expired: expected ${backendSessionId}, got ${currentSessionId}`,
3123
+ { code: "SESSION_EXPIRED" /* SESSION_EXPIRED */ }
3124
+ );
3125
+ }
3126
+ const messages = session.messages.map(toAgentMessage);
3127
+ yield* this.streamAgentEvents(agent, messages, options);
3128
+ }
3129
+ captureSessionId(agent) {
3130
+ if (agent.sessionId) {
3131
+ this._backendSessionId = agent.sessionId;
3132
+ }
3133
+ }
3134
+ };
3135
+
3136
+ // src/chat/backends/claude.ts
3137
+ var ClaudeChatAdapter = class extends BaseBackendAdapter {
3138
+ _backendSessionId = null;
3139
+ _claudeOptions;
3140
+ constructor(options) {
3141
+ const agentConfig = {
3142
+ ...options.agentConfig,
3143
+ sessionMode: "persistent"
3144
+ };
3145
+ super("claude", { ...options, agentConfig });
3146
+ this._claudeOptions = options.claudeOptions;
3147
+ }
3148
+ createService() {
3149
+ const { createAgentService: createAgentService2 } = (init_src(), __toCommonJS(src_exports));
3150
+ return createAgentService2("claude", this._claudeOptions);
3151
+ }
3152
+ get backendSessionId() {
3153
+ return this._backendSessionId;
3154
+ }
3155
+ canResume() {
3156
+ return this._backendSessionId !== null;
3157
+ }
3158
+ async *resume(session, backendSessionId, options) {
3159
+ this.assertNotDisposed();
3160
+ if (!backendSessionId) {
3161
+ throw new ChatError("Backend session ID is required for resume", {
3162
+ code: "INVALID_INPUT" /* INVALID_INPUT */
3163
+ });
3164
+ }
3165
+ const agent = this.getOrCreateAgent(options);
3166
+ const currentSessionId = agent.sessionId;
3167
+ if (!currentSessionId) {
3168
+ throw new ChatError(
3169
+ `No active session to resume (requested: ${backendSessionId})`,
3170
+ { code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
3171
+ );
3172
+ }
3173
+ if (currentSessionId !== backendSessionId) {
3174
+ throw new ChatError(
3175
+ `Session expired: expected ${backendSessionId}, got ${currentSessionId}`,
3176
+ { code: "SESSION_EXPIRED" /* SESSION_EXPIRED */ }
3177
+ );
3178
+ }
3179
+ const messages = session.messages.map(toAgentMessage);
3180
+ yield* this.streamAgentEvents(agent, messages, options);
3181
+ }
3182
+ captureSessionId(agent) {
3183
+ if (agent.sessionId) {
3184
+ this._backendSessionId = agent.sessionId;
3185
+ }
3186
+ }
3187
+ };
3188
+
3189
+ // src/chat/backends/vercel-ai.ts
3190
+ var VercelAIChatAdapter = class extends BaseBackendAdapter {
3191
+ _vercelOptions;
3192
+ constructor(options) {
3193
+ super("vercel-ai", options);
3194
+ this._vercelOptions = options.vercelOptions;
3195
+ }
3196
+ createService() {
3197
+ const { createAgentService: createAgentService2 } = (init_src(), __toCommonJS(src_exports));
3198
+ return createAgentService2("vercel-ai", this._vercelOptions);
3199
+ }
3200
+ get backendSessionId() {
3201
+ return null;
3202
+ }
3203
+ canResume() {
3204
+ return false;
3205
+ }
3206
+ async *resume(_session, _backendSessionId, _options) {
3207
+ throw new ChatError(
3208
+ "Vercel AI adapter does not support session resume (stateless)",
3209
+ { code: "PROVIDER_ERROR" /* PROVIDER_ERROR */ }
3210
+ );
3211
+ }
3212
+ captureSessionId(_agent) {
3213
+ }
3214
+ };
3215
+
3216
+ // src/chat/backends/transport.ts
3217
+ var SSEChatTransport = class {
3218
+ res;
3219
+ _open;
3220
+ _heartbeatTimer;
3221
+ constructor(res, options) {
3222
+ this.res = res;
3223
+ this._open = true;
3224
+ res.writeHead(200, {
3225
+ "Content-Type": "text/event-stream",
3226
+ "Cache-Control": "no-cache",
3227
+ "Connection": "keep-alive",
3228
+ "X-Accel-Buffering": "no"
3229
+ });
3230
+ if (options?.request) {
3231
+ options.request.on("close", () => {
3232
+ this._cleanup();
3233
+ });
3234
+ }
3235
+ const heartbeatMs = options?.heartbeatMs;
3236
+ if (heartbeatMs && heartbeatMs > 0) {
3237
+ this._heartbeatTimer = setInterval(() => {
3238
+ if (!this.isOpen) {
3239
+ this._clearHeartbeat();
3240
+ return;
3241
+ }
3242
+ this.res.write(": heartbeat\n\n");
3243
+ }, heartbeatMs);
3244
+ }
3245
+ }
3246
+ get isOpen() {
3247
+ return this._open && !this.res.writableEnded;
3248
+ }
3249
+ send(event) {
3250
+ if (!this.isOpen) return;
3251
+ this.res.write(`data: ${JSON.stringify(event)}
3252
+
3253
+ `);
3254
+ }
3255
+ close() {
3256
+ if (!this.isOpen) return;
3257
+ this._open = false;
3258
+ this._clearHeartbeat();
3259
+ this.res.write(`data: [DONE]
3260
+
3261
+ `);
3262
+ this.res.end();
3263
+ }
3264
+ error(err) {
3265
+ if (!this.isOpen) return;
3266
+ this._open = false;
3267
+ this._clearHeartbeat();
3268
+ const errorEvent = {
3269
+ type: "error",
3270
+ error: err.message,
3271
+ recoverable: false
3272
+ };
3273
+ this.res.write(`data: ${JSON.stringify(errorEvent)}
3274
+
3275
+ `);
3276
+ this.res.end();
3277
+ }
3278
+ _cleanup() {
3279
+ this._open = false;
3280
+ this._clearHeartbeat();
3281
+ }
3282
+ _clearHeartbeat() {
3283
+ if (this._heartbeatTimer !== void 0) {
3284
+ clearInterval(this._heartbeatTimer);
3285
+ this._heartbeatTimer = void 0;
3286
+ }
3287
+ }
3288
+ };
3289
+ async function streamToTransport(events, transport) {
3290
+ try {
3291
+ let accumulatedText = "";
3292
+ for await (const event of events) {
3293
+ if (!transport.isOpen) break;
3294
+ transport.send(event);
3295
+ if (event.type === "message:delta") {
3296
+ accumulatedText += event.text;
3297
+ }
3298
+ }
3299
+ if (transport.isOpen) {
3300
+ transport.send({ type: "done", finalOutput: accumulatedText || void 0 });
3301
+ }
3302
+ transport.close();
3303
+ } catch (err) {
3304
+ transport.error(err instanceof Error ? err : new Error(String(err)));
3305
+ }
3306
+ }
3307
+
3308
+ // src/chat/backends/ws-transport.ts
3309
+ var WS_READY_STATE = {
3310
+ CONNECTING: 0,
3311
+ OPEN: 1,
3312
+ CLOSING: 2,
3313
+ CLOSED: 3
3314
+ };
3315
+ var WsChatTransport = class {
3316
+ ws;
3317
+ serialize;
3318
+ _open;
3319
+ _heartbeatTimer;
3320
+ constructor(ws, options) {
3321
+ this.ws = ws;
3322
+ this.serialize = options?.serialize ?? JSON.stringify;
3323
+ this._open = ws.readyState === WS_READY_STATE.OPEN;
3324
+ ws.addEventListener("close", () => {
3325
+ this._cleanup();
3326
+ });
3327
+ ws.addEventListener("error", () => {
3328
+ this._cleanup();
3329
+ });
3330
+ const heartbeatMs = options?.heartbeatMs;
3331
+ if (heartbeatMs && heartbeatMs > 0) {
3332
+ this._heartbeatTimer = setInterval(() => {
3333
+ if (!this.isOpen) {
3334
+ this._clearHeartbeat();
3335
+ return;
3336
+ }
3337
+ this.ws.send(this.serialize({ type: "heartbeat" }));
3338
+ }, heartbeatMs);
3339
+ }
3340
+ }
3341
+ get isOpen() {
3342
+ return this._open && this.ws.readyState === WS_READY_STATE.OPEN;
3343
+ }
3344
+ send(event) {
3345
+ if (!this.isOpen) return;
3346
+ this.ws.send(this.serialize(event));
3347
+ }
3348
+ close() {
3349
+ if (!this.isOpen) return;
3350
+ this._open = false;
3351
+ this._clearHeartbeat();
3352
+ this.ws.send(this.serialize({ type: "done" }));
3353
+ this.ws.close(1e3, "stream complete");
3354
+ }
3355
+ error(err) {
3356
+ if (!this.isOpen) return;
3357
+ this._open = false;
3358
+ this._clearHeartbeat();
3359
+ const errorEvent = {
3360
+ type: "error",
3361
+ error: err.message,
3362
+ recoverable: false
3363
+ };
3364
+ this.ws.send(this.serialize(errorEvent));
3365
+ this.ws.close(1011, err.message);
3366
+ }
3367
+ _cleanup() {
3368
+ this._open = false;
3369
+ this._clearHeartbeat();
3370
+ }
3371
+ _clearHeartbeat() {
3372
+ if (this._heartbeatTimer !== void 0) {
3373
+ clearInterval(this._heartbeatTimer);
3374
+ this._heartbeatTimer = void 0;
3375
+ }
3376
+ }
3377
+ };
3378
+
3379
+ // src/chat/backends/in-process-transport.ts
3380
+ var InProcessChatTransport = class {
3381
+ _open = true;
3382
+ _buffer = [];
3383
+ _resolve = null;
3384
+ _error = null;
3385
+ get isOpen() {
3386
+ return this._open;
3387
+ }
3388
+ send(event) {
3389
+ if (!this._open) return;
3390
+ if (this._resolve) {
3391
+ const resolve2 = this._resolve;
3392
+ this._resolve = null;
3393
+ resolve2({ value: event, done: false });
3394
+ } else {
3395
+ this._buffer.push(event);
3396
+ }
3397
+ }
3398
+ close() {
3399
+ if (!this._open) return;
3400
+ this._open = false;
3401
+ if (this._resolve) {
3402
+ const resolve2 = this._resolve;
3403
+ this._resolve = null;
3404
+ resolve2({ value: void 0, done: true });
3405
+ }
3406
+ }
3407
+ error(err) {
3408
+ if (!this._open) return;
3409
+ this._open = false;
3410
+ const errorEvent = {
3411
+ type: "error",
3412
+ error: err.message,
3413
+ recoverable: false
3414
+ };
3415
+ if (this._resolve) {
3416
+ const resolve2 = this._resolve;
3417
+ this._resolve = null;
3418
+ resolve2({ value: errorEvent, done: false });
3419
+ } else {
3420
+ this._error = err;
3421
+ }
3422
+ }
3423
+ // ─── AsyncIterable protocol ────────────────────────────────
3424
+ [Symbol.asyncIterator]() {
3425
+ return {
3426
+ next: () => {
3427
+ if (this._buffer.length > 0) {
3428
+ return Promise.resolve({ value: this._buffer.shift(), done: false });
3429
+ }
3430
+ if (this._error) {
3431
+ const err = this._error;
3432
+ this._error = null;
3433
+ const errorEvent = {
3434
+ type: "error",
3435
+ error: err.message,
3436
+ recoverable: false
3437
+ };
3438
+ return Promise.resolve({ value: errorEvent, done: false });
3439
+ }
3440
+ if (!this._open) {
3441
+ return Promise.resolve({ value: void 0, done: true });
3442
+ }
3443
+ return new Promise((resolve2) => {
3444
+ this._resolve = resolve2;
3445
+ });
3446
+ }
3447
+ };
3448
+ }
3449
+ };
3450
+
3451
+ // src/chat/backends/interceptors.ts
3452
+ var InterceptedTransport = class {
3453
+ _inner;
3454
+ _interceptors;
3455
+ constructor(inner, interceptors) {
3456
+ this._inner = inner;
3457
+ this._interceptors = interceptors;
3458
+ }
3459
+ get isOpen() {
3460
+ return this._inner.isOpen;
3461
+ }
3462
+ send(event) {
3463
+ if (!this.isOpen) return;
3464
+ let current = event;
3465
+ for (const interceptor of this._interceptors) {
3466
+ if (!interceptor.beforeSend) continue;
3467
+ current = interceptor.beforeSend(current, this._inner);
3468
+ if (current === null) return;
3469
+ }
3470
+ this._inner.send(current);
3471
+ for (const interceptor of this._interceptors) {
3472
+ if (interceptor.afterSend) {
3473
+ interceptor.afterSend(current, this._inner);
3474
+ }
3475
+ }
3476
+ }
3477
+ close() {
3478
+ for (const interceptor of this._interceptors) {
3479
+ if (interceptor.beforeClose) {
3480
+ interceptor.beforeClose(this._inner);
3481
+ }
3482
+ }
3483
+ this._inner.close();
3484
+ }
3485
+ error(err) {
3486
+ for (const interceptor of this._interceptors) {
3487
+ if (interceptor.onError) {
3488
+ interceptor.onError(err, this._inner);
3489
+ }
3490
+ }
3491
+ this._inner.error(err);
3492
+ }
3493
+ };
3494
+ function withInterceptors(transport, interceptors) {
3495
+ if (interceptors.length === 0) return transport;
3496
+ return new InterceptedTransport(transport, interceptors);
3497
+ }
3498
+
3499
+ export { BaseBackendAdapter, ClaudeChatAdapter, CopilotChatAdapter, InProcessChatTransport, SSEChatTransport, VercelAIChatAdapter, WS_READY_STATE, WsChatTransport, streamToTransport, withInterceptors };
3500
+ //# sourceMappingURL=backends.js.map
3501
+ //# sourceMappingURL=backends.js.map