@witqq/agent-sdk 0.7.0 → 0.9.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/dist/{types-CqvUAYxt.d.ts → agent-C6H2CgJA.d.cts} +139 -102
- package/dist/{types-CqvUAYxt.d.cts → agent-F7oB6eKp.d.ts} +139 -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 +337 -112
- 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 +337 -112
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/mock-llm.cjs +719 -0
- package/dist/backends/mock-llm.cjs.map +1 -0
- package/dist/backends/mock-llm.d.cts +37 -0
- package/dist/backends/mock-llm.d.ts +37 -0
- package/dist/backends/mock-llm.js +717 -0
- package/dist/backends/mock-llm.js.map +1 -0
- package/dist/backends/vercel-ai.cjs +301 -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 +301 -61
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/backends-Cno0gZjy.d.cts +114 -0
- package/dist/backends-Cno0gZjy.d.ts +114 -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 +1084 -821
- 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 +1082 -800
- 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 +60 -27
- package/dist/chat/core.cjs.map +1 -1
- package/dist/chat/core.d.cts +41 -382
- package/dist/chat/core.d.ts +41 -382
- package/dist/chat/core.js +58 -28
- 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 +1612 -1125
- 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 +1600 -1097
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react/theme.css +2517 -0
- package/dist/chat/react.cjs +2212 -1158
- package/dist/chat/react.cjs.map +1 -1
- package/dist/chat/react.d.cts +665 -122
- package/dist/chat/react.d.ts +665 -122
- package/dist/chat/react.js +2191 -1156
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/runtime.cjs +405 -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 +405 -186
- package/dist/chat/runtime.js.map +1 -1
- package/dist/chat/server.cjs +2247 -212
- 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 +2234 -213
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/sessions.cjs +64 -66
- 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 +65 -67
- package/dist/chat/sessions.js.map +1 -1
- package/dist/chat/sqlite.cjs +536 -0
- package/dist/chat/sqlite.cjs.map +1 -0
- package/dist/chat/sqlite.d.cts +164 -0
- package/dist/chat/sqlite.d.ts +164 -0
- package/dist/chat/sqlite.js +527 -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 +58 -33
- package/dist/chat/storage.cjs.map +1 -1
- package/dist/chat/storage.d.cts +18 -8
- package/dist/chat/storage.d.ts +18 -8
- package/dist/chat/storage.js +59 -34
- 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-7EIit9Xk.d.ts} +72 -33
- package/dist/{in-process-transport-DG-w5G6k.d.cts → in-process-transport-Ct9YcX8I.d.cts} +72 -33
- package/dist/index.cjs +354 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +294 -123
- package/dist/index.d.ts +294 -123
- package/dist/index.js +347 -60
- 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 +1107 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +144 -0
- package/dist/testing.d.ts +144 -0
- package/dist/testing.js +1101 -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-DLWCN18G.d.cts} +5 -4
- package/dist/{transport-D1OaUgRk.d.ts → transport-DsuS-GeM.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-DgtI1hzh.d.ts +364 -0
- package/dist/types-DkSXALKg.d.cts +364 -0
- package/package.json +41 -5
- package/LICENSE +0 -21
- package/README.md +0 -948
- 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) => ({
|
|
@@ -467,17 +722,6 @@ function convertParameters(params) {
|
|
|
467
722
|
}
|
|
468
723
|
return params;
|
|
469
724
|
}
|
|
470
|
-
async function mapToolsToSDKAsync(tools) {
|
|
471
|
-
return tools.map((tool) => ({
|
|
472
|
-
name: tool.name,
|
|
473
|
-
description: tool.description,
|
|
474
|
-
parameters: convertParameters(tool.parameters),
|
|
475
|
-
handler: async (args) => {
|
|
476
|
-
const result = await tool.execute(args);
|
|
477
|
-
return typeof result === "string" ? result : JSON.stringify(result);
|
|
478
|
-
}
|
|
479
|
-
}));
|
|
480
|
-
}
|
|
481
725
|
function buildPermissionHandler(config) {
|
|
482
726
|
const onPermission = config.supervisor?.onPermission;
|
|
483
727
|
if (!onPermission) {
|
|
@@ -492,6 +736,7 @@ function buildPermissionHandler(config) {
|
|
|
492
736
|
const unifiedRequest = {
|
|
493
737
|
toolName,
|
|
494
738
|
toolArgs: { ...request },
|
|
739
|
+
toolCallId: request.toolCallId,
|
|
495
740
|
rawSDKRequest: request
|
|
496
741
|
};
|
|
497
742
|
const ac = new AbortController();
|
|
@@ -596,15 +841,21 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
596
841
|
};
|
|
597
842
|
case "session.error":
|
|
598
843
|
console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
844
|
+
{
|
|
845
|
+
const errorMsg = String(data.message ?? "Unknown error");
|
|
846
|
+
const code = classifyAgentError(errorMsg);
|
|
847
|
+
return {
|
|
848
|
+
type: "error",
|
|
849
|
+
error: errorMsg,
|
|
850
|
+
recoverable: isRecoverableErrorCode(code),
|
|
851
|
+
code
|
|
852
|
+
};
|
|
853
|
+
}
|
|
604
854
|
case "assistant.message": {
|
|
605
855
|
const doneEvent = {
|
|
606
856
|
type: "done",
|
|
607
|
-
finalOutput:
|
|
857
|
+
finalOutput: null,
|
|
858
|
+
streamed: true
|
|
608
859
|
};
|
|
609
860
|
if (thinkingTracker.endThinking()) {
|
|
610
861
|
return [{ type: "thinking_end" }, doneEvent];
|
|
@@ -615,66 +866,13 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
615
866
|
return null;
|
|
616
867
|
}
|
|
617
868
|
}
|
|
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
869
|
function withTimeout(promise, ms, message) {
|
|
672
|
-
return new Promise((
|
|
870
|
+
return new Promise((resolve, reject) => {
|
|
673
871
|
const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
|
|
674
872
|
promise.then(
|
|
675
873
|
(val) => {
|
|
676
874
|
clearTimeout(timer);
|
|
677
|
-
|
|
875
|
+
resolve(val);
|
|
678
876
|
},
|
|
679
877
|
(err) => {
|
|
680
878
|
clearTimeout(timer);
|
|
@@ -686,14 +884,15 @@ function withTimeout(promise, ms, message) {
|
|
|
686
884
|
function createCopilotService(options) {
|
|
687
885
|
return new CopilotAgentService(options);
|
|
688
886
|
}
|
|
689
|
-
var
|
|
887
|
+
var _sdkMock, ToolCallTracker, ThinkingTracker, CopilotAgent, CopilotAgentService;
|
|
690
888
|
var init_copilot = __esm({
|
|
691
889
|
"src/backends/copilot.ts"() {
|
|
692
|
-
|
|
890
|
+
init_types2();
|
|
693
891
|
init_base_agent();
|
|
694
|
-
|
|
892
|
+
init_errors2();
|
|
695
893
|
init_schema();
|
|
696
|
-
|
|
894
|
+
init_shared();
|
|
895
|
+
_sdkMock = null;
|
|
697
896
|
ToolCallTracker = class {
|
|
698
897
|
map = /* @__PURE__ */ new Map();
|
|
699
898
|
trackStart(toolCallId, toolName, args) {
|
|
@@ -741,6 +940,7 @@ var init_copilot = __esm({
|
|
|
741
940
|
isPersistent;
|
|
742
941
|
persistentSession = null;
|
|
743
942
|
_sessionId;
|
|
943
|
+
_persistentModel;
|
|
744
944
|
activeSession = null;
|
|
745
945
|
_resumeSessionId;
|
|
746
946
|
_toolsReady = null;
|
|
@@ -759,15 +959,15 @@ var init_copilot = __esm({
|
|
|
759
959
|
},
|
|
760
960
|
onPermissionRequest: buildPermissionHandler(config),
|
|
761
961
|
onUserInputRequest: buildUserInputHandler(config),
|
|
762
|
-
...config.availableTools
|
|
962
|
+
...config.availableTools ? { availableTools: config.availableTools } : {}
|
|
763
963
|
};
|
|
764
964
|
this._toolsReady = this._initToolsAsync(config);
|
|
765
965
|
this._resumeSessionId = resumeSessionId;
|
|
766
966
|
}
|
|
767
|
-
/** Pre-convert Zod schemas to JSON Schema
|
|
967
|
+
/** Pre-convert Zod schemas to JSON Schema.
|
|
768
968
|
* Updates sdkTools and sessionConfig.tools before first session creation. */
|
|
769
969
|
async _initToolsAsync(config) {
|
|
770
|
-
this.sdkTools =
|
|
970
|
+
this.sdkTools = mapToolsToSDK(config.tools ?? []);
|
|
771
971
|
this.sessionConfig.tools = this.sdkTools;
|
|
772
972
|
}
|
|
773
973
|
get sessionId() {
|
|
@@ -791,47 +991,63 @@ var init_copilot = __esm({
|
|
|
791
991
|
});
|
|
792
992
|
this.persistentSession = null;
|
|
793
993
|
this._sessionId = void 0;
|
|
994
|
+
this._persistentModel = void 0;
|
|
794
995
|
}
|
|
795
996
|
}
|
|
796
|
-
async getOrCreateSession(streaming) {
|
|
997
|
+
async getOrCreateSession(streaming, options) {
|
|
797
998
|
if (this.isPersistent && this.persistentSession) {
|
|
798
|
-
|
|
999
|
+
if (options.model !== this._persistentModel) {
|
|
1000
|
+
this.persistentSession.destroy().catch(() => {
|
|
1001
|
+
});
|
|
1002
|
+
this.persistentSession = null;
|
|
1003
|
+
this._sessionId = void 0;
|
|
1004
|
+
} else {
|
|
1005
|
+
return { session: this.persistentSession, isNew: false };
|
|
1006
|
+
}
|
|
799
1007
|
}
|
|
800
1008
|
if (this._toolsReady) {
|
|
801
1009
|
await this._toolsReady;
|
|
802
1010
|
this._toolsReady = null;
|
|
803
1011
|
}
|
|
1012
|
+
const sessionConfig = { ...this.sessionConfig };
|
|
1013
|
+
sessionConfig.model = options.model;
|
|
1014
|
+
const resolvedTools = this.resolveTools(options);
|
|
1015
|
+
if (options?.tools) {
|
|
1016
|
+
sessionConfig.tools = mapToolsToSDK(resolvedTools);
|
|
1017
|
+
}
|
|
804
1018
|
const client = await this.getClient();
|
|
805
1019
|
if (this._resumeSessionId) {
|
|
806
1020
|
const storedId = this._resumeSessionId;
|
|
807
1021
|
this._resumeSessionId = void 0;
|
|
808
1022
|
try {
|
|
809
1023
|
const session2 = await client.resumeSession(storedId, {
|
|
810
|
-
...
|
|
1024
|
+
...sessionConfig,
|
|
811
1025
|
streaming: this.isPersistent ? true : streaming
|
|
812
1026
|
});
|
|
813
1027
|
if (this.isPersistent) {
|
|
814
1028
|
this.persistentSession = session2;
|
|
815
1029
|
this._sessionId = session2.sessionId;
|
|
1030
|
+
this._persistentModel = options.model;
|
|
816
1031
|
}
|
|
817
1032
|
return { session: session2, isNew: false };
|
|
818
1033
|
} catch {
|
|
819
1034
|
}
|
|
820
1035
|
}
|
|
821
1036
|
const session = await client.createSession({
|
|
822
|
-
...
|
|
1037
|
+
...sessionConfig,
|
|
823
1038
|
streaming: this.isPersistent ? true : streaming
|
|
824
1039
|
});
|
|
825
1040
|
if (this.isPersistent) {
|
|
826
1041
|
this.persistentSession = session;
|
|
827
1042
|
this._sessionId = session.sessionId;
|
|
1043
|
+
this._persistentModel = options.model;
|
|
828
1044
|
}
|
|
829
1045
|
return { session, isNew: true };
|
|
830
1046
|
}
|
|
831
1047
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
832
|
-
async executeRun(messages,
|
|
1048
|
+
async executeRun(messages, options, signal) {
|
|
833
1049
|
this.checkAbort(signal);
|
|
834
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
|
|
1050
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(false, options);
|
|
835
1051
|
this.activeSession = session;
|
|
836
1052
|
const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
837
1053
|
const tracker = new ToolCallTracker();
|
|
@@ -928,9 +1144,9 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
928
1144
|
};
|
|
929
1145
|
}
|
|
930
1146
|
// ─── executeStream ──────────────────────────────────────────────
|
|
931
|
-
async *executeStream(messages,
|
|
1147
|
+
async *executeStream(messages, options, signal) {
|
|
932
1148
|
this.checkAbort(signal);
|
|
933
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
|
|
1149
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(true, options);
|
|
934
1150
|
this.activeSession = session;
|
|
935
1151
|
if (isNewSession) {
|
|
936
1152
|
yield this.emitSessionInfo(session.sessionId);
|
|
@@ -947,8 +1163,8 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
947
1163
|
notify = null;
|
|
948
1164
|
}
|
|
949
1165
|
};
|
|
950
|
-
const waitForItem = () => new Promise((
|
|
951
|
-
notify =
|
|
1166
|
+
const waitForItem = () => new Promise((resolve) => {
|
|
1167
|
+
notify = resolve;
|
|
952
1168
|
});
|
|
953
1169
|
const unsubscribe = session.on((event) => {
|
|
954
1170
|
const mapped = mapSessionEvent(event, tracker, thinkingTracker);
|
|
@@ -1042,7 +1258,11 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1042
1258
|
githubToken: this.options.githubToken,
|
|
1043
1259
|
useLoggedInUser: this.options.useLoggedInUser ?? !this.options.githubToken,
|
|
1044
1260
|
...this.options.cliArgs ? { cliArgs: this.options.cliArgs } : {},
|
|
1045
|
-
|
|
1261
|
+
env: {
|
|
1262
|
+
...process.env,
|
|
1263
|
+
...this.options.githubToken ? { GITHUB_TOKEN: this.options.githubToken } : {},
|
|
1264
|
+
...this.options.env
|
|
1265
|
+
}
|
|
1046
1266
|
});
|
|
1047
1267
|
const startupTimeout = this.options.startupTimeoutMs ?? 3e4;
|
|
1048
1268
|
await withTimeout(client.start(), startupTimeout, "CLI startup timed out");
|
|
@@ -1076,7 +1296,10 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1076
1296
|
return models.map((m) => ({
|
|
1077
1297
|
id: m.id,
|
|
1078
1298
|
name: m.name,
|
|
1079
|
-
provider: "copilot"
|
|
1299
|
+
provider: "copilot",
|
|
1300
|
+
...m.capabilities?.limits?.max_context_window_tokens != null && {
|
|
1301
|
+
contextWindow: m.capabilities.limits.max_context_window_tokens
|
|
1302
|
+
}
|
|
1080
1303
|
}));
|
|
1081
1304
|
}
|
|
1082
1305
|
async validate() {
|
|
@@ -1129,10 +1352,9 @@ function stripMcpPrefix(name) {
|
|
|
1129
1352
|
return name.startsWith(MCP_TOOL_PREFIX) ? name.slice(MCP_TOOL_PREFIX.length) : name;
|
|
1130
1353
|
}
|
|
1131
1354
|
async function loadSDK2() {
|
|
1132
|
-
if (
|
|
1355
|
+
if (_sdkMock2) return _sdkMock2;
|
|
1133
1356
|
try {
|
|
1134
|
-
|
|
1135
|
-
return sdkModule2;
|
|
1357
|
+
return await import('@anthropic-ai/claude-agent-sdk');
|
|
1136
1358
|
} catch {
|
|
1137
1359
|
throw new SubprocessError(
|
|
1138
1360
|
"@anthropic-ai/claude-agent-sdk is not installed. Install it: npm install @anthropic-ai/claude-agent-sdk"
|
|
@@ -1140,13 +1362,32 @@ async function loadSDK2() {
|
|
|
1140
1362
|
}
|
|
1141
1363
|
}
|
|
1142
1364
|
function _injectSDK2(mock) {
|
|
1143
|
-
|
|
1365
|
+
_sdkMock2 = mock;
|
|
1144
1366
|
}
|
|
1145
1367
|
function _resetSDK2() {
|
|
1146
|
-
|
|
1368
|
+
_sdkMock2 = null;
|
|
1369
|
+
}
|
|
1370
|
+
function normalizeAskUserInput(args) {
|
|
1371
|
+
if (typeof args.question === "string") {
|
|
1372
|
+
return {
|
|
1373
|
+
question: args.question,
|
|
1374
|
+
choices: Array.isArray(args.choices) ? args.choices : void 0,
|
|
1375
|
+
allowFreeform: args.allowFreeform !== false
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
const questions = args.questions;
|
|
1379
|
+
if (questions && questions.length > 0) {
|
|
1380
|
+
const first = questions[0];
|
|
1381
|
+
return {
|
|
1382
|
+
question: first.question,
|
|
1383
|
+
choices: first.options?.map((o) => o.label),
|
|
1384
|
+
allowFreeform: true
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
return { question: JSON.stringify(args), allowFreeform: true };
|
|
1147
1388
|
}
|
|
1148
|
-
function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
1149
|
-
if (tools.length === 0) return void 0;
|
|
1389
|
+
function buildMcpServer(sdk, tools, toolResultCapture, onAskUser) {
|
|
1390
|
+
if (tools.length === 0 && !onAskUser) return void 0;
|
|
1150
1391
|
const mcpTools = tools.map((tool) => {
|
|
1151
1392
|
const zodSchema = tool.parameters;
|
|
1152
1393
|
const inputSchema = zodSchema.shape ?? zodToJsonSchema(tool.parameters);
|
|
@@ -1170,6 +1411,39 @@ function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
|
1170
1411
|
}
|
|
1171
1412
|
);
|
|
1172
1413
|
});
|
|
1414
|
+
if (onAskUser) {
|
|
1415
|
+
const askUserTool = sdk.tool(
|
|
1416
|
+
"ask_user",
|
|
1417
|
+
"Ask the user a question and wait for their response",
|
|
1418
|
+
{
|
|
1419
|
+
question: { type: "string", description: "The question to ask the user" },
|
|
1420
|
+
choices: {
|
|
1421
|
+
type: "array",
|
|
1422
|
+
items: { type: "string" },
|
|
1423
|
+
description: "Optional list of choices for multiple choice"
|
|
1424
|
+
},
|
|
1425
|
+
questions: {
|
|
1426
|
+
type: "array",
|
|
1427
|
+
items: {
|
|
1428
|
+
type: "object",
|
|
1429
|
+
properties: {
|
|
1430
|
+
question: { type: "string" },
|
|
1431
|
+
options: { type: "array", items: { type: "object", properties: { label: { type: "string" } } } }
|
|
1432
|
+
}
|
|
1433
|
+
},
|
|
1434
|
+
description: "Alternative nested question format"
|
|
1435
|
+
}
|
|
1436
|
+
},
|
|
1437
|
+
async (args) => {
|
|
1438
|
+
const normalized = normalizeAskUserInput(args);
|
|
1439
|
+
const response = await onAskUser(normalized, AbortSignal.timeout(3e5));
|
|
1440
|
+
return {
|
|
1441
|
+
content: [{ type: "text", text: response.answer }]
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
);
|
|
1445
|
+
mcpTools.push(askUserTool);
|
|
1446
|
+
}
|
|
1173
1447
|
return sdk.createSdkMcpServer({
|
|
1174
1448
|
name: MCP_SERVER_NAME,
|
|
1175
1449
|
version: "1.0.0",
|
|
@@ -1219,6 +1493,7 @@ function buildCanUseTool(config) {
|
|
|
1219
1493
|
const unifiedRequest = {
|
|
1220
1494
|
toolName,
|
|
1221
1495
|
toolArgs: input,
|
|
1496
|
+
toolCallId: options.toolUseID,
|
|
1222
1497
|
suggestedScope: extractSuggestedScope(options.suggestions),
|
|
1223
1498
|
rawSDKRequest: { toolName, input, ...options }
|
|
1224
1499
|
};
|
|
@@ -1271,6 +1546,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1271
1546
|
if (block.type === "tool_use") {
|
|
1272
1547
|
const toolCallId = String(block.id ?? "");
|
|
1273
1548
|
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1549
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1274
1550
|
if (toolCallTracker) {
|
|
1275
1551
|
toolCallTracker.trackStart(toolCallId, toolName);
|
|
1276
1552
|
}
|
|
@@ -1294,6 +1570,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1294
1570
|
case "tool_use_summary": {
|
|
1295
1571
|
const summary = msg.summary;
|
|
1296
1572
|
const toolName = stripMcpPrefix(msg.tool_name ?? "unknown");
|
|
1573
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) return null;
|
|
1297
1574
|
const precedingIds = msg.preceding_tool_use_ids;
|
|
1298
1575
|
let toolCallId = "";
|
|
1299
1576
|
if (precedingIds && precedingIds.length > 0) {
|
|
@@ -1347,10 +1624,13 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1347
1624
|
}
|
|
1348
1625
|
if (msg.is_error) {
|
|
1349
1626
|
const r = msg;
|
|
1627
|
+
const errorMsg = r.errors?.join("; ") ?? "Unknown error";
|
|
1628
|
+
const code = classifyAgentError(errorMsg);
|
|
1350
1629
|
return {
|
|
1351
1630
|
type: "error",
|
|
1352
|
-
error:
|
|
1353
|
-
recoverable:
|
|
1631
|
+
error: errorMsg,
|
|
1632
|
+
recoverable: isRecoverableErrorCode(code),
|
|
1633
|
+
code
|
|
1354
1634
|
};
|
|
1355
1635
|
}
|
|
1356
1636
|
return null;
|
|
@@ -1359,72 +1639,21 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1359
1639
|
return null;
|
|
1360
1640
|
}
|
|
1361
1641
|
}
|
|
1362
|
-
function
|
|
1363
|
-
|
|
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}`;
|
|
1642
|
+
function createClaudeService(options) {
|
|
1643
|
+
return new ClaudeAgentService(options);
|
|
1379
1644
|
}
|
|
1380
|
-
|
|
1381
|
-
if (messages.length <= 1) {
|
|
1382
|
-
return extractLastUserPrompt2(messages);
|
|
1383
|
-
}
|
|
1384
|
-
const history = messages.slice(0, -1).map((msg) => {
|
|
1385
|
-
if (msg.role === "user") {
|
|
1386
|
-
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
1387
|
-
}
|
|
1388
|
-
if (msg.role === "tool" && msg.toolResults) {
|
|
1389
|
-
const results = msg.toolResults.map(serializeToolResult2).join("\n");
|
|
1390
|
-
return `Tool results:
|
|
1391
|
-
${results}`;
|
|
1392
|
-
}
|
|
1393
|
-
if (msg.role === "assistant") {
|
|
1394
|
-
const parts = [];
|
|
1395
|
-
const thinking = msg.thinking;
|
|
1396
|
-
if (thinking) {
|
|
1397
|
-
parts.push(`[reasoning: ${thinking}]`);
|
|
1398
|
-
}
|
|
1399
|
-
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
1400
|
-
if (text2) parts.push(text2);
|
|
1401
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
1402
|
-
parts.push(msg.toolCalls.map(serializeToolCall2).join("\n"));
|
|
1403
|
-
}
|
|
1404
|
-
return `Assistant: ${parts.join("\n")}`;
|
|
1405
|
-
}
|
|
1406
|
-
const text = msg.content ? getTextContent(msg.content) : "";
|
|
1407
|
-
return `${msg.role}: ${text}`;
|
|
1408
|
-
}).join("\n");
|
|
1409
|
-
const lastPrompt = extractLastUserPrompt2(messages);
|
|
1410
|
-
return `Conversation history:
|
|
1411
|
-
${history}
|
|
1412
|
-
|
|
1413
|
-
User: ${lastPrompt}`;
|
|
1414
|
-
}
|
|
1415
|
-
function createClaudeService(options) {
|
|
1416
|
-
return new ClaudeAgentService(options);
|
|
1417
|
-
}
|
|
1418
|
-
var MCP_SERVER_NAME, MCP_TOOL_PREFIX, sdkModule2, ANTHROPIC_MODELS_URL, ANTHROPIC_API_VERSION, ANTHROPIC_OAUTH_BETA, ClaudeToolCallTracker, ClaudeAgent, ClaudeAgentService;
|
|
1645
|
+
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
1646
|
var init_claude = __esm({
|
|
1420
1647
|
"src/backends/claude.ts"() {
|
|
1421
|
-
|
|
1648
|
+
init_types2();
|
|
1422
1649
|
init_base_agent();
|
|
1423
|
-
|
|
1650
|
+
init_errors2();
|
|
1424
1651
|
init_schema();
|
|
1652
|
+
init_shared();
|
|
1425
1653
|
MCP_SERVER_NAME = "agent-sdk-tools";
|
|
1426
1654
|
MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
1427
|
-
|
|
1655
|
+
CLAUDE_INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1656
|
+
_sdkMock2 = null;
|
|
1428
1657
|
ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
|
|
1429
1658
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
1430
1659
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
@@ -1469,11 +1698,6 @@ var init_claude = __esm({
|
|
|
1469
1698
|
if (options.resumeSessionId) {
|
|
1470
1699
|
this._sessionId = options.resumeSessionId;
|
|
1471
1700
|
}
|
|
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
1701
|
}
|
|
1478
1702
|
get sessionId() {
|
|
1479
1703
|
return this._sessionId;
|
|
@@ -1497,12 +1721,12 @@ var init_claude = __esm({
|
|
|
1497
1721
|
const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
|
|
1498
1722
|
return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
|
|
1499
1723
|
}
|
|
1500
|
-
buildQueryOptions(signal) {
|
|
1724
|
+
buildQueryOptions(signal, options) {
|
|
1501
1725
|
const ac = new AbortController();
|
|
1502
1726
|
signal.addEventListener("abort", () => ac.abort(), { once: true });
|
|
1503
1727
|
const opts = {
|
|
1504
1728
|
abortController: ac,
|
|
1505
|
-
model:
|
|
1729
|
+
model: options.model,
|
|
1506
1730
|
maxTurns: this.options.maxTurns,
|
|
1507
1731
|
cwd: this.options.workingDirectory,
|
|
1508
1732
|
pathToClaudeCodeExecutable: this.options.cliPath,
|
|
@@ -1532,25 +1756,85 @@ var init_claude = __esm({
|
|
|
1532
1756
|
return opts;
|
|
1533
1757
|
}
|
|
1534
1758
|
async buildMcpConfig(opts, toolResultCapture) {
|
|
1535
|
-
|
|
1759
|
+
const onAskUser = this.config.supervisor?.onAskUser;
|
|
1760
|
+
if (this.tools.length === 0 && !onAskUser) return opts;
|
|
1536
1761
|
const sdk = await loadSDK2();
|
|
1537
|
-
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture);
|
|
1762
|
+
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture, onAskUser);
|
|
1538
1763
|
if (mcpServer) {
|
|
1539
1764
|
opts.mcpServers = {
|
|
1540
1765
|
[MCP_SERVER_NAME]: mcpServer
|
|
1541
1766
|
};
|
|
1542
1767
|
const mcpToolNames = this.tools.map((t) => mcpToolName(t.name));
|
|
1768
|
+
if (onAskUser) {
|
|
1769
|
+
mcpToolNames.push(mcpToolName("ask_user"));
|
|
1770
|
+
}
|
|
1543
1771
|
opts.allowedTools = [...opts.allowedTools ?? [], ...mcpToolNames];
|
|
1544
1772
|
}
|
|
1773
|
+
if (onAskUser) {
|
|
1774
|
+
opts.disallowedTools = [...opts.disallowedTools ?? [], "AskUserQuestion"];
|
|
1775
|
+
}
|
|
1545
1776
|
return opts;
|
|
1546
1777
|
}
|
|
1778
|
+
// ─── Retry Helpers (shared across executeRun/RunStructured/Stream) ──
|
|
1779
|
+
/** Setup a retry query: clear session, rebuild with full history */
|
|
1780
|
+
async prepareRetryQuery(sdk, messages, signal, options, toolResultCapture, modifyOpts) {
|
|
1781
|
+
this.clearPersistentSession();
|
|
1782
|
+
const retryPrompt = buildContextualPrompt(messages);
|
|
1783
|
+
let retryOpts = this.buildQueryOptions(signal, options);
|
|
1784
|
+
toolResultCapture.clear();
|
|
1785
|
+
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1786
|
+
modifyOpts?.(retryOpts);
|
|
1787
|
+
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1788
|
+
this.activeQuery = retryQ;
|
|
1789
|
+
return retryQ;
|
|
1790
|
+
}
|
|
1791
|
+
/** Extract tool_use blocks from an assistant SDK message into toolCalls array */
|
|
1792
|
+
collectToolCallsFromMessage(msg, toolCalls, toolResultCapture) {
|
|
1793
|
+
if (msg.type !== "assistant") return;
|
|
1794
|
+
const betaMessage = msg.message;
|
|
1795
|
+
if (!betaMessage?.content) return;
|
|
1796
|
+
for (const block of betaMessage.content) {
|
|
1797
|
+
if (block.type === "tool_use") {
|
|
1798
|
+
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1799
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1800
|
+
toolCalls.push({
|
|
1801
|
+
toolName,
|
|
1802
|
+
args: block.input ?? {},
|
|
1803
|
+
result: toolResultCapture.get(toolName) ?? null,
|
|
1804
|
+
approved: true
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
/** Back-fill tool results from capture map on summary/result messages */
|
|
1810
|
+
backfillToolResults(msg, toolCalls, toolResultCapture) {
|
|
1811
|
+
if (msg.type !== "tool_use_summary" && msg.type !== "result") return;
|
|
1812
|
+
for (const tc of toolCalls) {
|
|
1813
|
+
if (tc.result === null) {
|
|
1814
|
+
const captured = toolResultCapture.get(tc.toolName);
|
|
1815
|
+
if (captured !== void 0) tc.result = captured;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
/** Wrap retry inner loop with shared error handling */
|
|
1820
|
+
async withRetryErrorHandling(signal, fn) {
|
|
1821
|
+
try {
|
|
1822
|
+
return await fn();
|
|
1823
|
+
} catch (retryError) {
|
|
1824
|
+
if (this.isPersistent) this.clearPersistentSession();
|
|
1825
|
+
if (signal.aborted) throw new AbortError();
|
|
1826
|
+
throw retryError;
|
|
1827
|
+
} finally {
|
|
1828
|
+
this.activeQuery = null;
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1547
1831
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
1548
|
-
async executeRun(messages,
|
|
1832
|
+
async executeRun(messages, options, signal) {
|
|
1549
1833
|
this.checkAbort(signal);
|
|
1550
1834
|
const sdk = await loadSDK2();
|
|
1551
1835
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1552
|
-
const prompt = isResuming ?
|
|
1553
|
-
let opts = this.buildQueryOptions(signal);
|
|
1836
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1837
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1554
1838
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1555
1839
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1556
1840
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1560,30 +1844,8 @@ var init_claude = __esm({
|
|
|
1560
1844
|
let usage;
|
|
1561
1845
|
try {
|
|
1562
1846
|
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
|
-
}
|
|
1847
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1848
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1587
1849
|
if (msg.type === "result") {
|
|
1588
1850
|
if (msg.subtype === "success") {
|
|
1589
1851
|
const r = msg;
|
|
@@ -1603,41 +1865,13 @@ var init_claude = __esm({
|
|
|
1603
1865
|
} catch (e) {
|
|
1604
1866
|
if (signal.aborted) throw new AbortError();
|
|
1605
1867
|
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;
|
|
1868
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1613
1869
|
toolCalls.length = 0;
|
|
1614
1870
|
output = null;
|
|
1615
|
-
|
|
1871
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1616
1872
|
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
|
-
}
|
|
1873
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1874
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1641
1875
|
if (msg.type === "result") {
|
|
1642
1876
|
if (msg.subtype === "success") {
|
|
1643
1877
|
const r = msg;
|
|
@@ -1654,23 +1888,17 @@ var init_claude = __esm({
|
|
|
1654
1888
|
}
|
|
1655
1889
|
}
|
|
1656
1890
|
}
|
|
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
|
-
};
|
|
1891
|
+
return {
|
|
1892
|
+
output,
|
|
1893
|
+
structuredOutput: void 0,
|
|
1894
|
+
toolCalls,
|
|
1895
|
+
messages: [
|
|
1896
|
+
...messages,
|
|
1897
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1898
|
+
],
|
|
1899
|
+
usage
|
|
1900
|
+
};
|
|
1901
|
+
});
|
|
1674
1902
|
}
|
|
1675
1903
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1676
1904
|
throw e;
|
|
@@ -1689,12 +1917,12 @@ var init_claude = __esm({
|
|
|
1689
1917
|
};
|
|
1690
1918
|
}
|
|
1691
1919
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
1692
|
-
async executeRunStructured(messages, schema,
|
|
1920
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
1693
1921
|
this.checkAbort(signal);
|
|
1694
1922
|
const sdk = await loadSDK2();
|
|
1695
1923
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1696
|
-
const prompt = isResuming ?
|
|
1697
|
-
let opts = this.buildQueryOptions(signal);
|
|
1924
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1925
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1698
1926
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1699
1927
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1700
1928
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
@@ -1710,30 +1938,8 @@ var init_claude = __esm({
|
|
|
1710
1938
|
let usage;
|
|
1711
1939
|
try {
|
|
1712
1940
|
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
|
-
}
|
|
1941
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1942
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1737
1943
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1738
1944
|
const r = msg;
|
|
1739
1945
|
output = r.result;
|
|
@@ -1768,46 +1974,23 @@ var init_claude = __esm({
|
|
|
1768
1974
|
} catch (e) {
|
|
1769
1975
|
if (signal.aborted) throw new AbortError();
|
|
1770
1976
|
if (isResuming && this.isPersistent) {
|
|
1771
|
-
this.
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
this.activeQuery = retryQ;
|
|
1977
|
+
const retryQ = await this.prepareRetryQuery(
|
|
1978
|
+
sdk,
|
|
1979
|
+
messages,
|
|
1980
|
+
signal,
|
|
1981
|
+
options,
|
|
1982
|
+
toolResultCapture,
|
|
1983
|
+
(opts2) => {
|
|
1984
|
+
opts2.outputFormat = { type: "json_schema", schema: jsonSchema };
|
|
1985
|
+
}
|
|
1986
|
+
);
|
|
1782
1987
|
toolCalls.length = 0;
|
|
1783
1988
|
output = null;
|
|
1784
1989
|
structuredOutput = void 0;
|
|
1785
|
-
|
|
1990
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1786
1991
|
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
|
-
}
|
|
1992
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1993
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1811
1994
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1812
1995
|
const r = msg;
|
|
1813
1996
|
output = r.result;
|
|
@@ -1839,23 +2022,17 @@ var init_claude = __esm({
|
|
|
1839
2022
|
);
|
|
1840
2023
|
}
|
|
1841
2024
|
}
|
|
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
|
-
};
|
|
2025
|
+
return {
|
|
2026
|
+
output,
|
|
2027
|
+
structuredOutput,
|
|
2028
|
+
toolCalls,
|
|
2029
|
+
messages: [
|
|
2030
|
+
...messages,
|
|
2031
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
2032
|
+
],
|
|
2033
|
+
usage
|
|
2034
|
+
};
|
|
2035
|
+
});
|
|
1859
2036
|
}
|
|
1860
2037
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1861
2038
|
throw e;
|
|
@@ -1874,12 +2051,12 @@ var init_claude = __esm({
|
|
|
1874
2051
|
};
|
|
1875
2052
|
}
|
|
1876
2053
|
// ─── executeStream ──────────────────────────────────────────────
|
|
1877
|
-
async *executeStream(messages,
|
|
2054
|
+
async *executeStream(messages, options, signal) {
|
|
1878
2055
|
this.checkAbort(signal);
|
|
1879
2056
|
const sdk = await loadSDK2();
|
|
1880
2057
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1881
|
-
const prompt = isResuming ?
|
|
1882
|
-
let opts = this.buildQueryOptions(signal);
|
|
2058
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
2059
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1883
2060
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1884
2061
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1885
2062
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1887,6 +2064,7 @@ var init_claude = __esm({
|
|
|
1887
2064
|
const thinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1888
2065
|
const toolCallTracker = new ClaudeToolCallTracker();
|
|
1889
2066
|
const pendingStreamToolCalls = /* @__PURE__ */ new Map();
|
|
2067
|
+
let hasStreamedText = false;
|
|
1890
2068
|
try {
|
|
1891
2069
|
for await (const msg of q) {
|
|
1892
2070
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1904,6 +2082,7 @@ var init_claude = __esm({
|
|
|
1904
2082
|
} else if (e.type === "tool_call_end") {
|
|
1905
2083
|
pendingStreamToolCalls.delete(e.toolCallId);
|
|
1906
2084
|
}
|
|
2085
|
+
if (e.type === "text_delta") hasStreamedText = true;
|
|
1907
2086
|
yield e;
|
|
1908
2087
|
}
|
|
1909
2088
|
}
|
|
@@ -1927,22 +2106,21 @@ var init_claude = __esm({
|
|
|
1927
2106
|
}
|
|
1928
2107
|
yield this.emitSessionInfo(r.session_id);
|
|
1929
2108
|
}
|
|
1930
|
-
yield {
|
|
2109
|
+
yield {
|
|
2110
|
+
type: "done",
|
|
2111
|
+
finalOutput: hasStreamedText ? null : r.result,
|
|
2112
|
+
...hasStreamedText ? { streamed: true } : {}
|
|
2113
|
+
};
|
|
1931
2114
|
}
|
|
1932
2115
|
}
|
|
1933
2116
|
} catch (e) {
|
|
1934
2117
|
if (signal.aborted) throw new AbortError();
|
|
1935
2118
|
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;
|
|
2119
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1943
2120
|
const retryThinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1944
2121
|
const retryToolCallTracker = new ClaudeToolCallTracker();
|
|
1945
2122
|
const retryPendingToolCalls = /* @__PURE__ */ new Map();
|
|
2123
|
+
let retryHasStreamedText = false;
|
|
1946
2124
|
try {
|
|
1947
2125
|
for await (const msg of retryQ) {
|
|
1948
2126
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1960,6 +2138,7 @@ var init_claude = __esm({
|
|
|
1960
2138
|
} else if (ev.type === "tool_call_end") {
|
|
1961
2139
|
retryPendingToolCalls.delete(ev.toolCallId);
|
|
1962
2140
|
}
|
|
2141
|
+
if (ev.type === "text_delta") retryHasStreamedText = true;
|
|
1963
2142
|
yield ev;
|
|
1964
2143
|
}
|
|
1965
2144
|
}
|
|
@@ -1983,7 +2162,11 @@ var init_claude = __esm({
|
|
|
1983
2162
|
}
|
|
1984
2163
|
yield this.emitSessionInfo(r.session_id);
|
|
1985
2164
|
}
|
|
1986
|
-
yield {
|
|
2165
|
+
yield {
|
|
2166
|
+
type: "done",
|
|
2167
|
+
finalOutput: retryHasStreamedText ? null : r.result,
|
|
2168
|
+
...retryHasStreamedText ? { streamed: true } : {}
|
|
2169
|
+
};
|
|
1987
2170
|
}
|
|
1988
2171
|
}
|
|
1989
2172
|
} catch (retryError) {
|
|
@@ -2045,7 +2228,8 @@ var init_claude = __esm({
|
|
|
2045
2228
|
this.cachedModels = body.data.map((m) => ({
|
|
2046
2229
|
id: m.id,
|
|
2047
2230
|
name: m.display_name,
|
|
2048
|
-
provider: "claude"
|
|
2231
|
+
provider: "claude",
|
|
2232
|
+
...m.max_input_tokens != null && { contextWindow: m.max_input_tokens }
|
|
2049
2233
|
}));
|
|
2050
2234
|
return this.cachedModels;
|
|
2051
2235
|
}
|
|
@@ -2103,32 +2287,30 @@ __export(vercel_ai_exports, {
|
|
|
2103
2287
|
createVercelAIService: () => createVercelAIService
|
|
2104
2288
|
});
|
|
2105
2289
|
async function loadSDK3() {
|
|
2106
|
-
if (
|
|
2290
|
+
if (_sdkMock3) return _sdkMock3;
|
|
2107
2291
|
try {
|
|
2108
|
-
|
|
2109
|
-
return sdkModule3;
|
|
2292
|
+
return await import('ai');
|
|
2110
2293
|
} catch {
|
|
2111
2294
|
throw new DependencyError("ai");
|
|
2112
2295
|
}
|
|
2113
2296
|
}
|
|
2114
2297
|
async function loadCompat() {
|
|
2115
|
-
if (
|
|
2298
|
+
if (_compatMock) return _compatMock;
|
|
2116
2299
|
try {
|
|
2117
|
-
|
|
2118
|
-
return compatModule;
|
|
2300
|
+
return await import('@ai-sdk/openai-compatible');
|
|
2119
2301
|
} catch {
|
|
2120
2302
|
throw new DependencyError("@ai-sdk/openai-compatible");
|
|
2121
2303
|
}
|
|
2122
2304
|
}
|
|
2123
2305
|
function _injectSDK3(mock) {
|
|
2124
|
-
|
|
2306
|
+
_sdkMock3 = mock;
|
|
2125
2307
|
}
|
|
2126
2308
|
function _injectCompat(mock) {
|
|
2127
|
-
|
|
2309
|
+
_compatMock = mock;
|
|
2128
2310
|
}
|
|
2129
2311
|
function _resetSDK3() {
|
|
2130
|
-
|
|
2131
|
-
|
|
2312
|
+
_sdkMock3 = null;
|
|
2313
|
+
_compatMock = null;
|
|
2132
2314
|
}
|
|
2133
2315
|
function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, signal) {
|
|
2134
2316
|
const toolMap = {};
|
|
@@ -2171,13 +2353,14 @@ function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, s
|
|
|
2171
2353
|
return toolMap;
|
|
2172
2354
|
}
|
|
2173
2355
|
function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
|
|
2174
|
-
return async (args) => {
|
|
2356
|
+
return async (args, options) => {
|
|
2175
2357
|
if (ourTool.needsApproval && supervisor?.onPermission) {
|
|
2176
2358
|
const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
|
|
2177
2359
|
if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
|
|
2178
2360
|
const request = {
|
|
2179
2361
|
toolName: ourTool.name,
|
|
2180
|
-
toolArgs: args ?? {}
|
|
2362
|
+
toolArgs: args ?? {},
|
|
2363
|
+
toolCallId: options?.toolCallId
|
|
2181
2364
|
};
|
|
2182
2365
|
const decision = await supervisor.onPermission(
|
|
2183
2366
|
request,
|
|
@@ -2284,7 +2467,8 @@ function mapStreamPart(part) {
|
|
|
2284
2467
|
return {
|
|
2285
2468
|
type: "error",
|
|
2286
2469
|
error: p.error instanceof Error ? p.error.message : String(p.error ?? "Tool execution failed"),
|
|
2287
|
-
recoverable: true
|
|
2470
|
+
recoverable: true,
|
|
2471
|
+
code: "TOOL_EXECUTION" /* TOOL_EXECUTION */
|
|
2288
2472
|
};
|
|
2289
2473
|
}
|
|
2290
2474
|
case "reasoning-start":
|
|
@@ -2305,10 +2489,13 @@ function mapStreamPart(part) {
|
|
|
2305
2489
|
}
|
|
2306
2490
|
case "error": {
|
|
2307
2491
|
const p = part;
|
|
2492
|
+
const errorMsg = p.error instanceof Error ? p.error.message : String(p.error ?? "Unknown error");
|
|
2493
|
+
const code = classifyAgentError(errorMsg);
|
|
2308
2494
|
return {
|
|
2309
2495
|
type: "error",
|
|
2310
|
-
error:
|
|
2311
|
-
recoverable:
|
|
2496
|
+
error: errorMsg,
|
|
2497
|
+
recoverable: isRecoverableErrorCode(code),
|
|
2498
|
+
code
|
|
2312
2499
|
};
|
|
2313
2500
|
}
|
|
2314
2501
|
default:
|
|
@@ -2318,15 +2505,15 @@ function mapStreamPart(part) {
|
|
|
2318
2505
|
function createVercelAIService(options) {
|
|
2319
2506
|
return new VercelAIAgentService(options);
|
|
2320
2507
|
}
|
|
2321
|
-
var
|
|
2508
|
+
var _sdkMock3, _compatMock, DEFAULT_BASE_URL, DEFAULT_PROVIDER, DEFAULT_MAX_TURNS, VercelAIAgent, VercelAIAgentService;
|
|
2322
2509
|
var init_vercel_ai = __esm({
|
|
2323
2510
|
"src/backends/vercel-ai.ts"() {
|
|
2324
|
-
|
|
2511
|
+
init_types2();
|
|
2325
2512
|
init_base_agent();
|
|
2326
|
-
|
|
2513
|
+
init_errors2();
|
|
2327
2514
|
init_schema();
|
|
2328
|
-
|
|
2329
|
-
|
|
2515
|
+
_sdkMock3 = null;
|
|
2516
|
+
_compatMock = null;
|
|
2330
2517
|
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
2331
2518
|
DEFAULT_PROVIDER = "openrouter";
|
|
2332
2519
|
DEFAULT_MAX_TURNS = 10;
|
|
@@ -2339,28 +2526,33 @@ var init_vercel_ai = __esm({
|
|
|
2339
2526
|
super(config);
|
|
2340
2527
|
this.backendOptions = backendOptions;
|
|
2341
2528
|
}
|
|
2342
|
-
async getModel() {
|
|
2343
|
-
|
|
2529
|
+
async getModel(options) {
|
|
2530
|
+
const requestedModel = options.model;
|
|
2531
|
+
const defaultModel = this.config.model;
|
|
2532
|
+
if (requestedModel === defaultModel && this.model) return this.model;
|
|
2344
2533
|
const compat = await loadCompat();
|
|
2345
2534
|
const provider = compat.createOpenAICompatible({
|
|
2346
2535
|
name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
|
|
2347
2536
|
baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
|
|
2348
2537
|
apiKey: this.backendOptions.apiKey
|
|
2349
2538
|
});
|
|
2350
|
-
const
|
|
2351
|
-
|
|
2352
|
-
|
|
2539
|
+
const model = provider.chatModel(requestedModel);
|
|
2540
|
+
if (requestedModel === defaultModel) {
|
|
2541
|
+
this.model = model;
|
|
2542
|
+
}
|
|
2543
|
+
return model;
|
|
2353
2544
|
}
|
|
2354
|
-
async getSDKTools(signal) {
|
|
2545
|
+
async getSDKTools(signal, options) {
|
|
2355
2546
|
const sdk = await loadSDK3();
|
|
2356
|
-
|
|
2547
|
+
const tools = this.resolveTools(options);
|
|
2548
|
+
return mapToolsToSDK2(sdk, tools, this.config, this.sessionApprovals, this.config.permissionStore, signal);
|
|
2357
2549
|
}
|
|
2358
2550
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
2359
|
-
async executeRun(messages,
|
|
2551
|
+
async executeRun(messages, options, signal) {
|
|
2360
2552
|
this.checkAbort(signal);
|
|
2361
2553
|
const sdk = await loadSDK3();
|
|
2362
|
-
const model = await this.getModel();
|
|
2363
|
-
const tools = await this.getSDKTools(signal);
|
|
2554
|
+
const model = await this.getModel(options);
|
|
2555
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2364
2556
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2365
2557
|
const sdkMessages = messagesToSDK(messages);
|
|
2366
2558
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2416,10 +2608,10 @@ var init_vercel_ai = __esm({
|
|
|
2416
2608
|
};
|
|
2417
2609
|
}
|
|
2418
2610
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
2419
|
-
async executeRunStructured(messages, schema,
|
|
2611
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
2420
2612
|
this.checkAbort(signal);
|
|
2421
2613
|
const sdk = await loadSDK3();
|
|
2422
|
-
const model = await this.getModel();
|
|
2614
|
+
const model = await this.getModel(options);
|
|
2423
2615
|
const sdkMessages = messagesToSDK(messages);
|
|
2424
2616
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
2425
2617
|
const result = await sdk.generateObject({
|
|
@@ -2461,11 +2653,11 @@ var init_vercel_ai = __esm({
|
|
|
2461
2653
|
};
|
|
2462
2654
|
}
|
|
2463
2655
|
// ─── executeStream ──────────────────────────────────────────────
|
|
2464
|
-
async *executeStream(messages,
|
|
2656
|
+
async *executeStream(messages, options, signal) {
|
|
2465
2657
|
this.checkAbort(signal);
|
|
2466
2658
|
const sdk = await loadSDK3();
|
|
2467
|
-
const model = await this.getModel();
|
|
2468
|
-
const tools = await this.getSDKTools(signal);
|
|
2659
|
+
const model = await this.getModel(options);
|
|
2660
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2469
2661
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2470
2662
|
const sdkMessages = messagesToSDK(messages);
|
|
2471
2663
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2490,6 +2682,7 @@ var init_vercel_ai = __esm({
|
|
|
2490
2682
|
}
|
|
2491
2683
|
});
|
|
2492
2684
|
let finalText = "";
|
|
2685
|
+
let lastFinishReason;
|
|
2493
2686
|
try {
|
|
2494
2687
|
for await (const part of result.fullStream) {
|
|
2495
2688
|
if (signal.aborted) throw new AbortError();
|
|
@@ -2500,10 +2693,15 @@ var init_vercel_ai = __esm({
|
|
|
2500
2693
|
}
|
|
2501
2694
|
if (part.type === "finish-step") {
|
|
2502
2695
|
const p = part;
|
|
2696
|
+
lastFinishReason = p.finishReason;
|
|
2503
2697
|
if (p.finishReason === "tool-calls") {
|
|
2504
2698
|
finalText = "";
|
|
2505
2699
|
}
|
|
2506
2700
|
}
|
|
2701
|
+
if (part.type === "finish") {
|
|
2702
|
+
const p = part;
|
|
2703
|
+
lastFinishReason = p.finishReason;
|
|
2704
|
+
}
|
|
2507
2705
|
}
|
|
2508
2706
|
const totalUsage = await result.totalUsage;
|
|
2509
2707
|
yield {
|
|
@@ -2511,9 +2709,12 @@ var init_vercel_ai = __esm({
|
|
|
2511
2709
|
promptTokens: Number(totalUsage?.inputTokens ?? 0),
|
|
2512
2710
|
completionTokens: Number(totalUsage?.outputTokens ?? 0)
|
|
2513
2711
|
};
|
|
2712
|
+
const hasStreamed = finalText.length > 0;
|
|
2514
2713
|
yield {
|
|
2515
2714
|
type: "done",
|
|
2516
|
-
finalOutput: finalText || null
|
|
2715
|
+
finalOutput: hasStreamed ? null : finalText || null,
|
|
2716
|
+
...hasStreamed ? { streamed: true } : {},
|
|
2717
|
+
...lastFinishReason ? { finishReason: lastFinishReason } : {}
|
|
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
|
+
}));
|
|
2553
2763
|
}
|
|
2554
|
-
|
|
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
|
+
}));
|
|
2771
|
+
}
|
|
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);
|
|
2803
|
+
// src/chat/backends/types.ts
|
|
2804
|
+
function isResumableBackend(adapter) {
|
|
2805
|
+
return "canResume" in adapter && typeof adapter.canResume === "function";
|
|
2597
2806
|
}
|
|
2598
|
-
function listBackends() {
|
|
2599
|
-
const names = new Set(registry.keys());
|
|
2600
|
-
for (const builtin of BUILTIN_BACKENDS) {
|
|
2601
|
-
names.add(builtin);
|
|
2602
|
-
}
|
|
2603
|
-
return [...names];
|
|
2604
|
-
}
|
|
2605
|
-
function resetRegistry() {
|
|
2606
|
-
registry.clear();
|
|
2607
|
-
}
|
|
2608
|
-
function isBuiltinName(name) {
|
|
2609
|
-
return BUILTIN_BACKENDS.has(name);
|
|
2610
|
-
}
|
|
2611
|
-
async function loadBuiltinFactory(name) {
|
|
2612
|
-
switch (name) {
|
|
2613
|
-
case "copilot": {
|
|
2614
|
-
const mod = await Promise.resolve().then(() => (init_copilot(), copilot_exports));
|
|
2615
|
-
return (opts) => mod.createCopilotService(opts);
|
|
2616
|
-
}
|
|
2617
|
-
case "claude": {
|
|
2618
|
-
const mod = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
2619
|
-
return (opts) => mod.createClaudeService(opts);
|
|
2620
|
-
}
|
|
2621
|
-
case "vercel-ai": {
|
|
2622
|
-
const mod = await Promise.resolve().then(() => (init_vercel_ai(), vercel_ai_exports));
|
|
2623
|
-
return (opts) => mod.createVercelAIService(opts);
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
async function createAgentService(name, options) {
|
|
2628
|
-
const entry = registry.get(name);
|
|
2629
|
-
if (entry) {
|
|
2630
|
-
return entry.factory(options);
|
|
2631
|
-
}
|
|
2632
|
-
if (isBuiltinName(name)) {
|
|
2633
|
-
const factory = await loadBuiltinFactory(name);
|
|
2634
|
-
registry.set(name, { factory, builtin: true });
|
|
2635
|
-
return factory(options);
|
|
2636
|
-
}
|
|
2637
|
-
throw new BackendNotFoundError(name);
|
|
2638
|
-
}
|
|
2639
|
-
var registry, BUILTIN_BACKENDS;
|
|
2640
|
-
var init_registry = __esm({
|
|
2641
|
-
"src/registry.ts"() {
|
|
2642
|
-
init_errors();
|
|
2643
|
-
registry = /* @__PURE__ */ new Map();
|
|
2644
|
-
BUILTIN_BACKENDS = /* @__PURE__ */ new Set([
|
|
2645
|
-
"copilot",
|
|
2646
|
-
"claude",
|
|
2647
|
-
"vercel-ai"
|
|
2648
|
-
]);
|
|
2649
|
-
}
|
|
2650
|
-
});
|
|
2651
|
-
|
|
2652
|
-
// src/utils/messages.ts
|
|
2653
|
-
function messagesToPrompt(messages) {
|
|
2654
|
-
return messages.map((msg) => {
|
|
2655
|
-
switch (msg.role) {
|
|
2656
|
-
case "user":
|
|
2657
|
-
return contentToText(msg.content);
|
|
2658
|
-
case "assistant":
|
|
2659
|
-
return contentToText(msg.content);
|
|
2660
|
-
case "system":
|
|
2661
|
-
return msg.content;
|
|
2662
|
-
case "tool":
|
|
2663
|
-
return msg.content ?? "";
|
|
2664
|
-
}
|
|
2665
|
-
}).filter(Boolean).join("\n\n");
|
|
2666
|
-
}
|
|
2667
|
-
function contentToText(content) {
|
|
2668
|
-
return getTextContent(content);
|
|
2669
|
-
}
|
|
2670
|
-
function buildSystemPrompt(base, schemaInstruction) {
|
|
2671
|
-
if (!schemaInstruction) return base;
|
|
2672
|
-
return `${base}
|
|
2673
|
-
|
|
2674
|
-
${schemaInstruction}`;
|
|
2675
|
-
}
|
|
2676
|
-
var init_messages = __esm({
|
|
2677
|
-
"src/utils/messages.ts"() {
|
|
2678
|
-
init_types();
|
|
2679
|
-
}
|
|
2680
|
-
});
|
|
2681
|
-
function createDefaultPermissionStore(projectDir) {
|
|
2682
|
-
const sessionStore = new InMemoryPermissionStore();
|
|
2683
|
-
const projectPath = projectDir ? path.join(projectDir, ".agent-sdk", "permissions.json") : path.join(process.cwd(), ".agent-sdk", "permissions.json");
|
|
2684
|
-
const userPath = path.join(os.homedir(), ".agent-sdk", "permissions.json");
|
|
2685
|
-
const projectStore = new FilePermissionStore(projectPath);
|
|
2686
|
-
const userStore = new FilePermissionStore(userPath);
|
|
2687
|
-
return new CompositePermissionStore(sessionStore, projectStore, userStore);
|
|
2688
|
-
}
|
|
2689
|
-
var InMemoryPermissionStore, FilePermissionStore, CompositePermissionStore;
|
|
2690
|
-
var init_permission_store = __esm({
|
|
2691
|
-
"src/permission-store.ts"() {
|
|
2692
|
-
InMemoryPermissionStore = class {
|
|
2693
|
-
approvals = /* @__PURE__ */ new Map();
|
|
2694
|
-
async isApproved(toolName) {
|
|
2695
|
-
return this.approvals.has(toolName);
|
|
2696
|
-
}
|
|
2697
|
-
async approve(toolName, scope) {
|
|
2698
|
-
if (scope === "once") return;
|
|
2699
|
-
this.approvals.set(toolName, scope);
|
|
2700
|
-
}
|
|
2701
|
-
async revoke(toolName) {
|
|
2702
|
-
this.approvals.delete(toolName);
|
|
2703
|
-
}
|
|
2704
|
-
async clear() {
|
|
2705
|
-
this.approvals.clear();
|
|
2706
|
-
}
|
|
2707
|
-
async dispose() {
|
|
2708
|
-
this.approvals.clear();
|
|
2709
|
-
}
|
|
2710
|
-
};
|
|
2711
|
-
FilePermissionStore = class {
|
|
2712
|
-
filePath;
|
|
2713
|
-
constructor(filePath) {
|
|
2714
|
-
this.filePath = path.resolve(filePath);
|
|
2715
|
-
}
|
|
2716
|
-
async isApproved(toolName) {
|
|
2717
|
-
const data = this.readFile();
|
|
2718
|
-
return toolName in data.approvals;
|
|
2719
|
-
}
|
|
2720
|
-
async approve(toolName, scope) {
|
|
2721
|
-
if (scope === "once") return;
|
|
2722
|
-
const data = this.readFile();
|
|
2723
|
-
data.approvals[toolName] = { scope, timestamp: Date.now() };
|
|
2724
|
-
this.writeFileAtomic(data);
|
|
2725
|
-
}
|
|
2726
|
-
async revoke(toolName) {
|
|
2727
|
-
const data = this.readFile();
|
|
2728
|
-
delete data.approvals[toolName];
|
|
2729
|
-
this.writeFileAtomic(data);
|
|
2730
|
-
}
|
|
2731
|
-
async clear() {
|
|
2732
|
-
this.writeFileAtomic({ approvals: {} });
|
|
2733
|
-
}
|
|
2734
|
-
async dispose() {
|
|
2735
|
-
}
|
|
2736
|
-
readFile() {
|
|
2737
|
-
try {
|
|
2738
|
-
const raw = fs.readFileSync(this.filePath, "utf-8");
|
|
2739
|
-
const parsed = JSON.parse(raw);
|
|
2740
|
-
if (parsed && typeof parsed.approvals === "object") return parsed;
|
|
2741
|
-
} catch {
|
|
2742
|
-
}
|
|
2743
|
-
return { approvals: {} };
|
|
2744
|
-
}
|
|
2745
|
-
writeFileAtomic(data) {
|
|
2746
|
-
const dir = path.dirname(this.filePath);
|
|
2747
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
2748
|
-
const tmpPath = this.filePath + `.tmp.${process.pid}.${Date.now()}`;
|
|
2749
|
-
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
2750
|
-
fs.renameSync(tmpPath, this.filePath);
|
|
2751
|
-
}
|
|
2752
|
-
};
|
|
2753
|
-
CompositePermissionStore = class {
|
|
2754
|
-
sessionStore;
|
|
2755
|
-
projectStore;
|
|
2756
|
-
userStore;
|
|
2757
|
-
constructor(sessionStore, projectStore, userStore) {
|
|
2758
|
-
this.sessionStore = sessionStore;
|
|
2759
|
-
this.projectStore = projectStore;
|
|
2760
|
-
this.userStore = userStore ?? projectStore;
|
|
2761
|
-
}
|
|
2762
|
-
async isApproved(toolName) {
|
|
2763
|
-
return await this.sessionStore.isApproved(toolName) || await this.projectStore.isApproved(toolName) || await this.userStore.isApproved(toolName);
|
|
2764
|
-
}
|
|
2765
|
-
async approve(toolName, scope) {
|
|
2766
|
-
if (scope === "once") return;
|
|
2767
|
-
if (scope === "session") {
|
|
2768
|
-
await this.sessionStore.approve(toolName, scope);
|
|
2769
|
-
} else if (scope === "project") {
|
|
2770
|
-
await this.projectStore.approve(toolName, scope);
|
|
2771
|
-
} else {
|
|
2772
|
-
await this.userStore.approve(toolName, scope);
|
|
2773
|
-
}
|
|
2774
|
-
}
|
|
2775
|
-
async revoke(toolName) {
|
|
2776
|
-
await this.sessionStore.revoke(toolName);
|
|
2777
|
-
await this.projectStore.revoke(toolName);
|
|
2778
|
-
await this.userStore.revoke(toolName);
|
|
2779
|
-
}
|
|
2780
|
-
async clear() {
|
|
2781
|
-
await this.sessionStore.clear();
|
|
2782
|
-
await this.projectStore.clear();
|
|
2783
|
-
await this.userStore.clear();
|
|
2784
|
-
}
|
|
2785
|
-
async dispose() {
|
|
2786
|
-
await this.sessionStore.dispose();
|
|
2787
|
-
await this.projectStore.dispose();
|
|
2788
|
-
if (this.userStore !== this.projectStore) {
|
|
2789
|
-
await this.userStore.dispose();
|
|
2790
|
-
}
|
|
2791
|
-
}
|
|
2792
|
-
};
|
|
2793
|
-
}
|
|
2794
|
-
});
|
|
2795
|
-
|
|
2796
|
-
// src/index.ts
|
|
2797
|
-
var src_exports = {};
|
|
2798
|
-
__export(src_exports, {
|
|
2799
|
-
AbortError: () => AbortError,
|
|
2800
|
-
AgentSDKError: () => AgentSDKError,
|
|
2801
|
-
BackendAlreadyRegisteredError: () => BackendAlreadyRegisteredError,
|
|
2802
|
-
BackendNotFoundError: () => BackendNotFoundError,
|
|
2803
|
-
BaseAgent: () => BaseAgent,
|
|
2804
|
-
CompositePermissionStore: () => CompositePermissionStore,
|
|
2805
|
-
DependencyError: () => DependencyError,
|
|
2806
|
-
DisposedError: () => DisposedError,
|
|
2807
|
-
FilePermissionStore: () => FilePermissionStore,
|
|
2808
|
-
InMemoryPermissionStore: () => InMemoryPermissionStore,
|
|
2809
|
-
ReentrancyError: () => ReentrancyError,
|
|
2810
|
-
StructuredOutputError: () => StructuredOutputError,
|
|
2811
|
-
SubprocessError: () => SubprocessError,
|
|
2812
|
-
ToolExecutionError: () => ToolExecutionError,
|
|
2813
|
-
buildSystemPrompt: () => buildSystemPrompt,
|
|
2814
|
-
contentToText: () => contentToText,
|
|
2815
|
-
createAgentService: () => createAgentService,
|
|
2816
|
-
createDefaultPermissionStore: () => createDefaultPermissionStore,
|
|
2817
|
-
getTextContent: () => getTextContent,
|
|
2818
|
-
hasBackend: () => hasBackend,
|
|
2819
|
-
isMultiPartContent: () => isMultiPartContent,
|
|
2820
|
-
isTextContent: () => isTextContent,
|
|
2821
|
-
isToolDefinition: () => isToolDefinition,
|
|
2822
|
-
listBackends: () => listBackends,
|
|
2823
|
-
messagesToPrompt: () => messagesToPrompt,
|
|
2824
|
-
registerBackend: () => registerBackend,
|
|
2825
|
-
resetRegistry: () => resetRegistry,
|
|
2826
|
-
unregisterBackend: () => unregisterBackend,
|
|
2827
|
-
zodToJsonSchema: () => zodToJsonSchema
|
|
2828
|
-
});
|
|
2829
|
-
var init_src = __esm({
|
|
2830
|
-
"src/index.ts"() {
|
|
2831
|
-
init_types();
|
|
2832
|
-
init_errors();
|
|
2833
|
-
init_registry();
|
|
2834
|
-
init_base_agent();
|
|
2835
|
-
init_schema();
|
|
2836
|
-
init_messages();
|
|
2837
|
-
init_permission_store();
|
|
2838
|
-
}
|
|
2839
|
-
});
|
|
2840
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":
|
|
@@ -2907,8 +2879,9 @@ function agentEventToChatEvent(event, messageId) {
|
|
|
2907
2879
|
case "ask_user":
|
|
2908
2880
|
case "ask_user_response":
|
|
2909
2881
|
case "session_info":
|
|
2910
|
-
case "done":
|
|
2911
2882
|
return null;
|
|
2883
|
+
case "done":
|
|
2884
|
+
return { type: "done", finalOutput: event.finalOutput ?? void 0, finishReason: event.finishReason };
|
|
2912
2885
|
default:
|
|
2913
2886
|
return null;
|
|
2914
2887
|
}
|
|
@@ -2921,26 +2894,42 @@ async function* adaptAgentEvents(events, messageId) {
|
|
|
2921
2894
|
}
|
|
2922
2895
|
}
|
|
2923
2896
|
}
|
|
2924
|
-
|
|
2897
|
+
|
|
2898
|
+
// src/chat/conversion.ts
|
|
2899
|
+
function toAgentMessages(message) {
|
|
2925
2900
|
const textContent = getMessageText(message);
|
|
2926
2901
|
const toolCallParts = getMessageToolCalls(message);
|
|
2927
2902
|
switch (message.role) {
|
|
2928
2903
|
case "user":
|
|
2929
|
-
return { role: "user", content: textContent };
|
|
2904
|
+
return [{ role: "user", content: textContent }];
|
|
2930
2905
|
case "assistant": {
|
|
2931
2906
|
const toolCalls = toolCallParts.length > 0 ? toolCallParts.map((p) => ({ id: p.toolCallId, name: p.name, args: p.args })) : void 0;
|
|
2932
|
-
|
|
2907
|
+
const assistantMsg = {
|
|
2933
2908
|
role: "assistant",
|
|
2934
2909
|
content: textContent,
|
|
2935
2910
|
toolCalls
|
|
2936
2911
|
};
|
|
2912
|
+
const toolResults = extractToolResults(message);
|
|
2913
|
+
if (toolResults.length > 0) {
|
|
2914
|
+
return [assistantMsg, { role: "tool", toolResults }];
|
|
2915
|
+
}
|
|
2916
|
+
return [assistantMsg];
|
|
2937
2917
|
}
|
|
2938
2918
|
case "system":
|
|
2939
|
-
return { role: "system", content: textContent };
|
|
2919
|
+
return [{ role: "system", content: textContent }];
|
|
2940
2920
|
}
|
|
2941
2921
|
}
|
|
2922
|
+
function extractToolResults(message) {
|
|
2923
|
+
return getMessageToolCalls(message).filter((p) => p.result !== void 0).map((p) => ({
|
|
2924
|
+
toolCallId: p.toolCallId,
|
|
2925
|
+
name: p.name,
|
|
2926
|
+
result: p.result,
|
|
2927
|
+
isError: p.status === "error" ? true : void 0
|
|
2928
|
+
}));
|
|
2929
|
+
}
|
|
2942
2930
|
|
|
2943
2931
|
// src/chat/errors.ts
|
|
2932
|
+
init_errors2();
|
|
2944
2933
|
init_errors();
|
|
2945
2934
|
var ChatError = class extends AgentSDKError {
|
|
2946
2935
|
code;
|
|
@@ -2948,7 +2937,11 @@ var ChatError = class extends AgentSDKError {
|
|
|
2948
2937
|
retryAfter;
|
|
2949
2938
|
timestamp;
|
|
2950
2939
|
constructor(message, options) {
|
|
2951
|
-
super(message, {
|
|
2940
|
+
super(message, {
|
|
2941
|
+
cause: options.cause,
|
|
2942
|
+
code: options.code,
|
|
2943
|
+
retryable: options.retryable
|
|
2944
|
+
});
|
|
2952
2945
|
this.name = "ChatError";
|
|
2953
2946
|
this.code = options.code;
|
|
2954
2947
|
this.retryable = options.retryable ?? false;
|
|
@@ -2960,25 +2953,51 @@ var ChatError = class extends AgentSDKError {
|
|
|
2960
2953
|
// src/chat/backends/base.ts
|
|
2961
2954
|
var BaseBackendAdapter = class {
|
|
2962
2955
|
name;
|
|
2963
|
-
_agentService;
|
|
2964
|
-
|
|
2956
|
+
_agentService = null;
|
|
2957
|
+
_agentServiceFactory = null;
|
|
2965
2958
|
_disposed = false;
|
|
2966
2959
|
_agentConfig;
|
|
2967
2960
|
_ownsService;
|
|
2961
|
+
// Agent lifecycle: tracks current agent and the model it was created with.
|
|
2962
|
+
// For persistent sessions, reused across calls when model matches.
|
|
2963
|
+
// For non-persistent, recreated every call.
|
|
2964
|
+
_currentAgent = null;
|
|
2968
2965
|
constructor(name, options) {
|
|
2969
2966
|
this.name = name;
|
|
2970
2967
|
this._agentConfig = options.agentConfig;
|
|
2971
2968
|
if (options.agentService) {
|
|
2972
2969
|
this._agentService = options.agentService;
|
|
2973
2970
|
this._ownsService = false;
|
|
2971
|
+
} else if (options.agentServiceFactory) {
|
|
2972
|
+
this._agentServiceFactory = options.agentServiceFactory;
|
|
2973
|
+
this._ownsService = true;
|
|
2974
2974
|
} else {
|
|
2975
2975
|
this._agentService = this.createService();
|
|
2976
2976
|
this._ownsService = true;
|
|
2977
2977
|
}
|
|
2978
2978
|
}
|
|
2979
2979
|
get agentService() {
|
|
2980
|
+
if (!this._agentService) {
|
|
2981
|
+
if (this._agentServiceFactory) {
|
|
2982
|
+
this._agentService = this._agentServiceFactory();
|
|
2983
|
+
this._agentServiceFactory = null;
|
|
2984
|
+
} else {
|
|
2985
|
+
throw new ChatError("Agent service not available", {
|
|
2986
|
+
code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */
|
|
2987
|
+
});
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2980
2990
|
return this._agentService;
|
|
2981
2991
|
}
|
|
2992
|
+
get currentModel() {
|
|
2993
|
+
return this._agentConfig.model;
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* @deprecated No-op. Tools are passed per-call via SendMessageOptions.tools.
|
|
2997
|
+
* Kept for backward compatibility with code that calls setTools() directly.
|
|
2998
|
+
*/
|
|
2999
|
+
setTools() {
|
|
3000
|
+
}
|
|
2982
3001
|
async sendMessage(session, message, options) {
|
|
2983
3002
|
this.assertNotDisposed();
|
|
2984
3003
|
const events = this.streamMessage(session, message, options);
|
|
@@ -3006,7 +3025,7 @@ var BaseBackendAdapter = class {
|
|
|
3006
3025
|
async *streamMessage(session, message, options) {
|
|
3007
3026
|
this.assertNotDisposed();
|
|
3008
3027
|
const agent = this.getOrCreateAgent(options);
|
|
3009
|
-
const messages = session.messages.
|
|
3028
|
+
const messages = session.messages.flatMap(toAgentMessages);
|
|
3010
3029
|
messages.push({ role: "user", content: message });
|
|
3011
3030
|
yield* this.streamAgentEvents(agent, messages, options);
|
|
3012
3031
|
}
|
|
@@ -3016,9 +3035,13 @@ var BaseBackendAdapter = class {
|
|
|
3016
3035
|
*/
|
|
3017
3036
|
async *streamAgentEvents(agent, messages, options) {
|
|
3018
3037
|
const messageId = createChatId();
|
|
3038
|
+
const model = options?.model ?? this._agentConfig.model ?? "";
|
|
3019
3039
|
const agentEvents = agent.streamWithContext(messages, {
|
|
3040
|
+
model,
|
|
3020
3041
|
signal: options?.signal,
|
|
3021
|
-
context: options?.context
|
|
3042
|
+
context: options?.context,
|
|
3043
|
+
tools: options?.tools,
|
|
3044
|
+
...options?.systemPrompt ? { systemMessage: options.systemPrompt } : {}
|
|
3022
3045
|
});
|
|
3023
3046
|
yield { type: "message:start", messageId, role: "assistant" };
|
|
3024
3047
|
let text = "";
|
|
@@ -3044,31 +3067,46 @@ var BaseBackendAdapter = class {
|
|
|
3044
3067
|
}
|
|
3045
3068
|
async listModels() {
|
|
3046
3069
|
this.assertNotDisposed();
|
|
3047
|
-
return this.
|
|
3070
|
+
return this.agentService.listModels();
|
|
3048
3071
|
}
|
|
3049
3072
|
async validate() {
|
|
3050
3073
|
this.assertNotDisposed();
|
|
3051
|
-
return this.
|
|
3074
|
+
return this.agentService.validate();
|
|
3052
3075
|
}
|
|
3053
3076
|
async dispose() {
|
|
3054
3077
|
if (this._disposed) return;
|
|
3055
3078
|
this._disposed = true;
|
|
3056
|
-
this.
|
|
3057
|
-
|
|
3058
|
-
|
|
3079
|
+
if (this._currentAgent) {
|
|
3080
|
+
this._currentAgent.instance.dispose();
|
|
3081
|
+
this._currentAgent = null;
|
|
3082
|
+
}
|
|
3083
|
+
if (this._ownsService && this._agentService && typeof this._agentService.dispose === "function") {
|
|
3059
3084
|
await this._agentService.dispose();
|
|
3060
3085
|
}
|
|
3061
3086
|
}
|
|
3062
|
-
/** Get or create an agent
|
|
3087
|
+
/** Get or create an agent. Model is passed per-call via RunOptions.
|
|
3088
|
+
* Tools are passed per-call via SendMessageOptions — not baked into config.
|
|
3089
|
+
* For persistent sessions, reuses agent when model matches. */
|
|
3063
3090
|
getOrCreateAgent(options) {
|
|
3064
|
-
const
|
|
3065
|
-
if (this._agentConfig.sessionMode === "persistent" && this.
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
this.
|
|
3071
|
-
}
|
|
3091
|
+
const model = options?.model ?? this._agentConfig.model;
|
|
3092
|
+
if (this._agentConfig.sessionMode === "persistent" && this._currentAgent) {
|
|
3093
|
+
if (this._currentAgent.model === model) {
|
|
3094
|
+
return this._currentAgent.instance;
|
|
3095
|
+
}
|
|
3096
|
+
this._currentAgent.instance.dispose();
|
|
3097
|
+
this._currentAgent = null;
|
|
3098
|
+
}
|
|
3099
|
+
if (this._currentAgent) {
|
|
3100
|
+
this._currentAgent.instance.dispose();
|
|
3101
|
+
this._currentAgent = null;
|
|
3102
|
+
}
|
|
3103
|
+
const config = {
|
|
3104
|
+
...this._agentConfig,
|
|
3105
|
+
...model !== void 0 && { model },
|
|
3106
|
+
...options?.tools?.length ? { tools: options.tools } : {}
|
|
3107
|
+
};
|
|
3108
|
+
const agent = this.agentService.createAgent(config);
|
|
3109
|
+
this._currentAgent = { instance: agent, model };
|
|
3072
3110
|
return agent;
|
|
3073
3111
|
}
|
|
3074
3112
|
assertNotDisposed() {
|
|
@@ -3080,21 +3118,15 @@ var BaseBackendAdapter = class {
|
|
|
3080
3118
|
}
|
|
3081
3119
|
};
|
|
3082
3120
|
|
|
3083
|
-
// src/chat/backends/
|
|
3084
|
-
var
|
|
3121
|
+
// src/chat/backends/resumable.ts
|
|
3122
|
+
var ResumableChatAdapter = class extends BaseBackendAdapter {
|
|
3085
3123
|
_backendSessionId = null;
|
|
3086
|
-
|
|
3087
|
-
constructor(options) {
|
|
3124
|
+
constructor(name, options) {
|
|
3088
3125
|
const agentConfig = {
|
|
3089
3126
|
...options.agentConfig,
|
|
3090
3127
|
sessionMode: "persistent"
|
|
3091
3128
|
};
|
|
3092
|
-
super(
|
|
3093
|
-
this._copilotOptions = options.copilotOptions;
|
|
3094
|
-
}
|
|
3095
|
-
createService() {
|
|
3096
|
-
const { createAgentService: createAgentService2 } = (init_src(), __toCommonJS(src_exports));
|
|
3097
|
-
return createAgentService2("copilot", this._copilotOptions);
|
|
3129
|
+
super(name, { ...options, agentConfig });
|
|
3098
3130
|
}
|
|
3099
3131
|
get backendSessionId() {
|
|
3100
3132
|
return this._backendSessionId;
|
|
@@ -3123,7 +3155,7 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
3123
3155
|
{ code: "SESSION_EXPIRED" /* SESSION_EXPIRED */ }
|
|
3124
3156
|
);
|
|
3125
3157
|
}
|
|
3126
|
-
const messages = session.messages.
|
|
3158
|
+
const messages = session.messages.flatMap(toAgentMessages);
|
|
3127
3159
|
yield* this.streamAgentEvents(agent, messages, options);
|
|
3128
3160
|
}
|
|
3129
3161
|
captureSessionId(agent) {
|
|
@@ -3133,81 +3165,325 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
3133
3165
|
}
|
|
3134
3166
|
};
|
|
3135
3167
|
|
|
3168
|
+
// src/chat/backends/copilot.ts
|
|
3169
|
+
var CopilotChatAdapter = class extends ResumableChatAdapter {
|
|
3170
|
+
_copilotOptions;
|
|
3171
|
+
constructor(options) {
|
|
3172
|
+
super("copilot", options);
|
|
3173
|
+
this._copilotOptions = options.copilotOptions;
|
|
3174
|
+
}
|
|
3175
|
+
createService() {
|
|
3176
|
+
const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
|
|
3177
|
+
return createCopilotService2(this._copilotOptions || {});
|
|
3178
|
+
}
|
|
3179
|
+
};
|
|
3180
|
+
|
|
3136
3181
|
// src/chat/backends/claude.ts
|
|
3137
|
-
var ClaudeChatAdapter = class extends
|
|
3138
|
-
_backendSessionId = null;
|
|
3182
|
+
var ClaudeChatAdapter = class extends ResumableChatAdapter {
|
|
3139
3183
|
_claudeOptions;
|
|
3140
3184
|
constructor(options) {
|
|
3141
|
-
|
|
3142
|
-
...options.agentConfig,
|
|
3143
|
-
sessionMode: "persistent"
|
|
3144
|
-
};
|
|
3145
|
-
super("claude", { ...options, agentConfig });
|
|
3185
|
+
super("claude", options);
|
|
3146
3186
|
this._claudeOptions = options.claudeOptions;
|
|
3147
3187
|
}
|
|
3148
3188
|
createService() {
|
|
3149
|
-
const {
|
|
3150
|
-
return
|
|
3189
|
+
const { createClaudeService: createClaudeService2 } = (init_claude(), __toCommonJS(claude_exports));
|
|
3190
|
+
return createClaudeService2(this._claudeOptions || {});
|
|
3151
3191
|
}
|
|
3152
|
-
|
|
3153
|
-
|
|
3192
|
+
};
|
|
3193
|
+
|
|
3194
|
+
// src/chat/backends/vercel-ai.ts
|
|
3195
|
+
var VercelAIChatAdapter = class extends BaseBackendAdapter {
|
|
3196
|
+
_vercelOptions;
|
|
3197
|
+
constructor(options) {
|
|
3198
|
+
super("vercel-ai", options);
|
|
3199
|
+
this._vercelOptions = options.vercelOptions;
|
|
3154
3200
|
}
|
|
3155
|
-
|
|
3156
|
-
|
|
3201
|
+
createService() {
|
|
3202
|
+
const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
|
|
3203
|
+
return createVercelAIService2(this._vercelOptions || {});
|
|
3157
3204
|
}
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3205
|
+
captureSessionId(_agent) {
|
|
3206
|
+
}
|
|
3207
|
+
};
|
|
3208
|
+
|
|
3209
|
+
// src/backends/mock-llm.ts
|
|
3210
|
+
init_base_agent();
|
|
3211
|
+
init_errors2();
|
|
3212
|
+
function extractPrompt(messages) {
|
|
3213
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3214
|
+
const msg = messages[i];
|
|
3215
|
+
if (msg.role === "user") {
|
|
3216
|
+
return typeof msg.content === "string" ? msg.content : msg.content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
return "";
|
|
3220
|
+
}
|
|
3221
|
+
function resolveResponse(mode, messages, callIndex) {
|
|
3222
|
+
switch (mode.type) {
|
|
3223
|
+
case "echo":
|
|
3224
|
+
return extractPrompt(messages);
|
|
3225
|
+
case "static":
|
|
3226
|
+
return mode.response;
|
|
3227
|
+
case "scripted": {
|
|
3228
|
+
if (mode.loop) {
|
|
3229
|
+
return mode.responses[callIndex % mode.responses.length];
|
|
3230
|
+
}
|
|
3231
|
+
if (callIndex < mode.responses.length) {
|
|
3232
|
+
return mode.responses[callIndex];
|
|
3233
|
+
}
|
|
3234
|
+
return mode.responses[mode.responses.length - 1];
|
|
3235
|
+
}
|
|
3236
|
+
case "error":
|
|
3237
|
+
throw new AgentSDKError(mode.error, {
|
|
3238
|
+
code: mode.code ?? "backend_error",
|
|
3239
|
+
retryable: mode.recoverable ?? false
|
|
3163
3240
|
});
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
async function applyLatency(latency, signal) {
|
|
3244
|
+
if (!latency) return;
|
|
3245
|
+
const ms = latency.type === "fixed" ? latency.ms : latency.minMs + Math.random() * (latency.maxMs - latency.minMs);
|
|
3246
|
+
if (ms <= 0) return;
|
|
3247
|
+
await new Promise((resolve, reject) => {
|
|
3248
|
+
const timer = setTimeout(resolve, ms);
|
|
3249
|
+
const onAbort = () => {
|
|
3250
|
+
clearTimeout(timer);
|
|
3251
|
+
reject(new Error("aborted"));
|
|
3252
|
+
};
|
|
3253
|
+
if (signal.aborted) {
|
|
3254
|
+
clearTimeout(timer);
|
|
3255
|
+
reject(new Error("aborted"));
|
|
3256
|
+
return;
|
|
3164
3257
|
}
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3258
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3259
|
+
});
|
|
3260
|
+
}
|
|
3261
|
+
function chunkText(text, streaming) {
|
|
3262
|
+
if (streaming?.chunkSize && streaming.chunkSize > 0) {
|
|
3263
|
+
const chunks = [];
|
|
3264
|
+
for (let i = 0; i < text.length; i += streaming.chunkSize) {
|
|
3265
|
+
chunks.push(text.slice(i, i + streaming.chunkSize));
|
|
3172
3266
|
}
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3267
|
+
return chunks;
|
|
3268
|
+
}
|
|
3269
|
+
return text.split(/(\s+)/).filter(Boolean);
|
|
3270
|
+
}
|
|
3271
|
+
async function chunkDelay(streaming, signal) {
|
|
3272
|
+
const ms = streaming?.chunkDelayMs;
|
|
3273
|
+
if (!ms || ms <= 0) return;
|
|
3274
|
+
await new Promise((resolve, reject) => {
|
|
3275
|
+
const timer = setTimeout(resolve, ms);
|
|
3276
|
+
const onAbort = () => {
|
|
3277
|
+
clearTimeout(timer);
|
|
3278
|
+
reject(new Error("aborted"));
|
|
3279
|
+
};
|
|
3280
|
+
if (signal.aborted) {
|
|
3281
|
+
clearTimeout(timer);
|
|
3282
|
+
reject(new Error("aborted"));
|
|
3283
|
+
return;
|
|
3178
3284
|
}
|
|
3179
|
-
|
|
3180
|
-
|
|
3285
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3286
|
+
});
|
|
3287
|
+
}
|
|
3288
|
+
var MockLLMAgent = class extends BaseAgent {
|
|
3289
|
+
backendName = "mock-llm";
|
|
3290
|
+
mode;
|
|
3291
|
+
latency;
|
|
3292
|
+
streaming;
|
|
3293
|
+
finishReason;
|
|
3294
|
+
permissions;
|
|
3295
|
+
toolCallConfigs;
|
|
3296
|
+
configuredStructuredOutput;
|
|
3297
|
+
callIndex = 0;
|
|
3298
|
+
constructor(config, options) {
|
|
3299
|
+
super(config);
|
|
3300
|
+
this.mode = options.mode ?? { type: "echo" };
|
|
3301
|
+
this.latency = options.latency;
|
|
3302
|
+
this.streaming = options.streaming;
|
|
3303
|
+
this.finishReason = options.finishReason ?? "stop";
|
|
3304
|
+
this.permissions = options.permissions;
|
|
3305
|
+
this.toolCallConfigs = options.toolCalls ?? [];
|
|
3306
|
+
this.configuredStructuredOutput = options.structuredOutput;
|
|
3307
|
+
}
|
|
3308
|
+
async executeRun(messages, _options, signal) {
|
|
3309
|
+
this.checkAbort(signal);
|
|
3310
|
+
await applyLatency(this.latency, signal);
|
|
3311
|
+
this.checkAbort(signal);
|
|
3312
|
+
const idx = this.callIndex++;
|
|
3313
|
+
const output = resolveResponse(this.mode, messages, idx);
|
|
3314
|
+
const toolCalls = this.toolCallConfigs.map((tc) => ({
|
|
3315
|
+
toolName: tc.toolName,
|
|
3316
|
+
args: tc.args ?? {},
|
|
3317
|
+
result: tc.result ?? null,
|
|
3318
|
+
approved: true
|
|
3319
|
+
}));
|
|
3320
|
+
return {
|
|
3321
|
+
output,
|
|
3322
|
+
structuredOutput: void 0,
|
|
3323
|
+
toolCalls,
|
|
3324
|
+
messages: [
|
|
3325
|
+
...messages,
|
|
3326
|
+
{ role: "assistant", content: output }
|
|
3327
|
+
],
|
|
3328
|
+
usage: { promptTokens: 10, completionTokens: output.length }
|
|
3329
|
+
};
|
|
3181
3330
|
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3331
|
+
async executeRunStructured(messages, _schema, _options, signal) {
|
|
3332
|
+
this.checkAbort(signal);
|
|
3333
|
+
await applyLatency(this.latency, signal);
|
|
3334
|
+
this.checkAbort(signal);
|
|
3335
|
+
const idx = this.callIndex++;
|
|
3336
|
+
const output = resolveResponse(this.mode, messages, idx);
|
|
3337
|
+
let parsed;
|
|
3338
|
+
if (this.configuredStructuredOutput !== void 0) {
|
|
3339
|
+
parsed = this.configuredStructuredOutput;
|
|
3340
|
+
} else {
|
|
3341
|
+
try {
|
|
3342
|
+
parsed = JSON.parse(output);
|
|
3343
|
+
} catch {
|
|
3344
|
+
parsed = output;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
return {
|
|
3348
|
+
output,
|
|
3349
|
+
structuredOutput: parsed,
|
|
3350
|
+
toolCalls: [],
|
|
3351
|
+
messages: [
|
|
3352
|
+
...messages,
|
|
3353
|
+
{ role: "assistant", content: output }
|
|
3354
|
+
],
|
|
3355
|
+
usage: { promptTokens: 10, completionTokens: output.length }
|
|
3356
|
+
};
|
|
3357
|
+
}
|
|
3358
|
+
async *executeStream(messages, _options, signal) {
|
|
3359
|
+
this.checkAbort(signal);
|
|
3360
|
+
await applyLatency(this.latency, signal);
|
|
3361
|
+
this.checkAbort(signal);
|
|
3362
|
+
if (this.permissions) {
|
|
3363
|
+
yield* this.simulatePermissions(signal);
|
|
3364
|
+
}
|
|
3365
|
+
if (this.toolCallConfigs.length > 0) {
|
|
3366
|
+
yield* this.simulateToolCalls(signal);
|
|
3367
|
+
}
|
|
3368
|
+
const idx = this.callIndex++;
|
|
3369
|
+
const output = resolveResponse(this.mode, messages, idx);
|
|
3370
|
+
const chunks = chunkText(output, this.streaming);
|
|
3371
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
3372
|
+
this.checkAbort(signal);
|
|
3373
|
+
if (i > 0) {
|
|
3374
|
+
await chunkDelay(this.streaming, signal);
|
|
3375
|
+
}
|
|
3376
|
+
yield { type: "text_delta", text: chunks[i] };
|
|
3377
|
+
}
|
|
3378
|
+
yield {
|
|
3379
|
+
type: "usage_update",
|
|
3380
|
+
promptTokens: 10,
|
|
3381
|
+
completionTokens: output.length
|
|
3382
|
+
};
|
|
3383
|
+
yield {
|
|
3384
|
+
type: "done",
|
|
3385
|
+
finalOutput: output,
|
|
3386
|
+
finishReason: this.finishReason
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3389
|
+
async *simulateToolCalls(signal) {
|
|
3390
|
+
for (let i = 0; i < this.toolCallConfigs.length; i++) {
|
|
3391
|
+
this.checkAbort(signal);
|
|
3392
|
+
const tc = this.toolCallConfigs[i];
|
|
3393
|
+
const toolCallId = tc.toolCallId ?? `mock-tc-${i}`;
|
|
3394
|
+
yield {
|
|
3395
|
+
type: "tool_call_start",
|
|
3396
|
+
toolCallId,
|
|
3397
|
+
toolName: tc.toolName,
|
|
3398
|
+
args: tc.args ?? {}
|
|
3399
|
+
};
|
|
3400
|
+
yield {
|
|
3401
|
+
type: "tool_call_end",
|
|
3402
|
+
toolCallId,
|
|
3403
|
+
toolName: tc.toolName,
|
|
3404
|
+
result: tc.result ?? null
|
|
3405
|
+
};
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
async *simulatePermissions(signal) {
|
|
3409
|
+
const perms = this.permissions;
|
|
3410
|
+
for (const toolName of perms.toolNames) {
|
|
3411
|
+
this.checkAbort(signal);
|
|
3412
|
+
const request = {
|
|
3413
|
+
toolName,
|
|
3414
|
+
toolArgs: {}
|
|
3415
|
+
};
|
|
3416
|
+
yield { type: "permission_request", request };
|
|
3417
|
+
if (perms.denyTools?.includes(toolName)) {
|
|
3418
|
+
yield {
|
|
3419
|
+
type: "permission_response",
|
|
3420
|
+
toolName,
|
|
3421
|
+
decision: { allowed: false, reason: "Denied by mock configuration" }
|
|
3422
|
+
};
|
|
3423
|
+
} else if (perms.autoApprove) {
|
|
3424
|
+
yield {
|
|
3425
|
+
type: "permission_response",
|
|
3426
|
+
toolName,
|
|
3427
|
+
decision: { allowed: true, scope: "once" }
|
|
3428
|
+
};
|
|
3429
|
+
} else {
|
|
3430
|
+
const supervisor = this.getConfig().supervisor;
|
|
3431
|
+
if (supervisor?.onPermission) {
|
|
3432
|
+
const decision = await supervisor.onPermission(request, signal);
|
|
3433
|
+
yield { type: "permission_response", toolName, decision };
|
|
3434
|
+
} else {
|
|
3435
|
+
yield {
|
|
3436
|
+
type: "permission_response",
|
|
3437
|
+
toolName,
|
|
3438
|
+
decision: { allowed: true, scope: "once" }
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3185
3442
|
}
|
|
3186
3443
|
}
|
|
3187
3444
|
};
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
constructor(options) {
|
|
3193
|
-
|
|
3194
|
-
this.
|
|
3445
|
+
var MockLLMService = class {
|
|
3446
|
+
name = "mock-llm";
|
|
3447
|
+
options;
|
|
3448
|
+
models;
|
|
3449
|
+
constructor(options = {}) {
|
|
3450
|
+
this.options = options;
|
|
3451
|
+
this.models = (options.models ?? [
|
|
3452
|
+
{ id: "mock-fast", name: "Mock Fast" },
|
|
3453
|
+
{ id: "mock-quality", name: "Mock Quality" }
|
|
3454
|
+
]).map((m) => ({
|
|
3455
|
+
id: m.id,
|
|
3456
|
+
name: m.name,
|
|
3457
|
+
description: m.description
|
|
3458
|
+
}));
|
|
3459
|
+
}
|
|
3460
|
+
createAgent(config) {
|
|
3461
|
+
return new MockLLMAgent(config, this.options);
|
|
3195
3462
|
}
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
return createAgentService2("vercel-ai", this._vercelOptions);
|
|
3463
|
+
async listModels() {
|
|
3464
|
+
return this.models;
|
|
3199
3465
|
}
|
|
3200
|
-
|
|
3201
|
-
return
|
|
3466
|
+
async validate() {
|
|
3467
|
+
return { valid: true, errors: [] };
|
|
3202
3468
|
}
|
|
3203
|
-
|
|
3204
|
-
return false;
|
|
3469
|
+
async dispose() {
|
|
3205
3470
|
}
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3471
|
+
};
|
|
3472
|
+
function createMockLLMService(options = {}) {
|
|
3473
|
+
return new MockLLMService(options);
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
// src/chat/backends/mock-llm.ts
|
|
3477
|
+
var MockLLMChatAdapter = class extends BaseBackendAdapter {
|
|
3478
|
+
constructor(options) {
|
|
3479
|
+
const mockOpts = options.mockOptions;
|
|
3480
|
+
super("mock-llm", {
|
|
3481
|
+
...options,
|
|
3482
|
+
agentServiceFactory: () => createMockLLMService(mockOpts || {})
|
|
3483
|
+
});
|
|
3484
|
+
}
|
|
3485
|
+
createService() {
|
|
3486
|
+
return createMockLLMService({});
|
|
3211
3487
|
}
|
|
3212
3488
|
captureSessionId(_agent) {
|
|
3213
3489
|
}
|
|
@@ -3288,16 +3564,22 @@ var SSEChatTransport = class {
|
|
|
3288
3564
|
};
|
|
3289
3565
|
async function streamToTransport(events, transport) {
|
|
3290
3566
|
try {
|
|
3291
|
-
|
|
3567
|
+
const textChunks = [];
|
|
3568
|
+
let finishReason;
|
|
3292
3569
|
for await (const event of events) {
|
|
3293
3570
|
if (!transport.isOpen) break;
|
|
3571
|
+
if (event.type === "done") {
|
|
3572
|
+
finishReason = event.finishReason;
|
|
3573
|
+
continue;
|
|
3574
|
+
}
|
|
3294
3575
|
transport.send(event);
|
|
3295
3576
|
if (event.type === "message:delta") {
|
|
3296
|
-
|
|
3577
|
+
textChunks.push(event.text);
|
|
3297
3578
|
}
|
|
3298
3579
|
}
|
|
3299
3580
|
if (transport.isOpen) {
|
|
3300
|
-
|
|
3581
|
+
const finalOutput = textChunks.length > 0 ? textChunks.join("") : void 0;
|
|
3582
|
+
transport.send({ type: "done", finalOutput, finishReason });
|
|
3301
3583
|
}
|
|
3302
3584
|
transport.close();
|
|
3303
3585
|
} catch (err) {
|
|
@@ -3388,9 +3670,9 @@ var InProcessChatTransport = class {
|
|
|
3388
3670
|
send(event) {
|
|
3389
3671
|
if (!this._open) return;
|
|
3390
3672
|
if (this._resolve) {
|
|
3391
|
-
const
|
|
3673
|
+
const resolve = this._resolve;
|
|
3392
3674
|
this._resolve = null;
|
|
3393
|
-
|
|
3675
|
+
resolve({ value: event, done: false });
|
|
3394
3676
|
} else {
|
|
3395
3677
|
this._buffer.push(event);
|
|
3396
3678
|
}
|
|
@@ -3399,9 +3681,9 @@ var InProcessChatTransport = class {
|
|
|
3399
3681
|
if (!this._open) return;
|
|
3400
3682
|
this._open = false;
|
|
3401
3683
|
if (this._resolve) {
|
|
3402
|
-
const
|
|
3684
|
+
const resolve = this._resolve;
|
|
3403
3685
|
this._resolve = null;
|
|
3404
|
-
|
|
3686
|
+
resolve({ value: void 0, done: true });
|
|
3405
3687
|
}
|
|
3406
3688
|
}
|
|
3407
3689
|
error(err) {
|
|
@@ -3413,9 +3695,9 @@ var InProcessChatTransport = class {
|
|
|
3413
3695
|
recoverable: false
|
|
3414
3696
|
};
|
|
3415
3697
|
if (this._resolve) {
|
|
3416
|
-
const
|
|
3698
|
+
const resolve = this._resolve;
|
|
3417
3699
|
this._resolve = null;
|
|
3418
|
-
|
|
3700
|
+
resolve({ value: errorEvent, done: false });
|
|
3419
3701
|
} else {
|
|
3420
3702
|
this._error = err;
|
|
3421
3703
|
}
|
|
@@ -3440,8 +3722,8 @@ var InProcessChatTransport = class {
|
|
|
3440
3722
|
if (!this._open) {
|
|
3441
3723
|
return Promise.resolve({ value: void 0, done: true });
|
|
3442
3724
|
}
|
|
3443
|
-
return new Promise((
|
|
3444
|
-
this._resolve =
|
|
3725
|
+
return new Promise((resolve) => {
|
|
3726
|
+
this._resolve = resolve;
|
|
3445
3727
|
});
|
|
3446
3728
|
}
|
|
3447
3729
|
};
|
|
@@ -3496,6 +3778,6 @@ function withInterceptors(transport, interceptors) {
|
|
|
3496
3778
|
return new InterceptedTransport(transport, interceptors);
|
|
3497
3779
|
}
|
|
3498
3780
|
|
|
3499
|
-
export { BaseBackendAdapter, ClaudeChatAdapter, CopilotChatAdapter, InProcessChatTransport, SSEChatTransport, VercelAIChatAdapter, WS_READY_STATE, WsChatTransport, streamToTransport, withInterceptors };
|
|
3781
|
+
export { BaseBackendAdapter, ClaudeChatAdapter, CopilotChatAdapter, InProcessChatTransport, MockLLMChatAdapter, ResumableChatAdapter, SSEChatTransport, VercelAIChatAdapter, WS_READY_STATE, WsChatTransport, isResumableBackend, streamToTransport, withInterceptors };
|
|
3500
3782
|
//# sourceMappingURL=backends.js.map
|
|
3501
3783
|
//# sourceMappingURL=backends.js.map
|