@witqq/agent-sdk 0.7.0 → 0.8.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.
- package/README.md +140 -34
- package/dist/{types-CqvUAYxt.d.cts → agent-CW9XbmG_.d.ts} +137 -102
- package/dist/{types-CqvUAYxt.d.ts → agent-DxY68NZL.d.cts} +137 -102
- package/dist/auth/index.cjs +72 -1
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +21 -154
- package/dist/auth/index.d.ts +21 -154
- package/dist/auth/index.js +72 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/backends/claude.cjs +480 -261
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +3 -1
- package/dist/backends/claude.d.ts +3 -1
- package/dist/backends/claude.js +480 -261
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +329 -97
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +12 -4
- package/dist/backends/copilot.d.ts +12 -4
- package/dist/backends/copilot.js +329 -97
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/vercel-ai.cjs +294 -61
- package/dist/backends/vercel-ai.cjs.map +1 -1
- package/dist/backends/vercel-ai.d.cts +3 -1
- package/dist/backends/vercel-ai.d.ts +3 -1
- package/dist/backends/vercel-ai.js +294 -61
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/backends-BSrsBYFn.d.cts +39 -0
- package/dist/backends-BSrsBYFn.d.ts +39 -0
- package/dist/chat/accumulator.cjs +1 -1
- package/dist/chat/accumulator.cjs.map +1 -1
- package/dist/chat/accumulator.d.cts +5 -2
- package/dist/chat/accumulator.d.ts +5 -2
- package/dist/chat/accumulator.js +1 -1
- package/dist/chat/accumulator.js.map +1 -1
- package/dist/chat/backends.cjs +736 -746
- package/dist/chat/backends.cjs.map +1 -1
- package/dist/chat/backends.d.cts +10 -6
- package/dist/chat/backends.d.ts +10 -6
- package/dist/chat/backends.js +736 -725
- package/dist/chat/backends.js.map +1 -1
- package/dist/chat/context.cjs +50 -0
- package/dist/chat/context.cjs.map +1 -1
- package/dist/chat/context.d.cts +27 -3
- package/dist/chat/context.d.ts +27 -3
- package/dist/chat/context.js +50 -0
- package/dist/chat/context.js.map +1 -1
- package/dist/chat/core.cjs +25 -2
- package/dist/chat/core.cjs.map +1 -1
- package/dist/chat/core.d.cts +30 -381
- package/dist/chat/core.d.ts +30 -381
- package/dist/chat/core.js +24 -3
- package/dist/chat/core.js.map +1 -1
- package/dist/chat/errors.cjs +48 -26
- package/dist/chat/errors.cjs.map +1 -1
- package/dist/chat/errors.d.cts +6 -31
- package/dist/chat/errors.d.ts +6 -31
- package/dist/chat/errors.js +48 -25
- package/dist/chat/errors.js.map +1 -1
- package/dist/chat/events.cjs.map +1 -1
- package/dist/chat/events.d.cts +6 -2
- package/dist/chat/events.d.ts +6 -2
- package/dist/chat/events.js.map +1 -1
- package/dist/chat/index.cjs +1199 -1008
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +35 -10
- package/dist/chat/index.d.ts +35 -10
- package/dist/chat/index.js +1196 -987
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react/theme.css +2517 -0
- package/dist/chat/react.cjs +2003 -1153
- package/dist/chat/react.cjs.map +1 -1
- package/dist/chat/react.d.cts +590 -121
- package/dist/chat/react.d.ts +590 -121
- package/dist/chat/react.js +1984 -1151
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/runtime.cjs +401 -186
- package/dist/chat/runtime.cjs.map +1 -1
- package/dist/chat/runtime.d.cts +92 -28
- package/dist/chat/runtime.d.ts +92 -28
- package/dist/chat/runtime.js +401 -186
- package/dist/chat/runtime.js.map +1 -1
- package/dist/chat/server.cjs +2234 -209
- package/dist/chat/server.cjs.map +1 -1
- package/dist/chat/server.d.cts +451 -90
- package/dist/chat/server.d.ts +451 -90
- package/dist/chat/server.js +2221 -210
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/sessions.cjs +25 -43
- package/dist/chat/sessions.cjs.map +1 -1
- package/dist/chat/sessions.d.cts +37 -118
- package/dist/chat/sessions.d.ts +37 -118
- package/dist/chat/sessions.js +25 -43
- package/dist/chat/sessions.js.map +1 -1
- package/dist/chat/sqlite.cjs +441 -0
- package/dist/chat/sqlite.cjs.map +1 -0
- package/dist/chat/sqlite.d.cts +128 -0
- package/dist/chat/sqlite.d.ts +128 -0
- package/dist/chat/sqlite.js +435 -0
- package/dist/chat/sqlite.js.map +1 -0
- package/dist/chat/state.cjs +14 -1
- package/dist/chat/state.cjs.map +1 -1
- package/dist/chat/state.d.cts +5 -2
- package/dist/chat/state.d.ts +5 -2
- package/dist/chat/state.js +14 -1
- package/dist/chat/state.js.map +1 -1
- package/dist/chat/storage.cjs +19 -10
- package/dist/chat/storage.cjs.map +1 -1
- package/dist/chat/storage.d.cts +11 -5
- package/dist/chat/storage.d.ts +11 -5
- package/dist/chat/storage.js +19 -10
- package/dist/chat/storage.js.map +1 -1
- package/dist/errors-C-so0M4t.d.cts +33 -0
- package/dist/errors-C-so0M4t.d.ts +33 -0
- package/dist/errors-CmVvczxZ.d.cts +28 -0
- package/dist/errors-CmVvczxZ.d.ts +28 -0
- package/dist/{in-process-transport-C2oPTYs6.d.ts → in-process-transport-C1JnJGVR.d.ts} +28 -23
- package/dist/{in-process-transport-DG-w5G6k.d.cts → in-process-transport-C7DSqPyX.d.cts} +28 -23
- package/dist/index.cjs +340 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +292 -123
- package/dist/index.d.ts +292 -123
- package/dist/index.js +334 -47
- package/dist/index.js.map +1 -1
- package/dist/provider-types-PTSlRPNB.d.cts +39 -0
- package/dist/provider-types-PTSlRPNB.d.ts +39 -0
- package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
- package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
- package/dist/testing.cjs +383 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +132 -0
- package/dist/testing.d.ts +132 -0
- package/dist/testing.js +377 -0
- package/dist/testing.js.map +1 -0
- package/dist/token-store-CSUBgYwn.d.ts +48 -0
- package/dist/token-store-CuC4hB9Z.d.cts +48 -0
- package/dist/{transport-DX1Nhm4N.d.cts → transport-Cdh3M0tS.d.cts} +5 -4
- package/dist/{transport-D1OaUgRk.d.ts → transport-Ciap4PWK.d.ts} +5 -4
- package/dist/{types-CGF7AEX1.d.cts → types-4vbcmPTp.d.cts} +4 -2
- package/dist/{types-Bh5AhqD-.d.ts → types-BxggH0Yh.d.ts} +4 -2
- package/dist/types-DRgd_9R7.d.cts +363 -0
- package/dist/types-ajANVzf7.d.ts +363 -0
- package/package.json +31 -6
- package/dist/errors-BDLbNu9w.d.cts +0 -13
- package/dist/errors-BDLbNu9w.d.ts +0 -13
- package/dist/types-DLZzlJxt.d.ts +0 -39
- package/dist/types-tE0CXwBl.d.cts +0 -39
package/dist/chat/backends.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
|
|
5
1
|
var __defProp = Object.defineProperty;
|
|
6
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -23,16 +19,69 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
23
19
|
};
|
|
24
20
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
21
|
|
|
26
|
-
// src/errors.ts
|
|
27
|
-
|
|
22
|
+
// src/types/errors.ts
|
|
23
|
+
function isRecoverableErrorCode(code) {
|
|
24
|
+
return RECOVERABLE_CODES.has(code);
|
|
25
|
+
}
|
|
26
|
+
function classifyAgentError(error) {
|
|
27
|
+
const msg = (error instanceof Error ? error.message : error).toLowerCase();
|
|
28
|
+
if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
|
|
29
|
+
return "TIMEOUT" /* TIMEOUT */;
|
|
30
|
+
}
|
|
31
|
+
if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
|
|
32
|
+
return "RATE_LIMIT" /* RATE_LIMIT */;
|
|
33
|
+
}
|
|
34
|
+
if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
|
|
35
|
+
return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
|
|
36
|
+
}
|
|
37
|
+
if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
|
|
38
|
+
return "NETWORK" /* NETWORK */;
|
|
39
|
+
}
|
|
40
|
+
if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
|
|
41
|
+
return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
|
|
42
|
+
}
|
|
43
|
+
if (msg.includes("abort") || msg.includes("cancel")) {
|
|
44
|
+
return "ABORTED" /* ABORTED */;
|
|
45
|
+
}
|
|
46
|
+
if (msg.includes("500") || msg.includes("502") || msg.includes("503") || msg.includes("internal server error") || msg.includes("service unavailable") || msg.includes("bad gateway") || msg.includes("overloaded")) {
|
|
47
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
48
|
+
}
|
|
49
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
50
|
+
}
|
|
51
|
+
var RECOVERABLE_CODES;
|
|
28
52
|
var init_errors = __esm({
|
|
53
|
+
"src/types/errors.ts"() {
|
|
54
|
+
RECOVERABLE_CODES = /* @__PURE__ */ new Set([
|
|
55
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
56
|
+
"RATE_LIMIT" /* RATE_LIMIT */,
|
|
57
|
+
"NETWORK" /* NETWORK */,
|
|
58
|
+
"TOOL_EXECUTION" /* TOOL_EXECUTION */,
|
|
59
|
+
"MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
|
|
60
|
+
"PROVIDER_ERROR" /* PROVIDER_ERROR */
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// src/errors.ts
|
|
66
|
+
var AgentSDKError, ReentrancyError, DisposedError, SubprocessError, DependencyError, AbortError, ToolExecutionError, ActivityTimeoutError;
|
|
67
|
+
var init_errors2 = __esm({
|
|
29
68
|
"src/errors.ts"() {
|
|
69
|
+
init_errors();
|
|
30
70
|
AgentSDKError = class extends Error {
|
|
31
71
|
/** @internal Marker for cross-bundle identity checks */
|
|
32
72
|
_agentSDKError = true;
|
|
73
|
+
/** Machine-readable error code. Prefer values from the ErrorCode enum. */
|
|
74
|
+
code;
|
|
75
|
+
/** Whether this error is safe to retry */
|
|
76
|
+
retryable;
|
|
77
|
+
/** HTTP status code hint for error classification */
|
|
78
|
+
httpStatus;
|
|
33
79
|
constructor(message, options) {
|
|
34
80
|
super(message, options);
|
|
35
81
|
this.name = "AgentSDKError";
|
|
82
|
+
this.code = options?.code;
|
|
83
|
+
this.retryable = options?.retryable ?? false;
|
|
84
|
+
this.httpStatus = options?.httpStatus;
|
|
36
85
|
}
|
|
37
86
|
/** Check if an error is an AgentSDKError (works across bundled copies) */
|
|
38
87
|
static is(error) {
|
|
@@ -41,83 +90,84 @@ var init_errors = __esm({
|
|
|
41
90
|
};
|
|
42
91
|
ReentrancyError = class extends AgentSDKError {
|
|
43
92
|
constructor() {
|
|
44
|
-
super("Agent is already running. Await the current run before starting another."
|
|
93
|
+
super("Agent is already running. Await the current run before starting another.", {
|
|
94
|
+
code: "REENTRANCY" /* REENTRANCY */
|
|
95
|
+
});
|
|
45
96
|
this.name = "ReentrancyError";
|
|
46
97
|
}
|
|
47
98
|
};
|
|
48
99
|
DisposedError = class extends AgentSDKError {
|
|
49
100
|
constructor(entity) {
|
|
50
|
-
super(`${entity} has been disposed and cannot be used
|
|
101
|
+
super(`${entity} has been disposed and cannot be used.`, {
|
|
102
|
+
code: "DISPOSED" /* DISPOSED */
|
|
103
|
+
});
|
|
51
104
|
this.name = "DisposedError";
|
|
52
105
|
}
|
|
53
106
|
};
|
|
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
107
|
SubprocessError = class extends AgentSDKError {
|
|
69
108
|
constructor(message, options) {
|
|
70
|
-
super(message, options);
|
|
109
|
+
super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
|
|
71
110
|
this.name = "SubprocessError";
|
|
72
111
|
}
|
|
73
112
|
};
|
|
74
113
|
DependencyError = class extends AgentSDKError {
|
|
75
114
|
packageName;
|
|
76
115
|
constructor(packageName) {
|
|
77
|
-
super(`${packageName} is not installed. Install it: npm install ${packageName}
|
|
116
|
+
super(`${packageName} is not installed. Install it: npm install ${packageName}`, {
|
|
117
|
+
code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */
|
|
118
|
+
});
|
|
78
119
|
this.name = "DependencyError";
|
|
79
120
|
this.packageName = packageName;
|
|
80
121
|
}
|
|
81
122
|
};
|
|
82
123
|
AbortError = class extends AgentSDKError {
|
|
83
124
|
constructor() {
|
|
84
|
-
super("Agent run was aborted.");
|
|
125
|
+
super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
|
|
85
126
|
this.name = "AbortError";
|
|
86
127
|
}
|
|
87
128
|
};
|
|
88
129
|
ToolExecutionError = class extends AgentSDKError {
|
|
89
130
|
toolName;
|
|
90
131
|
constructor(toolName, message, options) {
|
|
91
|
-
super(`Tool "${toolName}" failed: ${message}`, options);
|
|
132
|
+
super(`Tool "${toolName}" failed: ${message}`, { ...options, code: "TOOL_EXECUTION" /* TOOL_EXECUTION */ });
|
|
92
133
|
this.name = "ToolExecutionError";
|
|
93
134
|
this.toolName = toolName;
|
|
94
135
|
}
|
|
95
136
|
};
|
|
96
|
-
|
|
97
|
-
constructor(
|
|
98
|
-
super(`
|
|
99
|
-
|
|
137
|
+
ActivityTimeoutError = class extends AgentSDKError {
|
|
138
|
+
constructor(timeoutMs) {
|
|
139
|
+
super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
|
|
140
|
+
code: "TIMEOUT" /* TIMEOUT */,
|
|
141
|
+
retryable: true
|
|
142
|
+
});
|
|
143
|
+
this.name = "ActivityTimeoutError";
|
|
100
144
|
}
|
|
101
145
|
};
|
|
102
146
|
}
|
|
103
147
|
});
|
|
104
148
|
|
|
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
|
-
}
|
|
149
|
+
// src/types/guards.ts
|
|
115
150
|
function getTextContent(content) {
|
|
116
151
|
if (typeof content === "string") return content;
|
|
117
152
|
return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
118
153
|
}
|
|
154
|
+
var init_guards = __esm({
|
|
155
|
+
"src/types/guards.ts"() {
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// src/types/index.ts
|
|
119
160
|
var init_types = __esm({
|
|
161
|
+
"src/types/index.ts"() {
|
|
162
|
+
init_errors();
|
|
163
|
+
init_guards();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// src/types.ts
|
|
168
|
+
var init_types2 = __esm({
|
|
120
169
|
"src/types.ts"() {
|
|
170
|
+
init_types();
|
|
121
171
|
}
|
|
122
172
|
});
|
|
123
173
|
|
|
@@ -125,12 +175,15 @@ var init_types = __esm({
|
|
|
125
175
|
var BaseAgent;
|
|
126
176
|
var init_base_agent = __esm({
|
|
127
177
|
"src/base-agent.ts"() {
|
|
178
|
+
init_errors2();
|
|
179
|
+
init_errors2();
|
|
128
180
|
init_errors();
|
|
129
181
|
BaseAgent = class {
|
|
130
182
|
state = "idle";
|
|
131
183
|
abortController = null;
|
|
132
184
|
config;
|
|
133
185
|
_cleanupExternalSignal = null;
|
|
186
|
+
_streamMiddleware = [];
|
|
134
187
|
/** CLI session ID for persistent mode. Override in backends that support it. */
|
|
135
188
|
get sessionId() {
|
|
136
189
|
return void 0;
|
|
@@ -146,8 +199,11 @@ var init_base_agent = __esm({
|
|
|
146
199
|
this.state = "running";
|
|
147
200
|
try {
|
|
148
201
|
const messages = [{ role: "user", content: prompt }];
|
|
149
|
-
const result = await this.
|
|
150
|
-
|
|
202
|
+
const result = await this.withRetry(
|
|
203
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
204
|
+
options
|
|
205
|
+
);
|
|
206
|
+
this.enrichAndNotifyUsage(result, options);
|
|
151
207
|
return result;
|
|
152
208
|
} finally {
|
|
153
209
|
this.cleanupRun();
|
|
@@ -159,8 +215,11 @@ var init_base_agent = __esm({
|
|
|
159
215
|
const ac = this.createAbortController(options?.signal);
|
|
160
216
|
this.state = "running";
|
|
161
217
|
try {
|
|
162
|
-
const result = await this.
|
|
163
|
-
|
|
218
|
+
const result = await this.withRetry(
|
|
219
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
220
|
+
options
|
|
221
|
+
);
|
|
222
|
+
this.enrichAndNotifyUsage(result, options);
|
|
164
223
|
return result;
|
|
165
224
|
} finally {
|
|
166
225
|
this.cleanupRun();
|
|
@@ -173,13 +232,11 @@ var init_base_agent = __esm({
|
|
|
173
232
|
this.state = "running";
|
|
174
233
|
try {
|
|
175
234
|
const messages = [{ role: "user", content: prompt }];
|
|
176
|
-
const result = await this.
|
|
177
|
-
messages,
|
|
178
|
-
|
|
179
|
-
options,
|
|
180
|
-
ac.signal
|
|
235
|
+
const result = await this.withRetry(
|
|
236
|
+
() => this.executeRunStructured(messages, schema, options, ac.signal),
|
|
237
|
+
options
|
|
181
238
|
);
|
|
182
|
-
this.enrichAndNotifyUsage(result);
|
|
239
|
+
this.enrichAndNotifyUsage(result, options);
|
|
183
240
|
return result;
|
|
184
241
|
} finally {
|
|
185
242
|
this.cleanupRun();
|
|
@@ -192,8 +249,10 @@ var init_base_agent = __esm({
|
|
|
192
249
|
this.state = "streaming";
|
|
193
250
|
try {
|
|
194
251
|
const messages = [{ role: "user", content: prompt }];
|
|
195
|
-
|
|
196
|
-
|
|
252
|
+
yield* this.streamWithRetry(
|
|
253
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
254
|
+
options
|
|
255
|
+
);
|
|
197
256
|
} finally {
|
|
198
257
|
this.cleanupRun();
|
|
199
258
|
}
|
|
@@ -204,12 +263,37 @@ var init_base_agent = __esm({
|
|
|
204
263
|
const ac = this.createAbortController(options?.signal);
|
|
205
264
|
this.state = "streaming";
|
|
206
265
|
try {
|
|
207
|
-
|
|
208
|
-
|
|
266
|
+
yield* this.streamWithRetry(
|
|
267
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
268
|
+
options
|
|
269
|
+
);
|
|
209
270
|
} finally {
|
|
210
271
|
this.cleanupRun();
|
|
211
272
|
}
|
|
212
273
|
}
|
|
274
|
+
/** Register a stream middleware. Applied in registration order after built-in transforms. */
|
|
275
|
+
addStreamMiddleware(middleware) {
|
|
276
|
+
this.guardDisposed();
|
|
277
|
+
this._streamMiddleware.push(middleware);
|
|
278
|
+
}
|
|
279
|
+
/** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
|
|
280
|
+
async *applyStreamPipeline(source, options, ac) {
|
|
281
|
+
let stream = this.enrichStream(source, options);
|
|
282
|
+
stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
|
|
283
|
+
stream = this.heartbeatStream(stream);
|
|
284
|
+
if (this._streamMiddleware.length > 0) {
|
|
285
|
+
const ctx = {
|
|
286
|
+
model: options.model,
|
|
287
|
+
backend: this.backendName,
|
|
288
|
+
abortController: ac,
|
|
289
|
+
config: Object.freeze({ ...this.config })
|
|
290
|
+
};
|
|
291
|
+
for (const mw of this._streamMiddleware) {
|
|
292
|
+
stream = mw(stream, ctx);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
yield* stream;
|
|
296
|
+
}
|
|
213
297
|
abort() {
|
|
214
298
|
if (this.abortController) {
|
|
215
299
|
this.abortController.abort();
|
|
@@ -232,26 +316,109 @@ var init_base_agent = __esm({
|
|
|
232
316
|
this.abort();
|
|
233
317
|
this.state = "disposed";
|
|
234
318
|
}
|
|
319
|
+
// ─── Retry Logic ─────────────────────────────────────────────
|
|
320
|
+
/** Check if an error should be retried given the retry configuration. */
|
|
321
|
+
isRetryableError(error, retry) {
|
|
322
|
+
if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
if (AgentSDKError.is(error)) {
|
|
326
|
+
if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
|
|
327
|
+
return retry.retryableErrors.includes(error.code);
|
|
328
|
+
}
|
|
329
|
+
if (error.retryable) return true;
|
|
330
|
+
if (error.code) return isRecoverableErrorCode(error.code);
|
|
331
|
+
}
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
/** Execute a function with retry logic per RetryConfig. */
|
|
335
|
+
async withRetry(fn, options) {
|
|
336
|
+
const retry = options?.retry;
|
|
337
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
338
|
+
return fn();
|
|
339
|
+
}
|
|
340
|
+
const maxRetries = retry.maxRetries;
|
|
341
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
342
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
343
|
+
let lastError;
|
|
344
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
345
|
+
try {
|
|
346
|
+
return await fn();
|
|
347
|
+
} catch (err) {
|
|
348
|
+
lastError = err;
|
|
349
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
350
|
+
throw err;
|
|
351
|
+
}
|
|
352
|
+
const delay = initialDelay * Math.pow(multiplier, attempt);
|
|
353
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
354
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
355
|
+
throw err;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
throw lastError;
|
|
360
|
+
}
|
|
361
|
+
/** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
|
|
362
|
+
async *streamWithRetry(factory, options) {
|
|
363
|
+
const retry = options?.retry;
|
|
364
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
365
|
+
yield* factory();
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const maxRetries = retry.maxRetries;
|
|
369
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
370
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
371
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
372
|
+
try {
|
|
373
|
+
const stream = factory();
|
|
374
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
375
|
+
const first = await iterator.next();
|
|
376
|
+
if (first.done) return;
|
|
377
|
+
yield first.value;
|
|
378
|
+
while (true) {
|
|
379
|
+
const next = await iterator.next();
|
|
380
|
+
if (next.done) break;
|
|
381
|
+
yield next.value;
|
|
382
|
+
}
|
|
383
|
+
return;
|
|
384
|
+
} catch (err) {
|
|
385
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
386
|
+
throw err;
|
|
387
|
+
}
|
|
388
|
+
const delay = initialDelay * Math.pow(multiplier, attempt);
|
|
389
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
390
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
391
|
+
throw err;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// ─── CallOptions Resolution ──────────────────────────────────
|
|
397
|
+
/** Resolve tools to use for this call (per-call override > config default) */
|
|
398
|
+
resolveTools(options) {
|
|
399
|
+
return options?.tools ?? this.config.tools ?? [];
|
|
400
|
+
}
|
|
235
401
|
// ─── Usage Enrichment ───────────────────────────────────────────
|
|
236
402
|
/** Enrich result usage with model/backend and fire onUsage callback */
|
|
237
|
-
enrichAndNotifyUsage(result) {
|
|
403
|
+
enrichAndNotifyUsage(result, options) {
|
|
238
404
|
if (result.usage) {
|
|
239
405
|
result.usage = {
|
|
240
406
|
...result.usage,
|
|
241
|
-
model:
|
|
407
|
+
model: options.model,
|
|
242
408
|
backend: this.backendName
|
|
243
409
|
};
|
|
244
410
|
this.callOnUsage(result.usage);
|
|
245
411
|
}
|
|
246
412
|
}
|
|
247
413
|
/** Wrap a stream to enrich usage_update events and fire onUsage callback */
|
|
248
|
-
async *enrichStream(source) {
|
|
414
|
+
async *enrichStream(source, options) {
|
|
415
|
+
const model = options.model;
|
|
249
416
|
for await (const event of source) {
|
|
250
417
|
if (event.type === "usage_update") {
|
|
251
418
|
const usage = {
|
|
252
419
|
promptTokens: event.promptTokens,
|
|
253
420
|
completionTokens: event.completionTokens,
|
|
254
|
-
model
|
|
421
|
+
model,
|
|
255
422
|
backend: this.backendName
|
|
256
423
|
};
|
|
257
424
|
this.callOnUsage(usage);
|
|
@@ -287,9 +454,9 @@ var init_base_agent = __esm({
|
|
|
287
454
|
let heartbeatResolve = null;
|
|
288
455
|
const timer = setInterval(() => {
|
|
289
456
|
if (heartbeatResolve) {
|
|
290
|
-
const
|
|
457
|
+
const resolve = heartbeatResolve;
|
|
291
458
|
heartbeatResolve = null;
|
|
292
|
-
|
|
459
|
+
resolve();
|
|
293
460
|
}
|
|
294
461
|
}, interval);
|
|
295
462
|
try {
|
|
@@ -297,8 +464,8 @@ var init_base_agent = __esm({
|
|
|
297
464
|
if (!pendingEvent) {
|
|
298
465
|
pendingEvent = iterator.next();
|
|
299
466
|
}
|
|
300
|
-
const heartbeatPromise = new Promise((
|
|
301
|
-
heartbeatResolve =
|
|
467
|
+
const heartbeatPromise = new Promise((resolve) => {
|
|
468
|
+
heartbeatResolve = resolve;
|
|
302
469
|
});
|
|
303
470
|
const eventDone = pendingEvent.then(
|
|
304
471
|
(r) => ({ kind: "event", result: r })
|
|
@@ -321,6 +488,35 @@ var init_base_agent = __esm({
|
|
|
321
488
|
heartbeatResolve = null;
|
|
322
489
|
}
|
|
323
490
|
}
|
|
491
|
+
// ─── Activity Timeout ────────────────────────────────────────
|
|
492
|
+
/** Wrap a stream to abort on inactivity. Resets timer on every event.
|
|
493
|
+
* When timeoutMs is not set, passes through directly. */
|
|
494
|
+
async *activityTimeoutStream(source, timeoutMs, ac) {
|
|
495
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
496
|
+
yield* source;
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
500
|
+
let timerId;
|
|
501
|
+
try {
|
|
502
|
+
while (true) {
|
|
503
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
504
|
+
timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
|
|
505
|
+
});
|
|
506
|
+
const result = await Promise.race([iterator.next(), timeoutPromise]);
|
|
507
|
+
clearTimeout(timerId);
|
|
508
|
+
if (result.done) break;
|
|
509
|
+
yield result.value;
|
|
510
|
+
}
|
|
511
|
+
} catch (err) {
|
|
512
|
+
if (err instanceof ActivityTimeoutError) {
|
|
513
|
+
ac.abort(err);
|
|
514
|
+
}
|
|
515
|
+
throw err;
|
|
516
|
+
} finally {
|
|
517
|
+
clearTimeout(timerId);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
324
520
|
// ─── Guards ───────────────────────────────────────────────────
|
|
325
521
|
guardReentrancy() {
|
|
326
522
|
if (this.state === "running" || this.state === "streaming") {
|
|
@@ -425,6 +621,66 @@ var init_schema = __esm({
|
|
|
425
621
|
}
|
|
426
622
|
});
|
|
427
623
|
|
|
624
|
+
// src/backends/shared.ts
|
|
625
|
+
function extractLastUserPrompt(messages) {
|
|
626
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
627
|
+
const msg = messages[i];
|
|
628
|
+
if (msg.role === "user") {
|
|
629
|
+
return getTextContent(msg.content);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return "";
|
|
633
|
+
}
|
|
634
|
+
function serializeToolCall(tc) {
|
|
635
|
+
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
636
|
+
return ` Tool call: ${tc.name}(${args})`;
|
|
637
|
+
}
|
|
638
|
+
function serializeToolResult(tr) {
|
|
639
|
+
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
640
|
+
const prefix = tr.isError ? "[ERROR] " : "";
|
|
641
|
+
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
642
|
+
}
|
|
643
|
+
function buildContextualPrompt(messages) {
|
|
644
|
+
if (messages.length <= 1) {
|
|
645
|
+
return extractLastUserPrompt(messages);
|
|
646
|
+
}
|
|
647
|
+
const history = messages.slice(0, -1).map((msg) => {
|
|
648
|
+
if (msg.role === "user") {
|
|
649
|
+
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
650
|
+
}
|
|
651
|
+
if (msg.role === "tool" && msg.toolResults) {
|
|
652
|
+
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
653
|
+
return `Tool results:
|
|
654
|
+
${results}`;
|
|
655
|
+
}
|
|
656
|
+
if (msg.role === "assistant") {
|
|
657
|
+
const parts = [];
|
|
658
|
+
const thinking = msg.thinking;
|
|
659
|
+
if (thinking) {
|
|
660
|
+
parts.push(`[reasoning: ${thinking}]`);
|
|
661
|
+
}
|
|
662
|
+
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
663
|
+
if (text2) parts.push(text2);
|
|
664
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
665
|
+
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
666
|
+
}
|
|
667
|
+
return `Assistant: ${parts.join("\n")}`;
|
|
668
|
+
}
|
|
669
|
+
const text = msg.content ? getTextContent(msg.content) : "";
|
|
670
|
+
return `${msg.role}: ${text}`;
|
|
671
|
+
}).join("\n");
|
|
672
|
+
const lastPrompt = extractLastUserPrompt(messages);
|
|
673
|
+
return `Conversation history:
|
|
674
|
+
${history}
|
|
675
|
+
|
|
676
|
+
User: ${lastPrompt}`;
|
|
677
|
+
}
|
|
678
|
+
var init_shared = __esm({
|
|
679
|
+
"src/backends/shared.ts"() {
|
|
680
|
+
init_types2();
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
|
|
428
684
|
// src/backends/copilot.ts
|
|
429
685
|
var copilot_exports = {};
|
|
430
686
|
__export(copilot_exports, {
|
|
@@ -433,10 +689,9 @@ __export(copilot_exports, {
|
|
|
433
689
|
createCopilotService: () => createCopilotService
|
|
434
690
|
});
|
|
435
691
|
async function loadSDK() {
|
|
436
|
-
if (
|
|
692
|
+
if (_sdkMock) return _sdkMock;
|
|
437
693
|
try {
|
|
438
|
-
|
|
439
|
-
return sdkModule;
|
|
694
|
+
return await import('@github/copilot-sdk');
|
|
440
695
|
} catch {
|
|
441
696
|
throw new SubprocessError(
|
|
442
697
|
"@github/copilot-sdk is not installed. Install it: npm install @github/copilot-sdk"
|
|
@@ -444,10 +699,10 @@ async function loadSDK() {
|
|
|
444
699
|
}
|
|
445
700
|
}
|
|
446
701
|
function _injectSDK(mock) {
|
|
447
|
-
|
|
702
|
+
_sdkMock = mock;
|
|
448
703
|
}
|
|
449
704
|
function _resetSDK() {
|
|
450
|
-
|
|
705
|
+
_sdkMock = null;
|
|
451
706
|
}
|
|
452
707
|
function mapToolsToSDK(tools) {
|
|
453
708
|
return tools.map((tool) => ({
|
|
@@ -492,6 +747,7 @@ function buildPermissionHandler(config) {
|
|
|
492
747
|
const unifiedRequest = {
|
|
493
748
|
toolName,
|
|
494
749
|
toolArgs: { ...request },
|
|
750
|
+
toolCallId: request.toolCallId,
|
|
495
751
|
rawSDKRequest: request
|
|
496
752
|
};
|
|
497
753
|
const ac = new AbortController();
|
|
@@ -596,15 +852,21 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
596
852
|
};
|
|
597
853
|
case "session.error":
|
|
598
854
|
console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
855
|
+
{
|
|
856
|
+
const errorMsg = String(data.message ?? "Unknown error");
|
|
857
|
+
const code = classifyAgentError(errorMsg);
|
|
858
|
+
return {
|
|
859
|
+
type: "error",
|
|
860
|
+
error: errorMsg,
|
|
861
|
+
recoverable: isRecoverableErrorCode(code),
|
|
862
|
+
code
|
|
863
|
+
};
|
|
864
|
+
}
|
|
604
865
|
case "assistant.message": {
|
|
605
866
|
const doneEvent = {
|
|
606
867
|
type: "done",
|
|
607
|
-
finalOutput:
|
|
868
|
+
finalOutput: null,
|
|
869
|
+
streamed: true
|
|
608
870
|
};
|
|
609
871
|
if (thinkingTracker.endThinking()) {
|
|
610
872
|
return [{ type: "thinking_end" }, doneEvent];
|
|
@@ -615,66 +877,13 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
615
877
|
return null;
|
|
616
878
|
}
|
|
617
879
|
}
|
|
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
880
|
function withTimeout(promise, ms, message) {
|
|
672
|
-
return new Promise((
|
|
881
|
+
return new Promise((resolve, reject) => {
|
|
673
882
|
const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
|
|
674
883
|
promise.then(
|
|
675
884
|
(val) => {
|
|
676
885
|
clearTimeout(timer);
|
|
677
|
-
|
|
886
|
+
resolve(val);
|
|
678
887
|
},
|
|
679
888
|
(err) => {
|
|
680
889
|
clearTimeout(timer);
|
|
@@ -686,14 +895,15 @@ function withTimeout(promise, ms, message) {
|
|
|
686
895
|
function createCopilotService(options) {
|
|
687
896
|
return new CopilotAgentService(options);
|
|
688
897
|
}
|
|
689
|
-
var
|
|
898
|
+
var _sdkMock, ToolCallTracker, ThinkingTracker, CopilotAgent, CopilotAgentService;
|
|
690
899
|
var init_copilot = __esm({
|
|
691
900
|
"src/backends/copilot.ts"() {
|
|
692
|
-
|
|
901
|
+
init_types2();
|
|
693
902
|
init_base_agent();
|
|
694
|
-
|
|
903
|
+
init_errors2();
|
|
695
904
|
init_schema();
|
|
696
|
-
|
|
905
|
+
init_shared();
|
|
906
|
+
_sdkMock = null;
|
|
697
907
|
ToolCallTracker = class {
|
|
698
908
|
map = /* @__PURE__ */ new Map();
|
|
699
909
|
trackStart(toolCallId, toolName, args) {
|
|
@@ -741,6 +951,7 @@ var init_copilot = __esm({
|
|
|
741
951
|
isPersistent;
|
|
742
952
|
persistentSession = null;
|
|
743
953
|
_sessionId;
|
|
954
|
+
_persistentModel;
|
|
744
955
|
activeSession = null;
|
|
745
956
|
_resumeSessionId;
|
|
746
957
|
_toolsReady = null;
|
|
@@ -791,47 +1002,63 @@ var init_copilot = __esm({
|
|
|
791
1002
|
});
|
|
792
1003
|
this.persistentSession = null;
|
|
793
1004
|
this._sessionId = void 0;
|
|
1005
|
+
this._persistentModel = void 0;
|
|
794
1006
|
}
|
|
795
1007
|
}
|
|
796
|
-
async getOrCreateSession(streaming) {
|
|
1008
|
+
async getOrCreateSession(streaming, options) {
|
|
797
1009
|
if (this.isPersistent && this.persistentSession) {
|
|
798
|
-
|
|
1010
|
+
if (options.model !== this._persistentModel) {
|
|
1011
|
+
this.persistentSession.destroy().catch(() => {
|
|
1012
|
+
});
|
|
1013
|
+
this.persistentSession = null;
|
|
1014
|
+
this._sessionId = void 0;
|
|
1015
|
+
} else {
|
|
1016
|
+
return { session: this.persistentSession, isNew: false };
|
|
1017
|
+
}
|
|
799
1018
|
}
|
|
800
1019
|
if (this._toolsReady) {
|
|
801
1020
|
await this._toolsReady;
|
|
802
1021
|
this._toolsReady = null;
|
|
803
1022
|
}
|
|
1023
|
+
const sessionConfig = { ...this.sessionConfig };
|
|
1024
|
+
sessionConfig.model = options.model;
|
|
1025
|
+
const resolvedTools = this.resolveTools(options);
|
|
1026
|
+
if (options?.tools) {
|
|
1027
|
+
sessionConfig.tools = mapToolsToSDK(resolvedTools);
|
|
1028
|
+
}
|
|
804
1029
|
const client = await this.getClient();
|
|
805
1030
|
if (this._resumeSessionId) {
|
|
806
1031
|
const storedId = this._resumeSessionId;
|
|
807
1032
|
this._resumeSessionId = void 0;
|
|
808
1033
|
try {
|
|
809
1034
|
const session2 = await client.resumeSession(storedId, {
|
|
810
|
-
...
|
|
1035
|
+
...sessionConfig,
|
|
811
1036
|
streaming: this.isPersistent ? true : streaming
|
|
812
1037
|
});
|
|
813
1038
|
if (this.isPersistent) {
|
|
814
1039
|
this.persistentSession = session2;
|
|
815
1040
|
this._sessionId = session2.sessionId;
|
|
1041
|
+
this._persistentModel = options.model;
|
|
816
1042
|
}
|
|
817
1043
|
return { session: session2, isNew: false };
|
|
818
1044
|
} catch {
|
|
819
1045
|
}
|
|
820
1046
|
}
|
|
821
1047
|
const session = await client.createSession({
|
|
822
|
-
...
|
|
1048
|
+
...sessionConfig,
|
|
823
1049
|
streaming: this.isPersistent ? true : streaming
|
|
824
1050
|
});
|
|
825
1051
|
if (this.isPersistent) {
|
|
826
1052
|
this.persistentSession = session;
|
|
827
1053
|
this._sessionId = session.sessionId;
|
|
1054
|
+
this._persistentModel = options.model;
|
|
828
1055
|
}
|
|
829
1056
|
return { session, isNew: true };
|
|
830
1057
|
}
|
|
831
1058
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
832
|
-
async executeRun(messages,
|
|
1059
|
+
async executeRun(messages, options, signal) {
|
|
833
1060
|
this.checkAbort(signal);
|
|
834
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
|
|
1061
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(false, options);
|
|
835
1062
|
this.activeSession = session;
|
|
836
1063
|
const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
837
1064
|
const tracker = new ToolCallTracker();
|
|
@@ -928,9 +1155,9 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
928
1155
|
};
|
|
929
1156
|
}
|
|
930
1157
|
// ─── executeStream ──────────────────────────────────────────────
|
|
931
|
-
async *executeStream(messages,
|
|
1158
|
+
async *executeStream(messages, options, signal) {
|
|
932
1159
|
this.checkAbort(signal);
|
|
933
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
|
|
1160
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(true, options);
|
|
934
1161
|
this.activeSession = session;
|
|
935
1162
|
if (isNewSession) {
|
|
936
1163
|
yield this.emitSessionInfo(session.sessionId);
|
|
@@ -947,8 +1174,8 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
947
1174
|
notify = null;
|
|
948
1175
|
}
|
|
949
1176
|
};
|
|
950
|
-
const waitForItem = () => new Promise((
|
|
951
|
-
notify =
|
|
1177
|
+
const waitForItem = () => new Promise((resolve) => {
|
|
1178
|
+
notify = resolve;
|
|
952
1179
|
});
|
|
953
1180
|
const unsubscribe = session.on((event) => {
|
|
954
1181
|
const mapped = mapSessionEvent(event, tracker, thinkingTracker);
|
|
@@ -1076,7 +1303,10 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1076
1303
|
return models.map((m) => ({
|
|
1077
1304
|
id: m.id,
|
|
1078
1305
|
name: m.name,
|
|
1079
|
-
provider: "copilot"
|
|
1306
|
+
provider: "copilot",
|
|
1307
|
+
...m.capabilities?.limits?.max_context_window_tokens != null && {
|
|
1308
|
+
contextWindow: m.capabilities.limits.max_context_window_tokens
|
|
1309
|
+
}
|
|
1080
1310
|
}));
|
|
1081
1311
|
}
|
|
1082
1312
|
async validate() {
|
|
@@ -1129,10 +1359,9 @@ function stripMcpPrefix(name) {
|
|
|
1129
1359
|
return name.startsWith(MCP_TOOL_PREFIX) ? name.slice(MCP_TOOL_PREFIX.length) : name;
|
|
1130
1360
|
}
|
|
1131
1361
|
async function loadSDK2() {
|
|
1132
|
-
if (
|
|
1362
|
+
if (_sdkMock2) return _sdkMock2;
|
|
1133
1363
|
try {
|
|
1134
|
-
|
|
1135
|
-
return sdkModule2;
|
|
1364
|
+
return await import('@anthropic-ai/claude-agent-sdk');
|
|
1136
1365
|
} catch {
|
|
1137
1366
|
throw new SubprocessError(
|
|
1138
1367
|
"@anthropic-ai/claude-agent-sdk is not installed. Install it: npm install @anthropic-ai/claude-agent-sdk"
|
|
@@ -1140,13 +1369,32 @@ async function loadSDK2() {
|
|
|
1140
1369
|
}
|
|
1141
1370
|
}
|
|
1142
1371
|
function _injectSDK2(mock) {
|
|
1143
|
-
|
|
1372
|
+
_sdkMock2 = mock;
|
|
1144
1373
|
}
|
|
1145
1374
|
function _resetSDK2() {
|
|
1146
|
-
|
|
1375
|
+
_sdkMock2 = null;
|
|
1376
|
+
}
|
|
1377
|
+
function normalizeAskUserInput(args) {
|
|
1378
|
+
if (typeof args.question === "string") {
|
|
1379
|
+
return {
|
|
1380
|
+
question: args.question,
|
|
1381
|
+
choices: Array.isArray(args.choices) ? args.choices : void 0,
|
|
1382
|
+
allowFreeform: args.allowFreeform !== false
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
const questions = args.questions;
|
|
1386
|
+
if (questions && questions.length > 0) {
|
|
1387
|
+
const first = questions[0];
|
|
1388
|
+
return {
|
|
1389
|
+
question: first.question,
|
|
1390
|
+
choices: first.options?.map((o) => o.label),
|
|
1391
|
+
allowFreeform: true
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
return { question: JSON.stringify(args), allowFreeform: true };
|
|
1147
1395
|
}
|
|
1148
|
-
function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
1149
|
-
if (tools.length === 0) return void 0;
|
|
1396
|
+
function buildMcpServer(sdk, tools, toolResultCapture, onAskUser) {
|
|
1397
|
+
if (tools.length === 0 && !onAskUser) return void 0;
|
|
1150
1398
|
const mcpTools = tools.map((tool) => {
|
|
1151
1399
|
const zodSchema = tool.parameters;
|
|
1152
1400
|
const inputSchema = zodSchema.shape ?? zodToJsonSchema(tool.parameters);
|
|
@@ -1170,6 +1418,39 @@ function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
|
1170
1418
|
}
|
|
1171
1419
|
);
|
|
1172
1420
|
});
|
|
1421
|
+
if (onAskUser) {
|
|
1422
|
+
const askUserTool = sdk.tool(
|
|
1423
|
+
"ask_user",
|
|
1424
|
+
"Ask the user a question and wait for their response",
|
|
1425
|
+
{
|
|
1426
|
+
question: { type: "string", description: "The question to ask the user" },
|
|
1427
|
+
choices: {
|
|
1428
|
+
type: "array",
|
|
1429
|
+
items: { type: "string" },
|
|
1430
|
+
description: "Optional list of choices for multiple choice"
|
|
1431
|
+
},
|
|
1432
|
+
questions: {
|
|
1433
|
+
type: "array",
|
|
1434
|
+
items: {
|
|
1435
|
+
type: "object",
|
|
1436
|
+
properties: {
|
|
1437
|
+
question: { type: "string" },
|
|
1438
|
+
options: { type: "array", items: { type: "object", properties: { label: { type: "string" } } } }
|
|
1439
|
+
}
|
|
1440
|
+
},
|
|
1441
|
+
description: "Alternative nested question format"
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
async (args) => {
|
|
1445
|
+
const normalized = normalizeAskUserInput(args);
|
|
1446
|
+
const response = await onAskUser(normalized, AbortSignal.timeout(3e5));
|
|
1447
|
+
return {
|
|
1448
|
+
content: [{ type: "text", text: response.answer }]
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
);
|
|
1452
|
+
mcpTools.push(askUserTool);
|
|
1453
|
+
}
|
|
1173
1454
|
return sdk.createSdkMcpServer({
|
|
1174
1455
|
name: MCP_SERVER_NAME,
|
|
1175
1456
|
version: "1.0.0",
|
|
@@ -1219,6 +1500,7 @@ function buildCanUseTool(config) {
|
|
|
1219
1500
|
const unifiedRequest = {
|
|
1220
1501
|
toolName,
|
|
1221
1502
|
toolArgs: input,
|
|
1503
|
+
toolCallId: options.toolUseID,
|
|
1222
1504
|
suggestedScope: extractSuggestedScope(options.suggestions),
|
|
1223
1505
|
rawSDKRequest: { toolName, input, ...options }
|
|
1224
1506
|
};
|
|
@@ -1271,6 +1553,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1271
1553
|
if (block.type === "tool_use") {
|
|
1272
1554
|
const toolCallId = String(block.id ?? "");
|
|
1273
1555
|
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1556
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1274
1557
|
if (toolCallTracker) {
|
|
1275
1558
|
toolCallTracker.trackStart(toolCallId, toolName);
|
|
1276
1559
|
}
|
|
@@ -1294,6 +1577,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1294
1577
|
case "tool_use_summary": {
|
|
1295
1578
|
const summary = msg.summary;
|
|
1296
1579
|
const toolName = stripMcpPrefix(msg.tool_name ?? "unknown");
|
|
1580
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) return null;
|
|
1297
1581
|
const precedingIds = msg.preceding_tool_use_ids;
|
|
1298
1582
|
let toolCallId = "";
|
|
1299
1583
|
if (precedingIds && precedingIds.length > 0) {
|
|
@@ -1347,10 +1631,13 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1347
1631
|
}
|
|
1348
1632
|
if (msg.is_error) {
|
|
1349
1633
|
const r = msg;
|
|
1634
|
+
const errorMsg = r.errors?.join("; ") ?? "Unknown error";
|
|
1635
|
+
const code = classifyAgentError(errorMsg);
|
|
1350
1636
|
return {
|
|
1351
1637
|
type: "error",
|
|
1352
|
-
error:
|
|
1353
|
-
recoverable:
|
|
1638
|
+
error: errorMsg,
|
|
1639
|
+
recoverable: isRecoverableErrorCode(code),
|
|
1640
|
+
code
|
|
1354
1641
|
};
|
|
1355
1642
|
}
|
|
1356
1643
|
return null;
|
|
@@ -1359,72 +1646,21 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1359
1646
|
return null;
|
|
1360
1647
|
}
|
|
1361
1648
|
}
|
|
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
1649
|
function createClaudeService(options) {
|
|
1416
1650
|
return new ClaudeAgentService(options);
|
|
1417
1651
|
}
|
|
1418
|
-
var MCP_SERVER_NAME, MCP_TOOL_PREFIX,
|
|
1652
|
+
var MCP_SERVER_NAME, MCP_TOOL_PREFIX, CLAUDE_INTERNAL_TOOL_NAMES, _sdkMock2, ANTHROPIC_MODELS_URL, ANTHROPIC_API_VERSION, ANTHROPIC_OAUTH_BETA, ClaudeToolCallTracker, ClaudeAgent, ClaudeAgentService;
|
|
1419
1653
|
var init_claude = __esm({
|
|
1420
1654
|
"src/backends/claude.ts"() {
|
|
1421
|
-
|
|
1655
|
+
init_types2();
|
|
1422
1656
|
init_base_agent();
|
|
1423
|
-
|
|
1657
|
+
init_errors2();
|
|
1424
1658
|
init_schema();
|
|
1659
|
+
init_shared();
|
|
1425
1660
|
MCP_SERVER_NAME = "agent-sdk-tools";
|
|
1426
1661
|
MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
1427
|
-
|
|
1662
|
+
CLAUDE_INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1663
|
+
_sdkMock2 = null;
|
|
1428
1664
|
ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
|
|
1429
1665
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
1430
1666
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
@@ -1469,11 +1705,6 @@ var init_claude = __esm({
|
|
|
1469
1705
|
if (options.resumeSessionId) {
|
|
1470
1706
|
this._sessionId = options.resumeSessionId;
|
|
1471
1707
|
}
|
|
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
1708
|
}
|
|
1478
1709
|
get sessionId() {
|
|
1479
1710
|
return this._sessionId;
|
|
@@ -1497,12 +1728,12 @@ var init_claude = __esm({
|
|
|
1497
1728
|
const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
|
|
1498
1729
|
return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
|
|
1499
1730
|
}
|
|
1500
|
-
buildQueryOptions(signal) {
|
|
1731
|
+
buildQueryOptions(signal, options) {
|
|
1501
1732
|
const ac = new AbortController();
|
|
1502
1733
|
signal.addEventListener("abort", () => ac.abort(), { once: true });
|
|
1503
1734
|
const opts = {
|
|
1504
1735
|
abortController: ac,
|
|
1505
|
-
model:
|
|
1736
|
+
model: options.model,
|
|
1506
1737
|
maxTurns: this.options.maxTurns,
|
|
1507
1738
|
cwd: this.options.workingDirectory,
|
|
1508
1739
|
pathToClaudeCodeExecutable: this.options.cliPath,
|
|
@@ -1532,25 +1763,85 @@ var init_claude = __esm({
|
|
|
1532
1763
|
return opts;
|
|
1533
1764
|
}
|
|
1534
1765
|
async buildMcpConfig(opts, toolResultCapture) {
|
|
1535
|
-
|
|
1766
|
+
const onAskUser = this.config.supervisor?.onAskUser;
|
|
1767
|
+
if (this.tools.length === 0 && !onAskUser) return opts;
|
|
1536
1768
|
const sdk = await loadSDK2();
|
|
1537
|
-
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture);
|
|
1769
|
+
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture, onAskUser);
|
|
1538
1770
|
if (mcpServer) {
|
|
1539
1771
|
opts.mcpServers = {
|
|
1540
1772
|
[MCP_SERVER_NAME]: mcpServer
|
|
1541
1773
|
};
|
|
1542
1774
|
const mcpToolNames = this.tools.map((t) => mcpToolName(t.name));
|
|
1775
|
+
if (onAskUser) {
|
|
1776
|
+
mcpToolNames.push(mcpToolName("ask_user"));
|
|
1777
|
+
}
|
|
1543
1778
|
opts.allowedTools = [...opts.allowedTools ?? [], ...mcpToolNames];
|
|
1544
1779
|
}
|
|
1780
|
+
if (onAskUser) {
|
|
1781
|
+
opts.disallowedTools = [...opts.disallowedTools ?? [], "AskUserQuestion"];
|
|
1782
|
+
}
|
|
1545
1783
|
return opts;
|
|
1546
1784
|
}
|
|
1785
|
+
// ─── Retry Helpers (shared across executeRun/RunStructured/Stream) ──
|
|
1786
|
+
/** Setup a retry query: clear session, rebuild with full history */
|
|
1787
|
+
async prepareRetryQuery(sdk, messages, signal, options, toolResultCapture, modifyOpts) {
|
|
1788
|
+
this.clearPersistentSession();
|
|
1789
|
+
const retryPrompt = buildContextualPrompt(messages);
|
|
1790
|
+
let retryOpts = this.buildQueryOptions(signal, options);
|
|
1791
|
+
toolResultCapture.clear();
|
|
1792
|
+
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1793
|
+
modifyOpts?.(retryOpts);
|
|
1794
|
+
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1795
|
+
this.activeQuery = retryQ;
|
|
1796
|
+
return retryQ;
|
|
1797
|
+
}
|
|
1798
|
+
/** Extract tool_use blocks from an assistant SDK message into toolCalls array */
|
|
1799
|
+
collectToolCallsFromMessage(msg, toolCalls, toolResultCapture) {
|
|
1800
|
+
if (msg.type !== "assistant") return;
|
|
1801
|
+
const betaMessage = msg.message;
|
|
1802
|
+
if (!betaMessage?.content) return;
|
|
1803
|
+
for (const block of betaMessage.content) {
|
|
1804
|
+
if (block.type === "tool_use") {
|
|
1805
|
+
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1806
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1807
|
+
toolCalls.push({
|
|
1808
|
+
toolName,
|
|
1809
|
+
args: block.input ?? {},
|
|
1810
|
+
result: toolResultCapture.get(toolName) ?? null,
|
|
1811
|
+
approved: true
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
/** Back-fill tool results from capture map on summary/result messages */
|
|
1817
|
+
backfillToolResults(msg, toolCalls, toolResultCapture) {
|
|
1818
|
+
if (msg.type !== "tool_use_summary" && msg.type !== "result") return;
|
|
1819
|
+
for (const tc of toolCalls) {
|
|
1820
|
+
if (tc.result === null) {
|
|
1821
|
+
const captured = toolResultCapture.get(tc.toolName);
|
|
1822
|
+
if (captured !== void 0) tc.result = captured;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
/** Wrap retry inner loop with shared error handling */
|
|
1827
|
+
async withRetryErrorHandling(signal, fn) {
|
|
1828
|
+
try {
|
|
1829
|
+
return await fn();
|
|
1830
|
+
} catch (retryError) {
|
|
1831
|
+
if (this.isPersistent) this.clearPersistentSession();
|
|
1832
|
+
if (signal.aborted) throw new AbortError();
|
|
1833
|
+
throw retryError;
|
|
1834
|
+
} finally {
|
|
1835
|
+
this.activeQuery = null;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1547
1838
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
1548
|
-
async executeRun(messages,
|
|
1839
|
+
async executeRun(messages, options, signal) {
|
|
1549
1840
|
this.checkAbort(signal);
|
|
1550
1841
|
const sdk = await loadSDK2();
|
|
1551
1842
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1552
|
-
const prompt = isResuming ?
|
|
1553
|
-
let opts = this.buildQueryOptions(signal);
|
|
1843
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1844
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1554
1845
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1555
1846
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1556
1847
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1560,30 +1851,8 @@ var init_claude = __esm({
|
|
|
1560
1851
|
let usage;
|
|
1561
1852
|
try {
|
|
1562
1853
|
for await (const msg of q) {
|
|
1563
|
-
|
|
1564
|
-
|
|
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
|
-
}
|
|
1854
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1855
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1587
1856
|
if (msg.type === "result") {
|
|
1588
1857
|
if (msg.subtype === "success") {
|
|
1589
1858
|
const r = msg;
|
|
@@ -1603,41 +1872,13 @@ var init_claude = __esm({
|
|
|
1603
1872
|
} catch (e) {
|
|
1604
1873
|
if (signal.aborted) throw new AbortError();
|
|
1605
1874
|
if (isResuming && this.isPersistent) {
|
|
1606
|
-
this.
|
|
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;
|
|
1875
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1613
1876
|
toolCalls.length = 0;
|
|
1614
1877
|
output = null;
|
|
1615
|
-
|
|
1878
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1616
1879
|
for await (const msg of retryQ) {
|
|
1617
|
-
|
|
1618
|
-
|
|
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
|
-
}
|
|
1880
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1881
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1641
1882
|
if (msg.type === "result") {
|
|
1642
1883
|
if (msg.subtype === "success") {
|
|
1643
1884
|
const r = msg;
|
|
@@ -1654,23 +1895,17 @@ var init_claude = __esm({
|
|
|
1654
1895
|
}
|
|
1655
1896
|
}
|
|
1656
1897
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
messages: [
|
|
1669
|
-
...messages,
|
|
1670
|
-
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1671
|
-
],
|
|
1672
|
-
usage
|
|
1673
|
-
};
|
|
1898
|
+
return {
|
|
1899
|
+
output,
|
|
1900
|
+
structuredOutput: void 0,
|
|
1901
|
+
toolCalls,
|
|
1902
|
+
messages: [
|
|
1903
|
+
...messages,
|
|
1904
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1905
|
+
],
|
|
1906
|
+
usage
|
|
1907
|
+
};
|
|
1908
|
+
});
|
|
1674
1909
|
}
|
|
1675
1910
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1676
1911
|
throw e;
|
|
@@ -1689,12 +1924,12 @@ var init_claude = __esm({
|
|
|
1689
1924
|
};
|
|
1690
1925
|
}
|
|
1691
1926
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
1692
|
-
async executeRunStructured(messages, schema,
|
|
1927
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
1693
1928
|
this.checkAbort(signal);
|
|
1694
1929
|
const sdk = await loadSDK2();
|
|
1695
1930
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1696
|
-
const prompt = isResuming ?
|
|
1697
|
-
let opts = this.buildQueryOptions(signal);
|
|
1931
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1932
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1698
1933
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1699
1934
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1700
1935
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
@@ -1710,30 +1945,8 @@ var init_claude = __esm({
|
|
|
1710
1945
|
let usage;
|
|
1711
1946
|
try {
|
|
1712
1947
|
for await (const msg of q) {
|
|
1713
|
-
|
|
1714
|
-
|
|
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
|
-
}
|
|
1948
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1949
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1737
1950
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1738
1951
|
const r = msg;
|
|
1739
1952
|
output = r.result;
|
|
@@ -1768,46 +1981,23 @@ var init_claude = __esm({
|
|
|
1768
1981
|
} catch (e) {
|
|
1769
1982
|
if (signal.aborted) throw new AbortError();
|
|
1770
1983
|
if (isResuming && this.isPersistent) {
|
|
1771
|
-
this.
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
this.activeQuery = retryQ;
|
|
1984
|
+
const retryQ = await this.prepareRetryQuery(
|
|
1985
|
+
sdk,
|
|
1986
|
+
messages,
|
|
1987
|
+
signal,
|
|
1988
|
+
options,
|
|
1989
|
+
toolResultCapture,
|
|
1990
|
+
(opts2) => {
|
|
1991
|
+
opts2.outputFormat = { type: "json_schema", schema: jsonSchema };
|
|
1992
|
+
}
|
|
1993
|
+
);
|
|
1782
1994
|
toolCalls.length = 0;
|
|
1783
1995
|
output = null;
|
|
1784
1996
|
structuredOutput = void 0;
|
|
1785
|
-
|
|
1997
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1786
1998
|
for await (const msg of retryQ) {
|
|
1787
|
-
|
|
1788
|
-
|
|
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
|
-
}
|
|
1999
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
2000
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1811
2001
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1812
2002
|
const r = msg;
|
|
1813
2003
|
output = r.result;
|
|
@@ -1839,23 +2029,17 @@ var init_claude = __esm({
|
|
|
1839
2029
|
);
|
|
1840
2030
|
}
|
|
1841
2031
|
}
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
messages: [
|
|
1854
|
-
...messages,
|
|
1855
|
-
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1856
|
-
],
|
|
1857
|
-
usage
|
|
1858
|
-
};
|
|
2032
|
+
return {
|
|
2033
|
+
output,
|
|
2034
|
+
structuredOutput,
|
|
2035
|
+
toolCalls,
|
|
2036
|
+
messages: [
|
|
2037
|
+
...messages,
|
|
2038
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
2039
|
+
],
|
|
2040
|
+
usage
|
|
2041
|
+
};
|
|
2042
|
+
});
|
|
1859
2043
|
}
|
|
1860
2044
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1861
2045
|
throw e;
|
|
@@ -1874,12 +2058,12 @@ var init_claude = __esm({
|
|
|
1874
2058
|
};
|
|
1875
2059
|
}
|
|
1876
2060
|
// ─── executeStream ──────────────────────────────────────────────
|
|
1877
|
-
async *executeStream(messages,
|
|
2061
|
+
async *executeStream(messages, options, signal) {
|
|
1878
2062
|
this.checkAbort(signal);
|
|
1879
2063
|
const sdk = await loadSDK2();
|
|
1880
2064
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1881
|
-
const prompt = isResuming ?
|
|
1882
|
-
let opts = this.buildQueryOptions(signal);
|
|
2065
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
2066
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1883
2067
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1884
2068
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1885
2069
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1887,6 +2071,7 @@ var init_claude = __esm({
|
|
|
1887
2071
|
const thinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1888
2072
|
const toolCallTracker = new ClaudeToolCallTracker();
|
|
1889
2073
|
const pendingStreamToolCalls = /* @__PURE__ */ new Map();
|
|
2074
|
+
let hasStreamedText = false;
|
|
1890
2075
|
try {
|
|
1891
2076
|
for await (const msg of q) {
|
|
1892
2077
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1904,6 +2089,7 @@ var init_claude = __esm({
|
|
|
1904
2089
|
} else if (e.type === "tool_call_end") {
|
|
1905
2090
|
pendingStreamToolCalls.delete(e.toolCallId);
|
|
1906
2091
|
}
|
|
2092
|
+
if (e.type === "text_delta") hasStreamedText = true;
|
|
1907
2093
|
yield e;
|
|
1908
2094
|
}
|
|
1909
2095
|
}
|
|
@@ -1927,22 +2113,21 @@ var init_claude = __esm({
|
|
|
1927
2113
|
}
|
|
1928
2114
|
yield this.emitSessionInfo(r.session_id);
|
|
1929
2115
|
}
|
|
1930
|
-
yield {
|
|
2116
|
+
yield {
|
|
2117
|
+
type: "done",
|
|
2118
|
+
finalOutput: hasStreamedText ? null : r.result,
|
|
2119
|
+
...hasStreamedText ? { streamed: true } : {}
|
|
2120
|
+
};
|
|
1931
2121
|
}
|
|
1932
2122
|
}
|
|
1933
2123
|
} catch (e) {
|
|
1934
2124
|
if (signal.aborted) throw new AbortError();
|
|
1935
2125
|
if (isResuming && this.isPersistent) {
|
|
1936
|
-
this.
|
|
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;
|
|
2126
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1943
2127
|
const retryThinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1944
2128
|
const retryToolCallTracker = new ClaudeToolCallTracker();
|
|
1945
2129
|
const retryPendingToolCalls = /* @__PURE__ */ new Map();
|
|
2130
|
+
let retryHasStreamedText = false;
|
|
1946
2131
|
try {
|
|
1947
2132
|
for await (const msg of retryQ) {
|
|
1948
2133
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1960,6 +2145,7 @@ var init_claude = __esm({
|
|
|
1960
2145
|
} else if (ev.type === "tool_call_end") {
|
|
1961
2146
|
retryPendingToolCalls.delete(ev.toolCallId);
|
|
1962
2147
|
}
|
|
2148
|
+
if (ev.type === "text_delta") retryHasStreamedText = true;
|
|
1963
2149
|
yield ev;
|
|
1964
2150
|
}
|
|
1965
2151
|
}
|
|
@@ -1983,7 +2169,11 @@ var init_claude = __esm({
|
|
|
1983
2169
|
}
|
|
1984
2170
|
yield this.emitSessionInfo(r.session_id);
|
|
1985
2171
|
}
|
|
1986
|
-
yield {
|
|
2172
|
+
yield {
|
|
2173
|
+
type: "done",
|
|
2174
|
+
finalOutput: retryHasStreamedText ? null : r.result,
|
|
2175
|
+
...retryHasStreamedText ? { streamed: true } : {}
|
|
2176
|
+
};
|
|
1987
2177
|
}
|
|
1988
2178
|
}
|
|
1989
2179
|
} catch (retryError) {
|
|
@@ -2045,7 +2235,8 @@ var init_claude = __esm({
|
|
|
2045
2235
|
this.cachedModels = body.data.map((m) => ({
|
|
2046
2236
|
id: m.id,
|
|
2047
2237
|
name: m.display_name,
|
|
2048
|
-
provider: "claude"
|
|
2238
|
+
provider: "claude",
|
|
2239
|
+
...m.max_input_tokens != null && { contextWindow: m.max_input_tokens }
|
|
2049
2240
|
}));
|
|
2050
2241
|
return this.cachedModels;
|
|
2051
2242
|
}
|
|
@@ -2103,32 +2294,30 @@ __export(vercel_ai_exports, {
|
|
|
2103
2294
|
createVercelAIService: () => createVercelAIService
|
|
2104
2295
|
});
|
|
2105
2296
|
async function loadSDK3() {
|
|
2106
|
-
if (
|
|
2297
|
+
if (_sdkMock3) return _sdkMock3;
|
|
2107
2298
|
try {
|
|
2108
|
-
|
|
2109
|
-
return sdkModule3;
|
|
2299
|
+
return await import('ai');
|
|
2110
2300
|
} catch {
|
|
2111
2301
|
throw new DependencyError("ai");
|
|
2112
2302
|
}
|
|
2113
2303
|
}
|
|
2114
2304
|
async function loadCompat() {
|
|
2115
|
-
if (
|
|
2305
|
+
if (_compatMock) return _compatMock;
|
|
2116
2306
|
try {
|
|
2117
|
-
|
|
2118
|
-
return compatModule;
|
|
2307
|
+
return await import('@ai-sdk/openai-compatible');
|
|
2119
2308
|
} catch {
|
|
2120
2309
|
throw new DependencyError("@ai-sdk/openai-compatible");
|
|
2121
2310
|
}
|
|
2122
2311
|
}
|
|
2123
2312
|
function _injectSDK3(mock) {
|
|
2124
|
-
|
|
2313
|
+
_sdkMock3 = mock;
|
|
2125
2314
|
}
|
|
2126
2315
|
function _injectCompat(mock) {
|
|
2127
|
-
|
|
2316
|
+
_compatMock = mock;
|
|
2128
2317
|
}
|
|
2129
2318
|
function _resetSDK3() {
|
|
2130
|
-
|
|
2131
|
-
|
|
2319
|
+
_sdkMock3 = null;
|
|
2320
|
+
_compatMock = null;
|
|
2132
2321
|
}
|
|
2133
2322
|
function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, signal) {
|
|
2134
2323
|
const toolMap = {};
|
|
@@ -2171,13 +2360,14 @@ function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, s
|
|
|
2171
2360
|
return toolMap;
|
|
2172
2361
|
}
|
|
2173
2362
|
function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
|
|
2174
|
-
return async (args) => {
|
|
2363
|
+
return async (args, options) => {
|
|
2175
2364
|
if (ourTool.needsApproval && supervisor?.onPermission) {
|
|
2176
2365
|
const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
|
|
2177
2366
|
if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
|
|
2178
2367
|
const request = {
|
|
2179
2368
|
toolName: ourTool.name,
|
|
2180
|
-
toolArgs: args ?? {}
|
|
2369
|
+
toolArgs: args ?? {},
|
|
2370
|
+
toolCallId: options?.toolCallId
|
|
2181
2371
|
};
|
|
2182
2372
|
const decision = await supervisor.onPermission(
|
|
2183
2373
|
request,
|
|
@@ -2284,7 +2474,8 @@ function mapStreamPart(part) {
|
|
|
2284
2474
|
return {
|
|
2285
2475
|
type: "error",
|
|
2286
2476
|
error: p.error instanceof Error ? p.error.message : String(p.error ?? "Tool execution failed"),
|
|
2287
|
-
recoverable: true
|
|
2477
|
+
recoverable: true,
|
|
2478
|
+
code: "TOOL_EXECUTION" /* TOOL_EXECUTION */
|
|
2288
2479
|
};
|
|
2289
2480
|
}
|
|
2290
2481
|
case "reasoning-start":
|
|
@@ -2305,10 +2496,13 @@ function mapStreamPart(part) {
|
|
|
2305
2496
|
}
|
|
2306
2497
|
case "error": {
|
|
2307
2498
|
const p = part;
|
|
2499
|
+
const errorMsg = p.error instanceof Error ? p.error.message : String(p.error ?? "Unknown error");
|
|
2500
|
+
const code = classifyAgentError(errorMsg);
|
|
2308
2501
|
return {
|
|
2309
2502
|
type: "error",
|
|
2310
|
-
error:
|
|
2311
|
-
recoverable:
|
|
2503
|
+
error: errorMsg,
|
|
2504
|
+
recoverable: isRecoverableErrorCode(code),
|
|
2505
|
+
code
|
|
2312
2506
|
};
|
|
2313
2507
|
}
|
|
2314
2508
|
default:
|
|
@@ -2318,15 +2512,15 @@ function mapStreamPart(part) {
|
|
|
2318
2512
|
function createVercelAIService(options) {
|
|
2319
2513
|
return new VercelAIAgentService(options);
|
|
2320
2514
|
}
|
|
2321
|
-
var
|
|
2515
|
+
var _sdkMock3, _compatMock, DEFAULT_BASE_URL, DEFAULT_PROVIDER, DEFAULT_MAX_TURNS, VercelAIAgent, VercelAIAgentService;
|
|
2322
2516
|
var init_vercel_ai = __esm({
|
|
2323
2517
|
"src/backends/vercel-ai.ts"() {
|
|
2324
|
-
|
|
2518
|
+
init_types2();
|
|
2325
2519
|
init_base_agent();
|
|
2326
|
-
|
|
2520
|
+
init_errors2();
|
|
2327
2521
|
init_schema();
|
|
2328
|
-
|
|
2329
|
-
|
|
2522
|
+
_sdkMock3 = null;
|
|
2523
|
+
_compatMock = null;
|
|
2330
2524
|
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
2331
2525
|
DEFAULT_PROVIDER = "openrouter";
|
|
2332
2526
|
DEFAULT_MAX_TURNS = 10;
|
|
@@ -2339,28 +2533,33 @@ var init_vercel_ai = __esm({
|
|
|
2339
2533
|
super(config);
|
|
2340
2534
|
this.backendOptions = backendOptions;
|
|
2341
2535
|
}
|
|
2342
|
-
async getModel() {
|
|
2343
|
-
|
|
2536
|
+
async getModel(options) {
|
|
2537
|
+
const requestedModel = options.model;
|
|
2538
|
+
const defaultModel = this.config.model;
|
|
2539
|
+
if (requestedModel === defaultModel && this.model) return this.model;
|
|
2344
2540
|
const compat = await loadCompat();
|
|
2345
2541
|
const provider = compat.createOpenAICompatible({
|
|
2346
2542
|
name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
|
|
2347
2543
|
baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
|
|
2348
2544
|
apiKey: this.backendOptions.apiKey
|
|
2349
2545
|
});
|
|
2350
|
-
const
|
|
2351
|
-
|
|
2352
|
-
|
|
2546
|
+
const model = provider.chatModel(requestedModel);
|
|
2547
|
+
if (requestedModel === defaultModel) {
|
|
2548
|
+
this.model = model;
|
|
2549
|
+
}
|
|
2550
|
+
return model;
|
|
2353
2551
|
}
|
|
2354
|
-
async getSDKTools(signal) {
|
|
2552
|
+
async getSDKTools(signal, options) {
|
|
2355
2553
|
const sdk = await loadSDK3();
|
|
2356
|
-
|
|
2554
|
+
const tools = this.resolveTools(options);
|
|
2555
|
+
return mapToolsToSDK2(sdk, tools, this.config, this.sessionApprovals, this.config.permissionStore, signal);
|
|
2357
2556
|
}
|
|
2358
2557
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
2359
|
-
async executeRun(messages,
|
|
2558
|
+
async executeRun(messages, options, signal) {
|
|
2360
2559
|
this.checkAbort(signal);
|
|
2361
2560
|
const sdk = await loadSDK3();
|
|
2362
|
-
const model = await this.getModel();
|
|
2363
|
-
const tools = await this.getSDKTools(signal);
|
|
2561
|
+
const model = await this.getModel(options);
|
|
2562
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2364
2563
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2365
2564
|
const sdkMessages = messagesToSDK(messages);
|
|
2366
2565
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2416,10 +2615,10 @@ var init_vercel_ai = __esm({
|
|
|
2416
2615
|
};
|
|
2417
2616
|
}
|
|
2418
2617
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
2419
|
-
async executeRunStructured(messages, schema,
|
|
2618
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
2420
2619
|
this.checkAbort(signal);
|
|
2421
2620
|
const sdk = await loadSDK3();
|
|
2422
|
-
const model = await this.getModel();
|
|
2621
|
+
const model = await this.getModel(options);
|
|
2423
2622
|
const sdkMessages = messagesToSDK(messages);
|
|
2424
2623
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
2425
2624
|
const result = await sdk.generateObject({
|
|
@@ -2461,11 +2660,11 @@ var init_vercel_ai = __esm({
|
|
|
2461
2660
|
};
|
|
2462
2661
|
}
|
|
2463
2662
|
// ─── executeStream ──────────────────────────────────────────────
|
|
2464
|
-
async *executeStream(messages,
|
|
2663
|
+
async *executeStream(messages, options, signal) {
|
|
2465
2664
|
this.checkAbort(signal);
|
|
2466
2665
|
const sdk = await loadSDK3();
|
|
2467
|
-
const model = await this.getModel();
|
|
2468
|
-
const tools = await this.getSDKTools(signal);
|
|
2666
|
+
const model = await this.getModel(options);
|
|
2667
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2469
2668
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2470
2669
|
const sdkMessages = messagesToSDK(messages);
|
|
2471
2670
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2511,9 +2710,11 @@ var init_vercel_ai = __esm({
|
|
|
2511
2710
|
promptTokens: Number(totalUsage?.inputTokens ?? 0),
|
|
2512
2711
|
completionTokens: Number(totalUsage?.outputTokens ?? 0)
|
|
2513
2712
|
};
|
|
2713
|
+
const hasStreamed = finalText.length > 0;
|
|
2514
2714
|
yield {
|
|
2515
2715
|
type: "done",
|
|
2516
|
-
finalOutput: finalText || null
|
|
2716
|
+
finalOutput: hasStreamed ? null : finalText || null,
|
|
2717
|
+
...hasStreamed ? { streamed: true } : {}
|
|
2517
2718
|
};
|
|
2518
2719
|
} catch (e) {
|
|
2519
2720
|
if (signal.aborted) throw new AbortError();
|
|
@@ -2542,16 +2743,33 @@ var init_vercel_ai = __esm({
|
|
|
2542
2743
|
const baseUrl = (this.options.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
2543
2744
|
try {
|
|
2544
2745
|
const res = await globalThis.fetch(`${baseUrl}/models`, {
|
|
2545
|
-
headers: {
|
|
2746
|
+
headers: {
|
|
2747
|
+
Authorization: `Bearer ${this.options.apiKey}`,
|
|
2748
|
+
// OpenRouter requires HTTP-Referer for API access
|
|
2749
|
+
"HTTP-Referer": "https://github.com/nicepkg/agent-sdk"
|
|
2750
|
+
}
|
|
2546
2751
|
});
|
|
2547
2752
|
if (!res.ok) {
|
|
2548
2753
|
return [];
|
|
2549
2754
|
}
|
|
2550
2755
|
const body = await res.json();
|
|
2551
|
-
if (
|
|
2552
|
-
return
|
|
2756
|
+
if (body.data && Array.isArray(body.data)) {
|
|
2757
|
+
return body.data.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2758
|
+
id: m.id,
|
|
2759
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2760
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2761
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2762
|
+
}));
|
|
2763
|
+
}
|
|
2764
|
+
if (Array.isArray(body)) {
|
|
2765
|
+
return body.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2766
|
+
id: m.id,
|
|
2767
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2768
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2769
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2770
|
+
}));
|
|
2553
2771
|
}
|
|
2554
|
-
return
|
|
2772
|
+
return [];
|
|
2555
2773
|
} catch {
|
|
2556
2774
|
return [];
|
|
2557
2775
|
}
|
|
@@ -2582,272 +2800,25 @@ var init_vercel_ai = __esm({
|
|
|
2582
2800
|
}
|
|
2583
2801
|
});
|
|
2584
2802
|
|
|
2585
|
-
// src/
|
|
2586
|
-
function
|
|
2587
|
-
|
|
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);
|
|
2803
|
+
// src/chat/backends/types.ts
|
|
2804
|
+
function isResumableBackend(adapter) {
|
|
2805
|
+
return "canResume" in adapter && typeof adapter.canResume === "function";
|
|
2688
2806
|
}
|
|
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
2807
|
|
|
2841
|
-
// src/chat/
|
|
2808
|
+
// src/chat/types.ts
|
|
2842
2809
|
function createChatId() {
|
|
2843
2810
|
return crypto.randomUUID();
|
|
2844
2811
|
}
|
|
2812
|
+
|
|
2813
|
+
// src/chat/chat-utils.ts
|
|
2845
2814
|
function getMessageText(message) {
|
|
2846
2815
|
return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
2847
2816
|
}
|
|
2848
2817
|
function getMessageToolCalls(message) {
|
|
2849
2818
|
return message.parts.filter((p) => p.type === "tool_call");
|
|
2850
2819
|
}
|
|
2820
|
+
|
|
2821
|
+
// src/chat/bridge.ts
|
|
2851
2822
|
function agentEventToChatEvent(event, messageId) {
|
|
2852
2823
|
switch (event.type) {
|
|
2853
2824
|
case "text_delta":
|
|
@@ -2900,6 +2871,7 @@ function agentEventToChatEvent(event, messageId) {
|
|
|
2900
2871
|
type: "error",
|
|
2901
2872
|
error: event.error,
|
|
2902
2873
|
recoverable: event.recoverable,
|
|
2874
|
+
code: event.code,
|
|
2903
2875
|
messageId
|
|
2904
2876
|
};
|
|
2905
2877
|
case "heartbeat":
|
|
@@ -2921,6 +2893,8 @@ async function* adaptAgentEvents(events, messageId) {
|
|
|
2921
2893
|
}
|
|
2922
2894
|
}
|
|
2923
2895
|
}
|
|
2896
|
+
|
|
2897
|
+
// src/chat/conversion.ts
|
|
2924
2898
|
function toAgentMessage(message) {
|
|
2925
2899
|
const textContent = getMessageText(message);
|
|
2926
2900
|
const toolCallParts = getMessageToolCalls(message);
|
|
@@ -2941,6 +2915,7 @@ function toAgentMessage(message) {
|
|
|
2941
2915
|
}
|
|
2942
2916
|
|
|
2943
2917
|
// src/chat/errors.ts
|
|
2918
|
+
init_errors2();
|
|
2944
2919
|
init_errors();
|
|
2945
2920
|
var ChatError = class extends AgentSDKError {
|
|
2946
2921
|
code;
|
|
@@ -2948,7 +2923,11 @@ var ChatError = class extends AgentSDKError {
|
|
|
2948
2923
|
retryAfter;
|
|
2949
2924
|
timestamp;
|
|
2950
2925
|
constructor(message, options) {
|
|
2951
|
-
super(message, {
|
|
2926
|
+
super(message, {
|
|
2927
|
+
cause: options.cause,
|
|
2928
|
+
code: options.code,
|
|
2929
|
+
retryable: options.retryable
|
|
2930
|
+
});
|
|
2952
2931
|
this.name = "ChatError";
|
|
2953
2932
|
this.code = options.code;
|
|
2954
2933
|
this.retryable = options.retryable ?? false;
|
|
@@ -2960,25 +2939,51 @@ var ChatError = class extends AgentSDKError {
|
|
|
2960
2939
|
// src/chat/backends/base.ts
|
|
2961
2940
|
var BaseBackendAdapter = class {
|
|
2962
2941
|
name;
|
|
2963
|
-
_agentService;
|
|
2964
|
-
|
|
2942
|
+
_agentService = null;
|
|
2943
|
+
_agentServiceFactory = null;
|
|
2965
2944
|
_disposed = false;
|
|
2966
2945
|
_agentConfig;
|
|
2967
2946
|
_ownsService;
|
|
2947
|
+
// Agent lifecycle: tracks current agent and the model it was created with.
|
|
2948
|
+
// For persistent sessions, reused across calls when model matches.
|
|
2949
|
+
// For non-persistent, recreated every call.
|
|
2950
|
+
_currentAgent = null;
|
|
2968
2951
|
constructor(name, options) {
|
|
2969
2952
|
this.name = name;
|
|
2970
2953
|
this._agentConfig = options.agentConfig;
|
|
2971
2954
|
if (options.agentService) {
|
|
2972
2955
|
this._agentService = options.agentService;
|
|
2973
2956
|
this._ownsService = false;
|
|
2957
|
+
} else if (options.agentServiceFactory) {
|
|
2958
|
+
this._agentServiceFactory = options.agentServiceFactory;
|
|
2959
|
+
this._ownsService = true;
|
|
2974
2960
|
} else {
|
|
2975
2961
|
this._agentService = this.createService();
|
|
2976
2962
|
this._ownsService = true;
|
|
2977
2963
|
}
|
|
2978
2964
|
}
|
|
2979
2965
|
get agentService() {
|
|
2966
|
+
if (!this._agentService) {
|
|
2967
|
+
if (this._agentServiceFactory) {
|
|
2968
|
+
this._agentService = this._agentServiceFactory();
|
|
2969
|
+
this._agentServiceFactory = null;
|
|
2970
|
+
} else {
|
|
2971
|
+
throw new ChatError("Agent service not available", {
|
|
2972
|
+
code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */
|
|
2973
|
+
});
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2980
2976
|
return this._agentService;
|
|
2981
2977
|
}
|
|
2978
|
+
get currentModel() {
|
|
2979
|
+
return this._agentConfig.model;
|
|
2980
|
+
}
|
|
2981
|
+
/**
|
|
2982
|
+
* @deprecated No-op. Tools are passed per-call via SendMessageOptions.tools.
|
|
2983
|
+
* Kept for backward compatibility with code that calls setTools() directly.
|
|
2984
|
+
*/
|
|
2985
|
+
setTools() {
|
|
2986
|
+
}
|
|
2982
2987
|
async sendMessage(session, message, options) {
|
|
2983
2988
|
this.assertNotDisposed();
|
|
2984
2989
|
const events = this.streamMessage(session, message, options);
|
|
@@ -3016,9 +3021,13 @@ var BaseBackendAdapter = class {
|
|
|
3016
3021
|
*/
|
|
3017
3022
|
async *streamAgentEvents(agent, messages, options) {
|
|
3018
3023
|
const messageId = createChatId();
|
|
3024
|
+
const model = options?.model ?? this._agentConfig.model ?? "";
|
|
3019
3025
|
const agentEvents = agent.streamWithContext(messages, {
|
|
3026
|
+
model,
|
|
3020
3027
|
signal: options?.signal,
|
|
3021
|
-
context: options?.context
|
|
3028
|
+
context: options?.context,
|
|
3029
|
+
tools: options?.tools,
|
|
3030
|
+
...options?.systemPrompt ? { systemMessage: options.systemPrompt } : {}
|
|
3022
3031
|
});
|
|
3023
3032
|
yield { type: "message:start", messageId, role: "assistant" };
|
|
3024
3033
|
let text = "";
|
|
@@ -3044,31 +3053,45 @@ var BaseBackendAdapter = class {
|
|
|
3044
3053
|
}
|
|
3045
3054
|
async listModels() {
|
|
3046
3055
|
this.assertNotDisposed();
|
|
3047
|
-
return this.
|
|
3056
|
+
return this.agentService.listModels();
|
|
3048
3057
|
}
|
|
3049
3058
|
async validate() {
|
|
3050
3059
|
this.assertNotDisposed();
|
|
3051
|
-
return this.
|
|
3060
|
+
return this.agentService.validate();
|
|
3052
3061
|
}
|
|
3053
3062
|
async dispose() {
|
|
3054
3063
|
if (this._disposed) return;
|
|
3055
3064
|
this._disposed = true;
|
|
3056
|
-
this.
|
|
3057
|
-
|
|
3058
|
-
|
|
3065
|
+
if (this._currentAgent) {
|
|
3066
|
+
this._currentAgent.instance.dispose();
|
|
3067
|
+
this._currentAgent = null;
|
|
3068
|
+
}
|
|
3069
|
+
if (this._ownsService && this._agentService && typeof this._agentService.dispose === "function") {
|
|
3059
3070
|
await this._agentService.dispose();
|
|
3060
3071
|
}
|
|
3061
3072
|
}
|
|
3062
|
-
/** Get or create an agent
|
|
3073
|
+
/** Get or create an agent. Model is passed per-call via RunOptions.
|
|
3074
|
+
* Tools are passed per-call via SendMessageOptions — not baked into config.
|
|
3075
|
+
* For persistent sessions, reuses agent when model matches. */
|
|
3063
3076
|
getOrCreateAgent(options) {
|
|
3064
|
-
const
|
|
3065
|
-
if (this._agentConfig.sessionMode === "persistent" && this.
|
|
3066
|
-
|
|
3077
|
+
const model = options?.model ?? this._agentConfig.model;
|
|
3078
|
+
if (this._agentConfig.sessionMode === "persistent" && this._currentAgent) {
|
|
3079
|
+
if (this._currentAgent.model === model) {
|
|
3080
|
+
return this._currentAgent.instance;
|
|
3081
|
+
}
|
|
3082
|
+
this._currentAgent.instance.dispose();
|
|
3083
|
+
this._currentAgent = null;
|
|
3067
3084
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
this.
|
|
3085
|
+
if (this._currentAgent) {
|
|
3086
|
+
this._currentAgent.instance.dispose();
|
|
3087
|
+
this._currentAgent = null;
|
|
3071
3088
|
}
|
|
3089
|
+
const config = {
|
|
3090
|
+
...this._agentConfig,
|
|
3091
|
+
...model !== void 0 && { model }
|
|
3092
|
+
};
|
|
3093
|
+
const agent = this.agentService.createAgent(config);
|
|
3094
|
+
this._currentAgent = { instance: agent, model };
|
|
3072
3095
|
return agent;
|
|
3073
3096
|
}
|
|
3074
3097
|
assertNotDisposed() {
|
|
@@ -3093,8 +3116,8 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
3093
3116
|
this._copilotOptions = options.copilotOptions;
|
|
3094
3117
|
}
|
|
3095
3118
|
createService() {
|
|
3096
|
-
const {
|
|
3097
|
-
return
|
|
3119
|
+
const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
|
|
3120
|
+
return createCopilotService2(this._copilotOptions || {});
|
|
3098
3121
|
}
|
|
3099
3122
|
get backendSessionId() {
|
|
3100
3123
|
return this._backendSessionId;
|
|
@@ -3146,8 +3169,8 @@ var ClaudeChatAdapter = class extends BaseBackendAdapter {
|
|
|
3146
3169
|
this._claudeOptions = options.claudeOptions;
|
|
3147
3170
|
}
|
|
3148
3171
|
createService() {
|
|
3149
|
-
const {
|
|
3150
|
-
return
|
|
3172
|
+
const { createClaudeService: createClaudeService2 } = (init_claude(), __toCommonJS(claude_exports));
|
|
3173
|
+
return createClaudeService2(this._claudeOptions || {});
|
|
3151
3174
|
}
|
|
3152
3175
|
get backendSessionId() {
|
|
3153
3176
|
return this._backendSessionId;
|
|
@@ -3194,20 +3217,8 @@ var VercelAIChatAdapter = class extends BaseBackendAdapter {
|
|
|
3194
3217
|
this._vercelOptions = options.vercelOptions;
|
|
3195
3218
|
}
|
|
3196
3219
|
createService() {
|
|
3197
|
-
const {
|
|
3198
|
-
return
|
|
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
|
-
);
|
|
3220
|
+
const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
|
|
3221
|
+
return createVercelAIService2(this._vercelOptions || {});
|
|
3211
3222
|
}
|
|
3212
3223
|
captureSessionId(_agent) {
|
|
3213
3224
|
}
|
|
@@ -3388,9 +3399,9 @@ var InProcessChatTransport = class {
|
|
|
3388
3399
|
send(event) {
|
|
3389
3400
|
if (!this._open) return;
|
|
3390
3401
|
if (this._resolve) {
|
|
3391
|
-
const
|
|
3402
|
+
const resolve = this._resolve;
|
|
3392
3403
|
this._resolve = null;
|
|
3393
|
-
|
|
3404
|
+
resolve({ value: event, done: false });
|
|
3394
3405
|
} else {
|
|
3395
3406
|
this._buffer.push(event);
|
|
3396
3407
|
}
|
|
@@ -3399,9 +3410,9 @@ var InProcessChatTransport = class {
|
|
|
3399
3410
|
if (!this._open) return;
|
|
3400
3411
|
this._open = false;
|
|
3401
3412
|
if (this._resolve) {
|
|
3402
|
-
const
|
|
3413
|
+
const resolve = this._resolve;
|
|
3403
3414
|
this._resolve = null;
|
|
3404
|
-
|
|
3415
|
+
resolve({ value: void 0, done: true });
|
|
3405
3416
|
}
|
|
3406
3417
|
}
|
|
3407
3418
|
error(err) {
|
|
@@ -3413,9 +3424,9 @@ var InProcessChatTransport = class {
|
|
|
3413
3424
|
recoverable: false
|
|
3414
3425
|
};
|
|
3415
3426
|
if (this._resolve) {
|
|
3416
|
-
const
|
|
3427
|
+
const resolve = this._resolve;
|
|
3417
3428
|
this._resolve = null;
|
|
3418
|
-
|
|
3429
|
+
resolve({ value: errorEvent, done: false });
|
|
3419
3430
|
} else {
|
|
3420
3431
|
this._error = err;
|
|
3421
3432
|
}
|
|
@@ -3440,8 +3451,8 @@ var InProcessChatTransport = class {
|
|
|
3440
3451
|
if (!this._open) {
|
|
3441
3452
|
return Promise.resolve({ value: void 0, done: true });
|
|
3442
3453
|
}
|
|
3443
|
-
return new Promise((
|
|
3444
|
-
this._resolve =
|
|
3454
|
+
return new Promise((resolve) => {
|
|
3455
|
+
this._resolve = resolve;
|
|
3445
3456
|
});
|
|
3446
3457
|
}
|
|
3447
3458
|
};
|
|
@@ -3496,6 +3507,6 @@ function withInterceptors(transport, interceptors) {
|
|
|
3496
3507
|
return new InterceptedTransport(transport, interceptors);
|
|
3497
3508
|
}
|
|
3498
3509
|
|
|
3499
|
-
export { BaseBackendAdapter, ClaudeChatAdapter, CopilotChatAdapter, InProcessChatTransport, SSEChatTransport, VercelAIChatAdapter, WS_READY_STATE, WsChatTransport, streamToTransport, withInterceptors };
|
|
3510
|
+
export { BaseBackendAdapter, ClaudeChatAdapter, CopilotChatAdapter, InProcessChatTransport, SSEChatTransport, VercelAIChatAdapter, WS_READY_STATE, WsChatTransport, isResumableBackend, streamToTransport, withInterceptors };
|
|
3500
3511
|
//# sourceMappingURL=backends.js.map
|
|
3501
3512
|
//# sourceMappingURL=backends.js.map
|