@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.cjs
CHANGED
|
@@ -1,31 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fs = require('fs');
|
|
4
|
-
var path = require('path');
|
|
5
|
-
var os = require('os');
|
|
6
|
-
|
|
7
|
-
function _interopNamespace(e) {
|
|
8
|
-
if (e && e.__esModule) return e;
|
|
9
|
-
var n = Object.create(null);
|
|
10
|
-
if (e) {
|
|
11
|
-
Object.keys(e).forEach(function (k) {
|
|
12
|
-
if (k !== 'default') {
|
|
13
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
get: function () { return e[k]; }
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
n.default = e;
|
|
22
|
-
return Object.freeze(n);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
26
|
-
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
27
|
-
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
28
|
-
|
|
29
3
|
var __defProp = Object.defineProperty;
|
|
30
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
31
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -47,16 +21,69 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
47
21
|
};
|
|
48
22
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
49
23
|
|
|
50
|
-
// src/errors.ts
|
|
51
|
-
|
|
24
|
+
// src/types/errors.ts
|
|
25
|
+
function isRecoverableErrorCode(code) {
|
|
26
|
+
return RECOVERABLE_CODES.has(code);
|
|
27
|
+
}
|
|
28
|
+
function classifyAgentError(error) {
|
|
29
|
+
const msg = (error instanceof Error ? error.message : error).toLowerCase();
|
|
30
|
+
if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
|
|
31
|
+
return "TIMEOUT" /* TIMEOUT */;
|
|
32
|
+
}
|
|
33
|
+
if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
|
|
34
|
+
return "RATE_LIMIT" /* RATE_LIMIT */;
|
|
35
|
+
}
|
|
36
|
+
if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
|
|
37
|
+
return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
|
|
38
|
+
}
|
|
39
|
+
if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
|
|
40
|
+
return "NETWORK" /* NETWORK */;
|
|
41
|
+
}
|
|
42
|
+
if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
|
|
43
|
+
return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
|
|
44
|
+
}
|
|
45
|
+
if (msg.includes("abort") || msg.includes("cancel")) {
|
|
46
|
+
return "ABORTED" /* ABORTED */;
|
|
47
|
+
}
|
|
48
|
+
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")) {
|
|
49
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
50
|
+
}
|
|
51
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
52
|
+
}
|
|
53
|
+
var RECOVERABLE_CODES;
|
|
52
54
|
var init_errors = __esm({
|
|
55
|
+
"src/types/errors.ts"() {
|
|
56
|
+
RECOVERABLE_CODES = /* @__PURE__ */ new Set([
|
|
57
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
58
|
+
"RATE_LIMIT" /* RATE_LIMIT */,
|
|
59
|
+
"NETWORK" /* NETWORK */,
|
|
60
|
+
"TOOL_EXECUTION" /* TOOL_EXECUTION */,
|
|
61
|
+
"MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
|
|
62
|
+
"PROVIDER_ERROR" /* PROVIDER_ERROR */
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// src/errors.ts
|
|
68
|
+
var AgentSDKError, ReentrancyError, DisposedError, SubprocessError, DependencyError, AbortError, ToolExecutionError, ActivityTimeoutError;
|
|
69
|
+
var init_errors2 = __esm({
|
|
53
70
|
"src/errors.ts"() {
|
|
71
|
+
init_errors();
|
|
54
72
|
AgentSDKError = class extends Error {
|
|
55
73
|
/** @internal Marker for cross-bundle identity checks */
|
|
56
74
|
_agentSDKError = true;
|
|
75
|
+
/** Machine-readable error code. Prefer values from the ErrorCode enum. */
|
|
76
|
+
code;
|
|
77
|
+
/** Whether this error is safe to retry */
|
|
78
|
+
retryable;
|
|
79
|
+
/** HTTP status code hint for error classification */
|
|
80
|
+
httpStatus;
|
|
57
81
|
constructor(message, options) {
|
|
58
82
|
super(message, options);
|
|
59
83
|
this.name = "AgentSDKError";
|
|
84
|
+
this.code = options?.code;
|
|
85
|
+
this.retryable = options?.retryable ?? false;
|
|
86
|
+
this.httpStatus = options?.httpStatus;
|
|
60
87
|
}
|
|
61
88
|
/** Check if an error is an AgentSDKError (works across bundled copies) */
|
|
62
89
|
static is(error) {
|
|
@@ -65,83 +92,84 @@ var init_errors = __esm({
|
|
|
65
92
|
};
|
|
66
93
|
ReentrancyError = class extends AgentSDKError {
|
|
67
94
|
constructor() {
|
|
68
|
-
super("Agent is already running. Await the current run before starting another."
|
|
95
|
+
super("Agent is already running. Await the current run before starting another.", {
|
|
96
|
+
code: "REENTRANCY" /* REENTRANCY */
|
|
97
|
+
});
|
|
69
98
|
this.name = "ReentrancyError";
|
|
70
99
|
}
|
|
71
100
|
};
|
|
72
101
|
DisposedError = class extends AgentSDKError {
|
|
73
102
|
constructor(entity) {
|
|
74
|
-
super(`${entity} has been disposed and cannot be used
|
|
103
|
+
super(`${entity} has been disposed and cannot be used.`, {
|
|
104
|
+
code: "DISPOSED" /* DISPOSED */
|
|
105
|
+
});
|
|
75
106
|
this.name = "DisposedError";
|
|
76
107
|
}
|
|
77
108
|
};
|
|
78
|
-
BackendNotFoundError = class extends AgentSDKError {
|
|
79
|
-
constructor(backend) {
|
|
80
|
-
super(
|
|
81
|
-
`Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`
|
|
82
|
-
);
|
|
83
|
-
this.name = "BackendNotFoundError";
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
BackendAlreadyRegisteredError = class extends AgentSDKError {
|
|
87
|
-
constructor(backend) {
|
|
88
|
-
super(`Backend "${backend}" is already registered. Use a different name or unregister first.`);
|
|
89
|
-
this.name = "BackendAlreadyRegisteredError";
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
109
|
SubprocessError = class extends AgentSDKError {
|
|
93
110
|
constructor(message, options) {
|
|
94
|
-
super(message, options);
|
|
111
|
+
super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
|
|
95
112
|
this.name = "SubprocessError";
|
|
96
113
|
}
|
|
97
114
|
};
|
|
98
115
|
DependencyError = class extends AgentSDKError {
|
|
99
116
|
packageName;
|
|
100
117
|
constructor(packageName) {
|
|
101
|
-
super(`${packageName} is not installed. Install it: npm install ${packageName}
|
|
118
|
+
super(`${packageName} is not installed. Install it: npm install ${packageName}`, {
|
|
119
|
+
code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */
|
|
120
|
+
});
|
|
102
121
|
this.name = "DependencyError";
|
|
103
122
|
this.packageName = packageName;
|
|
104
123
|
}
|
|
105
124
|
};
|
|
106
125
|
AbortError = class extends AgentSDKError {
|
|
107
126
|
constructor() {
|
|
108
|
-
super("Agent run was aborted.");
|
|
127
|
+
super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
|
|
109
128
|
this.name = "AbortError";
|
|
110
129
|
}
|
|
111
130
|
};
|
|
112
131
|
ToolExecutionError = class extends AgentSDKError {
|
|
113
132
|
toolName;
|
|
114
133
|
constructor(toolName, message, options) {
|
|
115
|
-
super(`Tool "${toolName}" failed: ${message}`, options);
|
|
134
|
+
super(`Tool "${toolName}" failed: ${message}`, { ...options, code: "TOOL_EXECUTION" /* TOOL_EXECUTION */ });
|
|
116
135
|
this.name = "ToolExecutionError";
|
|
117
136
|
this.toolName = toolName;
|
|
118
137
|
}
|
|
119
138
|
};
|
|
120
|
-
|
|
121
|
-
constructor(
|
|
122
|
-
super(`
|
|
123
|
-
|
|
139
|
+
ActivityTimeoutError = class extends AgentSDKError {
|
|
140
|
+
constructor(timeoutMs) {
|
|
141
|
+
super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
|
|
142
|
+
code: "TIMEOUT" /* TIMEOUT */,
|
|
143
|
+
retryable: true
|
|
144
|
+
});
|
|
145
|
+
this.name = "ActivityTimeoutError";
|
|
124
146
|
}
|
|
125
147
|
};
|
|
126
148
|
}
|
|
127
149
|
});
|
|
128
150
|
|
|
129
|
-
// src/types.ts
|
|
130
|
-
function isToolDefinition(tool) {
|
|
131
|
-
return "execute" in tool && typeof tool.execute === "function";
|
|
132
|
-
}
|
|
133
|
-
function isTextContent(content) {
|
|
134
|
-
return typeof content === "string";
|
|
135
|
-
}
|
|
136
|
-
function isMultiPartContent(content) {
|
|
137
|
-
return Array.isArray(content);
|
|
138
|
-
}
|
|
151
|
+
// src/types/guards.ts
|
|
139
152
|
function getTextContent(content) {
|
|
140
153
|
if (typeof content === "string") return content;
|
|
141
154
|
return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
142
155
|
}
|
|
156
|
+
var init_guards = __esm({
|
|
157
|
+
"src/types/guards.ts"() {
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// src/types/index.ts
|
|
143
162
|
var init_types = __esm({
|
|
163
|
+
"src/types/index.ts"() {
|
|
164
|
+
init_errors();
|
|
165
|
+
init_guards();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// src/types.ts
|
|
170
|
+
var init_types2 = __esm({
|
|
144
171
|
"src/types.ts"() {
|
|
172
|
+
init_types();
|
|
145
173
|
}
|
|
146
174
|
});
|
|
147
175
|
|
|
@@ -149,12 +177,15 @@ var init_types = __esm({
|
|
|
149
177
|
var BaseAgent;
|
|
150
178
|
var init_base_agent = __esm({
|
|
151
179
|
"src/base-agent.ts"() {
|
|
180
|
+
init_errors2();
|
|
181
|
+
init_errors2();
|
|
152
182
|
init_errors();
|
|
153
183
|
BaseAgent = class {
|
|
154
184
|
state = "idle";
|
|
155
185
|
abortController = null;
|
|
156
186
|
config;
|
|
157
187
|
_cleanupExternalSignal = null;
|
|
188
|
+
_streamMiddleware = [];
|
|
158
189
|
/** CLI session ID for persistent mode. Override in backends that support it. */
|
|
159
190
|
get sessionId() {
|
|
160
191
|
return void 0;
|
|
@@ -170,8 +201,11 @@ var init_base_agent = __esm({
|
|
|
170
201
|
this.state = "running";
|
|
171
202
|
try {
|
|
172
203
|
const messages = [{ role: "user", content: prompt }];
|
|
173
|
-
const result = await this.
|
|
174
|
-
|
|
204
|
+
const result = await this.withRetry(
|
|
205
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
206
|
+
options
|
|
207
|
+
);
|
|
208
|
+
this.enrichAndNotifyUsage(result, options);
|
|
175
209
|
return result;
|
|
176
210
|
} finally {
|
|
177
211
|
this.cleanupRun();
|
|
@@ -183,8 +217,11 @@ var init_base_agent = __esm({
|
|
|
183
217
|
const ac = this.createAbortController(options?.signal);
|
|
184
218
|
this.state = "running";
|
|
185
219
|
try {
|
|
186
|
-
const result = await this.
|
|
187
|
-
|
|
220
|
+
const result = await this.withRetry(
|
|
221
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
222
|
+
options
|
|
223
|
+
);
|
|
224
|
+
this.enrichAndNotifyUsage(result, options);
|
|
188
225
|
return result;
|
|
189
226
|
} finally {
|
|
190
227
|
this.cleanupRun();
|
|
@@ -197,13 +234,11 @@ var init_base_agent = __esm({
|
|
|
197
234
|
this.state = "running";
|
|
198
235
|
try {
|
|
199
236
|
const messages = [{ role: "user", content: prompt }];
|
|
200
|
-
const result = await this.
|
|
201
|
-
messages,
|
|
202
|
-
|
|
203
|
-
options,
|
|
204
|
-
ac.signal
|
|
237
|
+
const result = await this.withRetry(
|
|
238
|
+
() => this.executeRunStructured(messages, schema, options, ac.signal),
|
|
239
|
+
options
|
|
205
240
|
);
|
|
206
|
-
this.enrichAndNotifyUsage(result);
|
|
241
|
+
this.enrichAndNotifyUsage(result, options);
|
|
207
242
|
return result;
|
|
208
243
|
} finally {
|
|
209
244
|
this.cleanupRun();
|
|
@@ -216,8 +251,10 @@ var init_base_agent = __esm({
|
|
|
216
251
|
this.state = "streaming";
|
|
217
252
|
try {
|
|
218
253
|
const messages = [{ role: "user", content: prompt }];
|
|
219
|
-
|
|
220
|
-
|
|
254
|
+
yield* this.streamWithRetry(
|
|
255
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
256
|
+
options
|
|
257
|
+
);
|
|
221
258
|
} finally {
|
|
222
259
|
this.cleanupRun();
|
|
223
260
|
}
|
|
@@ -228,12 +265,37 @@ var init_base_agent = __esm({
|
|
|
228
265
|
const ac = this.createAbortController(options?.signal);
|
|
229
266
|
this.state = "streaming";
|
|
230
267
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
268
|
+
yield* this.streamWithRetry(
|
|
269
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
270
|
+
options
|
|
271
|
+
);
|
|
233
272
|
} finally {
|
|
234
273
|
this.cleanupRun();
|
|
235
274
|
}
|
|
236
275
|
}
|
|
276
|
+
/** Register a stream middleware. Applied in registration order after built-in transforms. */
|
|
277
|
+
addStreamMiddleware(middleware) {
|
|
278
|
+
this.guardDisposed();
|
|
279
|
+
this._streamMiddleware.push(middleware);
|
|
280
|
+
}
|
|
281
|
+
/** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
|
|
282
|
+
async *applyStreamPipeline(source, options, ac) {
|
|
283
|
+
let stream = this.enrichStream(source, options);
|
|
284
|
+
stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
|
|
285
|
+
stream = this.heartbeatStream(stream);
|
|
286
|
+
if (this._streamMiddleware.length > 0) {
|
|
287
|
+
const ctx = {
|
|
288
|
+
model: options.model,
|
|
289
|
+
backend: this.backendName,
|
|
290
|
+
abortController: ac,
|
|
291
|
+
config: Object.freeze({ ...this.config })
|
|
292
|
+
};
|
|
293
|
+
for (const mw of this._streamMiddleware) {
|
|
294
|
+
stream = mw(stream, ctx);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
yield* stream;
|
|
298
|
+
}
|
|
237
299
|
abort() {
|
|
238
300
|
if (this.abortController) {
|
|
239
301
|
this.abortController.abort();
|
|
@@ -256,26 +318,109 @@ var init_base_agent = __esm({
|
|
|
256
318
|
this.abort();
|
|
257
319
|
this.state = "disposed";
|
|
258
320
|
}
|
|
321
|
+
// ─── Retry Logic ─────────────────────────────────────────────
|
|
322
|
+
/** Check if an error should be retried given the retry configuration. */
|
|
323
|
+
isRetryableError(error, retry) {
|
|
324
|
+
if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
if (AgentSDKError.is(error)) {
|
|
328
|
+
if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
|
|
329
|
+
return retry.retryableErrors.includes(error.code);
|
|
330
|
+
}
|
|
331
|
+
if (error.retryable) return true;
|
|
332
|
+
if (error.code) return isRecoverableErrorCode(error.code);
|
|
333
|
+
}
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
/** Execute a function with retry logic per RetryConfig. */
|
|
337
|
+
async withRetry(fn, options) {
|
|
338
|
+
const retry = options?.retry;
|
|
339
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
340
|
+
return fn();
|
|
341
|
+
}
|
|
342
|
+
const maxRetries = retry.maxRetries;
|
|
343
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
344
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
345
|
+
let lastError;
|
|
346
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
347
|
+
try {
|
|
348
|
+
return await fn();
|
|
349
|
+
} catch (err) {
|
|
350
|
+
lastError = err;
|
|
351
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
352
|
+
throw err;
|
|
353
|
+
}
|
|
354
|
+
const delay = initialDelay * Math.pow(multiplier, attempt);
|
|
355
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
356
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
357
|
+
throw err;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
throw lastError;
|
|
362
|
+
}
|
|
363
|
+
/** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
|
|
364
|
+
async *streamWithRetry(factory, options) {
|
|
365
|
+
const retry = options?.retry;
|
|
366
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
367
|
+
yield* factory();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const maxRetries = retry.maxRetries;
|
|
371
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
372
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
373
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
374
|
+
try {
|
|
375
|
+
const stream = factory();
|
|
376
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
377
|
+
const first = await iterator.next();
|
|
378
|
+
if (first.done) return;
|
|
379
|
+
yield first.value;
|
|
380
|
+
while (true) {
|
|
381
|
+
const next = await iterator.next();
|
|
382
|
+
if (next.done) break;
|
|
383
|
+
yield next.value;
|
|
384
|
+
}
|
|
385
|
+
return;
|
|
386
|
+
} catch (err) {
|
|
387
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
388
|
+
throw err;
|
|
389
|
+
}
|
|
390
|
+
const delay = initialDelay * Math.pow(multiplier, attempt);
|
|
391
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
392
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
393
|
+
throw err;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// ─── CallOptions Resolution ──────────────────────────────────
|
|
399
|
+
/** Resolve tools to use for this call (per-call override > config default) */
|
|
400
|
+
resolveTools(options) {
|
|
401
|
+
return options?.tools ?? this.config.tools ?? [];
|
|
402
|
+
}
|
|
259
403
|
// ─── Usage Enrichment ───────────────────────────────────────────
|
|
260
404
|
/** Enrich result usage with model/backend and fire onUsage callback */
|
|
261
|
-
enrichAndNotifyUsage(result) {
|
|
405
|
+
enrichAndNotifyUsage(result, options) {
|
|
262
406
|
if (result.usage) {
|
|
263
407
|
result.usage = {
|
|
264
408
|
...result.usage,
|
|
265
|
-
model:
|
|
409
|
+
model: options.model,
|
|
266
410
|
backend: this.backendName
|
|
267
411
|
};
|
|
268
412
|
this.callOnUsage(result.usage);
|
|
269
413
|
}
|
|
270
414
|
}
|
|
271
415
|
/** Wrap a stream to enrich usage_update events and fire onUsage callback */
|
|
272
|
-
async *enrichStream(source) {
|
|
416
|
+
async *enrichStream(source, options) {
|
|
417
|
+
const model = options.model;
|
|
273
418
|
for await (const event of source) {
|
|
274
419
|
if (event.type === "usage_update") {
|
|
275
420
|
const usage = {
|
|
276
421
|
promptTokens: event.promptTokens,
|
|
277
422
|
completionTokens: event.completionTokens,
|
|
278
|
-
model
|
|
423
|
+
model,
|
|
279
424
|
backend: this.backendName
|
|
280
425
|
};
|
|
281
426
|
this.callOnUsage(usage);
|
|
@@ -311,9 +456,9 @@ var init_base_agent = __esm({
|
|
|
311
456
|
let heartbeatResolve = null;
|
|
312
457
|
const timer = setInterval(() => {
|
|
313
458
|
if (heartbeatResolve) {
|
|
314
|
-
const
|
|
459
|
+
const resolve = heartbeatResolve;
|
|
315
460
|
heartbeatResolve = null;
|
|
316
|
-
|
|
461
|
+
resolve();
|
|
317
462
|
}
|
|
318
463
|
}, interval);
|
|
319
464
|
try {
|
|
@@ -321,8 +466,8 @@ var init_base_agent = __esm({
|
|
|
321
466
|
if (!pendingEvent) {
|
|
322
467
|
pendingEvent = iterator.next();
|
|
323
468
|
}
|
|
324
|
-
const heartbeatPromise = new Promise((
|
|
325
|
-
heartbeatResolve =
|
|
469
|
+
const heartbeatPromise = new Promise((resolve) => {
|
|
470
|
+
heartbeatResolve = resolve;
|
|
326
471
|
});
|
|
327
472
|
const eventDone = pendingEvent.then(
|
|
328
473
|
(r) => ({ kind: "event", result: r })
|
|
@@ -345,6 +490,35 @@ var init_base_agent = __esm({
|
|
|
345
490
|
heartbeatResolve = null;
|
|
346
491
|
}
|
|
347
492
|
}
|
|
493
|
+
// ─── Activity Timeout ────────────────────────────────────────
|
|
494
|
+
/** Wrap a stream to abort on inactivity. Resets timer on every event.
|
|
495
|
+
* When timeoutMs is not set, passes through directly. */
|
|
496
|
+
async *activityTimeoutStream(source, timeoutMs, ac) {
|
|
497
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
498
|
+
yield* source;
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
502
|
+
let timerId;
|
|
503
|
+
try {
|
|
504
|
+
while (true) {
|
|
505
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
506
|
+
timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
|
|
507
|
+
});
|
|
508
|
+
const result = await Promise.race([iterator.next(), timeoutPromise]);
|
|
509
|
+
clearTimeout(timerId);
|
|
510
|
+
if (result.done) break;
|
|
511
|
+
yield result.value;
|
|
512
|
+
}
|
|
513
|
+
} catch (err) {
|
|
514
|
+
if (err instanceof ActivityTimeoutError) {
|
|
515
|
+
ac.abort(err);
|
|
516
|
+
}
|
|
517
|
+
throw err;
|
|
518
|
+
} finally {
|
|
519
|
+
clearTimeout(timerId);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
348
522
|
// ─── Guards ───────────────────────────────────────────────────
|
|
349
523
|
guardReentrancy() {
|
|
350
524
|
if (this.state === "running" || this.state === "streaming") {
|
|
@@ -449,6 +623,66 @@ var init_schema = __esm({
|
|
|
449
623
|
}
|
|
450
624
|
});
|
|
451
625
|
|
|
626
|
+
// src/backends/shared.ts
|
|
627
|
+
function extractLastUserPrompt(messages) {
|
|
628
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
629
|
+
const msg = messages[i];
|
|
630
|
+
if (msg.role === "user") {
|
|
631
|
+
return getTextContent(msg.content);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return "";
|
|
635
|
+
}
|
|
636
|
+
function serializeToolCall(tc) {
|
|
637
|
+
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
638
|
+
return ` Tool call: ${tc.name}(${args})`;
|
|
639
|
+
}
|
|
640
|
+
function serializeToolResult(tr) {
|
|
641
|
+
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
642
|
+
const prefix = tr.isError ? "[ERROR] " : "";
|
|
643
|
+
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
644
|
+
}
|
|
645
|
+
function buildContextualPrompt(messages) {
|
|
646
|
+
if (messages.length <= 1) {
|
|
647
|
+
return extractLastUserPrompt(messages);
|
|
648
|
+
}
|
|
649
|
+
const history = messages.slice(0, -1).map((msg) => {
|
|
650
|
+
if (msg.role === "user") {
|
|
651
|
+
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
652
|
+
}
|
|
653
|
+
if (msg.role === "tool" && msg.toolResults) {
|
|
654
|
+
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
655
|
+
return `Tool results:
|
|
656
|
+
${results}`;
|
|
657
|
+
}
|
|
658
|
+
if (msg.role === "assistant") {
|
|
659
|
+
const parts = [];
|
|
660
|
+
const thinking = msg.thinking;
|
|
661
|
+
if (thinking) {
|
|
662
|
+
parts.push(`[reasoning: ${thinking}]`);
|
|
663
|
+
}
|
|
664
|
+
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
665
|
+
if (text2) parts.push(text2);
|
|
666
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
667
|
+
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
668
|
+
}
|
|
669
|
+
return `Assistant: ${parts.join("\n")}`;
|
|
670
|
+
}
|
|
671
|
+
const text = msg.content ? getTextContent(msg.content) : "";
|
|
672
|
+
return `${msg.role}: ${text}`;
|
|
673
|
+
}).join("\n");
|
|
674
|
+
const lastPrompt = extractLastUserPrompt(messages);
|
|
675
|
+
return `Conversation history:
|
|
676
|
+
${history}
|
|
677
|
+
|
|
678
|
+
User: ${lastPrompt}`;
|
|
679
|
+
}
|
|
680
|
+
var init_shared = __esm({
|
|
681
|
+
"src/backends/shared.ts"() {
|
|
682
|
+
init_types2();
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
|
|
452
686
|
// src/backends/copilot.ts
|
|
453
687
|
var copilot_exports = {};
|
|
454
688
|
__export(copilot_exports, {
|
|
@@ -457,10 +691,9 @@ __export(copilot_exports, {
|
|
|
457
691
|
createCopilotService: () => createCopilotService
|
|
458
692
|
});
|
|
459
693
|
async function loadSDK() {
|
|
460
|
-
if (
|
|
694
|
+
if (_sdkMock) return _sdkMock;
|
|
461
695
|
try {
|
|
462
|
-
|
|
463
|
-
return sdkModule;
|
|
696
|
+
return await import('@github/copilot-sdk');
|
|
464
697
|
} catch {
|
|
465
698
|
throw new SubprocessError(
|
|
466
699
|
"@github/copilot-sdk is not installed. Install it: npm install @github/copilot-sdk"
|
|
@@ -468,10 +701,10 @@ async function loadSDK() {
|
|
|
468
701
|
}
|
|
469
702
|
}
|
|
470
703
|
function _injectSDK(mock) {
|
|
471
|
-
|
|
704
|
+
_sdkMock = mock;
|
|
472
705
|
}
|
|
473
706
|
function _resetSDK() {
|
|
474
|
-
|
|
707
|
+
_sdkMock = null;
|
|
475
708
|
}
|
|
476
709
|
function mapToolsToSDK(tools) {
|
|
477
710
|
return tools.map((tool) => ({
|
|
@@ -491,17 +724,6 @@ function convertParameters(params) {
|
|
|
491
724
|
}
|
|
492
725
|
return params;
|
|
493
726
|
}
|
|
494
|
-
async function mapToolsToSDKAsync(tools) {
|
|
495
|
-
return tools.map((tool) => ({
|
|
496
|
-
name: tool.name,
|
|
497
|
-
description: tool.description,
|
|
498
|
-
parameters: convertParameters(tool.parameters),
|
|
499
|
-
handler: async (args) => {
|
|
500
|
-
const result = await tool.execute(args);
|
|
501
|
-
return typeof result === "string" ? result : JSON.stringify(result);
|
|
502
|
-
}
|
|
503
|
-
}));
|
|
504
|
-
}
|
|
505
727
|
function buildPermissionHandler(config) {
|
|
506
728
|
const onPermission = config.supervisor?.onPermission;
|
|
507
729
|
if (!onPermission) {
|
|
@@ -516,6 +738,7 @@ function buildPermissionHandler(config) {
|
|
|
516
738
|
const unifiedRequest = {
|
|
517
739
|
toolName,
|
|
518
740
|
toolArgs: { ...request },
|
|
741
|
+
toolCallId: request.toolCallId,
|
|
519
742
|
rawSDKRequest: request
|
|
520
743
|
};
|
|
521
744
|
const ac = new AbortController();
|
|
@@ -620,15 +843,21 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
620
843
|
};
|
|
621
844
|
case "session.error":
|
|
622
845
|
console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
846
|
+
{
|
|
847
|
+
const errorMsg = String(data.message ?? "Unknown error");
|
|
848
|
+
const code = classifyAgentError(errorMsg);
|
|
849
|
+
return {
|
|
850
|
+
type: "error",
|
|
851
|
+
error: errorMsg,
|
|
852
|
+
recoverable: isRecoverableErrorCode(code),
|
|
853
|
+
code
|
|
854
|
+
};
|
|
855
|
+
}
|
|
628
856
|
case "assistant.message": {
|
|
629
857
|
const doneEvent = {
|
|
630
858
|
type: "done",
|
|
631
|
-
finalOutput:
|
|
859
|
+
finalOutput: null,
|
|
860
|
+
streamed: true
|
|
632
861
|
};
|
|
633
862
|
if (thinkingTracker.endThinking()) {
|
|
634
863
|
return [{ type: "thinking_end" }, doneEvent];
|
|
@@ -639,66 +868,13 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
639
868
|
return null;
|
|
640
869
|
}
|
|
641
870
|
}
|
|
642
|
-
function extractLastUserPrompt(messages) {
|
|
643
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
644
|
-
const msg = messages[i];
|
|
645
|
-
if (msg.role === "user") {
|
|
646
|
-
return getTextContent(msg.content);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
return "";
|
|
650
|
-
}
|
|
651
|
-
function serializeToolCall(tc) {
|
|
652
|
-
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
653
|
-
return ` Tool call: ${tc.name}(${args})`;
|
|
654
|
-
}
|
|
655
|
-
function serializeToolResult(tr) {
|
|
656
|
-
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
657
|
-
const prefix = tr.isError ? "[ERROR] " : "";
|
|
658
|
-
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
659
|
-
}
|
|
660
|
-
function buildContextualPrompt(messages) {
|
|
661
|
-
if (messages.length <= 1) {
|
|
662
|
-
return extractLastUserPrompt(messages);
|
|
663
|
-
}
|
|
664
|
-
const history = messages.slice(0, -1).map((msg) => {
|
|
665
|
-
if (msg.role === "user") {
|
|
666
|
-
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
667
|
-
}
|
|
668
|
-
if (msg.role === "tool" && msg.toolResults) {
|
|
669
|
-
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
670
|
-
return `Tool results:
|
|
671
|
-
${results}`;
|
|
672
|
-
}
|
|
673
|
-
if (msg.role === "assistant") {
|
|
674
|
-
const parts = [];
|
|
675
|
-
const thinking = msg.thinking;
|
|
676
|
-
if (thinking) {
|
|
677
|
-
parts.push(`[reasoning: ${thinking}]`);
|
|
678
|
-
}
|
|
679
|
-
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
680
|
-
if (text2) parts.push(text2);
|
|
681
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
682
|
-
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
683
|
-
}
|
|
684
|
-
return `Assistant: ${parts.join("\n")}`;
|
|
685
|
-
}
|
|
686
|
-
const text = msg.content ? getTextContent(msg.content) : "";
|
|
687
|
-
return `${msg.role}: ${text}`;
|
|
688
|
-
}).join("\n");
|
|
689
|
-
const lastPrompt = extractLastUserPrompt(messages);
|
|
690
|
-
return `Conversation history:
|
|
691
|
-
${history}
|
|
692
|
-
|
|
693
|
-
User: ${lastPrompt}`;
|
|
694
|
-
}
|
|
695
871
|
function withTimeout(promise, ms, message) {
|
|
696
|
-
return new Promise((
|
|
872
|
+
return new Promise((resolve, reject) => {
|
|
697
873
|
const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
|
|
698
874
|
promise.then(
|
|
699
875
|
(val) => {
|
|
700
876
|
clearTimeout(timer);
|
|
701
|
-
|
|
877
|
+
resolve(val);
|
|
702
878
|
},
|
|
703
879
|
(err) => {
|
|
704
880
|
clearTimeout(timer);
|
|
@@ -710,14 +886,15 @@ function withTimeout(promise, ms, message) {
|
|
|
710
886
|
function createCopilotService(options) {
|
|
711
887
|
return new CopilotAgentService(options);
|
|
712
888
|
}
|
|
713
|
-
var
|
|
889
|
+
var _sdkMock, ToolCallTracker, ThinkingTracker, CopilotAgent, CopilotAgentService;
|
|
714
890
|
var init_copilot = __esm({
|
|
715
891
|
"src/backends/copilot.ts"() {
|
|
716
|
-
|
|
892
|
+
init_types2();
|
|
717
893
|
init_base_agent();
|
|
718
|
-
|
|
894
|
+
init_errors2();
|
|
719
895
|
init_schema();
|
|
720
|
-
|
|
896
|
+
init_shared();
|
|
897
|
+
_sdkMock = null;
|
|
721
898
|
ToolCallTracker = class {
|
|
722
899
|
map = /* @__PURE__ */ new Map();
|
|
723
900
|
trackStart(toolCallId, toolName, args) {
|
|
@@ -765,6 +942,7 @@ var init_copilot = __esm({
|
|
|
765
942
|
isPersistent;
|
|
766
943
|
persistentSession = null;
|
|
767
944
|
_sessionId;
|
|
945
|
+
_persistentModel;
|
|
768
946
|
activeSession = null;
|
|
769
947
|
_resumeSessionId;
|
|
770
948
|
_toolsReady = null;
|
|
@@ -783,15 +961,15 @@ var init_copilot = __esm({
|
|
|
783
961
|
},
|
|
784
962
|
onPermissionRequest: buildPermissionHandler(config),
|
|
785
963
|
onUserInputRequest: buildUserInputHandler(config),
|
|
786
|
-
...config.availableTools
|
|
964
|
+
...config.availableTools ? { availableTools: config.availableTools } : {}
|
|
787
965
|
};
|
|
788
966
|
this._toolsReady = this._initToolsAsync(config);
|
|
789
967
|
this._resumeSessionId = resumeSessionId;
|
|
790
968
|
}
|
|
791
|
-
/** Pre-convert Zod schemas to JSON Schema
|
|
969
|
+
/** Pre-convert Zod schemas to JSON Schema.
|
|
792
970
|
* Updates sdkTools and sessionConfig.tools before first session creation. */
|
|
793
971
|
async _initToolsAsync(config) {
|
|
794
|
-
this.sdkTools =
|
|
972
|
+
this.sdkTools = mapToolsToSDK(config.tools ?? []);
|
|
795
973
|
this.sessionConfig.tools = this.sdkTools;
|
|
796
974
|
}
|
|
797
975
|
get sessionId() {
|
|
@@ -815,47 +993,63 @@ var init_copilot = __esm({
|
|
|
815
993
|
});
|
|
816
994
|
this.persistentSession = null;
|
|
817
995
|
this._sessionId = void 0;
|
|
996
|
+
this._persistentModel = void 0;
|
|
818
997
|
}
|
|
819
998
|
}
|
|
820
|
-
async getOrCreateSession(streaming) {
|
|
999
|
+
async getOrCreateSession(streaming, options) {
|
|
821
1000
|
if (this.isPersistent && this.persistentSession) {
|
|
822
|
-
|
|
1001
|
+
if (options.model !== this._persistentModel) {
|
|
1002
|
+
this.persistentSession.destroy().catch(() => {
|
|
1003
|
+
});
|
|
1004
|
+
this.persistentSession = null;
|
|
1005
|
+
this._sessionId = void 0;
|
|
1006
|
+
} else {
|
|
1007
|
+
return { session: this.persistentSession, isNew: false };
|
|
1008
|
+
}
|
|
823
1009
|
}
|
|
824
1010
|
if (this._toolsReady) {
|
|
825
1011
|
await this._toolsReady;
|
|
826
1012
|
this._toolsReady = null;
|
|
827
1013
|
}
|
|
1014
|
+
const sessionConfig = { ...this.sessionConfig };
|
|
1015
|
+
sessionConfig.model = options.model;
|
|
1016
|
+
const resolvedTools = this.resolveTools(options);
|
|
1017
|
+
if (options?.tools) {
|
|
1018
|
+
sessionConfig.tools = mapToolsToSDK(resolvedTools);
|
|
1019
|
+
}
|
|
828
1020
|
const client = await this.getClient();
|
|
829
1021
|
if (this._resumeSessionId) {
|
|
830
1022
|
const storedId = this._resumeSessionId;
|
|
831
1023
|
this._resumeSessionId = void 0;
|
|
832
1024
|
try {
|
|
833
1025
|
const session2 = await client.resumeSession(storedId, {
|
|
834
|
-
...
|
|
1026
|
+
...sessionConfig,
|
|
835
1027
|
streaming: this.isPersistent ? true : streaming
|
|
836
1028
|
});
|
|
837
1029
|
if (this.isPersistent) {
|
|
838
1030
|
this.persistentSession = session2;
|
|
839
1031
|
this._sessionId = session2.sessionId;
|
|
1032
|
+
this._persistentModel = options.model;
|
|
840
1033
|
}
|
|
841
1034
|
return { session: session2, isNew: false };
|
|
842
1035
|
} catch {
|
|
843
1036
|
}
|
|
844
1037
|
}
|
|
845
1038
|
const session = await client.createSession({
|
|
846
|
-
...
|
|
1039
|
+
...sessionConfig,
|
|
847
1040
|
streaming: this.isPersistent ? true : streaming
|
|
848
1041
|
});
|
|
849
1042
|
if (this.isPersistent) {
|
|
850
1043
|
this.persistentSession = session;
|
|
851
1044
|
this._sessionId = session.sessionId;
|
|
1045
|
+
this._persistentModel = options.model;
|
|
852
1046
|
}
|
|
853
1047
|
return { session, isNew: true };
|
|
854
1048
|
}
|
|
855
1049
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
856
|
-
async executeRun(messages,
|
|
1050
|
+
async executeRun(messages, options, signal) {
|
|
857
1051
|
this.checkAbort(signal);
|
|
858
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
|
|
1052
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(false, options);
|
|
859
1053
|
this.activeSession = session;
|
|
860
1054
|
const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
861
1055
|
const tracker = new ToolCallTracker();
|
|
@@ -952,9 +1146,9 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
952
1146
|
};
|
|
953
1147
|
}
|
|
954
1148
|
// ─── executeStream ──────────────────────────────────────────────
|
|
955
|
-
async *executeStream(messages,
|
|
1149
|
+
async *executeStream(messages, options, signal) {
|
|
956
1150
|
this.checkAbort(signal);
|
|
957
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
|
|
1151
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(true, options);
|
|
958
1152
|
this.activeSession = session;
|
|
959
1153
|
if (isNewSession) {
|
|
960
1154
|
yield this.emitSessionInfo(session.sessionId);
|
|
@@ -971,8 +1165,8 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
971
1165
|
notify = null;
|
|
972
1166
|
}
|
|
973
1167
|
};
|
|
974
|
-
const waitForItem = () => new Promise((
|
|
975
|
-
notify =
|
|
1168
|
+
const waitForItem = () => new Promise((resolve) => {
|
|
1169
|
+
notify = resolve;
|
|
976
1170
|
});
|
|
977
1171
|
const unsubscribe = session.on((event) => {
|
|
978
1172
|
const mapped = mapSessionEvent(event, tracker, thinkingTracker);
|
|
@@ -1066,7 +1260,11 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1066
1260
|
githubToken: this.options.githubToken,
|
|
1067
1261
|
useLoggedInUser: this.options.useLoggedInUser ?? !this.options.githubToken,
|
|
1068
1262
|
...this.options.cliArgs ? { cliArgs: this.options.cliArgs } : {},
|
|
1069
|
-
|
|
1263
|
+
env: {
|
|
1264
|
+
...process.env,
|
|
1265
|
+
...this.options.githubToken ? { GITHUB_TOKEN: this.options.githubToken } : {},
|
|
1266
|
+
...this.options.env
|
|
1267
|
+
}
|
|
1070
1268
|
});
|
|
1071
1269
|
const startupTimeout = this.options.startupTimeoutMs ?? 3e4;
|
|
1072
1270
|
await withTimeout(client.start(), startupTimeout, "CLI startup timed out");
|
|
@@ -1100,7 +1298,10 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1100
1298
|
return models.map((m) => ({
|
|
1101
1299
|
id: m.id,
|
|
1102
1300
|
name: m.name,
|
|
1103
|
-
provider: "copilot"
|
|
1301
|
+
provider: "copilot",
|
|
1302
|
+
...m.capabilities?.limits?.max_context_window_tokens != null && {
|
|
1303
|
+
contextWindow: m.capabilities.limits.max_context_window_tokens
|
|
1304
|
+
}
|
|
1104
1305
|
}));
|
|
1105
1306
|
}
|
|
1106
1307
|
async validate() {
|
|
@@ -1153,10 +1354,9 @@ function stripMcpPrefix(name) {
|
|
|
1153
1354
|
return name.startsWith(MCP_TOOL_PREFIX) ? name.slice(MCP_TOOL_PREFIX.length) : name;
|
|
1154
1355
|
}
|
|
1155
1356
|
async function loadSDK2() {
|
|
1156
|
-
if (
|
|
1357
|
+
if (_sdkMock2) return _sdkMock2;
|
|
1157
1358
|
try {
|
|
1158
|
-
|
|
1159
|
-
return sdkModule2;
|
|
1359
|
+
return await import('@anthropic-ai/claude-agent-sdk');
|
|
1160
1360
|
} catch {
|
|
1161
1361
|
throw new SubprocessError(
|
|
1162
1362
|
"@anthropic-ai/claude-agent-sdk is not installed. Install it: npm install @anthropic-ai/claude-agent-sdk"
|
|
@@ -1164,13 +1364,32 @@ async function loadSDK2() {
|
|
|
1164
1364
|
}
|
|
1165
1365
|
}
|
|
1166
1366
|
function _injectSDK2(mock) {
|
|
1167
|
-
|
|
1367
|
+
_sdkMock2 = mock;
|
|
1168
1368
|
}
|
|
1169
1369
|
function _resetSDK2() {
|
|
1170
|
-
|
|
1370
|
+
_sdkMock2 = null;
|
|
1171
1371
|
}
|
|
1172
|
-
function
|
|
1173
|
-
if (
|
|
1372
|
+
function normalizeAskUserInput(args) {
|
|
1373
|
+
if (typeof args.question === "string") {
|
|
1374
|
+
return {
|
|
1375
|
+
question: args.question,
|
|
1376
|
+
choices: Array.isArray(args.choices) ? args.choices : void 0,
|
|
1377
|
+
allowFreeform: args.allowFreeform !== false
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
const questions = args.questions;
|
|
1381
|
+
if (questions && questions.length > 0) {
|
|
1382
|
+
const first = questions[0];
|
|
1383
|
+
return {
|
|
1384
|
+
question: first.question,
|
|
1385
|
+
choices: first.options?.map((o) => o.label),
|
|
1386
|
+
allowFreeform: true
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
return { question: JSON.stringify(args), allowFreeform: true };
|
|
1390
|
+
}
|
|
1391
|
+
function buildMcpServer(sdk, tools, toolResultCapture, onAskUser) {
|
|
1392
|
+
if (tools.length === 0 && !onAskUser) return void 0;
|
|
1174
1393
|
const mcpTools = tools.map((tool) => {
|
|
1175
1394
|
const zodSchema = tool.parameters;
|
|
1176
1395
|
const inputSchema = zodSchema.shape ?? zodToJsonSchema(tool.parameters);
|
|
@@ -1194,6 +1413,39 @@ function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
|
1194
1413
|
}
|
|
1195
1414
|
);
|
|
1196
1415
|
});
|
|
1416
|
+
if (onAskUser) {
|
|
1417
|
+
const askUserTool = sdk.tool(
|
|
1418
|
+
"ask_user",
|
|
1419
|
+
"Ask the user a question and wait for their response",
|
|
1420
|
+
{
|
|
1421
|
+
question: { type: "string", description: "The question to ask the user" },
|
|
1422
|
+
choices: {
|
|
1423
|
+
type: "array",
|
|
1424
|
+
items: { type: "string" },
|
|
1425
|
+
description: "Optional list of choices for multiple choice"
|
|
1426
|
+
},
|
|
1427
|
+
questions: {
|
|
1428
|
+
type: "array",
|
|
1429
|
+
items: {
|
|
1430
|
+
type: "object",
|
|
1431
|
+
properties: {
|
|
1432
|
+
question: { type: "string" },
|
|
1433
|
+
options: { type: "array", items: { type: "object", properties: { label: { type: "string" } } } }
|
|
1434
|
+
}
|
|
1435
|
+
},
|
|
1436
|
+
description: "Alternative nested question format"
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
async (args) => {
|
|
1440
|
+
const normalized = normalizeAskUserInput(args);
|
|
1441
|
+
const response = await onAskUser(normalized, AbortSignal.timeout(3e5));
|
|
1442
|
+
return {
|
|
1443
|
+
content: [{ type: "text", text: response.answer }]
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
);
|
|
1447
|
+
mcpTools.push(askUserTool);
|
|
1448
|
+
}
|
|
1197
1449
|
return sdk.createSdkMcpServer({
|
|
1198
1450
|
name: MCP_SERVER_NAME,
|
|
1199
1451
|
version: "1.0.0",
|
|
@@ -1243,6 +1495,7 @@ function buildCanUseTool(config) {
|
|
|
1243
1495
|
const unifiedRequest = {
|
|
1244
1496
|
toolName,
|
|
1245
1497
|
toolArgs: input,
|
|
1498
|
+
toolCallId: options.toolUseID,
|
|
1246
1499
|
suggestedScope: extractSuggestedScope(options.suggestions),
|
|
1247
1500
|
rawSDKRequest: { toolName, input, ...options }
|
|
1248
1501
|
};
|
|
@@ -1295,6 +1548,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1295
1548
|
if (block.type === "tool_use") {
|
|
1296
1549
|
const toolCallId = String(block.id ?? "");
|
|
1297
1550
|
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1551
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1298
1552
|
if (toolCallTracker) {
|
|
1299
1553
|
toolCallTracker.trackStart(toolCallId, toolName);
|
|
1300
1554
|
}
|
|
@@ -1318,6 +1572,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1318
1572
|
case "tool_use_summary": {
|
|
1319
1573
|
const summary = msg.summary;
|
|
1320
1574
|
const toolName = stripMcpPrefix(msg.tool_name ?? "unknown");
|
|
1575
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) return null;
|
|
1321
1576
|
const precedingIds = msg.preceding_tool_use_ids;
|
|
1322
1577
|
let toolCallId = "";
|
|
1323
1578
|
if (precedingIds && precedingIds.length > 0) {
|
|
@@ -1371,10 +1626,13 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1371
1626
|
}
|
|
1372
1627
|
if (msg.is_error) {
|
|
1373
1628
|
const r = msg;
|
|
1629
|
+
const errorMsg = r.errors?.join("; ") ?? "Unknown error";
|
|
1630
|
+
const code = classifyAgentError(errorMsg);
|
|
1374
1631
|
return {
|
|
1375
1632
|
type: "error",
|
|
1376
|
-
error:
|
|
1377
|
-
recoverable:
|
|
1633
|
+
error: errorMsg,
|
|
1634
|
+
recoverable: isRecoverableErrorCode(code),
|
|
1635
|
+
code
|
|
1378
1636
|
};
|
|
1379
1637
|
}
|
|
1380
1638
|
return null;
|
|
@@ -1383,72 +1641,21 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1383
1641
|
return null;
|
|
1384
1642
|
}
|
|
1385
1643
|
}
|
|
1386
|
-
function
|
|
1387
|
-
|
|
1388
|
-
const msg = messages[i];
|
|
1389
|
-
if (msg.role === "user") {
|
|
1390
|
-
return getTextContent(msg.content);
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
return "";
|
|
1394
|
-
}
|
|
1395
|
-
function serializeToolCall2(tc) {
|
|
1396
|
-
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
1397
|
-
return ` Tool call: ${tc.name}(${args})`;
|
|
1644
|
+
function createClaudeService(options) {
|
|
1645
|
+
return new ClaudeAgentService(options);
|
|
1398
1646
|
}
|
|
1399
|
-
|
|
1400
|
-
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
1401
|
-
const prefix = tr.isError ? "[ERROR] " : "";
|
|
1402
|
-
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
1403
|
-
}
|
|
1404
|
-
function buildContextualPrompt2(messages) {
|
|
1405
|
-
if (messages.length <= 1) {
|
|
1406
|
-
return extractLastUserPrompt2(messages);
|
|
1407
|
-
}
|
|
1408
|
-
const history = messages.slice(0, -1).map((msg) => {
|
|
1409
|
-
if (msg.role === "user") {
|
|
1410
|
-
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
1411
|
-
}
|
|
1412
|
-
if (msg.role === "tool" && msg.toolResults) {
|
|
1413
|
-
const results = msg.toolResults.map(serializeToolResult2).join("\n");
|
|
1414
|
-
return `Tool results:
|
|
1415
|
-
${results}`;
|
|
1416
|
-
}
|
|
1417
|
-
if (msg.role === "assistant") {
|
|
1418
|
-
const parts = [];
|
|
1419
|
-
const thinking = msg.thinking;
|
|
1420
|
-
if (thinking) {
|
|
1421
|
-
parts.push(`[reasoning: ${thinking}]`);
|
|
1422
|
-
}
|
|
1423
|
-
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
1424
|
-
if (text2) parts.push(text2);
|
|
1425
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
1426
|
-
parts.push(msg.toolCalls.map(serializeToolCall2).join("\n"));
|
|
1427
|
-
}
|
|
1428
|
-
return `Assistant: ${parts.join("\n")}`;
|
|
1429
|
-
}
|
|
1430
|
-
const text = msg.content ? getTextContent(msg.content) : "";
|
|
1431
|
-
return `${msg.role}: ${text}`;
|
|
1432
|
-
}).join("\n");
|
|
1433
|
-
const lastPrompt = extractLastUserPrompt2(messages);
|
|
1434
|
-
return `Conversation history:
|
|
1435
|
-
${history}
|
|
1436
|
-
|
|
1437
|
-
User: ${lastPrompt}`;
|
|
1438
|
-
}
|
|
1439
|
-
function createClaudeService(options) {
|
|
1440
|
-
return new ClaudeAgentService(options);
|
|
1441
|
-
}
|
|
1442
|
-
var MCP_SERVER_NAME, MCP_TOOL_PREFIX, sdkModule2, ANTHROPIC_MODELS_URL, ANTHROPIC_API_VERSION, ANTHROPIC_OAUTH_BETA, ClaudeToolCallTracker, ClaudeAgent, ClaudeAgentService;
|
|
1647
|
+
var MCP_SERVER_NAME, MCP_TOOL_PREFIX, CLAUDE_INTERNAL_TOOL_NAMES, _sdkMock2, ANTHROPIC_MODELS_URL, ANTHROPIC_API_VERSION, ANTHROPIC_OAUTH_BETA, ClaudeToolCallTracker, ClaudeAgent, ClaudeAgentService;
|
|
1443
1648
|
var init_claude = __esm({
|
|
1444
1649
|
"src/backends/claude.ts"() {
|
|
1445
|
-
|
|
1650
|
+
init_types2();
|
|
1446
1651
|
init_base_agent();
|
|
1447
|
-
|
|
1652
|
+
init_errors2();
|
|
1448
1653
|
init_schema();
|
|
1654
|
+
init_shared();
|
|
1449
1655
|
MCP_SERVER_NAME = "agent-sdk-tools";
|
|
1450
1656
|
MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
1451
|
-
|
|
1657
|
+
CLAUDE_INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1658
|
+
_sdkMock2 = null;
|
|
1452
1659
|
ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
|
|
1453
1660
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
1454
1661
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
@@ -1493,11 +1700,6 @@ var init_claude = __esm({
|
|
|
1493
1700
|
if (options.resumeSessionId) {
|
|
1494
1701
|
this._sessionId = options.resumeSessionId;
|
|
1495
1702
|
}
|
|
1496
|
-
if (config.supervisor?.onAskUser) {
|
|
1497
|
-
console.warn(
|
|
1498
|
-
"[agent-sdk/claude] supervisor.onAskUser is not supported by the Claude CLI backend. User interaction requests from the model will not be forwarded."
|
|
1499
|
-
);
|
|
1500
|
-
}
|
|
1501
1703
|
}
|
|
1502
1704
|
get sessionId() {
|
|
1503
1705
|
return this._sessionId;
|
|
@@ -1521,12 +1723,12 @@ var init_claude = __esm({
|
|
|
1521
1723
|
const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
|
|
1522
1724
|
return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
|
|
1523
1725
|
}
|
|
1524
|
-
buildQueryOptions(signal) {
|
|
1726
|
+
buildQueryOptions(signal, options) {
|
|
1525
1727
|
const ac = new AbortController();
|
|
1526
1728
|
signal.addEventListener("abort", () => ac.abort(), { once: true });
|
|
1527
1729
|
const opts = {
|
|
1528
1730
|
abortController: ac,
|
|
1529
|
-
model:
|
|
1731
|
+
model: options.model,
|
|
1530
1732
|
maxTurns: this.options.maxTurns,
|
|
1531
1733
|
cwd: this.options.workingDirectory,
|
|
1532
1734
|
pathToClaudeCodeExecutable: this.options.cliPath,
|
|
@@ -1556,25 +1758,85 @@ var init_claude = __esm({
|
|
|
1556
1758
|
return opts;
|
|
1557
1759
|
}
|
|
1558
1760
|
async buildMcpConfig(opts, toolResultCapture) {
|
|
1559
|
-
|
|
1761
|
+
const onAskUser = this.config.supervisor?.onAskUser;
|
|
1762
|
+
if (this.tools.length === 0 && !onAskUser) return opts;
|
|
1560
1763
|
const sdk = await loadSDK2();
|
|
1561
|
-
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture);
|
|
1764
|
+
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture, onAskUser);
|
|
1562
1765
|
if (mcpServer) {
|
|
1563
1766
|
opts.mcpServers = {
|
|
1564
1767
|
[MCP_SERVER_NAME]: mcpServer
|
|
1565
1768
|
};
|
|
1566
1769
|
const mcpToolNames = this.tools.map((t) => mcpToolName(t.name));
|
|
1770
|
+
if (onAskUser) {
|
|
1771
|
+
mcpToolNames.push(mcpToolName("ask_user"));
|
|
1772
|
+
}
|
|
1567
1773
|
opts.allowedTools = [...opts.allowedTools ?? [], ...mcpToolNames];
|
|
1568
1774
|
}
|
|
1775
|
+
if (onAskUser) {
|
|
1776
|
+
opts.disallowedTools = [...opts.disallowedTools ?? [], "AskUserQuestion"];
|
|
1777
|
+
}
|
|
1569
1778
|
return opts;
|
|
1570
1779
|
}
|
|
1780
|
+
// ─── Retry Helpers (shared across executeRun/RunStructured/Stream) ──
|
|
1781
|
+
/** Setup a retry query: clear session, rebuild with full history */
|
|
1782
|
+
async prepareRetryQuery(sdk, messages, signal, options, toolResultCapture, modifyOpts) {
|
|
1783
|
+
this.clearPersistentSession();
|
|
1784
|
+
const retryPrompt = buildContextualPrompt(messages);
|
|
1785
|
+
let retryOpts = this.buildQueryOptions(signal, options);
|
|
1786
|
+
toolResultCapture.clear();
|
|
1787
|
+
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1788
|
+
modifyOpts?.(retryOpts);
|
|
1789
|
+
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1790
|
+
this.activeQuery = retryQ;
|
|
1791
|
+
return retryQ;
|
|
1792
|
+
}
|
|
1793
|
+
/** Extract tool_use blocks from an assistant SDK message into toolCalls array */
|
|
1794
|
+
collectToolCallsFromMessage(msg, toolCalls, toolResultCapture) {
|
|
1795
|
+
if (msg.type !== "assistant") return;
|
|
1796
|
+
const betaMessage = msg.message;
|
|
1797
|
+
if (!betaMessage?.content) return;
|
|
1798
|
+
for (const block of betaMessage.content) {
|
|
1799
|
+
if (block.type === "tool_use") {
|
|
1800
|
+
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1801
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1802
|
+
toolCalls.push({
|
|
1803
|
+
toolName,
|
|
1804
|
+
args: block.input ?? {},
|
|
1805
|
+
result: toolResultCapture.get(toolName) ?? null,
|
|
1806
|
+
approved: true
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
/** Back-fill tool results from capture map on summary/result messages */
|
|
1812
|
+
backfillToolResults(msg, toolCalls, toolResultCapture) {
|
|
1813
|
+
if (msg.type !== "tool_use_summary" && msg.type !== "result") return;
|
|
1814
|
+
for (const tc of toolCalls) {
|
|
1815
|
+
if (tc.result === null) {
|
|
1816
|
+
const captured = toolResultCapture.get(tc.toolName);
|
|
1817
|
+
if (captured !== void 0) tc.result = captured;
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
/** Wrap retry inner loop with shared error handling */
|
|
1822
|
+
async withRetryErrorHandling(signal, fn) {
|
|
1823
|
+
try {
|
|
1824
|
+
return await fn();
|
|
1825
|
+
} catch (retryError) {
|
|
1826
|
+
if (this.isPersistent) this.clearPersistentSession();
|
|
1827
|
+
if (signal.aborted) throw new AbortError();
|
|
1828
|
+
throw retryError;
|
|
1829
|
+
} finally {
|
|
1830
|
+
this.activeQuery = null;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1571
1833
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
1572
|
-
async executeRun(messages,
|
|
1834
|
+
async executeRun(messages, options, signal) {
|
|
1573
1835
|
this.checkAbort(signal);
|
|
1574
1836
|
const sdk = await loadSDK2();
|
|
1575
1837
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1576
|
-
const prompt = isResuming ?
|
|
1577
|
-
let opts = this.buildQueryOptions(signal);
|
|
1838
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1839
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1578
1840
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1579
1841
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1580
1842
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1584,30 +1846,8 @@ var init_claude = __esm({
|
|
|
1584
1846
|
let usage;
|
|
1585
1847
|
try {
|
|
1586
1848
|
for await (const msg of q) {
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
if (betaMessage?.content) {
|
|
1590
|
-
for (const block of betaMessage.content) {
|
|
1591
|
-
if (block.type === "tool_use") {
|
|
1592
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1593
|
-
toolCalls.push({
|
|
1594
|
-
toolName,
|
|
1595
|
-
args: block.input ?? {},
|
|
1596
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1597
|
-
approved: true
|
|
1598
|
-
});
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1604
|
-
for (const tc of toolCalls) {
|
|
1605
|
-
if (tc.result === null) {
|
|
1606
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1607
|
-
if (captured !== void 0) tc.result = captured;
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1849
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1850
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1611
1851
|
if (msg.type === "result") {
|
|
1612
1852
|
if (msg.subtype === "success") {
|
|
1613
1853
|
const r = msg;
|
|
@@ -1627,41 +1867,13 @@ var init_claude = __esm({
|
|
|
1627
1867
|
} catch (e) {
|
|
1628
1868
|
if (signal.aborted) throw new AbortError();
|
|
1629
1869
|
if (isResuming && this.isPersistent) {
|
|
1630
|
-
this.
|
|
1631
|
-
const retryPrompt = buildContextualPrompt2(messages);
|
|
1632
|
-
let retryOpts = this.buildQueryOptions(signal);
|
|
1633
|
-
toolResultCapture.clear();
|
|
1634
|
-
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1635
|
-
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1636
|
-
this.activeQuery = retryQ;
|
|
1870
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1637
1871
|
toolCalls.length = 0;
|
|
1638
1872
|
output = null;
|
|
1639
|
-
|
|
1873
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1640
1874
|
for await (const msg of retryQ) {
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
if (betaMessage?.content) {
|
|
1644
|
-
for (const block of betaMessage.content) {
|
|
1645
|
-
if (block.type === "tool_use") {
|
|
1646
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1647
|
-
toolCalls.push({
|
|
1648
|
-
toolName,
|
|
1649
|
-
args: block.input ?? {},
|
|
1650
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1651
|
-
approved: true
|
|
1652
|
-
});
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1658
|
-
for (const tc of toolCalls) {
|
|
1659
|
-
if (tc.result === null) {
|
|
1660
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1661
|
-
if (captured !== void 0) tc.result = captured;
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1875
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1876
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1665
1877
|
if (msg.type === "result") {
|
|
1666
1878
|
if (msg.subtype === "success") {
|
|
1667
1879
|
const r = msg;
|
|
@@ -1678,23 +1890,17 @@ var init_claude = __esm({
|
|
|
1678
1890
|
}
|
|
1679
1891
|
}
|
|
1680
1892
|
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
messages: [
|
|
1693
|
-
...messages,
|
|
1694
|
-
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1695
|
-
],
|
|
1696
|
-
usage
|
|
1697
|
-
};
|
|
1893
|
+
return {
|
|
1894
|
+
output,
|
|
1895
|
+
structuredOutput: void 0,
|
|
1896
|
+
toolCalls,
|
|
1897
|
+
messages: [
|
|
1898
|
+
...messages,
|
|
1899
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1900
|
+
],
|
|
1901
|
+
usage
|
|
1902
|
+
};
|
|
1903
|
+
});
|
|
1698
1904
|
}
|
|
1699
1905
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1700
1906
|
throw e;
|
|
@@ -1713,12 +1919,12 @@ var init_claude = __esm({
|
|
|
1713
1919
|
};
|
|
1714
1920
|
}
|
|
1715
1921
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
1716
|
-
async executeRunStructured(messages, schema,
|
|
1922
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
1717
1923
|
this.checkAbort(signal);
|
|
1718
1924
|
const sdk = await loadSDK2();
|
|
1719
1925
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1720
|
-
const prompt = isResuming ?
|
|
1721
|
-
let opts = this.buildQueryOptions(signal);
|
|
1926
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1927
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1722
1928
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1723
1929
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1724
1930
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
@@ -1734,30 +1940,8 @@ var init_claude = __esm({
|
|
|
1734
1940
|
let usage;
|
|
1735
1941
|
try {
|
|
1736
1942
|
for await (const msg of q) {
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
if (betaMessage?.content) {
|
|
1740
|
-
for (const block of betaMessage.content) {
|
|
1741
|
-
if (block.type === "tool_use") {
|
|
1742
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1743
|
-
toolCalls.push({
|
|
1744
|
-
toolName,
|
|
1745
|
-
args: block.input ?? {},
|
|
1746
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1747
|
-
approved: true
|
|
1748
|
-
});
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1754
|
-
for (const tc of toolCalls) {
|
|
1755
|
-
if (tc.result === null) {
|
|
1756
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1757
|
-
if (captured !== void 0) tc.result = captured;
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1943
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1944
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1761
1945
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1762
1946
|
const r = msg;
|
|
1763
1947
|
output = r.result;
|
|
@@ -1792,46 +1976,23 @@ var init_claude = __esm({
|
|
|
1792
1976
|
} catch (e) {
|
|
1793
1977
|
if (signal.aborted) throw new AbortError();
|
|
1794
1978
|
if (isResuming && this.isPersistent) {
|
|
1795
|
-
this.
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
this.activeQuery = retryQ;
|
|
1979
|
+
const retryQ = await this.prepareRetryQuery(
|
|
1980
|
+
sdk,
|
|
1981
|
+
messages,
|
|
1982
|
+
signal,
|
|
1983
|
+
options,
|
|
1984
|
+
toolResultCapture,
|
|
1985
|
+
(opts2) => {
|
|
1986
|
+
opts2.outputFormat = { type: "json_schema", schema: jsonSchema };
|
|
1987
|
+
}
|
|
1988
|
+
);
|
|
1806
1989
|
toolCalls.length = 0;
|
|
1807
1990
|
output = null;
|
|
1808
1991
|
structuredOutput = void 0;
|
|
1809
|
-
|
|
1992
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1810
1993
|
for await (const msg of retryQ) {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
if (betaMessage?.content) {
|
|
1814
|
-
for (const block of betaMessage.content) {
|
|
1815
|
-
if (block.type === "tool_use") {
|
|
1816
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1817
|
-
toolCalls.push({
|
|
1818
|
-
toolName,
|
|
1819
|
-
args: block.input ?? {},
|
|
1820
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1821
|
-
approved: true
|
|
1822
|
-
});
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1828
|
-
for (const tc of toolCalls) {
|
|
1829
|
-
if (tc.result === null) {
|
|
1830
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1831
|
-
if (captured !== void 0) tc.result = captured;
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
}
|
|
1994
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1995
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1835
1996
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1836
1997
|
const r = msg;
|
|
1837
1998
|
output = r.result;
|
|
@@ -1863,23 +2024,17 @@ var init_claude = __esm({
|
|
|
1863
2024
|
);
|
|
1864
2025
|
}
|
|
1865
2026
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
messages: [
|
|
1878
|
-
...messages,
|
|
1879
|
-
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1880
|
-
],
|
|
1881
|
-
usage
|
|
1882
|
-
};
|
|
2027
|
+
return {
|
|
2028
|
+
output,
|
|
2029
|
+
structuredOutput,
|
|
2030
|
+
toolCalls,
|
|
2031
|
+
messages: [
|
|
2032
|
+
...messages,
|
|
2033
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
2034
|
+
],
|
|
2035
|
+
usage
|
|
2036
|
+
};
|
|
2037
|
+
});
|
|
1883
2038
|
}
|
|
1884
2039
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1885
2040
|
throw e;
|
|
@@ -1898,12 +2053,12 @@ var init_claude = __esm({
|
|
|
1898
2053
|
};
|
|
1899
2054
|
}
|
|
1900
2055
|
// ─── executeStream ──────────────────────────────────────────────
|
|
1901
|
-
async *executeStream(messages,
|
|
2056
|
+
async *executeStream(messages, options, signal) {
|
|
1902
2057
|
this.checkAbort(signal);
|
|
1903
2058
|
const sdk = await loadSDK2();
|
|
1904
2059
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1905
|
-
const prompt = isResuming ?
|
|
1906
|
-
let opts = this.buildQueryOptions(signal);
|
|
2060
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
2061
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1907
2062
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1908
2063
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1909
2064
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1911,6 +2066,7 @@ var init_claude = __esm({
|
|
|
1911
2066
|
const thinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1912
2067
|
const toolCallTracker = new ClaudeToolCallTracker();
|
|
1913
2068
|
const pendingStreamToolCalls = /* @__PURE__ */ new Map();
|
|
2069
|
+
let hasStreamedText = false;
|
|
1914
2070
|
try {
|
|
1915
2071
|
for await (const msg of q) {
|
|
1916
2072
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1928,6 +2084,7 @@ var init_claude = __esm({
|
|
|
1928
2084
|
} else if (e.type === "tool_call_end") {
|
|
1929
2085
|
pendingStreamToolCalls.delete(e.toolCallId);
|
|
1930
2086
|
}
|
|
2087
|
+
if (e.type === "text_delta") hasStreamedText = true;
|
|
1931
2088
|
yield e;
|
|
1932
2089
|
}
|
|
1933
2090
|
}
|
|
@@ -1951,22 +2108,21 @@ var init_claude = __esm({
|
|
|
1951
2108
|
}
|
|
1952
2109
|
yield this.emitSessionInfo(r.session_id);
|
|
1953
2110
|
}
|
|
1954
|
-
yield {
|
|
2111
|
+
yield {
|
|
2112
|
+
type: "done",
|
|
2113
|
+
finalOutput: hasStreamedText ? null : r.result,
|
|
2114
|
+
...hasStreamedText ? { streamed: true } : {}
|
|
2115
|
+
};
|
|
1955
2116
|
}
|
|
1956
2117
|
}
|
|
1957
2118
|
} catch (e) {
|
|
1958
2119
|
if (signal.aborted) throw new AbortError();
|
|
1959
2120
|
if (isResuming && this.isPersistent) {
|
|
1960
|
-
this.
|
|
1961
|
-
const retryPrompt = buildContextualPrompt2(messages);
|
|
1962
|
-
let retryOpts = this.buildQueryOptions(signal);
|
|
1963
|
-
toolResultCapture.clear();
|
|
1964
|
-
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1965
|
-
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1966
|
-
this.activeQuery = retryQ;
|
|
2121
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1967
2122
|
const retryThinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1968
2123
|
const retryToolCallTracker = new ClaudeToolCallTracker();
|
|
1969
2124
|
const retryPendingToolCalls = /* @__PURE__ */ new Map();
|
|
2125
|
+
let retryHasStreamedText = false;
|
|
1970
2126
|
try {
|
|
1971
2127
|
for await (const msg of retryQ) {
|
|
1972
2128
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1984,6 +2140,7 @@ var init_claude = __esm({
|
|
|
1984
2140
|
} else if (ev.type === "tool_call_end") {
|
|
1985
2141
|
retryPendingToolCalls.delete(ev.toolCallId);
|
|
1986
2142
|
}
|
|
2143
|
+
if (ev.type === "text_delta") retryHasStreamedText = true;
|
|
1987
2144
|
yield ev;
|
|
1988
2145
|
}
|
|
1989
2146
|
}
|
|
@@ -2007,7 +2164,11 @@ var init_claude = __esm({
|
|
|
2007
2164
|
}
|
|
2008
2165
|
yield this.emitSessionInfo(r.session_id);
|
|
2009
2166
|
}
|
|
2010
|
-
yield {
|
|
2167
|
+
yield {
|
|
2168
|
+
type: "done",
|
|
2169
|
+
finalOutput: retryHasStreamedText ? null : r.result,
|
|
2170
|
+
...retryHasStreamedText ? { streamed: true } : {}
|
|
2171
|
+
};
|
|
2011
2172
|
}
|
|
2012
2173
|
}
|
|
2013
2174
|
} catch (retryError) {
|
|
@@ -2069,7 +2230,8 @@ var init_claude = __esm({
|
|
|
2069
2230
|
this.cachedModels = body.data.map((m) => ({
|
|
2070
2231
|
id: m.id,
|
|
2071
2232
|
name: m.display_name,
|
|
2072
|
-
provider: "claude"
|
|
2233
|
+
provider: "claude",
|
|
2234
|
+
...m.max_input_tokens != null && { contextWindow: m.max_input_tokens }
|
|
2073
2235
|
}));
|
|
2074
2236
|
return this.cachedModels;
|
|
2075
2237
|
}
|
|
@@ -2127,32 +2289,30 @@ __export(vercel_ai_exports, {
|
|
|
2127
2289
|
createVercelAIService: () => createVercelAIService
|
|
2128
2290
|
});
|
|
2129
2291
|
async function loadSDK3() {
|
|
2130
|
-
if (
|
|
2292
|
+
if (_sdkMock3) return _sdkMock3;
|
|
2131
2293
|
try {
|
|
2132
|
-
|
|
2133
|
-
return sdkModule3;
|
|
2294
|
+
return await import('ai');
|
|
2134
2295
|
} catch {
|
|
2135
2296
|
throw new DependencyError("ai");
|
|
2136
2297
|
}
|
|
2137
2298
|
}
|
|
2138
2299
|
async function loadCompat() {
|
|
2139
|
-
if (
|
|
2300
|
+
if (_compatMock) return _compatMock;
|
|
2140
2301
|
try {
|
|
2141
|
-
|
|
2142
|
-
return compatModule;
|
|
2302
|
+
return await import('@ai-sdk/openai-compatible');
|
|
2143
2303
|
} catch {
|
|
2144
2304
|
throw new DependencyError("@ai-sdk/openai-compatible");
|
|
2145
2305
|
}
|
|
2146
2306
|
}
|
|
2147
2307
|
function _injectSDK3(mock) {
|
|
2148
|
-
|
|
2308
|
+
_sdkMock3 = mock;
|
|
2149
2309
|
}
|
|
2150
2310
|
function _injectCompat(mock) {
|
|
2151
|
-
|
|
2311
|
+
_compatMock = mock;
|
|
2152
2312
|
}
|
|
2153
2313
|
function _resetSDK3() {
|
|
2154
|
-
|
|
2155
|
-
|
|
2314
|
+
_sdkMock3 = null;
|
|
2315
|
+
_compatMock = null;
|
|
2156
2316
|
}
|
|
2157
2317
|
function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, signal) {
|
|
2158
2318
|
const toolMap = {};
|
|
@@ -2195,13 +2355,14 @@ function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, s
|
|
|
2195
2355
|
return toolMap;
|
|
2196
2356
|
}
|
|
2197
2357
|
function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
|
|
2198
|
-
return async (args) => {
|
|
2358
|
+
return async (args, options) => {
|
|
2199
2359
|
if (ourTool.needsApproval && supervisor?.onPermission) {
|
|
2200
2360
|
const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
|
|
2201
2361
|
if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
|
|
2202
2362
|
const request = {
|
|
2203
2363
|
toolName: ourTool.name,
|
|
2204
|
-
toolArgs: args ?? {}
|
|
2364
|
+
toolArgs: args ?? {},
|
|
2365
|
+
toolCallId: options?.toolCallId
|
|
2205
2366
|
};
|
|
2206
2367
|
const decision = await supervisor.onPermission(
|
|
2207
2368
|
request,
|
|
@@ -2308,7 +2469,8 @@ function mapStreamPart(part) {
|
|
|
2308
2469
|
return {
|
|
2309
2470
|
type: "error",
|
|
2310
2471
|
error: p.error instanceof Error ? p.error.message : String(p.error ?? "Tool execution failed"),
|
|
2311
|
-
recoverable: true
|
|
2472
|
+
recoverable: true,
|
|
2473
|
+
code: "TOOL_EXECUTION" /* TOOL_EXECUTION */
|
|
2312
2474
|
};
|
|
2313
2475
|
}
|
|
2314
2476
|
case "reasoning-start":
|
|
@@ -2329,10 +2491,13 @@ function mapStreamPart(part) {
|
|
|
2329
2491
|
}
|
|
2330
2492
|
case "error": {
|
|
2331
2493
|
const p = part;
|
|
2494
|
+
const errorMsg = p.error instanceof Error ? p.error.message : String(p.error ?? "Unknown error");
|
|
2495
|
+
const code = classifyAgentError(errorMsg);
|
|
2332
2496
|
return {
|
|
2333
2497
|
type: "error",
|
|
2334
|
-
error:
|
|
2335
|
-
recoverable:
|
|
2498
|
+
error: errorMsg,
|
|
2499
|
+
recoverable: isRecoverableErrorCode(code),
|
|
2500
|
+
code
|
|
2336
2501
|
};
|
|
2337
2502
|
}
|
|
2338
2503
|
default:
|
|
@@ -2342,15 +2507,15 @@ function mapStreamPart(part) {
|
|
|
2342
2507
|
function createVercelAIService(options) {
|
|
2343
2508
|
return new VercelAIAgentService(options);
|
|
2344
2509
|
}
|
|
2345
|
-
var
|
|
2510
|
+
var _sdkMock3, _compatMock, DEFAULT_BASE_URL, DEFAULT_PROVIDER, DEFAULT_MAX_TURNS, VercelAIAgent, VercelAIAgentService;
|
|
2346
2511
|
var init_vercel_ai = __esm({
|
|
2347
2512
|
"src/backends/vercel-ai.ts"() {
|
|
2348
|
-
|
|
2513
|
+
init_types2();
|
|
2349
2514
|
init_base_agent();
|
|
2350
|
-
|
|
2515
|
+
init_errors2();
|
|
2351
2516
|
init_schema();
|
|
2352
|
-
|
|
2353
|
-
|
|
2517
|
+
_sdkMock3 = null;
|
|
2518
|
+
_compatMock = null;
|
|
2354
2519
|
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
2355
2520
|
DEFAULT_PROVIDER = "openrouter";
|
|
2356
2521
|
DEFAULT_MAX_TURNS = 10;
|
|
@@ -2363,28 +2528,33 @@ var init_vercel_ai = __esm({
|
|
|
2363
2528
|
super(config);
|
|
2364
2529
|
this.backendOptions = backendOptions;
|
|
2365
2530
|
}
|
|
2366
|
-
async getModel() {
|
|
2367
|
-
|
|
2531
|
+
async getModel(options) {
|
|
2532
|
+
const requestedModel = options.model;
|
|
2533
|
+
const defaultModel = this.config.model;
|
|
2534
|
+
if (requestedModel === defaultModel && this.model) return this.model;
|
|
2368
2535
|
const compat = await loadCompat();
|
|
2369
2536
|
const provider = compat.createOpenAICompatible({
|
|
2370
2537
|
name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
|
|
2371
2538
|
baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
|
|
2372
2539
|
apiKey: this.backendOptions.apiKey
|
|
2373
2540
|
});
|
|
2374
|
-
const
|
|
2375
|
-
|
|
2376
|
-
|
|
2541
|
+
const model = provider.chatModel(requestedModel);
|
|
2542
|
+
if (requestedModel === defaultModel) {
|
|
2543
|
+
this.model = model;
|
|
2544
|
+
}
|
|
2545
|
+
return model;
|
|
2377
2546
|
}
|
|
2378
|
-
async getSDKTools(signal) {
|
|
2547
|
+
async getSDKTools(signal, options) {
|
|
2379
2548
|
const sdk = await loadSDK3();
|
|
2380
|
-
|
|
2549
|
+
const tools = this.resolveTools(options);
|
|
2550
|
+
return mapToolsToSDK2(sdk, tools, this.config, this.sessionApprovals, this.config.permissionStore, signal);
|
|
2381
2551
|
}
|
|
2382
2552
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
2383
|
-
async executeRun(messages,
|
|
2553
|
+
async executeRun(messages, options, signal) {
|
|
2384
2554
|
this.checkAbort(signal);
|
|
2385
2555
|
const sdk = await loadSDK3();
|
|
2386
|
-
const model = await this.getModel();
|
|
2387
|
-
const tools = await this.getSDKTools(signal);
|
|
2556
|
+
const model = await this.getModel(options);
|
|
2557
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2388
2558
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2389
2559
|
const sdkMessages = messagesToSDK(messages);
|
|
2390
2560
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2440,10 +2610,10 @@ var init_vercel_ai = __esm({
|
|
|
2440
2610
|
};
|
|
2441
2611
|
}
|
|
2442
2612
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
2443
|
-
async executeRunStructured(messages, schema,
|
|
2613
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
2444
2614
|
this.checkAbort(signal);
|
|
2445
2615
|
const sdk = await loadSDK3();
|
|
2446
|
-
const model = await this.getModel();
|
|
2616
|
+
const model = await this.getModel(options);
|
|
2447
2617
|
const sdkMessages = messagesToSDK(messages);
|
|
2448
2618
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
2449
2619
|
const result = await sdk.generateObject({
|
|
@@ -2485,11 +2655,11 @@ var init_vercel_ai = __esm({
|
|
|
2485
2655
|
};
|
|
2486
2656
|
}
|
|
2487
2657
|
// ─── executeStream ──────────────────────────────────────────────
|
|
2488
|
-
async *executeStream(messages,
|
|
2658
|
+
async *executeStream(messages, options, signal) {
|
|
2489
2659
|
this.checkAbort(signal);
|
|
2490
2660
|
const sdk = await loadSDK3();
|
|
2491
|
-
const model = await this.getModel();
|
|
2492
|
-
const tools = await this.getSDKTools(signal);
|
|
2661
|
+
const model = await this.getModel(options);
|
|
2662
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2493
2663
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2494
2664
|
const sdkMessages = messagesToSDK(messages);
|
|
2495
2665
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2514,6 +2684,7 @@ var init_vercel_ai = __esm({
|
|
|
2514
2684
|
}
|
|
2515
2685
|
});
|
|
2516
2686
|
let finalText = "";
|
|
2687
|
+
let lastFinishReason;
|
|
2517
2688
|
try {
|
|
2518
2689
|
for await (const part of result.fullStream) {
|
|
2519
2690
|
if (signal.aborted) throw new AbortError();
|
|
@@ -2524,10 +2695,15 @@ var init_vercel_ai = __esm({
|
|
|
2524
2695
|
}
|
|
2525
2696
|
if (part.type === "finish-step") {
|
|
2526
2697
|
const p = part;
|
|
2698
|
+
lastFinishReason = p.finishReason;
|
|
2527
2699
|
if (p.finishReason === "tool-calls") {
|
|
2528
2700
|
finalText = "";
|
|
2529
2701
|
}
|
|
2530
2702
|
}
|
|
2703
|
+
if (part.type === "finish") {
|
|
2704
|
+
const p = part;
|
|
2705
|
+
lastFinishReason = p.finishReason;
|
|
2706
|
+
}
|
|
2531
2707
|
}
|
|
2532
2708
|
const totalUsage = await result.totalUsage;
|
|
2533
2709
|
yield {
|
|
@@ -2535,9 +2711,12 @@ var init_vercel_ai = __esm({
|
|
|
2535
2711
|
promptTokens: Number(totalUsage?.inputTokens ?? 0),
|
|
2536
2712
|
completionTokens: Number(totalUsage?.outputTokens ?? 0)
|
|
2537
2713
|
};
|
|
2714
|
+
const hasStreamed = finalText.length > 0;
|
|
2538
2715
|
yield {
|
|
2539
2716
|
type: "done",
|
|
2540
|
-
finalOutput: finalText || null
|
|
2717
|
+
finalOutput: hasStreamed ? null : finalText || null,
|
|
2718
|
+
...hasStreamed ? { streamed: true } : {},
|
|
2719
|
+
...lastFinishReason ? { finishReason: lastFinishReason } : {}
|
|
2541
2720
|
};
|
|
2542
2721
|
} catch (e) {
|
|
2543
2722
|
if (signal.aborted) throw new AbortError();
|
|
@@ -2566,16 +2745,33 @@ var init_vercel_ai = __esm({
|
|
|
2566
2745
|
const baseUrl = (this.options.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
2567
2746
|
try {
|
|
2568
2747
|
const res = await globalThis.fetch(`${baseUrl}/models`, {
|
|
2569
|
-
headers: {
|
|
2748
|
+
headers: {
|
|
2749
|
+
Authorization: `Bearer ${this.options.apiKey}`,
|
|
2750
|
+
// OpenRouter requires HTTP-Referer for API access
|
|
2751
|
+
"HTTP-Referer": "https://github.com/nicepkg/agent-sdk"
|
|
2752
|
+
}
|
|
2570
2753
|
});
|
|
2571
2754
|
if (!res.ok) {
|
|
2572
2755
|
return [];
|
|
2573
2756
|
}
|
|
2574
2757
|
const body = await res.json();
|
|
2575
|
-
if (
|
|
2576
|
-
return
|
|
2758
|
+
if (body.data && Array.isArray(body.data)) {
|
|
2759
|
+
return body.data.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2760
|
+
id: m.id,
|
|
2761
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2762
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2763
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2764
|
+
}));
|
|
2765
|
+
}
|
|
2766
|
+
if (Array.isArray(body)) {
|
|
2767
|
+
return body.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2768
|
+
id: m.id,
|
|
2769
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2770
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2771
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2772
|
+
}));
|
|
2577
2773
|
}
|
|
2578
|
-
return
|
|
2774
|
+
return [];
|
|
2579
2775
|
} catch {
|
|
2580
2776
|
return [];
|
|
2581
2777
|
}
|
|
@@ -2606,272 +2802,25 @@ var init_vercel_ai = __esm({
|
|
|
2606
2802
|
}
|
|
2607
2803
|
});
|
|
2608
2804
|
|
|
2609
|
-
// src/
|
|
2610
|
-
function
|
|
2611
|
-
|
|
2612
|
-
throw new BackendAlreadyRegisteredError(name);
|
|
2613
|
-
}
|
|
2614
|
-
registry.set(name, { factory, builtin: false });
|
|
2615
|
-
}
|
|
2616
|
-
function unregisterBackend(name) {
|
|
2617
|
-
return registry.delete(name);
|
|
2618
|
-
}
|
|
2619
|
-
function hasBackend(name) {
|
|
2620
|
-
return registry.has(name) || isBuiltinName(name);
|
|
2621
|
-
}
|
|
2622
|
-
function listBackends() {
|
|
2623
|
-
const names = new Set(registry.keys());
|
|
2624
|
-
for (const builtin of BUILTIN_BACKENDS) {
|
|
2625
|
-
names.add(builtin);
|
|
2626
|
-
}
|
|
2627
|
-
return [...names];
|
|
2805
|
+
// src/chat/backends/types.ts
|
|
2806
|
+
function isResumableBackend(adapter) {
|
|
2807
|
+
return "canResume" in adapter && typeof adapter.canResume === "function";
|
|
2628
2808
|
}
|
|
2629
|
-
function resetRegistry() {
|
|
2630
|
-
registry.clear();
|
|
2631
|
-
}
|
|
2632
|
-
function isBuiltinName(name) {
|
|
2633
|
-
return BUILTIN_BACKENDS.has(name);
|
|
2634
|
-
}
|
|
2635
|
-
async function loadBuiltinFactory(name) {
|
|
2636
|
-
switch (name) {
|
|
2637
|
-
case "copilot": {
|
|
2638
|
-
const mod = await Promise.resolve().then(() => (init_copilot(), copilot_exports));
|
|
2639
|
-
return (opts) => mod.createCopilotService(opts);
|
|
2640
|
-
}
|
|
2641
|
-
case "claude": {
|
|
2642
|
-
const mod = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
2643
|
-
return (opts) => mod.createClaudeService(opts);
|
|
2644
|
-
}
|
|
2645
|
-
case "vercel-ai": {
|
|
2646
|
-
const mod = await Promise.resolve().then(() => (init_vercel_ai(), vercel_ai_exports));
|
|
2647
|
-
return (opts) => mod.createVercelAIService(opts);
|
|
2648
|
-
}
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
async function createAgentService(name, options) {
|
|
2652
|
-
const entry = registry.get(name);
|
|
2653
|
-
if (entry) {
|
|
2654
|
-
return entry.factory(options);
|
|
2655
|
-
}
|
|
2656
|
-
if (isBuiltinName(name)) {
|
|
2657
|
-
const factory = await loadBuiltinFactory(name);
|
|
2658
|
-
registry.set(name, { factory, builtin: true });
|
|
2659
|
-
return factory(options);
|
|
2660
|
-
}
|
|
2661
|
-
throw new BackendNotFoundError(name);
|
|
2662
|
-
}
|
|
2663
|
-
var registry, BUILTIN_BACKENDS;
|
|
2664
|
-
var init_registry = __esm({
|
|
2665
|
-
"src/registry.ts"() {
|
|
2666
|
-
init_errors();
|
|
2667
|
-
registry = /* @__PURE__ */ new Map();
|
|
2668
|
-
BUILTIN_BACKENDS = /* @__PURE__ */ new Set([
|
|
2669
|
-
"copilot",
|
|
2670
|
-
"claude",
|
|
2671
|
-
"vercel-ai"
|
|
2672
|
-
]);
|
|
2673
|
-
}
|
|
2674
|
-
});
|
|
2675
|
-
|
|
2676
|
-
// src/utils/messages.ts
|
|
2677
|
-
function messagesToPrompt(messages) {
|
|
2678
|
-
return messages.map((msg) => {
|
|
2679
|
-
switch (msg.role) {
|
|
2680
|
-
case "user":
|
|
2681
|
-
return contentToText(msg.content);
|
|
2682
|
-
case "assistant":
|
|
2683
|
-
return contentToText(msg.content);
|
|
2684
|
-
case "system":
|
|
2685
|
-
return msg.content;
|
|
2686
|
-
case "tool":
|
|
2687
|
-
return msg.content ?? "";
|
|
2688
|
-
}
|
|
2689
|
-
}).filter(Boolean).join("\n\n");
|
|
2690
|
-
}
|
|
2691
|
-
function contentToText(content) {
|
|
2692
|
-
return getTextContent(content);
|
|
2693
|
-
}
|
|
2694
|
-
function buildSystemPrompt(base, schemaInstruction) {
|
|
2695
|
-
if (!schemaInstruction) return base;
|
|
2696
|
-
return `${base}
|
|
2697
2809
|
|
|
2698
|
-
|
|
2699
|
-
}
|
|
2700
|
-
var init_messages = __esm({
|
|
2701
|
-
"src/utils/messages.ts"() {
|
|
2702
|
-
init_types();
|
|
2703
|
-
}
|
|
2704
|
-
});
|
|
2705
|
-
function createDefaultPermissionStore(projectDir) {
|
|
2706
|
-
const sessionStore = new InMemoryPermissionStore();
|
|
2707
|
-
const projectPath = projectDir ? path__namespace.join(projectDir, ".agent-sdk", "permissions.json") : path__namespace.join(process.cwd(), ".agent-sdk", "permissions.json");
|
|
2708
|
-
const userPath = path__namespace.join(os__namespace.homedir(), ".agent-sdk", "permissions.json");
|
|
2709
|
-
const projectStore = new FilePermissionStore(projectPath);
|
|
2710
|
-
const userStore = new FilePermissionStore(userPath);
|
|
2711
|
-
return new CompositePermissionStore(sessionStore, projectStore, userStore);
|
|
2712
|
-
}
|
|
2713
|
-
var InMemoryPermissionStore, FilePermissionStore, CompositePermissionStore;
|
|
2714
|
-
var init_permission_store = __esm({
|
|
2715
|
-
"src/permission-store.ts"() {
|
|
2716
|
-
InMemoryPermissionStore = class {
|
|
2717
|
-
approvals = /* @__PURE__ */ new Map();
|
|
2718
|
-
async isApproved(toolName) {
|
|
2719
|
-
return this.approvals.has(toolName);
|
|
2720
|
-
}
|
|
2721
|
-
async approve(toolName, scope) {
|
|
2722
|
-
if (scope === "once") return;
|
|
2723
|
-
this.approvals.set(toolName, scope);
|
|
2724
|
-
}
|
|
2725
|
-
async revoke(toolName) {
|
|
2726
|
-
this.approvals.delete(toolName);
|
|
2727
|
-
}
|
|
2728
|
-
async clear() {
|
|
2729
|
-
this.approvals.clear();
|
|
2730
|
-
}
|
|
2731
|
-
async dispose() {
|
|
2732
|
-
this.approvals.clear();
|
|
2733
|
-
}
|
|
2734
|
-
};
|
|
2735
|
-
FilePermissionStore = class {
|
|
2736
|
-
filePath;
|
|
2737
|
-
constructor(filePath) {
|
|
2738
|
-
this.filePath = path__namespace.resolve(filePath);
|
|
2739
|
-
}
|
|
2740
|
-
async isApproved(toolName) {
|
|
2741
|
-
const data = this.readFile();
|
|
2742
|
-
return toolName in data.approvals;
|
|
2743
|
-
}
|
|
2744
|
-
async approve(toolName, scope) {
|
|
2745
|
-
if (scope === "once") return;
|
|
2746
|
-
const data = this.readFile();
|
|
2747
|
-
data.approvals[toolName] = { scope, timestamp: Date.now() };
|
|
2748
|
-
this.writeFileAtomic(data);
|
|
2749
|
-
}
|
|
2750
|
-
async revoke(toolName) {
|
|
2751
|
-
const data = this.readFile();
|
|
2752
|
-
delete data.approvals[toolName];
|
|
2753
|
-
this.writeFileAtomic(data);
|
|
2754
|
-
}
|
|
2755
|
-
async clear() {
|
|
2756
|
-
this.writeFileAtomic({ approvals: {} });
|
|
2757
|
-
}
|
|
2758
|
-
async dispose() {
|
|
2759
|
-
}
|
|
2760
|
-
readFile() {
|
|
2761
|
-
try {
|
|
2762
|
-
const raw = fs__namespace.readFileSync(this.filePath, "utf-8");
|
|
2763
|
-
const parsed = JSON.parse(raw);
|
|
2764
|
-
if (parsed && typeof parsed.approvals === "object") return parsed;
|
|
2765
|
-
} catch {
|
|
2766
|
-
}
|
|
2767
|
-
return { approvals: {} };
|
|
2768
|
-
}
|
|
2769
|
-
writeFileAtomic(data) {
|
|
2770
|
-
const dir = path__namespace.dirname(this.filePath);
|
|
2771
|
-
fs__namespace.mkdirSync(dir, { recursive: true });
|
|
2772
|
-
const tmpPath = this.filePath + `.tmp.${process.pid}.${Date.now()}`;
|
|
2773
|
-
fs__namespace.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
2774
|
-
fs__namespace.renameSync(tmpPath, this.filePath);
|
|
2775
|
-
}
|
|
2776
|
-
};
|
|
2777
|
-
CompositePermissionStore = class {
|
|
2778
|
-
sessionStore;
|
|
2779
|
-
projectStore;
|
|
2780
|
-
userStore;
|
|
2781
|
-
constructor(sessionStore, projectStore, userStore) {
|
|
2782
|
-
this.sessionStore = sessionStore;
|
|
2783
|
-
this.projectStore = projectStore;
|
|
2784
|
-
this.userStore = userStore ?? projectStore;
|
|
2785
|
-
}
|
|
2786
|
-
async isApproved(toolName) {
|
|
2787
|
-
return await this.sessionStore.isApproved(toolName) || await this.projectStore.isApproved(toolName) || await this.userStore.isApproved(toolName);
|
|
2788
|
-
}
|
|
2789
|
-
async approve(toolName, scope) {
|
|
2790
|
-
if (scope === "once") return;
|
|
2791
|
-
if (scope === "session") {
|
|
2792
|
-
await this.sessionStore.approve(toolName, scope);
|
|
2793
|
-
} else if (scope === "project") {
|
|
2794
|
-
await this.projectStore.approve(toolName, scope);
|
|
2795
|
-
} else {
|
|
2796
|
-
await this.userStore.approve(toolName, scope);
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
async revoke(toolName) {
|
|
2800
|
-
await this.sessionStore.revoke(toolName);
|
|
2801
|
-
await this.projectStore.revoke(toolName);
|
|
2802
|
-
await this.userStore.revoke(toolName);
|
|
2803
|
-
}
|
|
2804
|
-
async clear() {
|
|
2805
|
-
await this.sessionStore.clear();
|
|
2806
|
-
await this.projectStore.clear();
|
|
2807
|
-
await this.userStore.clear();
|
|
2808
|
-
}
|
|
2809
|
-
async dispose() {
|
|
2810
|
-
await this.sessionStore.dispose();
|
|
2811
|
-
await this.projectStore.dispose();
|
|
2812
|
-
if (this.userStore !== this.projectStore) {
|
|
2813
|
-
await this.userStore.dispose();
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
};
|
|
2817
|
-
}
|
|
2818
|
-
});
|
|
2819
|
-
|
|
2820
|
-
// src/index.ts
|
|
2821
|
-
var src_exports = {};
|
|
2822
|
-
__export(src_exports, {
|
|
2823
|
-
AbortError: () => AbortError,
|
|
2824
|
-
AgentSDKError: () => AgentSDKError,
|
|
2825
|
-
BackendAlreadyRegisteredError: () => BackendAlreadyRegisteredError,
|
|
2826
|
-
BackendNotFoundError: () => BackendNotFoundError,
|
|
2827
|
-
BaseAgent: () => BaseAgent,
|
|
2828
|
-
CompositePermissionStore: () => CompositePermissionStore,
|
|
2829
|
-
DependencyError: () => DependencyError,
|
|
2830
|
-
DisposedError: () => DisposedError,
|
|
2831
|
-
FilePermissionStore: () => FilePermissionStore,
|
|
2832
|
-
InMemoryPermissionStore: () => InMemoryPermissionStore,
|
|
2833
|
-
ReentrancyError: () => ReentrancyError,
|
|
2834
|
-
StructuredOutputError: () => StructuredOutputError,
|
|
2835
|
-
SubprocessError: () => SubprocessError,
|
|
2836
|
-
ToolExecutionError: () => ToolExecutionError,
|
|
2837
|
-
buildSystemPrompt: () => buildSystemPrompt,
|
|
2838
|
-
contentToText: () => contentToText,
|
|
2839
|
-
createAgentService: () => createAgentService,
|
|
2840
|
-
createDefaultPermissionStore: () => createDefaultPermissionStore,
|
|
2841
|
-
getTextContent: () => getTextContent,
|
|
2842
|
-
hasBackend: () => hasBackend,
|
|
2843
|
-
isMultiPartContent: () => isMultiPartContent,
|
|
2844
|
-
isTextContent: () => isTextContent,
|
|
2845
|
-
isToolDefinition: () => isToolDefinition,
|
|
2846
|
-
listBackends: () => listBackends,
|
|
2847
|
-
messagesToPrompt: () => messagesToPrompt,
|
|
2848
|
-
registerBackend: () => registerBackend,
|
|
2849
|
-
resetRegistry: () => resetRegistry,
|
|
2850
|
-
unregisterBackend: () => unregisterBackend,
|
|
2851
|
-
zodToJsonSchema: () => zodToJsonSchema
|
|
2852
|
-
});
|
|
2853
|
-
var init_src = __esm({
|
|
2854
|
-
"src/index.ts"() {
|
|
2855
|
-
init_types();
|
|
2856
|
-
init_errors();
|
|
2857
|
-
init_registry();
|
|
2858
|
-
init_base_agent();
|
|
2859
|
-
init_schema();
|
|
2860
|
-
init_messages();
|
|
2861
|
-
init_permission_store();
|
|
2862
|
-
}
|
|
2863
|
-
});
|
|
2864
|
-
|
|
2865
|
-
// src/chat/core.ts
|
|
2810
|
+
// src/chat/types.ts
|
|
2866
2811
|
function createChatId() {
|
|
2867
2812
|
return crypto.randomUUID();
|
|
2868
2813
|
}
|
|
2814
|
+
|
|
2815
|
+
// src/chat/chat-utils.ts
|
|
2869
2816
|
function getMessageText(message) {
|
|
2870
2817
|
return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
2871
2818
|
}
|
|
2872
2819
|
function getMessageToolCalls(message) {
|
|
2873
2820
|
return message.parts.filter((p) => p.type === "tool_call");
|
|
2874
2821
|
}
|
|
2822
|
+
|
|
2823
|
+
// src/chat/bridge.ts
|
|
2875
2824
|
function agentEventToChatEvent(event, messageId) {
|
|
2876
2825
|
switch (event.type) {
|
|
2877
2826
|
case "text_delta":
|
|
@@ -2924,6 +2873,7 @@ function agentEventToChatEvent(event, messageId) {
|
|
|
2924
2873
|
type: "error",
|
|
2925
2874
|
error: event.error,
|
|
2926
2875
|
recoverable: event.recoverable,
|
|
2876
|
+
code: event.code,
|
|
2927
2877
|
messageId
|
|
2928
2878
|
};
|
|
2929
2879
|
case "heartbeat":
|
|
@@ -2931,8 +2881,9 @@ function agentEventToChatEvent(event, messageId) {
|
|
|
2931
2881
|
case "ask_user":
|
|
2932
2882
|
case "ask_user_response":
|
|
2933
2883
|
case "session_info":
|
|
2934
|
-
case "done":
|
|
2935
2884
|
return null;
|
|
2885
|
+
case "done":
|
|
2886
|
+
return { type: "done", finalOutput: event.finalOutput ?? void 0, finishReason: event.finishReason };
|
|
2936
2887
|
default:
|
|
2937
2888
|
return null;
|
|
2938
2889
|
}
|
|
@@ -2945,26 +2896,42 @@ async function* adaptAgentEvents(events, messageId) {
|
|
|
2945
2896
|
}
|
|
2946
2897
|
}
|
|
2947
2898
|
}
|
|
2948
|
-
|
|
2899
|
+
|
|
2900
|
+
// src/chat/conversion.ts
|
|
2901
|
+
function toAgentMessages(message) {
|
|
2949
2902
|
const textContent = getMessageText(message);
|
|
2950
2903
|
const toolCallParts = getMessageToolCalls(message);
|
|
2951
2904
|
switch (message.role) {
|
|
2952
2905
|
case "user":
|
|
2953
|
-
return { role: "user", content: textContent };
|
|
2906
|
+
return [{ role: "user", content: textContent }];
|
|
2954
2907
|
case "assistant": {
|
|
2955
2908
|
const toolCalls = toolCallParts.length > 0 ? toolCallParts.map((p) => ({ id: p.toolCallId, name: p.name, args: p.args })) : void 0;
|
|
2956
|
-
|
|
2909
|
+
const assistantMsg = {
|
|
2957
2910
|
role: "assistant",
|
|
2958
2911
|
content: textContent,
|
|
2959
2912
|
toolCalls
|
|
2960
2913
|
};
|
|
2914
|
+
const toolResults = extractToolResults(message);
|
|
2915
|
+
if (toolResults.length > 0) {
|
|
2916
|
+
return [assistantMsg, { role: "tool", toolResults }];
|
|
2917
|
+
}
|
|
2918
|
+
return [assistantMsg];
|
|
2961
2919
|
}
|
|
2962
2920
|
case "system":
|
|
2963
|
-
return { role: "system", content: textContent };
|
|
2921
|
+
return [{ role: "system", content: textContent }];
|
|
2964
2922
|
}
|
|
2965
2923
|
}
|
|
2924
|
+
function extractToolResults(message) {
|
|
2925
|
+
return getMessageToolCalls(message).filter((p) => p.result !== void 0).map((p) => ({
|
|
2926
|
+
toolCallId: p.toolCallId,
|
|
2927
|
+
name: p.name,
|
|
2928
|
+
result: p.result,
|
|
2929
|
+
isError: p.status === "error" ? true : void 0
|
|
2930
|
+
}));
|
|
2931
|
+
}
|
|
2966
2932
|
|
|
2967
2933
|
// src/chat/errors.ts
|
|
2934
|
+
init_errors2();
|
|
2968
2935
|
init_errors();
|
|
2969
2936
|
var ChatError = class extends AgentSDKError {
|
|
2970
2937
|
code;
|
|
@@ -2972,7 +2939,11 @@ var ChatError = class extends AgentSDKError {
|
|
|
2972
2939
|
retryAfter;
|
|
2973
2940
|
timestamp;
|
|
2974
2941
|
constructor(message, options) {
|
|
2975
|
-
super(message, {
|
|
2942
|
+
super(message, {
|
|
2943
|
+
cause: options.cause,
|
|
2944
|
+
code: options.code,
|
|
2945
|
+
retryable: options.retryable
|
|
2946
|
+
});
|
|
2976
2947
|
this.name = "ChatError";
|
|
2977
2948
|
this.code = options.code;
|
|
2978
2949
|
this.retryable = options.retryable ?? false;
|
|
@@ -2984,25 +2955,51 @@ var ChatError = class extends AgentSDKError {
|
|
|
2984
2955
|
// src/chat/backends/base.ts
|
|
2985
2956
|
var BaseBackendAdapter = class {
|
|
2986
2957
|
name;
|
|
2987
|
-
_agentService;
|
|
2988
|
-
|
|
2958
|
+
_agentService = null;
|
|
2959
|
+
_agentServiceFactory = null;
|
|
2989
2960
|
_disposed = false;
|
|
2990
2961
|
_agentConfig;
|
|
2991
2962
|
_ownsService;
|
|
2963
|
+
// Agent lifecycle: tracks current agent and the model it was created with.
|
|
2964
|
+
// For persistent sessions, reused across calls when model matches.
|
|
2965
|
+
// For non-persistent, recreated every call.
|
|
2966
|
+
_currentAgent = null;
|
|
2992
2967
|
constructor(name, options) {
|
|
2993
2968
|
this.name = name;
|
|
2994
2969
|
this._agentConfig = options.agentConfig;
|
|
2995
2970
|
if (options.agentService) {
|
|
2996
2971
|
this._agentService = options.agentService;
|
|
2997
2972
|
this._ownsService = false;
|
|
2973
|
+
} else if (options.agentServiceFactory) {
|
|
2974
|
+
this._agentServiceFactory = options.agentServiceFactory;
|
|
2975
|
+
this._ownsService = true;
|
|
2998
2976
|
} else {
|
|
2999
2977
|
this._agentService = this.createService();
|
|
3000
2978
|
this._ownsService = true;
|
|
3001
2979
|
}
|
|
3002
2980
|
}
|
|
3003
2981
|
get agentService() {
|
|
2982
|
+
if (!this._agentService) {
|
|
2983
|
+
if (this._agentServiceFactory) {
|
|
2984
|
+
this._agentService = this._agentServiceFactory();
|
|
2985
|
+
this._agentServiceFactory = null;
|
|
2986
|
+
} else {
|
|
2987
|
+
throw new ChatError("Agent service not available", {
|
|
2988
|
+
code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */
|
|
2989
|
+
});
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
3004
2992
|
return this._agentService;
|
|
3005
2993
|
}
|
|
2994
|
+
get currentModel() {
|
|
2995
|
+
return this._agentConfig.model;
|
|
2996
|
+
}
|
|
2997
|
+
/**
|
|
2998
|
+
* @deprecated No-op. Tools are passed per-call via SendMessageOptions.tools.
|
|
2999
|
+
* Kept for backward compatibility with code that calls setTools() directly.
|
|
3000
|
+
*/
|
|
3001
|
+
setTools() {
|
|
3002
|
+
}
|
|
3006
3003
|
async sendMessage(session, message, options) {
|
|
3007
3004
|
this.assertNotDisposed();
|
|
3008
3005
|
const events = this.streamMessage(session, message, options);
|
|
@@ -3030,7 +3027,7 @@ var BaseBackendAdapter = class {
|
|
|
3030
3027
|
async *streamMessage(session, message, options) {
|
|
3031
3028
|
this.assertNotDisposed();
|
|
3032
3029
|
const agent = this.getOrCreateAgent(options);
|
|
3033
|
-
const messages = session.messages.
|
|
3030
|
+
const messages = session.messages.flatMap(toAgentMessages);
|
|
3034
3031
|
messages.push({ role: "user", content: message });
|
|
3035
3032
|
yield* this.streamAgentEvents(agent, messages, options);
|
|
3036
3033
|
}
|
|
@@ -3040,9 +3037,13 @@ var BaseBackendAdapter = class {
|
|
|
3040
3037
|
*/
|
|
3041
3038
|
async *streamAgentEvents(agent, messages, options) {
|
|
3042
3039
|
const messageId = createChatId();
|
|
3040
|
+
const model = options?.model ?? this._agentConfig.model ?? "";
|
|
3043
3041
|
const agentEvents = agent.streamWithContext(messages, {
|
|
3042
|
+
model,
|
|
3044
3043
|
signal: options?.signal,
|
|
3045
|
-
context: options?.context
|
|
3044
|
+
context: options?.context,
|
|
3045
|
+
tools: options?.tools,
|
|
3046
|
+
...options?.systemPrompt ? { systemMessage: options.systemPrompt } : {}
|
|
3046
3047
|
});
|
|
3047
3048
|
yield { type: "message:start", messageId, role: "assistant" };
|
|
3048
3049
|
let text = "";
|
|
@@ -3068,31 +3069,46 @@ var BaseBackendAdapter = class {
|
|
|
3068
3069
|
}
|
|
3069
3070
|
async listModels() {
|
|
3070
3071
|
this.assertNotDisposed();
|
|
3071
|
-
return this.
|
|
3072
|
+
return this.agentService.listModels();
|
|
3072
3073
|
}
|
|
3073
3074
|
async validate() {
|
|
3074
3075
|
this.assertNotDisposed();
|
|
3075
|
-
return this.
|
|
3076
|
+
return this.agentService.validate();
|
|
3076
3077
|
}
|
|
3077
3078
|
async dispose() {
|
|
3078
3079
|
if (this._disposed) return;
|
|
3079
3080
|
this._disposed = true;
|
|
3080
|
-
this.
|
|
3081
|
-
|
|
3082
|
-
|
|
3081
|
+
if (this._currentAgent) {
|
|
3082
|
+
this._currentAgent.instance.dispose();
|
|
3083
|
+
this._currentAgent = null;
|
|
3084
|
+
}
|
|
3085
|
+
if (this._ownsService && this._agentService && typeof this._agentService.dispose === "function") {
|
|
3083
3086
|
await this._agentService.dispose();
|
|
3084
3087
|
}
|
|
3085
3088
|
}
|
|
3086
|
-
/** Get or create an agent
|
|
3089
|
+
/** Get or create an agent. Model is passed per-call via RunOptions.
|
|
3090
|
+
* Tools are passed per-call via SendMessageOptions — not baked into config.
|
|
3091
|
+
* For persistent sessions, reuses agent when model matches. */
|
|
3087
3092
|
getOrCreateAgent(options) {
|
|
3088
|
-
const
|
|
3089
|
-
if (this._agentConfig.sessionMode === "persistent" && this.
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
this.
|
|
3095
|
-
}
|
|
3093
|
+
const model = options?.model ?? this._agentConfig.model;
|
|
3094
|
+
if (this._agentConfig.sessionMode === "persistent" && this._currentAgent) {
|
|
3095
|
+
if (this._currentAgent.model === model) {
|
|
3096
|
+
return this._currentAgent.instance;
|
|
3097
|
+
}
|
|
3098
|
+
this._currentAgent.instance.dispose();
|
|
3099
|
+
this._currentAgent = null;
|
|
3100
|
+
}
|
|
3101
|
+
if (this._currentAgent) {
|
|
3102
|
+
this._currentAgent.instance.dispose();
|
|
3103
|
+
this._currentAgent = null;
|
|
3104
|
+
}
|
|
3105
|
+
const config = {
|
|
3106
|
+
...this._agentConfig,
|
|
3107
|
+
...model !== void 0 && { model },
|
|
3108
|
+
...options?.tools?.length ? { tools: options.tools } : {}
|
|
3109
|
+
};
|
|
3110
|
+
const agent = this.agentService.createAgent(config);
|
|
3111
|
+
this._currentAgent = { instance: agent, model };
|
|
3096
3112
|
return agent;
|
|
3097
3113
|
}
|
|
3098
3114
|
assertNotDisposed() {
|
|
@@ -3104,21 +3120,15 @@ var BaseBackendAdapter = class {
|
|
|
3104
3120
|
}
|
|
3105
3121
|
};
|
|
3106
3122
|
|
|
3107
|
-
// src/chat/backends/
|
|
3108
|
-
var
|
|
3123
|
+
// src/chat/backends/resumable.ts
|
|
3124
|
+
var ResumableChatAdapter = class extends BaseBackendAdapter {
|
|
3109
3125
|
_backendSessionId = null;
|
|
3110
|
-
|
|
3111
|
-
constructor(options) {
|
|
3126
|
+
constructor(name, options) {
|
|
3112
3127
|
const agentConfig = {
|
|
3113
3128
|
...options.agentConfig,
|
|
3114
3129
|
sessionMode: "persistent"
|
|
3115
3130
|
};
|
|
3116
|
-
super(
|
|
3117
|
-
this._copilotOptions = options.copilotOptions;
|
|
3118
|
-
}
|
|
3119
|
-
createService() {
|
|
3120
|
-
const { createAgentService: createAgentService2 } = (init_src(), __toCommonJS(src_exports));
|
|
3121
|
-
return createAgentService2("copilot", this._copilotOptions);
|
|
3131
|
+
super(name, { ...options, agentConfig });
|
|
3122
3132
|
}
|
|
3123
3133
|
get backendSessionId() {
|
|
3124
3134
|
return this._backendSessionId;
|
|
@@ -3147,7 +3157,7 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
3147
3157
|
{ code: "SESSION_EXPIRED" /* SESSION_EXPIRED */ }
|
|
3148
3158
|
);
|
|
3149
3159
|
}
|
|
3150
|
-
const messages = session.messages.
|
|
3160
|
+
const messages = session.messages.flatMap(toAgentMessages);
|
|
3151
3161
|
yield* this.streamAgentEvents(agent, messages, options);
|
|
3152
3162
|
}
|
|
3153
3163
|
captureSessionId(agent) {
|
|
@@ -3157,81 +3167,325 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
3157
3167
|
}
|
|
3158
3168
|
};
|
|
3159
3169
|
|
|
3170
|
+
// src/chat/backends/copilot.ts
|
|
3171
|
+
var CopilotChatAdapter = class extends ResumableChatAdapter {
|
|
3172
|
+
_copilotOptions;
|
|
3173
|
+
constructor(options) {
|
|
3174
|
+
super("copilot", options);
|
|
3175
|
+
this._copilotOptions = options.copilotOptions;
|
|
3176
|
+
}
|
|
3177
|
+
createService() {
|
|
3178
|
+
const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
|
|
3179
|
+
return createCopilotService2(this._copilotOptions || {});
|
|
3180
|
+
}
|
|
3181
|
+
};
|
|
3182
|
+
|
|
3160
3183
|
// src/chat/backends/claude.ts
|
|
3161
|
-
var ClaudeChatAdapter = class extends
|
|
3162
|
-
_backendSessionId = null;
|
|
3184
|
+
var ClaudeChatAdapter = class extends ResumableChatAdapter {
|
|
3163
3185
|
_claudeOptions;
|
|
3164
3186
|
constructor(options) {
|
|
3165
|
-
|
|
3166
|
-
...options.agentConfig,
|
|
3167
|
-
sessionMode: "persistent"
|
|
3168
|
-
};
|
|
3169
|
-
super("claude", { ...options, agentConfig });
|
|
3187
|
+
super("claude", options);
|
|
3170
3188
|
this._claudeOptions = options.claudeOptions;
|
|
3171
3189
|
}
|
|
3172
3190
|
createService() {
|
|
3173
|
-
const {
|
|
3174
|
-
return
|
|
3191
|
+
const { createClaudeService: createClaudeService2 } = (init_claude(), __toCommonJS(claude_exports));
|
|
3192
|
+
return createClaudeService2(this._claudeOptions || {});
|
|
3175
3193
|
}
|
|
3176
|
-
|
|
3177
|
-
|
|
3194
|
+
};
|
|
3195
|
+
|
|
3196
|
+
// src/chat/backends/vercel-ai.ts
|
|
3197
|
+
var VercelAIChatAdapter = class extends BaseBackendAdapter {
|
|
3198
|
+
_vercelOptions;
|
|
3199
|
+
constructor(options) {
|
|
3200
|
+
super("vercel-ai", options);
|
|
3201
|
+
this._vercelOptions = options.vercelOptions;
|
|
3178
3202
|
}
|
|
3179
|
-
|
|
3180
|
-
|
|
3203
|
+
createService() {
|
|
3204
|
+
const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
|
|
3205
|
+
return createVercelAIService2(this._vercelOptions || {});
|
|
3181
3206
|
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3207
|
+
captureSessionId(_agent) {
|
|
3208
|
+
}
|
|
3209
|
+
};
|
|
3210
|
+
|
|
3211
|
+
// src/backends/mock-llm.ts
|
|
3212
|
+
init_base_agent();
|
|
3213
|
+
init_errors2();
|
|
3214
|
+
function extractPrompt(messages) {
|
|
3215
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3216
|
+
const msg = messages[i];
|
|
3217
|
+
if (msg.role === "user") {
|
|
3218
|
+
return typeof msg.content === "string" ? msg.content : msg.content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
return "";
|
|
3222
|
+
}
|
|
3223
|
+
function resolveResponse(mode, messages, callIndex) {
|
|
3224
|
+
switch (mode.type) {
|
|
3225
|
+
case "echo":
|
|
3226
|
+
return extractPrompt(messages);
|
|
3227
|
+
case "static":
|
|
3228
|
+
return mode.response;
|
|
3229
|
+
case "scripted": {
|
|
3230
|
+
if (mode.loop) {
|
|
3231
|
+
return mode.responses[callIndex % mode.responses.length];
|
|
3232
|
+
}
|
|
3233
|
+
if (callIndex < mode.responses.length) {
|
|
3234
|
+
return mode.responses[callIndex];
|
|
3235
|
+
}
|
|
3236
|
+
return mode.responses[mode.responses.length - 1];
|
|
3237
|
+
}
|
|
3238
|
+
case "error":
|
|
3239
|
+
throw new AgentSDKError(mode.error, {
|
|
3240
|
+
code: mode.code ?? "backend_error",
|
|
3241
|
+
retryable: mode.recoverable ?? false
|
|
3187
3242
|
});
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
async function applyLatency(latency, signal) {
|
|
3246
|
+
if (!latency) return;
|
|
3247
|
+
const ms = latency.type === "fixed" ? latency.ms : latency.minMs + Math.random() * (latency.maxMs - latency.minMs);
|
|
3248
|
+
if (ms <= 0) return;
|
|
3249
|
+
await new Promise((resolve, reject) => {
|
|
3250
|
+
const timer = setTimeout(resolve, ms);
|
|
3251
|
+
const onAbort = () => {
|
|
3252
|
+
clearTimeout(timer);
|
|
3253
|
+
reject(new Error("aborted"));
|
|
3254
|
+
};
|
|
3255
|
+
if (signal.aborted) {
|
|
3256
|
+
clearTimeout(timer);
|
|
3257
|
+
reject(new Error("aborted"));
|
|
3258
|
+
return;
|
|
3188
3259
|
}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3260
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3261
|
+
});
|
|
3262
|
+
}
|
|
3263
|
+
function chunkText(text, streaming) {
|
|
3264
|
+
if (streaming?.chunkSize && streaming.chunkSize > 0) {
|
|
3265
|
+
const chunks = [];
|
|
3266
|
+
for (let i = 0; i < text.length; i += streaming.chunkSize) {
|
|
3267
|
+
chunks.push(text.slice(i, i + streaming.chunkSize));
|
|
3196
3268
|
}
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3269
|
+
return chunks;
|
|
3270
|
+
}
|
|
3271
|
+
return text.split(/(\s+)/).filter(Boolean);
|
|
3272
|
+
}
|
|
3273
|
+
async function chunkDelay(streaming, signal) {
|
|
3274
|
+
const ms = streaming?.chunkDelayMs;
|
|
3275
|
+
if (!ms || ms <= 0) return;
|
|
3276
|
+
await new Promise((resolve, reject) => {
|
|
3277
|
+
const timer = setTimeout(resolve, ms);
|
|
3278
|
+
const onAbort = () => {
|
|
3279
|
+
clearTimeout(timer);
|
|
3280
|
+
reject(new Error("aborted"));
|
|
3281
|
+
};
|
|
3282
|
+
if (signal.aborted) {
|
|
3283
|
+
clearTimeout(timer);
|
|
3284
|
+
reject(new Error("aborted"));
|
|
3285
|
+
return;
|
|
3202
3286
|
}
|
|
3203
|
-
|
|
3204
|
-
|
|
3287
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
3290
|
+
var MockLLMAgent = class extends BaseAgent {
|
|
3291
|
+
backendName = "mock-llm";
|
|
3292
|
+
mode;
|
|
3293
|
+
latency;
|
|
3294
|
+
streaming;
|
|
3295
|
+
finishReason;
|
|
3296
|
+
permissions;
|
|
3297
|
+
toolCallConfigs;
|
|
3298
|
+
configuredStructuredOutput;
|
|
3299
|
+
callIndex = 0;
|
|
3300
|
+
constructor(config, options) {
|
|
3301
|
+
super(config);
|
|
3302
|
+
this.mode = options.mode ?? { type: "echo" };
|
|
3303
|
+
this.latency = options.latency;
|
|
3304
|
+
this.streaming = options.streaming;
|
|
3305
|
+
this.finishReason = options.finishReason ?? "stop";
|
|
3306
|
+
this.permissions = options.permissions;
|
|
3307
|
+
this.toolCallConfigs = options.toolCalls ?? [];
|
|
3308
|
+
this.configuredStructuredOutput = options.structuredOutput;
|
|
3309
|
+
}
|
|
3310
|
+
async executeRun(messages, _options, signal) {
|
|
3311
|
+
this.checkAbort(signal);
|
|
3312
|
+
await applyLatency(this.latency, signal);
|
|
3313
|
+
this.checkAbort(signal);
|
|
3314
|
+
const idx = this.callIndex++;
|
|
3315
|
+
const output = resolveResponse(this.mode, messages, idx);
|
|
3316
|
+
const toolCalls = this.toolCallConfigs.map((tc) => ({
|
|
3317
|
+
toolName: tc.toolName,
|
|
3318
|
+
args: tc.args ?? {},
|
|
3319
|
+
result: tc.result ?? null,
|
|
3320
|
+
approved: true
|
|
3321
|
+
}));
|
|
3322
|
+
return {
|
|
3323
|
+
output,
|
|
3324
|
+
structuredOutput: void 0,
|
|
3325
|
+
toolCalls,
|
|
3326
|
+
messages: [
|
|
3327
|
+
...messages,
|
|
3328
|
+
{ role: "assistant", content: output }
|
|
3329
|
+
],
|
|
3330
|
+
usage: { promptTokens: 10, completionTokens: output.length }
|
|
3331
|
+
};
|
|
3205
3332
|
}
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3333
|
+
async executeRunStructured(messages, _schema, _options, signal) {
|
|
3334
|
+
this.checkAbort(signal);
|
|
3335
|
+
await applyLatency(this.latency, signal);
|
|
3336
|
+
this.checkAbort(signal);
|
|
3337
|
+
const idx = this.callIndex++;
|
|
3338
|
+
const output = resolveResponse(this.mode, messages, idx);
|
|
3339
|
+
let parsed;
|
|
3340
|
+
if (this.configuredStructuredOutput !== void 0) {
|
|
3341
|
+
parsed = this.configuredStructuredOutput;
|
|
3342
|
+
} else {
|
|
3343
|
+
try {
|
|
3344
|
+
parsed = JSON.parse(output);
|
|
3345
|
+
} catch {
|
|
3346
|
+
parsed = output;
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
return {
|
|
3350
|
+
output,
|
|
3351
|
+
structuredOutput: parsed,
|
|
3352
|
+
toolCalls: [],
|
|
3353
|
+
messages: [
|
|
3354
|
+
...messages,
|
|
3355
|
+
{ role: "assistant", content: output }
|
|
3356
|
+
],
|
|
3357
|
+
usage: { promptTokens: 10, completionTokens: output.length }
|
|
3358
|
+
};
|
|
3359
|
+
}
|
|
3360
|
+
async *executeStream(messages, _options, signal) {
|
|
3361
|
+
this.checkAbort(signal);
|
|
3362
|
+
await applyLatency(this.latency, signal);
|
|
3363
|
+
this.checkAbort(signal);
|
|
3364
|
+
if (this.permissions) {
|
|
3365
|
+
yield* this.simulatePermissions(signal);
|
|
3366
|
+
}
|
|
3367
|
+
if (this.toolCallConfigs.length > 0) {
|
|
3368
|
+
yield* this.simulateToolCalls(signal);
|
|
3369
|
+
}
|
|
3370
|
+
const idx = this.callIndex++;
|
|
3371
|
+
const output = resolveResponse(this.mode, messages, idx);
|
|
3372
|
+
const chunks = chunkText(output, this.streaming);
|
|
3373
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
3374
|
+
this.checkAbort(signal);
|
|
3375
|
+
if (i > 0) {
|
|
3376
|
+
await chunkDelay(this.streaming, signal);
|
|
3377
|
+
}
|
|
3378
|
+
yield { type: "text_delta", text: chunks[i] };
|
|
3379
|
+
}
|
|
3380
|
+
yield {
|
|
3381
|
+
type: "usage_update",
|
|
3382
|
+
promptTokens: 10,
|
|
3383
|
+
completionTokens: output.length
|
|
3384
|
+
};
|
|
3385
|
+
yield {
|
|
3386
|
+
type: "done",
|
|
3387
|
+
finalOutput: output,
|
|
3388
|
+
finishReason: this.finishReason
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
async *simulateToolCalls(signal) {
|
|
3392
|
+
for (let i = 0; i < this.toolCallConfigs.length; i++) {
|
|
3393
|
+
this.checkAbort(signal);
|
|
3394
|
+
const tc = this.toolCallConfigs[i];
|
|
3395
|
+
const toolCallId = tc.toolCallId ?? `mock-tc-${i}`;
|
|
3396
|
+
yield {
|
|
3397
|
+
type: "tool_call_start",
|
|
3398
|
+
toolCallId,
|
|
3399
|
+
toolName: tc.toolName,
|
|
3400
|
+
args: tc.args ?? {}
|
|
3401
|
+
};
|
|
3402
|
+
yield {
|
|
3403
|
+
type: "tool_call_end",
|
|
3404
|
+
toolCallId,
|
|
3405
|
+
toolName: tc.toolName,
|
|
3406
|
+
result: tc.result ?? null
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
async *simulatePermissions(signal) {
|
|
3411
|
+
const perms = this.permissions;
|
|
3412
|
+
for (const toolName of perms.toolNames) {
|
|
3413
|
+
this.checkAbort(signal);
|
|
3414
|
+
const request = {
|
|
3415
|
+
toolName,
|
|
3416
|
+
toolArgs: {}
|
|
3417
|
+
};
|
|
3418
|
+
yield { type: "permission_request", request };
|
|
3419
|
+
if (perms.denyTools?.includes(toolName)) {
|
|
3420
|
+
yield {
|
|
3421
|
+
type: "permission_response",
|
|
3422
|
+
toolName,
|
|
3423
|
+
decision: { allowed: false, reason: "Denied by mock configuration" }
|
|
3424
|
+
};
|
|
3425
|
+
} else if (perms.autoApprove) {
|
|
3426
|
+
yield {
|
|
3427
|
+
type: "permission_response",
|
|
3428
|
+
toolName,
|
|
3429
|
+
decision: { allowed: true, scope: "once" }
|
|
3430
|
+
};
|
|
3431
|
+
} else {
|
|
3432
|
+
const supervisor = this.getConfig().supervisor;
|
|
3433
|
+
if (supervisor?.onPermission) {
|
|
3434
|
+
const decision = await supervisor.onPermission(request, signal);
|
|
3435
|
+
yield { type: "permission_response", toolName, decision };
|
|
3436
|
+
} else {
|
|
3437
|
+
yield {
|
|
3438
|
+
type: "permission_response",
|
|
3439
|
+
toolName,
|
|
3440
|
+
decision: { allowed: true, scope: "once" }
|
|
3441
|
+
};
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3209
3444
|
}
|
|
3210
3445
|
}
|
|
3211
3446
|
};
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
constructor(options) {
|
|
3217
|
-
|
|
3218
|
-
this.
|
|
3447
|
+
var MockLLMService = class {
|
|
3448
|
+
name = "mock-llm";
|
|
3449
|
+
options;
|
|
3450
|
+
models;
|
|
3451
|
+
constructor(options = {}) {
|
|
3452
|
+
this.options = options;
|
|
3453
|
+
this.models = (options.models ?? [
|
|
3454
|
+
{ id: "mock-fast", name: "Mock Fast" },
|
|
3455
|
+
{ id: "mock-quality", name: "Mock Quality" }
|
|
3456
|
+
]).map((m) => ({
|
|
3457
|
+
id: m.id,
|
|
3458
|
+
name: m.name,
|
|
3459
|
+
description: m.description
|
|
3460
|
+
}));
|
|
3461
|
+
}
|
|
3462
|
+
createAgent(config) {
|
|
3463
|
+
return new MockLLMAgent(config, this.options);
|
|
3219
3464
|
}
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
return createAgentService2("vercel-ai", this._vercelOptions);
|
|
3465
|
+
async listModels() {
|
|
3466
|
+
return this.models;
|
|
3223
3467
|
}
|
|
3224
|
-
|
|
3225
|
-
return
|
|
3468
|
+
async validate() {
|
|
3469
|
+
return { valid: true, errors: [] };
|
|
3226
3470
|
}
|
|
3227
|
-
|
|
3228
|
-
return false;
|
|
3471
|
+
async dispose() {
|
|
3229
3472
|
}
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3473
|
+
};
|
|
3474
|
+
function createMockLLMService(options = {}) {
|
|
3475
|
+
return new MockLLMService(options);
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
// src/chat/backends/mock-llm.ts
|
|
3479
|
+
var MockLLMChatAdapter = class extends BaseBackendAdapter {
|
|
3480
|
+
constructor(options) {
|
|
3481
|
+
const mockOpts = options.mockOptions;
|
|
3482
|
+
super("mock-llm", {
|
|
3483
|
+
...options,
|
|
3484
|
+
agentServiceFactory: () => createMockLLMService(mockOpts || {})
|
|
3485
|
+
});
|
|
3486
|
+
}
|
|
3487
|
+
createService() {
|
|
3488
|
+
return createMockLLMService({});
|
|
3235
3489
|
}
|
|
3236
3490
|
captureSessionId(_agent) {
|
|
3237
3491
|
}
|
|
@@ -3312,16 +3566,22 @@ var SSEChatTransport = class {
|
|
|
3312
3566
|
};
|
|
3313
3567
|
async function streamToTransport(events, transport) {
|
|
3314
3568
|
try {
|
|
3315
|
-
|
|
3569
|
+
const textChunks = [];
|
|
3570
|
+
let finishReason;
|
|
3316
3571
|
for await (const event of events) {
|
|
3317
3572
|
if (!transport.isOpen) break;
|
|
3573
|
+
if (event.type === "done") {
|
|
3574
|
+
finishReason = event.finishReason;
|
|
3575
|
+
continue;
|
|
3576
|
+
}
|
|
3318
3577
|
transport.send(event);
|
|
3319
3578
|
if (event.type === "message:delta") {
|
|
3320
|
-
|
|
3579
|
+
textChunks.push(event.text);
|
|
3321
3580
|
}
|
|
3322
3581
|
}
|
|
3323
3582
|
if (transport.isOpen) {
|
|
3324
|
-
|
|
3583
|
+
const finalOutput = textChunks.length > 0 ? textChunks.join("") : void 0;
|
|
3584
|
+
transport.send({ type: "done", finalOutput, finishReason });
|
|
3325
3585
|
}
|
|
3326
3586
|
transport.close();
|
|
3327
3587
|
} catch (err) {
|
|
@@ -3412,9 +3672,9 @@ var InProcessChatTransport = class {
|
|
|
3412
3672
|
send(event) {
|
|
3413
3673
|
if (!this._open) return;
|
|
3414
3674
|
if (this._resolve) {
|
|
3415
|
-
const
|
|
3675
|
+
const resolve = this._resolve;
|
|
3416
3676
|
this._resolve = null;
|
|
3417
|
-
|
|
3677
|
+
resolve({ value: event, done: false });
|
|
3418
3678
|
} else {
|
|
3419
3679
|
this._buffer.push(event);
|
|
3420
3680
|
}
|
|
@@ -3423,9 +3683,9 @@ var InProcessChatTransport = class {
|
|
|
3423
3683
|
if (!this._open) return;
|
|
3424
3684
|
this._open = false;
|
|
3425
3685
|
if (this._resolve) {
|
|
3426
|
-
const
|
|
3686
|
+
const resolve = this._resolve;
|
|
3427
3687
|
this._resolve = null;
|
|
3428
|
-
|
|
3688
|
+
resolve({ value: void 0, done: true });
|
|
3429
3689
|
}
|
|
3430
3690
|
}
|
|
3431
3691
|
error(err) {
|
|
@@ -3437,9 +3697,9 @@ var InProcessChatTransport = class {
|
|
|
3437
3697
|
recoverable: false
|
|
3438
3698
|
};
|
|
3439
3699
|
if (this._resolve) {
|
|
3440
|
-
const
|
|
3700
|
+
const resolve = this._resolve;
|
|
3441
3701
|
this._resolve = null;
|
|
3442
|
-
|
|
3702
|
+
resolve({ value: errorEvent, done: false });
|
|
3443
3703
|
} else {
|
|
3444
3704
|
this._error = err;
|
|
3445
3705
|
}
|
|
@@ -3464,8 +3724,8 @@ var InProcessChatTransport = class {
|
|
|
3464
3724
|
if (!this._open) {
|
|
3465
3725
|
return Promise.resolve({ value: void 0, done: true });
|
|
3466
3726
|
}
|
|
3467
|
-
return new Promise((
|
|
3468
|
-
this._resolve =
|
|
3727
|
+
return new Promise((resolve) => {
|
|
3728
|
+
this._resolve = resolve;
|
|
3469
3729
|
});
|
|
3470
3730
|
}
|
|
3471
3731
|
};
|
|
@@ -3524,10 +3784,13 @@ exports.BaseBackendAdapter = BaseBackendAdapter;
|
|
|
3524
3784
|
exports.ClaudeChatAdapter = ClaudeChatAdapter;
|
|
3525
3785
|
exports.CopilotChatAdapter = CopilotChatAdapter;
|
|
3526
3786
|
exports.InProcessChatTransport = InProcessChatTransport;
|
|
3787
|
+
exports.MockLLMChatAdapter = MockLLMChatAdapter;
|
|
3788
|
+
exports.ResumableChatAdapter = ResumableChatAdapter;
|
|
3527
3789
|
exports.SSEChatTransport = SSEChatTransport;
|
|
3528
3790
|
exports.VercelAIChatAdapter = VercelAIChatAdapter;
|
|
3529
3791
|
exports.WS_READY_STATE = WS_READY_STATE;
|
|
3530
3792
|
exports.WsChatTransport = WsChatTransport;
|
|
3793
|
+
exports.isResumableBackend = isResumableBackend;
|
|
3531
3794
|
exports.streamToTransport = streamToTransport;
|
|
3532
3795
|
exports.withInterceptors = withInterceptors;
|
|
3533
3796
|
//# sourceMappingURL=backends.cjs.map
|