@witqq/agent-sdk 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -34
- package/dist/{types-CqvUAYxt.d.cts → agent-CW9XbmG_.d.ts} +137 -102
- package/dist/{types-CqvUAYxt.d.ts → agent-DxY68NZL.d.cts} +137 -102
- package/dist/auth/index.cjs +72 -1
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +21 -154
- package/dist/auth/index.d.ts +21 -154
- package/dist/auth/index.js +72 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/backends/claude.cjs +480 -261
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +3 -1
- package/dist/backends/claude.d.ts +3 -1
- package/dist/backends/claude.js +480 -261
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +329 -97
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +12 -4
- package/dist/backends/copilot.d.ts +12 -4
- package/dist/backends/copilot.js +329 -97
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/vercel-ai.cjs +294 -61
- package/dist/backends/vercel-ai.cjs.map +1 -1
- package/dist/backends/vercel-ai.d.cts +3 -1
- package/dist/backends/vercel-ai.d.ts +3 -1
- package/dist/backends/vercel-ai.js +294 -61
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/backends-BSrsBYFn.d.cts +39 -0
- package/dist/backends-BSrsBYFn.d.ts +39 -0
- package/dist/chat/accumulator.cjs +1 -1
- package/dist/chat/accumulator.cjs.map +1 -1
- package/dist/chat/accumulator.d.cts +5 -2
- package/dist/chat/accumulator.d.ts +5 -2
- package/dist/chat/accumulator.js +1 -1
- package/dist/chat/accumulator.js.map +1 -1
- package/dist/chat/backends.cjs +736 -746
- package/dist/chat/backends.cjs.map +1 -1
- package/dist/chat/backends.d.cts +10 -6
- package/dist/chat/backends.d.ts +10 -6
- package/dist/chat/backends.js +736 -725
- package/dist/chat/backends.js.map +1 -1
- package/dist/chat/context.cjs +50 -0
- package/dist/chat/context.cjs.map +1 -1
- package/dist/chat/context.d.cts +27 -3
- package/dist/chat/context.d.ts +27 -3
- package/dist/chat/context.js +50 -0
- package/dist/chat/context.js.map +1 -1
- package/dist/chat/core.cjs +25 -2
- package/dist/chat/core.cjs.map +1 -1
- package/dist/chat/core.d.cts +30 -381
- package/dist/chat/core.d.ts +30 -381
- package/dist/chat/core.js +24 -3
- package/dist/chat/core.js.map +1 -1
- package/dist/chat/errors.cjs +48 -26
- package/dist/chat/errors.cjs.map +1 -1
- package/dist/chat/errors.d.cts +6 -31
- package/dist/chat/errors.d.ts +6 -31
- package/dist/chat/errors.js +48 -25
- package/dist/chat/errors.js.map +1 -1
- package/dist/chat/events.cjs.map +1 -1
- package/dist/chat/events.d.cts +6 -2
- package/dist/chat/events.d.ts +6 -2
- package/dist/chat/events.js.map +1 -1
- package/dist/chat/index.cjs +1199 -1008
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +35 -10
- package/dist/chat/index.d.ts +35 -10
- package/dist/chat/index.js +1196 -987
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react/theme.css +2517 -0
- package/dist/chat/react.cjs +2003 -1153
- package/dist/chat/react.cjs.map +1 -1
- package/dist/chat/react.d.cts +590 -121
- package/dist/chat/react.d.ts +590 -121
- package/dist/chat/react.js +1984 -1151
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/runtime.cjs +401 -186
- package/dist/chat/runtime.cjs.map +1 -1
- package/dist/chat/runtime.d.cts +92 -28
- package/dist/chat/runtime.d.ts +92 -28
- package/dist/chat/runtime.js +401 -186
- package/dist/chat/runtime.js.map +1 -1
- package/dist/chat/server.cjs +2234 -209
- package/dist/chat/server.cjs.map +1 -1
- package/dist/chat/server.d.cts +451 -90
- package/dist/chat/server.d.ts +451 -90
- package/dist/chat/server.js +2221 -210
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/sessions.cjs +25 -43
- package/dist/chat/sessions.cjs.map +1 -1
- package/dist/chat/sessions.d.cts +37 -118
- package/dist/chat/sessions.d.ts +37 -118
- package/dist/chat/sessions.js +25 -43
- package/dist/chat/sessions.js.map +1 -1
- package/dist/chat/sqlite.cjs +441 -0
- package/dist/chat/sqlite.cjs.map +1 -0
- package/dist/chat/sqlite.d.cts +128 -0
- package/dist/chat/sqlite.d.ts +128 -0
- package/dist/chat/sqlite.js +435 -0
- package/dist/chat/sqlite.js.map +1 -0
- package/dist/chat/state.cjs +14 -1
- package/dist/chat/state.cjs.map +1 -1
- package/dist/chat/state.d.cts +5 -2
- package/dist/chat/state.d.ts +5 -2
- package/dist/chat/state.js +14 -1
- package/dist/chat/state.js.map +1 -1
- package/dist/chat/storage.cjs +19 -10
- package/dist/chat/storage.cjs.map +1 -1
- package/dist/chat/storage.d.cts +11 -5
- package/dist/chat/storage.d.ts +11 -5
- package/dist/chat/storage.js +19 -10
- package/dist/chat/storage.js.map +1 -1
- package/dist/errors-C-so0M4t.d.cts +33 -0
- package/dist/errors-C-so0M4t.d.ts +33 -0
- package/dist/errors-CmVvczxZ.d.cts +28 -0
- package/dist/errors-CmVvczxZ.d.ts +28 -0
- package/dist/{in-process-transport-C2oPTYs6.d.ts → in-process-transport-C1JnJGVR.d.ts} +28 -23
- package/dist/{in-process-transport-DG-w5G6k.d.cts → in-process-transport-C7DSqPyX.d.cts} +28 -23
- package/dist/index.cjs +340 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +292 -123
- package/dist/index.d.ts +292 -123
- package/dist/index.js +334 -47
- package/dist/index.js.map +1 -1
- package/dist/provider-types-PTSlRPNB.d.cts +39 -0
- package/dist/provider-types-PTSlRPNB.d.ts +39 -0
- package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
- package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
- package/dist/testing.cjs +383 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +132 -0
- package/dist/testing.d.ts +132 -0
- package/dist/testing.js +377 -0
- package/dist/testing.js.map +1 -0
- package/dist/token-store-CSUBgYwn.d.ts +48 -0
- package/dist/token-store-CuC4hB9Z.d.cts +48 -0
- package/dist/{transport-DX1Nhm4N.d.cts → transport-Cdh3M0tS.d.cts} +5 -4
- package/dist/{transport-D1OaUgRk.d.ts → transport-Ciap4PWK.d.ts} +5 -4
- package/dist/{types-CGF7AEX1.d.cts → types-4vbcmPTp.d.cts} +4 -2
- package/dist/{types-Bh5AhqD-.d.ts → types-BxggH0Yh.d.ts} +4 -2
- package/dist/types-DRgd_9R7.d.cts +363 -0
- package/dist/types-ajANVzf7.d.ts +363 -0
- package/package.json +31 -6
- package/dist/errors-BDLbNu9w.d.cts +0 -13
- package/dist/errors-BDLbNu9w.d.ts +0 -13
- package/dist/types-DLZzlJxt.d.ts +0 -39
- package/dist/types-tE0CXwBl.d.cts +0 -39
package/dist/chat/index.cjs
CHANGED
|
@@ -2,29 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var fs = require('fs');
|
|
4
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
5
|
|
|
29
6
|
var __defProp = Object.defineProperty;
|
|
30
7
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -47,16 +24,100 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
47
24
|
};
|
|
48
25
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
49
26
|
|
|
50
|
-
// src/errors.ts
|
|
51
|
-
|
|
27
|
+
// src/types/errors.ts
|
|
28
|
+
function isRecoverableErrorCode(code) {
|
|
29
|
+
return RECOVERABLE_CODES.has(code);
|
|
30
|
+
}
|
|
31
|
+
function classifyAgentError(error) {
|
|
32
|
+
const msg = (error instanceof Error ? error.message : error).toLowerCase();
|
|
33
|
+
if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
|
|
34
|
+
return "TIMEOUT" /* TIMEOUT */;
|
|
35
|
+
}
|
|
36
|
+
if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
|
|
37
|
+
return "RATE_LIMIT" /* RATE_LIMIT */;
|
|
38
|
+
}
|
|
39
|
+
if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
|
|
40
|
+
return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
|
|
41
|
+
}
|
|
42
|
+
if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
|
|
43
|
+
return "NETWORK" /* NETWORK */;
|
|
44
|
+
}
|
|
45
|
+
if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
|
|
46
|
+
return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
|
|
47
|
+
}
|
|
48
|
+
if (msg.includes("abort") || msg.includes("cancel")) {
|
|
49
|
+
return "ABORTED" /* ABORTED */;
|
|
50
|
+
}
|
|
51
|
+
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")) {
|
|
52
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
53
|
+
}
|
|
54
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
55
|
+
}
|
|
56
|
+
exports.ErrorCode = void 0; var RECOVERABLE_CODES;
|
|
52
57
|
var init_errors = __esm({
|
|
58
|
+
"src/types/errors.ts"() {
|
|
59
|
+
exports.ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
60
|
+
ErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
|
|
61
|
+
ErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
|
|
62
|
+
ErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
|
|
63
|
+
ErrorCode2["NETWORK"] = "NETWORK";
|
|
64
|
+
ErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
65
|
+
ErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
|
|
66
|
+
ErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
|
|
67
|
+
ErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
|
|
68
|
+
ErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
|
|
69
|
+
ErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
|
|
70
|
+
ErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
|
|
71
|
+
ErrorCode2["REENTRANCY"] = "REENTRANCY";
|
|
72
|
+
ErrorCode2["DISPOSED"] = "DISPOSED";
|
|
73
|
+
ErrorCode2["ABORTED"] = "ABORTED";
|
|
74
|
+
ErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
|
|
75
|
+
ErrorCode2["DEPENDENCY_MISSING"] = "DEPENDENCY_MISSING";
|
|
76
|
+
ErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
|
|
77
|
+
ErrorCode2["TOOL_EXECUTION"] = "TOOL_EXECUTION";
|
|
78
|
+
ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
79
|
+
ErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
|
|
80
|
+
ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
|
|
81
|
+
ErrorCode2["PROVIDER_NOT_FOUND"] = "PROVIDER_NOT_FOUND";
|
|
82
|
+
ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
|
|
83
|
+
ErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
|
|
84
|
+
ErrorCode2["STORAGE_NOT_FOUND"] = "STORAGE_NOT_FOUND";
|
|
85
|
+
ErrorCode2["STORAGE_DUPLICATE_KEY"] = "STORAGE_DUPLICATE_KEY";
|
|
86
|
+
ErrorCode2["STORAGE_IO_ERROR"] = "STORAGE_IO_ERROR";
|
|
87
|
+
ErrorCode2["STORAGE_SERIALIZATION_ERROR"] = "STORAGE_SERIALIZATION_ERROR";
|
|
88
|
+
return ErrorCode2;
|
|
89
|
+
})(exports.ErrorCode || {});
|
|
90
|
+
RECOVERABLE_CODES = /* @__PURE__ */ new Set([
|
|
91
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
92
|
+
"RATE_LIMIT" /* RATE_LIMIT */,
|
|
93
|
+
"NETWORK" /* NETWORK */,
|
|
94
|
+
"TOOL_EXECUTION" /* TOOL_EXECUTION */,
|
|
95
|
+
"MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
|
|
96
|
+
"PROVIDER_ERROR" /* PROVIDER_ERROR */
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// src/errors.ts
|
|
102
|
+
var AgentSDKError, ReentrancyError, DisposedError, SubprocessError, DependencyError, AbortError, ToolExecutionError, ActivityTimeoutError;
|
|
103
|
+
var init_errors2 = __esm({
|
|
53
104
|
"src/errors.ts"() {
|
|
105
|
+
init_errors();
|
|
54
106
|
AgentSDKError = class extends Error {
|
|
55
107
|
/** @internal Marker for cross-bundle identity checks */
|
|
56
108
|
_agentSDKError = true;
|
|
109
|
+
/** Machine-readable error code. Prefer values from the ErrorCode enum. */
|
|
110
|
+
code;
|
|
111
|
+
/** Whether this error is safe to retry */
|
|
112
|
+
retryable;
|
|
113
|
+
/** HTTP status code hint for error classification */
|
|
114
|
+
httpStatus;
|
|
57
115
|
constructor(message, options) {
|
|
58
116
|
super(message, options);
|
|
59
117
|
this.name = "AgentSDKError";
|
|
118
|
+
this.code = options?.code;
|
|
119
|
+
this.retryable = options?.retryable ?? false;
|
|
120
|
+
this.httpStatus = options?.httpStatus;
|
|
60
121
|
}
|
|
61
122
|
/** Check if an error is an AgentSDKError (works across bundled copies) */
|
|
62
123
|
static is(error) {
|
|
@@ -65,83 +126,84 @@ var init_errors = __esm({
|
|
|
65
126
|
};
|
|
66
127
|
ReentrancyError = class extends AgentSDKError {
|
|
67
128
|
constructor() {
|
|
68
|
-
super("Agent is already running. Await the current run before starting another."
|
|
129
|
+
super("Agent is already running. Await the current run before starting another.", {
|
|
130
|
+
code: "REENTRANCY" /* REENTRANCY */
|
|
131
|
+
});
|
|
69
132
|
this.name = "ReentrancyError";
|
|
70
133
|
}
|
|
71
134
|
};
|
|
72
135
|
DisposedError = class extends AgentSDKError {
|
|
73
136
|
constructor(entity) {
|
|
74
|
-
super(`${entity} has been disposed and cannot be used
|
|
137
|
+
super(`${entity} has been disposed and cannot be used.`, {
|
|
138
|
+
code: "DISPOSED" /* DISPOSED */
|
|
139
|
+
});
|
|
75
140
|
this.name = "DisposedError";
|
|
76
141
|
}
|
|
77
142
|
};
|
|
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
143
|
SubprocessError = class extends AgentSDKError {
|
|
93
144
|
constructor(message, options) {
|
|
94
|
-
super(message, options);
|
|
145
|
+
super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
|
|
95
146
|
this.name = "SubprocessError";
|
|
96
147
|
}
|
|
97
148
|
};
|
|
98
149
|
DependencyError = class extends AgentSDKError {
|
|
99
150
|
packageName;
|
|
100
151
|
constructor(packageName) {
|
|
101
|
-
super(`${packageName} is not installed. Install it: npm install ${packageName}
|
|
152
|
+
super(`${packageName} is not installed. Install it: npm install ${packageName}`, {
|
|
153
|
+
code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */
|
|
154
|
+
});
|
|
102
155
|
this.name = "DependencyError";
|
|
103
156
|
this.packageName = packageName;
|
|
104
157
|
}
|
|
105
158
|
};
|
|
106
159
|
AbortError = class extends AgentSDKError {
|
|
107
160
|
constructor() {
|
|
108
|
-
super("Agent run was aborted.");
|
|
161
|
+
super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
|
|
109
162
|
this.name = "AbortError";
|
|
110
163
|
}
|
|
111
164
|
};
|
|
112
165
|
ToolExecutionError = class extends AgentSDKError {
|
|
113
166
|
toolName;
|
|
114
167
|
constructor(toolName, message, options) {
|
|
115
|
-
super(`Tool "${toolName}" failed: ${message}`, options);
|
|
168
|
+
super(`Tool "${toolName}" failed: ${message}`, { ...options, code: "TOOL_EXECUTION" /* TOOL_EXECUTION */ });
|
|
116
169
|
this.name = "ToolExecutionError";
|
|
117
170
|
this.toolName = toolName;
|
|
118
171
|
}
|
|
119
172
|
};
|
|
120
|
-
|
|
121
|
-
constructor(
|
|
122
|
-
super(`
|
|
123
|
-
|
|
173
|
+
ActivityTimeoutError = class extends AgentSDKError {
|
|
174
|
+
constructor(timeoutMs) {
|
|
175
|
+
super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
|
|
176
|
+
code: "TIMEOUT" /* TIMEOUT */,
|
|
177
|
+
retryable: true
|
|
178
|
+
});
|
|
179
|
+
this.name = "ActivityTimeoutError";
|
|
124
180
|
}
|
|
125
181
|
};
|
|
126
182
|
}
|
|
127
183
|
});
|
|
128
184
|
|
|
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
|
-
}
|
|
185
|
+
// src/types/guards.ts
|
|
139
186
|
function getTextContent(content) {
|
|
140
187
|
if (typeof content === "string") return content;
|
|
141
188
|
return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
142
189
|
}
|
|
190
|
+
var init_guards = __esm({
|
|
191
|
+
"src/types/guards.ts"() {
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// src/types/index.ts
|
|
143
196
|
var init_types = __esm({
|
|
197
|
+
"src/types/index.ts"() {
|
|
198
|
+
init_errors();
|
|
199
|
+
init_guards();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// src/types.ts
|
|
204
|
+
var init_types2 = __esm({
|
|
144
205
|
"src/types.ts"() {
|
|
206
|
+
init_types();
|
|
145
207
|
}
|
|
146
208
|
});
|
|
147
209
|
|
|
@@ -149,12 +211,15 @@ var init_types = __esm({
|
|
|
149
211
|
var BaseAgent;
|
|
150
212
|
var init_base_agent = __esm({
|
|
151
213
|
"src/base-agent.ts"() {
|
|
214
|
+
init_errors2();
|
|
215
|
+
init_errors2();
|
|
152
216
|
init_errors();
|
|
153
217
|
BaseAgent = class {
|
|
154
218
|
state = "idle";
|
|
155
219
|
abortController = null;
|
|
156
220
|
config;
|
|
157
221
|
_cleanupExternalSignal = null;
|
|
222
|
+
_streamMiddleware = [];
|
|
158
223
|
/** CLI session ID for persistent mode. Override in backends that support it. */
|
|
159
224
|
get sessionId() {
|
|
160
225
|
return void 0;
|
|
@@ -170,8 +235,11 @@ var init_base_agent = __esm({
|
|
|
170
235
|
this.state = "running";
|
|
171
236
|
try {
|
|
172
237
|
const messages = [{ role: "user", content: prompt }];
|
|
173
|
-
const result = await this.
|
|
174
|
-
|
|
238
|
+
const result = await this.withRetry(
|
|
239
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
240
|
+
options
|
|
241
|
+
);
|
|
242
|
+
this.enrichAndNotifyUsage(result, options);
|
|
175
243
|
return result;
|
|
176
244
|
} finally {
|
|
177
245
|
this.cleanupRun();
|
|
@@ -183,8 +251,11 @@ var init_base_agent = __esm({
|
|
|
183
251
|
const ac = this.createAbortController(options?.signal);
|
|
184
252
|
this.state = "running";
|
|
185
253
|
try {
|
|
186
|
-
const result = await this.
|
|
187
|
-
|
|
254
|
+
const result = await this.withRetry(
|
|
255
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
256
|
+
options
|
|
257
|
+
);
|
|
258
|
+
this.enrichAndNotifyUsage(result, options);
|
|
188
259
|
return result;
|
|
189
260
|
} finally {
|
|
190
261
|
this.cleanupRun();
|
|
@@ -197,13 +268,11 @@ var init_base_agent = __esm({
|
|
|
197
268
|
this.state = "running";
|
|
198
269
|
try {
|
|
199
270
|
const messages = [{ role: "user", content: prompt }];
|
|
200
|
-
const result = await this.
|
|
201
|
-
messages,
|
|
202
|
-
|
|
203
|
-
options,
|
|
204
|
-
ac.signal
|
|
271
|
+
const result = await this.withRetry(
|
|
272
|
+
() => this.executeRunStructured(messages, schema, options, ac.signal),
|
|
273
|
+
options
|
|
205
274
|
);
|
|
206
|
-
this.enrichAndNotifyUsage(result);
|
|
275
|
+
this.enrichAndNotifyUsage(result, options);
|
|
207
276
|
return result;
|
|
208
277
|
} finally {
|
|
209
278
|
this.cleanupRun();
|
|
@@ -216,8 +285,10 @@ var init_base_agent = __esm({
|
|
|
216
285
|
this.state = "streaming";
|
|
217
286
|
try {
|
|
218
287
|
const messages = [{ role: "user", content: prompt }];
|
|
219
|
-
|
|
220
|
-
|
|
288
|
+
yield* this.streamWithRetry(
|
|
289
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
290
|
+
options
|
|
291
|
+
);
|
|
221
292
|
} finally {
|
|
222
293
|
this.cleanupRun();
|
|
223
294
|
}
|
|
@@ -228,12 +299,37 @@ var init_base_agent = __esm({
|
|
|
228
299
|
const ac = this.createAbortController(options?.signal);
|
|
229
300
|
this.state = "streaming";
|
|
230
301
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
302
|
+
yield* this.streamWithRetry(
|
|
303
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
304
|
+
options
|
|
305
|
+
);
|
|
233
306
|
} finally {
|
|
234
307
|
this.cleanupRun();
|
|
235
308
|
}
|
|
236
309
|
}
|
|
310
|
+
/** Register a stream middleware. Applied in registration order after built-in transforms. */
|
|
311
|
+
addStreamMiddleware(middleware) {
|
|
312
|
+
this.guardDisposed();
|
|
313
|
+
this._streamMiddleware.push(middleware);
|
|
314
|
+
}
|
|
315
|
+
/** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
|
|
316
|
+
async *applyStreamPipeline(source, options, ac) {
|
|
317
|
+
let stream = this.enrichStream(source, options);
|
|
318
|
+
stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
|
|
319
|
+
stream = this.heartbeatStream(stream);
|
|
320
|
+
if (this._streamMiddleware.length > 0) {
|
|
321
|
+
const ctx = {
|
|
322
|
+
model: options.model,
|
|
323
|
+
backend: this.backendName,
|
|
324
|
+
abortController: ac,
|
|
325
|
+
config: Object.freeze({ ...this.config })
|
|
326
|
+
};
|
|
327
|
+
for (const mw of this._streamMiddleware) {
|
|
328
|
+
stream = mw(stream, ctx);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
yield* stream;
|
|
332
|
+
}
|
|
237
333
|
abort() {
|
|
238
334
|
if (this.abortController) {
|
|
239
335
|
this.abortController.abort();
|
|
@@ -256,26 +352,109 @@ var init_base_agent = __esm({
|
|
|
256
352
|
this.abort();
|
|
257
353
|
this.state = "disposed";
|
|
258
354
|
}
|
|
355
|
+
// ─── Retry Logic ─────────────────────────────────────────────
|
|
356
|
+
/** Check if an error should be retried given the retry configuration. */
|
|
357
|
+
isRetryableError(error, retry) {
|
|
358
|
+
if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
if (AgentSDKError.is(error)) {
|
|
362
|
+
if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
|
|
363
|
+
return retry.retryableErrors.includes(error.code);
|
|
364
|
+
}
|
|
365
|
+
if (error.retryable) return true;
|
|
366
|
+
if (error.code) return isRecoverableErrorCode(error.code);
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
/** Execute a function with retry logic per RetryConfig. */
|
|
371
|
+
async withRetry(fn, options) {
|
|
372
|
+
const retry = options?.retry;
|
|
373
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
374
|
+
return fn();
|
|
375
|
+
}
|
|
376
|
+
const maxRetries = retry.maxRetries;
|
|
377
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
378
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
379
|
+
let lastError;
|
|
380
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
381
|
+
try {
|
|
382
|
+
return await fn();
|
|
383
|
+
} catch (err) {
|
|
384
|
+
lastError = err;
|
|
385
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
386
|
+
throw err;
|
|
387
|
+
}
|
|
388
|
+
const delay2 = initialDelay * Math.pow(multiplier, attempt);
|
|
389
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
390
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
391
|
+
throw err;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
throw lastError;
|
|
396
|
+
}
|
|
397
|
+
/** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
|
|
398
|
+
async *streamWithRetry(factory, options) {
|
|
399
|
+
const retry = options?.retry;
|
|
400
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
401
|
+
yield* factory();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const maxRetries = retry.maxRetries;
|
|
405
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
406
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
407
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
408
|
+
try {
|
|
409
|
+
const stream = factory();
|
|
410
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
411
|
+
const first = await iterator.next();
|
|
412
|
+
if (first.done) return;
|
|
413
|
+
yield first.value;
|
|
414
|
+
while (true) {
|
|
415
|
+
const next = await iterator.next();
|
|
416
|
+
if (next.done) break;
|
|
417
|
+
yield next.value;
|
|
418
|
+
}
|
|
419
|
+
return;
|
|
420
|
+
} catch (err) {
|
|
421
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
422
|
+
throw err;
|
|
423
|
+
}
|
|
424
|
+
const delay2 = initialDelay * Math.pow(multiplier, attempt);
|
|
425
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
426
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
427
|
+
throw err;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// ─── CallOptions Resolution ──────────────────────────────────
|
|
433
|
+
/** Resolve tools to use for this call (per-call override > config default) */
|
|
434
|
+
resolveTools(options) {
|
|
435
|
+
return options?.tools ?? this.config.tools ?? [];
|
|
436
|
+
}
|
|
259
437
|
// ─── Usage Enrichment ───────────────────────────────────────────
|
|
260
438
|
/** Enrich result usage with model/backend and fire onUsage callback */
|
|
261
|
-
enrichAndNotifyUsage(result) {
|
|
439
|
+
enrichAndNotifyUsage(result, options) {
|
|
262
440
|
if (result.usage) {
|
|
263
441
|
result.usage = {
|
|
264
442
|
...result.usage,
|
|
265
|
-
model:
|
|
443
|
+
model: options.model,
|
|
266
444
|
backend: this.backendName
|
|
267
445
|
};
|
|
268
446
|
this.callOnUsage(result.usage);
|
|
269
447
|
}
|
|
270
448
|
}
|
|
271
449
|
/** Wrap a stream to enrich usage_update events and fire onUsage callback */
|
|
272
|
-
async *enrichStream(source) {
|
|
450
|
+
async *enrichStream(source, options) {
|
|
451
|
+
const model = options.model;
|
|
273
452
|
for await (const event of source) {
|
|
274
453
|
if (event.type === "usage_update") {
|
|
275
454
|
const usage = {
|
|
276
455
|
promptTokens: event.promptTokens,
|
|
277
456
|
completionTokens: event.completionTokens,
|
|
278
|
-
model
|
|
457
|
+
model,
|
|
279
458
|
backend: this.backendName
|
|
280
459
|
};
|
|
281
460
|
this.callOnUsage(usage);
|
|
@@ -311,9 +490,9 @@ var init_base_agent = __esm({
|
|
|
311
490
|
let heartbeatResolve = null;
|
|
312
491
|
const timer = setInterval(() => {
|
|
313
492
|
if (heartbeatResolve) {
|
|
314
|
-
const
|
|
493
|
+
const resolve = heartbeatResolve;
|
|
315
494
|
heartbeatResolve = null;
|
|
316
|
-
|
|
495
|
+
resolve();
|
|
317
496
|
}
|
|
318
497
|
}, interval);
|
|
319
498
|
try {
|
|
@@ -321,8 +500,8 @@ var init_base_agent = __esm({
|
|
|
321
500
|
if (!pendingEvent) {
|
|
322
501
|
pendingEvent = iterator.next();
|
|
323
502
|
}
|
|
324
|
-
const heartbeatPromise = new Promise((
|
|
325
|
-
heartbeatResolve =
|
|
503
|
+
const heartbeatPromise = new Promise((resolve) => {
|
|
504
|
+
heartbeatResolve = resolve;
|
|
326
505
|
});
|
|
327
506
|
const eventDone = pendingEvent.then(
|
|
328
507
|
(r) => ({ kind: "event", result: r })
|
|
@@ -345,6 +524,35 @@ var init_base_agent = __esm({
|
|
|
345
524
|
heartbeatResolve = null;
|
|
346
525
|
}
|
|
347
526
|
}
|
|
527
|
+
// ─── Activity Timeout ────────────────────────────────────────
|
|
528
|
+
/** Wrap a stream to abort on inactivity. Resets timer on every event.
|
|
529
|
+
* When timeoutMs is not set, passes through directly. */
|
|
530
|
+
async *activityTimeoutStream(source, timeoutMs, ac) {
|
|
531
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
532
|
+
yield* source;
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
536
|
+
let timerId;
|
|
537
|
+
try {
|
|
538
|
+
while (true) {
|
|
539
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
540
|
+
timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
|
|
541
|
+
});
|
|
542
|
+
const result = await Promise.race([iterator.next(), timeoutPromise]);
|
|
543
|
+
clearTimeout(timerId);
|
|
544
|
+
if (result.done) break;
|
|
545
|
+
yield result.value;
|
|
546
|
+
}
|
|
547
|
+
} catch (err) {
|
|
548
|
+
if (err instanceof ActivityTimeoutError) {
|
|
549
|
+
ac.abort(err);
|
|
550
|
+
}
|
|
551
|
+
throw err;
|
|
552
|
+
} finally {
|
|
553
|
+
clearTimeout(timerId);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
348
556
|
// ─── Guards ───────────────────────────────────────────────────
|
|
349
557
|
guardReentrancy() {
|
|
350
558
|
if (this.state === "running" || this.state === "streaming") {
|
|
@@ -449,6 +657,66 @@ var init_schema = __esm({
|
|
|
449
657
|
}
|
|
450
658
|
});
|
|
451
659
|
|
|
660
|
+
// src/backends/shared.ts
|
|
661
|
+
function extractLastUserPrompt(messages) {
|
|
662
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
663
|
+
const msg = messages[i];
|
|
664
|
+
if (msg.role === "user") {
|
|
665
|
+
return getTextContent(msg.content);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return "";
|
|
669
|
+
}
|
|
670
|
+
function serializeToolCall(tc) {
|
|
671
|
+
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
672
|
+
return ` Tool call: ${tc.name}(${args})`;
|
|
673
|
+
}
|
|
674
|
+
function serializeToolResult(tr) {
|
|
675
|
+
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
676
|
+
const prefix = tr.isError ? "[ERROR] " : "";
|
|
677
|
+
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
678
|
+
}
|
|
679
|
+
function buildContextualPrompt(messages) {
|
|
680
|
+
if (messages.length <= 1) {
|
|
681
|
+
return extractLastUserPrompt(messages);
|
|
682
|
+
}
|
|
683
|
+
const history = messages.slice(0, -1).map((msg) => {
|
|
684
|
+
if (msg.role === "user") {
|
|
685
|
+
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
686
|
+
}
|
|
687
|
+
if (msg.role === "tool" && msg.toolResults) {
|
|
688
|
+
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
689
|
+
return `Tool results:
|
|
690
|
+
${results}`;
|
|
691
|
+
}
|
|
692
|
+
if (msg.role === "assistant") {
|
|
693
|
+
const parts = [];
|
|
694
|
+
const thinking = msg.thinking;
|
|
695
|
+
if (thinking) {
|
|
696
|
+
parts.push(`[reasoning: ${thinking}]`);
|
|
697
|
+
}
|
|
698
|
+
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
699
|
+
if (text2) parts.push(text2);
|
|
700
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
701
|
+
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
702
|
+
}
|
|
703
|
+
return `Assistant: ${parts.join("\n")}`;
|
|
704
|
+
}
|
|
705
|
+
const text = msg.content ? getTextContent(msg.content) : "";
|
|
706
|
+
return `${msg.role}: ${text}`;
|
|
707
|
+
}).join("\n");
|
|
708
|
+
const lastPrompt = extractLastUserPrompt(messages);
|
|
709
|
+
return `Conversation history:
|
|
710
|
+
${history}
|
|
711
|
+
|
|
712
|
+
User: ${lastPrompt}`;
|
|
713
|
+
}
|
|
714
|
+
var init_shared = __esm({
|
|
715
|
+
"src/backends/shared.ts"() {
|
|
716
|
+
init_types2();
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
|
|
452
720
|
// src/backends/copilot.ts
|
|
453
721
|
var copilot_exports = {};
|
|
454
722
|
__export(copilot_exports, {
|
|
@@ -457,10 +725,9 @@ __export(copilot_exports, {
|
|
|
457
725
|
createCopilotService: () => createCopilotService
|
|
458
726
|
});
|
|
459
727
|
async function loadSDK() {
|
|
460
|
-
if (
|
|
728
|
+
if (_sdkMock) return _sdkMock;
|
|
461
729
|
try {
|
|
462
|
-
|
|
463
|
-
return sdkModule;
|
|
730
|
+
return await import('@github/copilot-sdk');
|
|
464
731
|
} catch {
|
|
465
732
|
throw new SubprocessError(
|
|
466
733
|
"@github/copilot-sdk is not installed. Install it: npm install @github/copilot-sdk"
|
|
@@ -468,10 +735,10 @@ async function loadSDK() {
|
|
|
468
735
|
}
|
|
469
736
|
}
|
|
470
737
|
function _injectSDK(mock) {
|
|
471
|
-
|
|
738
|
+
_sdkMock = mock;
|
|
472
739
|
}
|
|
473
740
|
function _resetSDK() {
|
|
474
|
-
|
|
741
|
+
_sdkMock = null;
|
|
475
742
|
}
|
|
476
743
|
function mapToolsToSDK(tools) {
|
|
477
744
|
return tools.map((tool) => ({
|
|
@@ -516,6 +783,7 @@ function buildPermissionHandler(config) {
|
|
|
516
783
|
const unifiedRequest = {
|
|
517
784
|
toolName,
|
|
518
785
|
toolArgs: { ...request },
|
|
786
|
+
toolCallId: request.toolCallId,
|
|
519
787
|
rawSDKRequest: request
|
|
520
788
|
};
|
|
521
789
|
const ac = new AbortController();
|
|
@@ -620,15 +888,21 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
620
888
|
};
|
|
621
889
|
case "session.error":
|
|
622
890
|
console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
891
|
+
{
|
|
892
|
+
const errorMsg = String(data.message ?? "Unknown error");
|
|
893
|
+
const code = classifyAgentError(errorMsg);
|
|
894
|
+
return {
|
|
895
|
+
type: "error",
|
|
896
|
+
error: errorMsg,
|
|
897
|
+
recoverable: isRecoverableErrorCode(code),
|
|
898
|
+
code
|
|
899
|
+
};
|
|
900
|
+
}
|
|
628
901
|
case "assistant.message": {
|
|
629
902
|
const doneEvent = {
|
|
630
903
|
type: "done",
|
|
631
|
-
finalOutput:
|
|
904
|
+
finalOutput: null,
|
|
905
|
+
streamed: true
|
|
632
906
|
};
|
|
633
907
|
if (thinkingTracker.endThinking()) {
|
|
634
908
|
return [{ type: "thinking_end" }, doneEvent];
|
|
@@ -639,66 +913,13 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
639
913
|
return null;
|
|
640
914
|
}
|
|
641
915
|
}
|
|
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
916
|
function withTimeout(promise, ms, message) {
|
|
696
|
-
return new Promise((
|
|
917
|
+
return new Promise((resolve, reject) => {
|
|
697
918
|
const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
|
|
698
919
|
promise.then(
|
|
699
920
|
(val) => {
|
|
700
921
|
clearTimeout(timer);
|
|
701
|
-
|
|
922
|
+
resolve(val);
|
|
702
923
|
},
|
|
703
924
|
(err) => {
|
|
704
925
|
clearTimeout(timer);
|
|
@@ -710,14 +931,15 @@ function withTimeout(promise, ms, message) {
|
|
|
710
931
|
function createCopilotService(options) {
|
|
711
932
|
return new CopilotAgentService(options);
|
|
712
933
|
}
|
|
713
|
-
var
|
|
934
|
+
var _sdkMock, ToolCallTracker, ThinkingTracker, CopilotAgent, CopilotAgentService;
|
|
714
935
|
var init_copilot = __esm({
|
|
715
936
|
"src/backends/copilot.ts"() {
|
|
716
|
-
|
|
937
|
+
init_types2();
|
|
717
938
|
init_base_agent();
|
|
718
|
-
|
|
939
|
+
init_errors2();
|
|
719
940
|
init_schema();
|
|
720
|
-
|
|
941
|
+
init_shared();
|
|
942
|
+
_sdkMock = null;
|
|
721
943
|
ToolCallTracker = class {
|
|
722
944
|
map = /* @__PURE__ */ new Map();
|
|
723
945
|
trackStart(toolCallId, toolName, args) {
|
|
@@ -765,6 +987,7 @@ var init_copilot = __esm({
|
|
|
765
987
|
isPersistent;
|
|
766
988
|
persistentSession = null;
|
|
767
989
|
_sessionId;
|
|
990
|
+
_persistentModel;
|
|
768
991
|
activeSession = null;
|
|
769
992
|
_resumeSessionId;
|
|
770
993
|
_toolsReady = null;
|
|
@@ -815,47 +1038,63 @@ var init_copilot = __esm({
|
|
|
815
1038
|
});
|
|
816
1039
|
this.persistentSession = null;
|
|
817
1040
|
this._sessionId = void 0;
|
|
1041
|
+
this._persistentModel = void 0;
|
|
818
1042
|
}
|
|
819
1043
|
}
|
|
820
|
-
async getOrCreateSession(streaming) {
|
|
1044
|
+
async getOrCreateSession(streaming, options) {
|
|
821
1045
|
if (this.isPersistent && this.persistentSession) {
|
|
822
|
-
|
|
1046
|
+
if (options.model !== this._persistentModel) {
|
|
1047
|
+
this.persistentSession.destroy().catch(() => {
|
|
1048
|
+
});
|
|
1049
|
+
this.persistentSession = null;
|
|
1050
|
+
this._sessionId = void 0;
|
|
1051
|
+
} else {
|
|
1052
|
+
return { session: this.persistentSession, isNew: false };
|
|
1053
|
+
}
|
|
823
1054
|
}
|
|
824
1055
|
if (this._toolsReady) {
|
|
825
1056
|
await this._toolsReady;
|
|
826
1057
|
this._toolsReady = null;
|
|
827
1058
|
}
|
|
1059
|
+
const sessionConfig = { ...this.sessionConfig };
|
|
1060
|
+
sessionConfig.model = options.model;
|
|
1061
|
+
const resolvedTools = this.resolveTools(options);
|
|
1062
|
+
if (options?.tools) {
|
|
1063
|
+
sessionConfig.tools = mapToolsToSDK(resolvedTools);
|
|
1064
|
+
}
|
|
828
1065
|
const client = await this.getClient();
|
|
829
1066
|
if (this._resumeSessionId) {
|
|
830
1067
|
const storedId = this._resumeSessionId;
|
|
831
1068
|
this._resumeSessionId = void 0;
|
|
832
1069
|
try {
|
|
833
1070
|
const session2 = await client.resumeSession(storedId, {
|
|
834
|
-
...
|
|
1071
|
+
...sessionConfig,
|
|
835
1072
|
streaming: this.isPersistent ? true : streaming
|
|
836
1073
|
});
|
|
837
1074
|
if (this.isPersistent) {
|
|
838
1075
|
this.persistentSession = session2;
|
|
839
1076
|
this._sessionId = session2.sessionId;
|
|
1077
|
+
this._persistentModel = options.model;
|
|
840
1078
|
}
|
|
841
1079
|
return { session: session2, isNew: false };
|
|
842
1080
|
} catch {
|
|
843
1081
|
}
|
|
844
1082
|
}
|
|
845
1083
|
const session = await client.createSession({
|
|
846
|
-
...
|
|
1084
|
+
...sessionConfig,
|
|
847
1085
|
streaming: this.isPersistent ? true : streaming
|
|
848
1086
|
});
|
|
849
1087
|
if (this.isPersistent) {
|
|
850
1088
|
this.persistentSession = session;
|
|
851
1089
|
this._sessionId = session.sessionId;
|
|
1090
|
+
this._persistentModel = options.model;
|
|
852
1091
|
}
|
|
853
1092
|
return { session, isNew: true };
|
|
854
1093
|
}
|
|
855
1094
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
856
|
-
async executeRun(messages,
|
|
1095
|
+
async executeRun(messages, options, signal) {
|
|
857
1096
|
this.checkAbort(signal);
|
|
858
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
|
|
1097
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(false, options);
|
|
859
1098
|
this.activeSession = session;
|
|
860
1099
|
const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
861
1100
|
const tracker = new ToolCallTracker();
|
|
@@ -952,9 +1191,9 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
952
1191
|
};
|
|
953
1192
|
}
|
|
954
1193
|
// ─── executeStream ──────────────────────────────────────────────
|
|
955
|
-
async *executeStream(messages,
|
|
1194
|
+
async *executeStream(messages, options, signal) {
|
|
956
1195
|
this.checkAbort(signal);
|
|
957
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
|
|
1196
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(true, options);
|
|
958
1197
|
this.activeSession = session;
|
|
959
1198
|
if (isNewSession) {
|
|
960
1199
|
yield this.emitSessionInfo(session.sessionId);
|
|
@@ -971,8 +1210,8 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
971
1210
|
notify = null;
|
|
972
1211
|
}
|
|
973
1212
|
};
|
|
974
|
-
const waitForItem = () => new Promise((
|
|
975
|
-
notify =
|
|
1213
|
+
const waitForItem = () => new Promise((resolve) => {
|
|
1214
|
+
notify = resolve;
|
|
976
1215
|
});
|
|
977
1216
|
const unsubscribe = session.on((event) => {
|
|
978
1217
|
const mapped = mapSessionEvent(event, tracker, thinkingTracker);
|
|
@@ -1100,7 +1339,10 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1100
1339
|
return models.map((m) => ({
|
|
1101
1340
|
id: m.id,
|
|
1102
1341
|
name: m.name,
|
|
1103
|
-
provider: "copilot"
|
|
1342
|
+
provider: "copilot",
|
|
1343
|
+
...m.capabilities?.limits?.max_context_window_tokens != null && {
|
|
1344
|
+
contextWindow: m.capabilities.limits.max_context_window_tokens
|
|
1345
|
+
}
|
|
1104
1346
|
}));
|
|
1105
1347
|
}
|
|
1106
1348
|
async validate() {
|
|
@@ -1153,10 +1395,9 @@ function stripMcpPrefix(name) {
|
|
|
1153
1395
|
return name.startsWith(MCP_TOOL_PREFIX) ? name.slice(MCP_TOOL_PREFIX.length) : name;
|
|
1154
1396
|
}
|
|
1155
1397
|
async function loadSDK2() {
|
|
1156
|
-
if (
|
|
1398
|
+
if (_sdkMock2) return _sdkMock2;
|
|
1157
1399
|
try {
|
|
1158
|
-
|
|
1159
|
-
return sdkModule2;
|
|
1400
|
+
return await import('@anthropic-ai/claude-agent-sdk');
|
|
1160
1401
|
} catch {
|
|
1161
1402
|
throw new SubprocessError(
|
|
1162
1403
|
"@anthropic-ai/claude-agent-sdk is not installed. Install it: npm install @anthropic-ai/claude-agent-sdk"
|
|
@@ -1164,13 +1405,32 @@ async function loadSDK2() {
|
|
|
1164
1405
|
}
|
|
1165
1406
|
}
|
|
1166
1407
|
function _injectSDK2(mock) {
|
|
1167
|
-
|
|
1408
|
+
_sdkMock2 = mock;
|
|
1168
1409
|
}
|
|
1169
1410
|
function _resetSDK2() {
|
|
1170
|
-
|
|
1411
|
+
_sdkMock2 = null;
|
|
1412
|
+
}
|
|
1413
|
+
function normalizeAskUserInput(args) {
|
|
1414
|
+
if (typeof args.question === "string") {
|
|
1415
|
+
return {
|
|
1416
|
+
question: args.question,
|
|
1417
|
+
choices: Array.isArray(args.choices) ? args.choices : void 0,
|
|
1418
|
+
allowFreeform: args.allowFreeform !== false
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
const questions = args.questions;
|
|
1422
|
+
if (questions && questions.length > 0) {
|
|
1423
|
+
const first = questions[0];
|
|
1424
|
+
return {
|
|
1425
|
+
question: first.question,
|
|
1426
|
+
choices: first.options?.map((o) => o.label),
|
|
1427
|
+
allowFreeform: true
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
return { question: JSON.stringify(args), allowFreeform: true };
|
|
1171
1431
|
}
|
|
1172
|
-
function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
1173
|
-
if (tools.length === 0) return void 0;
|
|
1432
|
+
function buildMcpServer(sdk, tools, toolResultCapture, onAskUser) {
|
|
1433
|
+
if (tools.length === 0 && !onAskUser) return void 0;
|
|
1174
1434
|
const mcpTools = tools.map((tool) => {
|
|
1175
1435
|
const zodSchema = tool.parameters;
|
|
1176
1436
|
const inputSchema = zodSchema.shape ?? zodToJsonSchema(tool.parameters);
|
|
@@ -1194,6 +1454,39 @@ function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
|
1194
1454
|
}
|
|
1195
1455
|
);
|
|
1196
1456
|
});
|
|
1457
|
+
if (onAskUser) {
|
|
1458
|
+
const askUserTool = sdk.tool(
|
|
1459
|
+
"ask_user",
|
|
1460
|
+
"Ask the user a question and wait for their response",
|
|
1461
|
+
{
|
|
1462
|
+
question: { type: "string", description: "The question to ask the user" },
|
|
1463
|
+
choices: {
|
|
1464
|
+
type: "array",
|
|
1465
|
+
items: { type: "string" },
|
|
1466
|
+
description: "Optional list of choices for multiple choice"
|
|
1467
|
+
},
|
|
1468
|
+
questions: {
|
|
1469
|
+
type: "array",
|
|
1470
|
+
items: {
|
|
1471
|
+
type: "object",
|
|
1472
|
+
properties: {
|
|
1473
|
+
question: { type: "string" },
|
|
1474
|
+
options: { type: "array", items: { type: "object", properties: { label: { type: "string" } } } }
|
|
1475
|
+
}
|
|
1476
|
+
},
|
|
1477
|
+
description: "Alternative nested question format"
|
|
1478
|
+
}
|
|
1479
|
+
},
|
|
1480
|
+
async (args) => {
|
|
1481
|
+
const normalized = normalizeAskUserInput(args);
|
|
1482
|
+
const response = await onAskUser(normalized, AbortSignal.timeout(3e5));
|
|
1483
|
+
return {
|
|
1484
|
+
content: [{ type: "text", text: response.answer }]
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
);
|
|
1488
|
+
mcpTools.push(askUserTool);
|
|
1489
|
+
}
|
|
1197
1490
|
return sdk.createSdkMcpServer({
|
|
1198
1491
|
name: MCP_SERVER_NAME,
|
|
1199
1492
|
version: "1.0.0",
|
|
@@ -1243,6 +1536,7 @@ function buildCanUseTool(config) {
|
|
|
1243
1536
|
const unifiedRequest = {
|
|
1244
1537
|
toolName,
|
|
1245
1538
|
toolArgs: input,
|
|
1539
|
+
toolCallId: options.toolUseID,
|
|
1246
1540
|
suggestedScope: extractSuggestedScope(options.suggestions),
|
|
1247
1541
|
rawSDKRequest: { toolName, input, ...options }
|
|
1248
1542
|
};
|
|
@@ -1295,6 +1589,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1295
1589
|
if (block.type === "tool_use") {
|
|
1296
1590
|
const toolCallId = String(block.id ?? "");
|
|
1297
1591
|
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1592
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1298
1593
|
if (toolCallTracker) {
|
|
1299
1594
|
toolCallTracker.trackStart(toolCallId, toolName);
|
|
1300
1595
|
}
|
|
@@ -1318,6 +1613,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1318
1613
|
case "tool_use_summary": {
|
|
1319
1614
|
const summary = msg.summary;
|
|
1320
1615
|
const toolName = stripMcpPrefix(msg.tool_name ?? "unknown");
|
|
1616
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) return null;
|
|
1321
1617
|
const precedingIds = msg.preceding_tool_use_ids;
|
|
1322
1618
|
let toolCallId = "";
|
|
1323
1619
|
if (precedingIds && precedingIds.length > 0) {
|
|
@@ -1371,10 +1667,13 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1371
1667
|
}
|
|
1372
1668
|
if (msg.is_error) {
|
|
1373
1669
|
const r = msg;
|
|
1670
|
+
const errorMsg = r.errors?.join("; ") ?? "Unknown error";
|
|
1671
|
+
const code = classifyAgentError(errorMsg);
|
|
1374
1672
|
return {
|
|
1375
1673
|
type: "error",
|
|
1376
|
-
error:
|
|
1377
|
-
recoverable:
|
|
1674
|
+
error: errorMsg,
|
|
1675
|
+
recoverable: isRecoverableErrorCode(code),
|
|
1676
|
+
code
|
|
1378
1677
|
};
|
|
1379
1678
|
}
|
|
1380
1679
|
return null;
|
|
@@ -1383,72 +1682,21 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1383
1682
|
return null;
|
|
1384
1683
|
}
|
|
1385
1684
|
}
|
|
1386
|
-
function extractLastUserPrompt2(messages) {
|
|
1387
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
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})`;
|
|
1398
|
-
}
|
|
1399
|
-
function serializeToolResult2(tr) {
|
|
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
1685
|
function createClaudeService(options) {
|
|
1440
1686
|
return new ClaudeAgentService(options);
|
|
1441
1687
|
}
|
|
1442
|
-
var MCP_SERVER_NAME, MCP_TOOL_PREFIX,
|
|
1688
|
+
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
1689
|
var init_claude = __esm({
|
|
1444
1690
|
"src/backends/claude.ts"() {
|
|
1445
|
-
|
|
1691
|
+
init_types2();
|
|
1446
1692
|
init_base_agent();
|
|
1447
|
-
|
|
1693
|
+
init_errors2();
|
|
1448
1694
|
init_schema();
|
|
1695
|
+
init_shared();
|
|
1449
1696
|
MCP_SERVER_NAME = "agent-sdk-tools";
|
|
1450
1697
|
MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
1451
|
-
|
|
1698
|
+
CLAUDE_INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1699
|
+
_sdkMock2 = null;
|
|
1452
1700
|
ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
|
|
1453
1701
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
1454
1702
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
@@ -1493,11 +1741,6 @@ var init_claude = __esm({
|
|
|
1493
1741
|
if (options.resumeSessionId) {
|
|
1494
1742
|
this._sessionId = options.resumeSessionId;
|
|
1495
1743
|
}
|
|
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
1744
|
}
|
|
1502
1745
|
get sessionId() {
|
|
1503
1746
|
return this._sessionId;
|
|
@@ -1521,12 +1764,12 @@ var init_claude = __esm({
|
|
|
1521
1764
|
const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
|
|
1522
1765
|
return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
|
|
1523
1766
|
}
|
|
1524
|
-
buildQueryOptions(signal) {
|
|
1767
|
+
buildQueryOptions(signal, options) {
|
|
1525
1768
|
const ac = new AbortController();
|
|
1526
1769
|
signal.addEventListener("abort", () => ac.abort(), { once: true });
|
|
1527
1770
|
const opts = {
|
|
1528
1771
|
abortController: ac,
|
|
1529
|
-
model:
|
|
1772
|
+
model: options.model,
|
|
1530
1773
|
maxTurns: this.options.maxTurns,
|
|
1531
1774
|
cwd: this.options.workingDirectory,
|
|
1532
1775
|
pathToClaudeCodeExecutable: this.options.cliPath,
|
|
@@ -1556,25 +1799,85 @@ var init_claude = __esm({
|
|
|
1556
1799
|
return opts;
|
|
1557
1800
|
}
|
|
1558
1801
|
async buildMcpConfig(opts, toolResultCapture) {
|
|
1559
|
-
|
|
1802
|
+
const onAskUser = this.config.supervisor?.onAskUser;
|
|
1803
|
+
if (this.tools.length === 0 && !onAskUser) return opts;
|
|
1560
1804
|
const sdk = await loadSDK2();
|
|
1561
|
-
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture);
|
|
1805
|
+
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture, onAskUser);
|
|
1562
1806
|
if (mcpServer) {
|
|
1563
1807
|
opts.mcpServers = {
|
|
1564
1808
|
[MCP_SERVER_NAME]: mcpServer
|
|
1565
1809
|
};
|
|
1566
1810
|
const mcpToolNames = this.tools.map((t) => mcpToolName(t.name));
|
|
1811
|
+
if (onAskUser) {
|
|
1812
|
+
mcpToolNames.push(mcpToolName("ask_user"));
|
|
1813
|
+
}
|
|
1567
1814
|
opts.allowedTools = [...opts.allowedTools ?? [], ...mcpToolNames];
|
|
1568
1815
|
}
|
|
1816
|
+
if (onAskUser) {
|
|
1817
|
+
opts.disallowedTools = [...opts.disallowedTools ?? [], "AskUserQuestion"];
|
|
1818
|
+
}
|
|
1569
1819
|
return opts;
|
|
1570
1820
|
}
|
|
1821
|
+
// ─── Retry Helpers (shared across executeRun/RunStructured/Stream) ──
|
|
1822
|
+
/** Setup a retry query: clear session, rebuild with full history */
|
|
1823
|
+
async prepareRetryQuery(sdk, messages, signal, options, toolResultCapture, modifyOpts) {
|
|
1824
|
+
this.clearPersistentSession();
|
|
1825
|
+
const retryPrompt = buildContextualPrompt(messages);
|
|
1826
|
+
let retryOpts = this.buildQueryOptions(signal, options);
|
|
1827
|
+
toolResultCapture.clear();
|
|
1828
|
+
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1829
|
+
modifyOpts?.(retryOpts);
|
|
1830
|
+
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1831
|
+
this.activeQuery = retryQ;
|
|
1832
|
+
return retryQ;
|
|
1833
|
+
}
|
|
1834
|
+
/** Extract tool_use blocks from an assistant SDK message into toolCalls array */
|
|
1835
|
+
collectToolCallsFromMessage(msg, toolCalls, toolResultCapture) {
|
|
1836
|
+
if (msg.type !== "assistant") return;
|
|
1837
|
+
const betaMessage = msg.message;
|
|
1838
|
+
if (!betaMessage?.content) return;
|
|
1839
|
+
for (const block of betaMessage.content) {
|
|
1840
|
+
if (block.type === "tool_use") {
|
|
1841
|
+
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1842
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1843
|
+
toolCalls.push({
|
|
1844
|
+
toolName,
|
|
1845
|
+
args: block.input ?? {},
|
|
1846
|
+
result: toolResultCapture.get(toolName) ?? null,
|
|
1847
|
+
approved: true
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
/** Back-fill tool results from capture map on summary/result messages */
|
|
1853
|
+
backfillToolResults(msg, toolCalls, toolResultCapture) {
|
|
1854
|
+
if (msg.type !== "tool_use_summary" && msg.type !== "result") return;
|
|
1855
|
+
for (const tc of toolCalls) {
|
|
1856
|
+
if (tc.result === null) {
|
|
1857
|
+
const captured = toolResultCapture.get(tc.toolName);
|
|
1858
|
+
if (captured !== void 0) tc.result = captured;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
/** Wrap retry inner loop with shared error handling */
|
|
1863
|
+
async withRetryErrorHandling(signal, fn) {
|
|
1864
|
+
try {
|
|
1865
|
+
return await fn();
|
|
1866
|
+
} catch (retryError) {
|
|
1867
|
+
if (this.isPersistent) this.clearPersistentSession();
|
|
1868
|
+
if (signal.aborted) throw new AbortError();
|
|
1869
|
+
throw retryError;
|
|
1870
|
+
} finally {
|
|
1871
|
+
this.activeQuery = null;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1571
1874
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
1572
|
-
async executeRun(messages,
|
|
1875
|
+
async executeRun(messages, options, signal) {
|
|
1573
1876
|
this.checkAbort(signal);
|
|
1574
1877
|
const sdk = await loadSDK2();
|
|
1575
1878
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1576
|
-
const prompt = isResuming ?
|
|
1577
|
-
let opts = this.buildQueryOptions(signal);
|
|
1879
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1880
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1578
1881
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1579
1882
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1580
1883
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1584,30 +1887,8 @@ var init_claude = __esm({
|
|
|
1584
1887
|
let usage;
|
|
1585
1888
|
try {
|
|
1586
1889
|
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
|
-
}
|
|
1890
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1891
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1611
1892
|
if (msg.type === "result") {
|
|
1612
1893
|
if (msg.subtype === "success") {
|
|
1613
1894
|
const r = msg;
|
|
@@ -1627,41 +1908,13 @@ var init_claude = __esm({
|
|
|
1627
1908
|
} catch (e) {
|
|
1628
1909
|
if (signal.aborted) throw new AbortError();
|
|
1629
1910
|
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;
|
|
1911
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1637
1912
|
toolCalls.length = 0;
|
|
1638
1913
|
output = null;
|
|
1639
|
-
|
|
1914
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1640
1915
|
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
|
-
}
|
|
1916
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1917
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1665
1918
|
if (msg.type === "result") {
|
|
1666
1919
|
if (msg.subtype === "success") {
|
|
1667
1920
|
const r = msg;
|
|
@@ -1678,23 +1931,17 @@ var init_claude = __esm({
|
|
|
1678
1931
|
}
|
|
1679
1932
|
}
|
|
1680
1933
|
}
|
|
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
|
-
};
|
|
1934
|
+
return {
|
|
1935
|
+
output,
|
|
1936
|
+
structuredOutput: void 0,
|
|
1937
|
+
toolCalls,
|
|
1938
|
+
messages: [
|
|
1939
|
+
...messages,
|
|
1940
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1941
|
+
],
|
|
1942
|
+
usage
|
|
1943
|
+
};
|
|
1944
|
+
});
|
|
1698
1945
|
}
|
|
1699
1946
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1700
1947
|
throw e;
|
|
@@ -1713,12 +1960,12 @@ var init_claude = __esm({
|
|
|
1713
1960
|
};
|
|
1714
1961
|
}
|
|
1715
1962
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
1716
|
-
async executeRunStructured(messages, schema,
|
|
1963
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
1717
1964
|
this.checkAbort(signal);
|
|
1718
1965
|
const sdk = await loadSDK2();
|
|
1719
1966
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1720
|
-
const prompt = isResuming ?
|
|
1721
|
-
let opts = this.buildQueryOptions(signal);
|
|
1967
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1968
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1722
1969
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1723
1970
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1724
1971
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
@@ -1734,30 +1981,8 @@ var init_claude = __esm({
|
|
|
1734
1981
|
let usage;
|
|
1735
1982
|
try {
|
|
1736
1983
|
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
|
-
}
|
|
1984
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1985
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1761
1986
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1762
1987
|
const r = msg;
|
|
1763
1988
|
output = r.result;
|
|
@@ -1792,46 +2017,23 @@ var init_claude = __esm({
|
|
|
1792
2017
|
} catch (e) {
|
|
1793
2018
|
if (signal.aborted) throw new AbortError();
|
|
1794
2019
|
if (isResuming && this.isPersistent) {
|
|
1795
|
-
this.
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
this.activeQuery = retryQ;
|
|
2020
|
+
const retryQ = await this.prepareRetryQuery(
|
|
2021
|
+
sdk,
|
|
2022
|
+
messages,
|
|
2023
|
+
signal,
|
|
2024
|
+
options,
|
|
2025
|
+
toolResultCapture,
|
|
2026
|
+
(opts2) => {
|
|
2027
|
+
opts2.outputFormat = { type: "json_schema", schema: jsonSchema };
|
|
2028
|
+
}
|
|
2029
|
+
);
|
|
1806
2030
|
toolCalls.length = 0;
|
|
1807
2031
|
output = null;
|
|
1808
2032
|
structuredOutput = void 0;
|
|
1809
|
-
|
|
2033
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1810
2034
|
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
|
-
}
|
|
2035
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
2036
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1835
2037
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1836
2038
|
const r = msg;
|
|
1837
2039
|
output = r.result;
|
|
@@ -1863,23 +2065,17 @@ var init_claude = __esm({
|
|
|
1863
2065
|
);
|
|
1864
2066
|
}
|
|
1865
2067
|
}
|
|
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
|
-
};
|
|
2068
|
+
return {
|
|
2069
|
+
output,
|
|
2070
|
+
structuredOutput,
|
|
2071
|
+
toolCalls,
|
|
2072
|
+
messages: [
|
|
2073
|
+
...messages,
|
|
2074
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
2075
|
+
],
|
|
2076
|
+
usage
|
|
2077
|
+
};
|
|
2078
|
+
});
|
|
1883
2079
|
}
|
|
1884
2080
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1885
2081
|
throw e;
|
|
@@ -1898,12 +2094,12 @@ var init_claude = __esm({
|
|
|
1898
2094
|
};
|
|
1899
2095
|
}
|
|
1900
2096
|
// ─── executeStream ──────────────────────────────────────────────
|
|
1901
|
-
async *executeStream(messages,
|
|
2097
|
+
async *executeStream(messages, options, signal) {
|
|
1902
2098
|
this.checkAbort(signal);
|
|
1903
2099
|
const sdk = await loadSDK2();
|
|
1904
2100
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1905
|
-
const prompt = isResuming ?
|
|
1906
|
-
let opts = this.buildQueryOptions(signal);
|
|
2101
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
2102
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1907
2103
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1908
2104
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1909
2105
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1911,6 +2107,7 @@ var init_claude = __esm({
|
|
|
1911
2107
|
const thinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1912
2108
|
const toolCallTracker = new ClaudeToolCallTracker();
|
|
1913
2109
|
const pendingStreamToolCalls = /* @__PURE__ */ new Map();
|
|
2110
|
+
let hasStreamedText = false;
|
|
1914
2111
|
try {
|
|
1915
2112
|
for await (const msg of q) {
|
|
1916
2113
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1928,6 +2125,7 @@ var init_claude = __esm({
|
|
|
1928
2125
|
} else if (e.type === "tool_call_end") {
|
|
1929
2126
|
pendingStreamToolCalls.delete(e.toolCallId);
|
|
1930
2127
|
}
|
|
2128
|
+
if (e.type === "text_delta") hasStreamedText = true;
|
|
1931
2129
|
yield e;
|
|
1932
2130
|
}
|
|
1933
2131
|
}
|
|
@@ -1951,22 +2149,21 @@ var init_claude = __esm({
|
|
|
1951
2149
|
}
|
|
1952
2150
|
yield this.emitSessionInfo(r.session_id);
|
|
1953
2151
|
}
|
|
1954
|
-
yield {
|
|
2152
|
+
yield {
|
|
2153
|
+
type: "done",
|
|
2154
|
+
finalOutput: hasStreamedText ? null : r.result,
|
|
2155
|
+
...hasStreamedText ? { streamed: true } : {}
|
|
2156
|
+
};
|
|
1955
2157
|
}
|
|
1956
2158
|
}
|
|
1957
2159
|
} catch (e) {
|
|
1958
2160
|
if (signal.aborted) throw new AbortError();
|
|
1959
2161
|
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;
|
|
2162
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1967
2163
|
const retryThinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1968
2164
|
const retryToolCallTracker = new ClaudeToolCallTracker();
|
|
1969
2165
|
const retryPendingToolCalls = /* @__PURE__ */ new Map();
|
|
2166
|
+
let retryHasStreamedText = false;
|
|
1970
2167
|
try {
|
|
1971
2168
|
for await (const msg of retryQ) {
|
|
1972
2169
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1984,6 +2181,7 @@ var init_claude = __esm({
|
|
|
1984
2181
|
} else if (ev.type === "tool_call_end") {
|
|
1985
2182
|
retryPendingToolCalls.delete(ev.toolCallId);
|
|
1986
2183
|
}
|
|
2184
|
+
if (ev.type === "text_delta") retryHasStreamedText = true;
|
|
1987
2185
|
yield ev;
|
|
1988
2186
|
}
|
|
1989
2187
|
}
|
|
@@ -2007,7 +2205,11 @@ var init_claude = __esm({
|
|
|
2007
2205
|
}
|
|
2008
2206
|
yield this.emitSessionInfo(r.session_id);
|
|
2009
2207
|
}
|
|
2010
|
-
yield {
|
|
2208
|
+
yield {
|
|
2209
|
+
type: "done",
|
|
2210
|
+
finalOutput: retryHasStreamedText ? null : r.result,
|
|
2211
|
+
...retryHasStreamedText ? { streamed: true } : {}
|
|
2212
|
+
};
|
|
2011
2213
|
}
|
|
2012
2214
|
}
|
|
2013
2215
|
} catch (retryError) {
|
|
@@ -2069,7 +2271,8 @@ var init_claude = __esm({
|
|
|
2069
2271
|
this.cachedModels = body.data.map((m) => ({
|
|
2070
2272
|
id: m.id,
|
|
2071
2273
|
name: m.display_name,
|
|
2072
|
-
provider: "claude"
|
|
2274
|
+
provider: "claude",
|
|
2275
|
+
...m.max_input_tokens != null && { contextWindow: m.max_input_tokens }
|
|
2073
2276
|
}));
|
|
2074
2277
|
return this.cachedModels;
|
|
2075
2278
|
}
|
|
@@ -2127,32 +2330,30 @@ __export(vercel_ai_exports, {
|
|
|
2127
2330
|
createVercelAIService: () => createVercelAIService
|
|
2128
2331
|
});
|
|
2129
2332
|
async function loadSDK3() {
|
|
2130
|
-
if (
|
|
2333
|
+
if (_sdkMock3) return _sdkMock3;
|
|
2131
2334
|
try {
|
|
2132
|
-
|
|
2133
|
-
return sdkModule3;
|
|
2335
|
+
return await import('ai');
|
|
2134
2336
|
} catch {
|
|
2135
2337
|
throw new DependencyError("ai");
|
|
2136
2338
|
}
|
|
2137
2339
|
}
|
|
2138
2340
|
async function loadCompat() {
|
|
2139
|
-
if (
|
|
2341
|
+
if (_compatMock) return _compatMock;
|
|
2140
2342
|
try {
|
|
2141
|
-
|
|
2142
|
-
return compatModule;
|
|
2343
|
+
return await import('@ai-sdk/openai-compatible');
|
|
2143
2344
|
} catch {
|
|
2144
2345
|
throw new DependencyError("@ai-sdk/openai-compatible");
|
|
2145
2346
|
}
|
|
2146
2347
|
}
|
|
2147
2348
|
function _injectSDK3(mock) {
|
|
2148
|
-
|
|
2349
|
+
_sdkMock3 = mock;
|
|
2149
2350
|
}
|
|
2150
2351
|
function _injectCompat(mock) {
|
|
2151
|
-
|
|
2352
|
+
_compatMock = mock;
|
|
2152
2353
|
}
|
|
2153
2354
|
function _resetSDK3() {
|
|
2154
|
-
|
|
2155
|
-
|
|
2355
|
+
_sdkMock3 = null;
|
|
2356
|
+
_compatMock = null;
|
|
2156
2357
|
}
|
|
2157
2358
|
function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, signal) {
|
|
2158
2359
|
const toolMap = {};
|
|
@@ -2195,13 +2396,14 @@ function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, s
|
|
|
2195
2396
|
return toolMap;
|
|
2196
2397
|
}
|
|
2197
2398
|
function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
|
|
2198
|
-
return async (args) => {
|
|
2399
|
+
return async (args, options) => {
|
|
2199
2400
|
if (ourTool.needsApproval && supervisor?.onPermission) {
|
|
2200
2401
|
const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
|
|
2201
2402
|
if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
|
|
2202
2403
|
const request = {
|
|
2203
2404
|
toolName: ourTool.name,
|
|
2204
|
-
toolArgs: args ?? {}
|
|
2405
|
+
toolArgs: args ?? {},
|
|
2406
|
+
toolCallId: options?.toolCallId
|
|
2205
2407
|
};
|
|
2206
2408
|
const decision = await supervisor.onPermission(
|
|
2207
2409
|
request,
|
|
@@ -2308,7 +2510,8 @@ function mapStreamPart(part) {
|
|
|
2308
2510
|
return {
|
|
2309
2511
|
type: "error",
|
|
2310
2512
|
error: p.error instanceof Error ? p.error.message : String(p.error ?? "Tool execution failed"),
|
|
2311
|
-
recoverable: true
|
|
2513
|
+
recoverable: true,
|
|
2514
|
+
code: "TOOL_EXECUTION" /* TOOL_EXECUTION */
|
|
2312
2515
|
};
|
|
2313
2516
|
}
|
|
2314
2517
|
case "reasoning-start":
|
|
@@ -2329,10 +2532,13 @@ function mapStreamPart(part) {
|
|
|
2329
2532
|
}
|
|
2330
2533
|
case "error": {
|
|
2331
2534
|
const p = part;
|
|
2535
|
+
const errorMsg = p.error instanceof Error ? p.error.message : String(p.error ?? "Unknown error");
|
|
2536
|
+
const code = classifyAgentError(errorMsg);
|
|
2332
2537
|
return {
|
|
2333
2538
|
type: "error",
|
|
2334
|
-
error:
|
|
2335
|
-
recoverable:
|
|
2539
|
+
error: errorMsg,
|
|
2540
|
+
recoverable: isRecoverableErrorCode(code),
|
|
2541
|
+
code
|
|
2336
2542
|
};
|
|
2337
2543
|
}
|
|
2338
2544
|
default:
|
|
@@ -2342,15 +2548,15 @@ function mapStreamPart(part) {
|
|
|
2342
2548
|
function createVercelAIService(options) {
|
|
2343
2549
|
return new VercelAIAgentService(options);
|
|
2344
2550
|
}
|
|
2345
|
-
var
|
|
2551
|
+
var _sdkMock3, _compatMock, DEFAULT_BASE_URL, DEFAULT_PROVIDER, DEFAULT_MAX_TURNS, VercelAIAgent, VercelAIAgentService;
|
|
2346
2552
|
var init_vercel_ai = __esm({
|
|
2347
2553
|
"src/backends/vercel-ai.ts"() {
|
|
2348
|
-
|
|
2554
|
+
init_types2();
|
|
2349
2555
|
init_base_agent();
|
|
2350
|
-
|
|
2556
|
+
init_errors2();
|
|
2351
2557
|
init_schema();
|
|
2352
|
-
|
|
2353
|
-
|
|
2558
|
+
_sdkMock3 = null;
|
|
2559
|
+
_compatMock = null;
|
|
2354
2560
|
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
2355
2561
|
DEFAULT_PROVIDER = "openrouter";
|
|
2356
2562
|
DEFAULT_MAX_TURNS = 10;
|
|
@@ -2363,28 +2569,33 @@ var init_vercel_ai = __esm({
|
|
|
2363
2569
|
super(config);
|
|
2364
2570
|
this.backendOptions = backendOptions;
|
|
2365
2571
|
}
|
|
2366
|
-
async getModel() {
|
|
2367
|
-
|
|
2572
|
+
async getModel(options) {
|
|
2573
|
+
const requestedModel = options.model;
|
|
2574
|
+
const defaultModel = this.config.model;
|
|
2575
|
+
if (requestedModel === defaultModel && this.model) return this.model;
|
|
2368
2576
|
const compat = await loadCompat();
|
|
2369
2577
|
const provider = compat.createOpenAICompatible({
|
|
2370
2578
|
name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
|
|
2371
2579
|
baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
|
|
2372
2580
|
apiKey: this.backendOptions.apiKey
|
|
2373
2581
|
});
|
|
2374
|
-
const
|
|
2375
|
-
|
|
2376
|
-
|
|
2582
|
+
const model = provider.chatModel(requestedModel);
|
|
2583
|
+
if (requestedModel === defaultModel) {
|
|
2584
|
+
this.model = model;
|
|
2585
|
+
}
|
|
2586
|
+
return model;
|
|
2377
2587
|
}
|
|
2378
|
-
async getSDKTools(signal) {
|
|
2588
|
+
async getSDKTools(signal, options) {
|
|
2379
2589
|
const sdk = await loadSDK3();
|
|
2380
|
-
|
|
2590
|
+
const tools = this.resolveTools(options);
|
|
2591
|
+
return mapToolsToSDK2(sdk, tools, this.config, this.sessionApprovals, this.config.permissionStore, signal);
|
|
2381
2592
|
}
|
|
2382
2593
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
2383
|
-
async executeRun(messages,
|
|
2594
|
+
async executeRun(messages, options, signal) {
|
|
2384
2595
|
this.checkAbort(signal);
|
|
2385
2596
|
const sdk = await loadSDK3();
|
|
2386
|
-
const model = await this.getModel();
|
|
2387
|
-
const tools = await this.getSDKTools(signal);
|
|
2597
|
+
const model = await this.getModel(options);
|
|
2598
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2388
2599
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2389
2600
|
const sdkMessages = messagesToSDK(messages);
|
|
2390
2601
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2440,10 +2651,10 @@ var init_vercel_ai = __esm({
|
|
|
2440
2651
|
};
|
|
2441
2652
|
}
|
|
2442
2653
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
2443
|
-
async executeRunStructured(messages, schema,
|
|
2654
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
2444
2655
|
this.checkAbort(signal);
|
|
2445
2656
|
const sdk = await loadSDK3();
|
|
2446
|
-
const model = await this.getModel();
|
|
2657
|
+
const model = await this.getModel(options);
|
|
2447
2658
|
const sdkMessages = messagesToSDK(messages);
|
|
2448
2659
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
2449
2660
|
const result = await sdk.generateObject({
|
|
@@ -2485,11 +2696,11 @@ var init_vercel_ai = __esm({
|
|
|
2485
2696
|
};
|
|
2486
2697
|
}
|
|
2487
2698
|
// ─── executeStream ──────────────────────────────────────────────
|
|
2488
|
-
async *executeStream(messages,
|
|
2699
|
+
async *executeStream(messages, options, signal) {
|
|
2489
2700
|
this.checkAbort(signal);
|
|
2490
2701
|
const sdk = await loadSDK3();
|
|
2491
|
-
const model = await this.getModel();
|
|
2492
|
-
const tools = await this.getSDKTools(signal);
|
|
2702
|
+
const model = await this.getModel(options);
|
|
2703
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2493
2704
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2494
2705
|
const sdkMessages = messagesToSDK(messages);
|
|
2495
2706
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2535,9 +2746,11 @@ var init_vercel_ai = __esm({
|
|
|
2535
2746
|
promptTokens: Number(totalUsage?.inputTokens ?? 0),
|
|
2536
2747
|
completionTokens: Number(totalUsage?.outputTokens ?? 0)
|
|
2537
2748
|
};
|
|
2749
|
+
const hasStreamed = finalText.length > 0;
|
|
2538
2750
|
yield {
|
|
2539
2751
|
type: "done",
|
|
2540
|
-
finalOutput: finalText || null
|
|
2752
|
+
finalOutput: hasStreamed ? null : finalText || null,
|
|
2753
|
+
...hasStreamed ? { streamed: true } : {}
|
|
2541
2754
|
};
|
|
2542
2755
|
} catch (e) {
|
|
2543
2756
|
if (signal.aborted) throw new AbortError();
|
|
@@ -2566,16 +2779,33 @@ var init_vercel_ai = __esm({
|
|
|
2566
2779
|
const baseUrl = (this.options.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
2567
2780
|
try {
|
|
2568
2781
|
const res = await globalThis.fetch(`${baseUrl}/models`, {
|
|
2569
|
-
headers: {
|
|
2782
|
+
headers: {
|
|
2783
|
+
Authorization: `Bearer ${this.options.apiKey}`,
|
|
2784
|
+
// OpenRouter requires HTTP-Referer for API access
|
|
2785
|
+
"HTTP-Referer": "https://github.com/nicepkg/agent-sdk"
|
|
2786
|
+
}
|
|
2570
2787
|
});
|
|
2571
2788
|
if (!res.ok) {
|
|
2572
2789
|
return [];
|
|
2573
2790
|
}
|
|
2574
2791
|
const body = await res.json();
|
|
2575
|
-
if (
|
|
2576
|
-
return
|
|
2792
|
+
if (body.data && Array.isArray(body.data)) {
|
|
2793
|
+
return body.data.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2794
|
+
id: m.id,
|
|
2795
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2796
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2797
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2798
|
+
}));
|
|
2577
2799
|
}
|
|
2578
|
-
|
|
2800
|
+
if (Array.isArray(body)) {
|
|
2801
|
+
return body.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2802
|
+
id: m.id,
|
|
2803
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2804
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2805
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2806
|
+
}));
|
|
2807
|
+
}
|
|
2808
|
+
return [];
|
|
2579
2809
|
} catch {
|
|
2580
2810
|
return [];
|
|
2581
2811
|
}
|
|
@@ -2589,280 +2819,24 @@ var init_vercel_ai = __esm({
|
|
|
2589
2819
|
try {
|
|
2590
2820
|
await loadSDK3();
|
|
2591
2821
|
} catch (e) {
|
|
2592
|
-
errors.push(e instanceof Error ? e.message : String(e));
|
|
2593
|
-
}
|
|
2594
|
-
try {
|
|
2595
|
-
await loadCompat();
|
|
2596
|
-
} catch (e) {
|
|
2597
|
-
errors.push(e instanceof Error ? e.message : String(e));
|
|
2598
|
-
}
|
|
2599
|
-
return { valid: errors.length === 0, errors };
|
|
2600
|
-
}
|
|
2601
|
-
async dispose() {
|
|
2602
|
-
if (this.disposed) return;
|
|
2603
|
-
this.disposed = true;
|
|
2604
|
-
}
|
|
2605
|
-
};
|
|
2606
|
-
}
|
|
2607
|
-
});
|
|
2608
|
-
|
|
2609
|
-
// src/registry.ts
|
|
2610
|
-
function registerBackend(name, factory) {
|
|
2611
|
-
if (registry.has(name)) {
|
|
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];
|
|
2628
|
-
}
|
|
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
|
-
|
|
2698
|
-
${schemaInstruction}`;
|
|
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);
|
|
2822
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
2797
2823
|
}
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
async clear() {
|
|
2805
|
-
await this.sessionStore.clear();
|
|
2806
|
-
await this.projectStore.clear();
|
|
2807
|
-
await this.userStore.clear();
|
|
2824
|
+
try {
|
|
2825
|
+
await loadCompat();
|
|
2826
|
+
} catch (e) {
|
|
2827
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
2828
|
+
}
|
|
2829
|
+
return { valid: errors.length === 0, errors };
|
|
2808
2830
|
}
|
|
2809
2831
|
async dispose() {
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
if (this.userStore !== this.projectStore) {
|
|
2813
|
-
await this.userStore.dispose();
|
|
2814
|
-
}
|
|
2832
|
+
if (this.disposed) return;
|
|
2833
|
+
this.disposed = true;
|
|
2815
2834
|
}
|
|
2816
2835
|
};
|
|
2817
2836
|
}
|
|
2818
2837
|
});
|
|
2819
2838
|
|
|
2820
|
-
// src/
|
|
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
|
|
2839
|
+
// src/chat/types.ts
|
|
2866
2840
|
function createChatId() {
|
|
2867
2841
|
return crypto.randomUUID();
|
|
2868
2842
|
}
|
|
@@ -2873,6 +2847,20 @@ function toChatId(value) {
|
|
|
2873
2847
|
}
|
|
2874
2848
|
return value;
|
|
2875
2849
|
}
|
|
2850
|
+
function createTextMessage(text, role = "user") {
|
|
2851
|
+
return {
|
|
2852
|
+
id: createChatId(),
|
|
2853
|
+
role,
|
|
2854
|
+
parts: [{ type: "text", text, status: "complete" }],
|
|
2855
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2856
|
+
status: "complete"
|
|
2857
|
+
};
|
|
2858
|
+
}
|
|
2859
|
+
function isObservableSession(session) {
|
|
2860
|
+
return "subscribe" in session && typeof session.subscribe === "function" && "getSnapshot" in session && typeof session.getSnapshot === "function";
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
// src/chat/chat-utils.ts
|
|
2876
2864
|
function getMessageText(message) {
|
|
2877
2865
|
return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
2878
2866
|
}
|
|
@@ -2882,6 +2870,8 @@ function getMessageToolCalls(message) {
|
|
|
2882
2870
|
function getMessageReasoning(message) {
|
|
2883
2871
|
return message.parts.filter((p) => p.type === "reasoning").map((p) => p.text).join("");
|
|
2884
2872
|
}
|
|
2873
|
+
|
|
2874
|
+
// src/chat/guards.ts
|
|
2885
2875
|
function isChatMessage(value) {
|
|
2886
2876
|
if (typeof value !== "object" || value === null) return false;
|
|
2887
2877
|
const obj = value;
|
|
@@ -2947,6 +2937,8 @@ function isChatEvent(value) {
|
|
|
2947
2937
|
];
|
|
2948
2938
|
return validTypes.includes(obj.type);
|
|
2949
2939
|
}
|
|
2940
|
+
|
|
2941
|
+
// src/chat/bridge.ts
|
|
2950
2942
|
function agentEventToChatEvent(event, messageId) {
|
|
2951
2943
|
switch (event.type) {
|
|
2952
2944
|
case "text_delta":
|
|
@@ -2999,6 +2991,7 @@ function agentEventToChatEvent(event, messageId) {
|
|
|
2999
2991
|
type: "error",
|
|
3000
2992
|
error: event.error,
|
|
3001
2993
|
recoverable: event.recoverable,
|
|
2994
|
+
code: event.code,
|
|
3002
2995
|
messageId
|
|
3003
2996
|
};
|
|
3004
2997
|
case "heartbeat":
|
|
@@ -3045,11 +3038,13 @@ function chatEventToAgentEvent(event) {
|
|
|
3045
3038
|
result: event.result
|
|
3046
3039
|
};
|
|
3047
3040
|
case "error":
|
|
3048
|
-
return { type: "error", error: event.error, recoverable: event.recoverable };
|
|
3041
|
+
return { type: "error", error: event.error, recoverable: event.recoverable, code: event.code };
|
|
3049
3042
|
default:
|
|
3050
3043
|
return null;
|
|
3051
3044
|
}
|
|
3052
3045
|
}
|
|
3046
|
+
|
|
3047
|
+
// src/chat/conversion.ts
|
|
3053
3048
|
function toAgentMessage(message) {
|
|
3054
3049
|
const textContent = getMessageText(message);
|
|
3055
3050
|
const toolCallParts = getMessageToolCalls(message);
|
|
@@ -3220,6 +3215,56 @@ var ContextWindowManager = class {
|
|
|
3220
3215
|
});
|
|
3221
3216
|
return { ...result, messages: updatedMessages };
|
|
3222
3217
|
}
|
|
3218
|
+
/**
|
|
3219
|
+
* Trim messages using real token usage data from the previous API call.
|
|
3220
|
+
* Uses average-based algorithm: `avgTokensPerMessage = lastPromptTokens / messageCount`.
|
|
3221
|
+
* Removes oldest non-system messages until freed budget brings usage under modelContextWindow.
|
|
3222
|
+
*
|
|
3223
|
+
* @param messages - All messages in the session
|
|
3224
|
+
* @param lastPromptTokens - Real prompt tokens from the last API response
|
|
3225
|
+
* @param modelContextWindow - Model's total context window size in tokens
|
|
3226
|
+
* @returns Result with fitted messages and metadata
|
|
3227
|
+
*/
|
|
3228
|
+
fitMessagesWithUsage(messages, lastPromptTokens, modelContextWindow) {
|
|
3229
|
+
if (messages.length === 0) {
|
|
3230
|
+
return { messages: [], totalTokens: 0, removedCount: 0, wasTruncated: false };
|
|
3231
|
+
}
|
|
3232
|
+
const budget = modelContextWindow - this.config.reservedTokens;
|
|
3233
|
+
if (budget <= 0 || lastPromptTokens <= budget) {
|
|
3234
|
+
return {
|
|
3235
|
+
messages: [...messages],
|
|
3236
|
+
totalTokens: lastPromptTokens,
|
|
3237
|
+
removedCount: 0,
|
|
3238
|
+
wasTruncated: false
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
const avgTokensPerMessage = lastPromptTokens / messages.length;
|
|
3242
|
+
const tokensToFree = lastPromptTokens - budget;
|
|
3243
|
+
const messagesToRemove = Math.ceil(tokensToFree / avgTokensPerMessage);
|
|
3244
|
+
const nonSystemIndices = [];
|
|
3245
|
+
for (let i = 0; i < messages.length; i++) {
|
|
3246
|
+
if (messages[i].role === "system") ; else {
|
|
3247
|
+
nonSystemIndices.push(i);
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
const removableCount = Math.min(messagesToRemove, nonSystemIndices.length);
|
|
3251
|
+
const removedIndices = new Set(nonSystemIndices.slice(0, removableCount));
|
|
3252
|
+
const result = [];
|
|
3253
|
+
for (let i = 0; i < messages.length; i++) {
|
|
3254
|
+
if (!removedIndices.has(i)) {
|
|
3255
|
+
result.push(messages[i]);
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
const estimatedTokens = Math.round(
|
|
3259
|
+
lastPromptTokens * (result.length / messages.length)
|
|
3260
|
+
);
|
|
3261
|
+
return {
|
|
3262
|
+
messages: result,
|
|
3263
|
+
totalTokens: estimatedTokens,
|
|
3264
|
+
removedCount: removableCount,
|
|
3265
|
+
wasTruncated: removableCount > 0
|
|
3266
|
+
};
|
|
3267
|
+
}
|
|
3223
3268
|
/**
|
|
3224
3269
|
* Truncate oldest: keeps system messages, removes oldest non-system messages first.
|
|
3225
3270
|
* Always keeps the most recent user message.
|
|
@@ -3337,37 +3382,19 @@ var ContextWindowManager = class {
|
|
|
3337
3382
|
};
|
|
3338
3383
|
|
|
3339
3384
|
// src/chat/errors.ts
|
|
3385
|
+
init_errors2();
|
|
3340
3386
|
init_errors();
|
|
3341
|
-
var ChatErrorCode = /* @__PURE__ */ ((ChatErrorCode2) => {
|
|
3342
|
-
ChatErrorCode2["NETWORK"] = "NETWORK";
|
|
3343
|
-
ChatErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
3344
|
-
ChatErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
|
|
3345
|
-
ChatErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
|
|
3346
|
-
ChatErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
|
|
3347
|
-
ChatErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
|
|
3348
|
-
ChatErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
|
|
3349
|
-
ChatErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
|
|
3350
|
-
ChatErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
|
|
3351
|
-
ChatErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
|
|
3352
|
-
ChatErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
|
|
3353
|
-
ChatErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
3354
|
-
ChatErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
|
|
3355
|
-
ChatErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
|
|
3356
|
-
ChatErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
|
|
3357
|
-
ChatErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
|
|
3358
|
-
ChatErrorCode2["DISPOSED"] = "DISPOSED";
|
|
3359
|
-
ChatErrorCode2["ABORTED"] = "ABORTED";
|
|
3360
|
-
ChatErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
|
|
3361
|
-
ChatErrorCode2["REENTRANCY"] = "REENTRANCY";
|
|
3362
|
-
return ChatErrorCode2;
|
|
3363
|
-
})(ChatErrorCode || {});
|
|
3364
3387
|
var ChatError = class extends AgentSDKError {
|
|
3365
3388
|
code;
|
|
3366
3389
|
retryable;
|
|
3367
3390
|
retryAfter;
|
|
3368
3391
|
timestamp;
|
|
3369
3392
|
constructor(message, options) {
|
|
3370
|
-
super(message, {
|
|
3393
|
+
super(message, {
|
|
3394
|
+
cause: options.cause,
|
|
3395
|
+
code: options.code,
|
|
3396
|
+
retryable: options.retryable
|
|
3397
|
+
});
|
|
3371
3398
|
this.name = "ChatError";
|
|
3372
3399
|
this.code = options.code;
|
|
3373
3400
|
this.retryable = options.retryable ?? false;
|
|
@@ -3546,12 +3573,12 @@ function isRetryable(error) {
|
|
|
3546
3573
|
return classified.retryable;
|
|
3547
3574
|
}
|
|
3548
3575
|
function sleep(ms, signal) {
|
|
3549
|
-
return new Promise((
|
|
3576
|
+
return new Promise((resolve, reject) => {
|
|
3550
3577
|
if (signal?.aborted) {
|
|
3551
3578
|
reject(new ChatError("Retry aborted", { code: "ABORTED" /* ABORTED */ }));
|
|
3552
3579
|
return;
|
|
3553
3580
|
}
|
|
3554
|
-
const timer = setTimeout(
|
|
3581
|
+
const timer = setTimeout(resolve, ms);
|
|
3555
3582
|
signal?.addEventListener(
|
|
3556
3583
|
"abort",
|
|
3557
3584
|
() => {
|
|
@@ -3875,6 +3902,35 @@ var CancellableTimeout = class {
|
|
|
3875
3902
|
}
|
|
3876
3903
|
};
|
|
3877
3904
|
|
|
3905
|
+
// src/chat/listener-set.ts
|
|
3906
|
+
var ListenerSet = class {
|
|
3907
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
3908
|
+
/** Add a listener. Returns an unsubscribe function. */
|
|
3909
|
+
add(callback) {
|
|
3910
|
+
this._listeners.add(callback);
|
|
3911
|
+
return () => {
|
|
3912
|
+
this._listeners.delete(callback);
|
|
3913
|
+
};
|
|
3914
|
+
}
|
|
3915
|
+
/** Notify all listeners with the given arguments. Errors are isolated per listener. */
|
|
3916
|
+
notify(...args) {
|
|
3917
|
+
for (const cb of this._listeners) {
|
|
3918
|
+
try {
|
|
3919
|
+
cb(...args);
|
|
3920
|
+
} catch {
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
/** Remove all listeners. */
|
|
3925
|
+
clear() {
|
|
3926
|
+
this._listeners.clear();
|
|
3927
|
+
}
|
|
3928
|
+
/** Current number of listeners. */
|
|
3929
|
+
get size() {
|
|
3930
|
+
return this._listeners.size;
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
|
|
3878
3934
|
// src/chat/runtime.ts
|
|
3879
3935
|
var ChatRuntime = class {
|
|
3880
3936
|
_state;
|
|
@@ -3886,20 +3942,19 @@ var ChatRuntime = class {
|
|
|
3886
3942
|
_tools = /* @__PURE__ */ new Map();
|
|
3887
3943
|
_retryConfig;
|
|
3888
3944
|
_contextStats = /* @__PURE__ */ new Map();
|
|
3945
|
+
_sessionUsage = /* @__PURE__ */ new Map();
|
|
3946
|
+
_modelContextWindows = /* @__PURE__ */ new Map();
|
|
3889
3947
|
_onContextTrimmed;
|
|
3890
3948
|
_streamTimeoutMs;
|
|
3891
|
-
_sessionListeners =
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
_currentModel;
|
|
3895
|
-
_activeSessionId = null;
|
|
3949
|
+
_sessionListeners = new ListenerSet();
|
|
3950
|
+
_adapterPool = /* @__PURE__ */ new Map();
|
|
3951
|
+
_defaultBackend;
|
|
3896
3952
|
_abortController = null;
|
|
3897
3953
|
constructor(options) {
|
|
3898
3954
|
this._state = new StateMachine("idle", RUNTIME_TRANSITIONS);
|
|
3899
3955
|
this._guard = new ChatReentrancyGuard();
|
|
3900
3956
|
this._backends = options.backends;
|
|
3901
|
-
this.
|
|
3902
|
-
this._currentModel = options.defaultModel;
|
|
3957
|
+
this._defaultBackend = options.defaultBackend;
|
|
3903
3958
|
this._sessionStore = options.sessionStore;
|
|
3904
3959
|
this._contextConfig = options.context;
|
|
3905
3960
|
this._middleware = [...options.middleware ?? []];
|
|
@@ -3912,6 +3967,11 @@ var ChatRuntime = class {
|
|
|
3912
3967
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
3913
3968
|
);
|
|
3914
3969
|
}
|
|
3970
|
+
if (options.tools) {
|
|
3971
|
+
for (const tool of options.tools) {
|
|
3972
|
+
this._tools.set(tool.name, tool);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3915
3975
|
}
|
|
3916
3976
|
// ── Lifecycle ──────────────────────────────────────────────
|
|
3917
3977
|
get status() {
|
|
@@ -3923,24 +3983,23 @@ var ChatRuntime = class {
|
|
|
3923
3983
|
this._abortController?.dispose();
|
|
3924
3984
|
this._abortController = null;
|
|
3925
3985
|
this._state.transition("disposed");
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3986
|
+
for (const adapter of this._adapterPool.values()) {
|
|
3987
|
+
try {
|
|
3988
|
+
await adapter.dispose();
|
|
3989
|
+
} catch {
|
|
3990
|
+
}
|
|
3929
3991
|
}
|
|
3992
|
+
this._adapterPool.clear();
|
|
3930
3993
|
}
|
|
3931
3994
|
// ── Sessions ───────────────────────────────────────────────
|
|
3932
|
-
get activeSessionId() {
|
|
3933
|
-
return this._activeSessionId;
|
|
3934
|
-
}
|
|
3935
3995
|
async createSession(options) {
|
|
3936
3996
|
this.assertNotDisposed();
|
|
3937
3997
|
const config = {
|
|
3938
|
-
model: options.config?.model ??
|
|
3939
|
-
backend: options.config?.backend ?? this.
|
|
3998
|
+
model: options.config?.model ?? "",
|
|
3999
|
+
backend: options.config?.backend ?? this._defaultBackend,
|
|
3940
4000
|
...options.config
|
|
3941
4001
|
};
|
|
3942
4002
|
const session = await this._sessionStore.createSession({ ...options, config });
|
|
3943
|
-
this._activeSessionId = session.id;
|
|
3944
4003
|
this._notifySessionChange();
|
|
3945
4004
|
return session;
|
|
3946
4005
|
}
|
|
@@ -3960,36 +4019,12 @@ var ChatRuntime = class {
|
|
|
3960
4019
|
if (!session) return;
|
|
3961
4020
|
await this._sessionStore.deleteSession(cid);
|
|
3962
4021
|
this._contextStats.delete(cid);
|
|
3963
|
-
|
|
3964
|
-
this._activeSessionId = null;
|
|
3965
|
-
}
|
|
3966
|
-
this._notifySessionChange();
|
|
3967
|
-
}
|
|
3968
|
-
async archiveSession(id) {
|
|
3969
|
-
this.assertNotDisposed();
|
|
3970
|
-
const cid = toChatId(id);
|
|
3971
|
-
await this._sessionStore.archiveSession(cid);
|
|
4022
|
+
this._sessionUsage.delete(cid);
|
|
3972
4023
|
this._notifySessionChange();
|
|
3973
4024
|
}
|
|
3974
|
-
async switchSession(id) {
|
|
3975
|
-
this.assertNotDisposed();
|
|
3976
|
-
const cid = toChatId(id);
|
|
3977
|
-
const session = await this._sessionStore.getSession(cid);
|
|
3978
|
-
if (!session) {
|
|
3979
|
-
throw new ChatError(
|
|
3980
|
-
`Session "${id}" not found`,
|
|
3981
|
-
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
3982
|
-
);
|
|
3983
|
-
}
|
|
3984
|
-
this._activeSessionId = session.id;
|
|
3985
|
-
return session;
|
|
3986
|
-
}
|
|
3987
4025
|
// ── Messaging ──────────────────────────────────────────────
|
|
3988
4026
|
async *send(sessionId, message, options) {
|
|
3989
|
-
this.
|
|
3990
|
-
if (!message || message.trim().length === 0) {
|
|
3991
|
-
throw new ChatError("Message cannot be empty", { code: "INVALID_INPUT" /* INVALID_INPUT */ });
|
|
3992
|
-
}
|
|
4027
|
+
this.validateSendInput(message, options);
|
|
3993
4028
|
this._guard.acquire();
|
|
3994
4029
|
const cid = toChatId(sessionId);
|
|
3995
4030
|
this._abortController = new ChatAbortController(options?.signal);
|
|
@@ -3998,150 +4033,274 @@ var ChatRuntime = class {
|
|
|
3998
4033
|
this._state.transition("idle");
|
|
3999
4034
|
}
|
|
4000
4035
|
this._state.transition("streaming");
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
throw new ChatError(
|
|
4004
|
-
`Session "${cid}" not found`,
|
|
4005
|
-
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
4006
|
-
);
|
|
4007
|
-
}
|
|
4008
|
-
const middlewareContext = {
|
|
4036
|
+
await this.loadSession(cid);
|
|
4037
|
+
const mwCtx = {
|
|
4009
4038
|
sessionId: cid,
|
|
4010
4039
|
signal: this._abortController.signal
|
|
4011
4040
|
};
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
const updatedSession = await this._sessionStore.getSession(cid);
|
|
4020
|
-
let messagesToSend = updatedSession.messages;
|
|
4021
|
-
if (this._contextConfig) {
|
|
4022
|
-
const ctxManager = new ContextWindowManager(this._contextConfig);
|
|
4023
|
-
const result = await ctxManager.fitMessagesAsync(messagesToSend);
|
|
4024
|
-
this._contextStats.set(cid, {
|
|
4025
|
-
totalTokens: result.totalTokens,
|
|
4026
|
-
removedCount: result.removedCount,
|
|
4027
|
-
wasTruncated: result.wasTruncated,
|
|
4028
|
-
availableBudget: ctxManager.availableBudget
|
|
4029
|
-
});
|
|
4030
|
-
if (result.wasTruncated && this._onContextTrimmed) {
|
|
4031
|
-
const keptIds = new Set(result.messages.map((m) => m.id));
|
|
4032
|
-
const removed = messagesToSend.filter((m) => !keptIds.has(m.id));
|
|
4033
|
-
if (removed.length > 0) {
|
|
4034
|
-
try {
|
|
4035
|
-
this._onContextTrimmed(cid, removed);
|
|
4036
|
-
} catch {
|
|
4037
|
-
}
|
|
4038
|
-
}
|
|
4039
|
-
}
|
|
4040
|
-
messagesToSend = result.messages;
|
|
4041
|
+
const userMessage = await this.applyBeforeSendMiddleware(
|
|
4042
|
+
this.createUserMessage(message),
|
|
4043
|
+
mwCtx
|
|
4044
|
+
);
|
|
4045
|
+
if (userMessage === null) {
|
|
4046
|
+
this._state.transition("idle");
|
|
4047
|
+
return;
|
|
4041
4048
|
}
|
|
4042
|
-
const
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4049
|
+
const updatedSession = await this.persistAndReload(cid, userMessage);
|
|
4050
|
+
const sessionForAdapter = await this.trimSessionContext(cid, updatedSession, options.model);
|
|
4051
|
+
const stream = await this.prepareEventStream(
|
|
4052
|
+
cid,
|
|
4053
|
+
sessionForAdapter,
|
|
4054
|
+
updatedSession,
|
|
4055
|
+
message,
|
|
4056
|
+
options
|
|
4057
|
+
);
|
|
4047
4058
|
const accumulator = new MessageAccumulator();
|
|
4048
|
-
const runtimeTools = this._tools.size > 0 ? this.injectToolContext([...this._tools.values()], {
|
|
4049
|
-
sessionId: cid,
|
|
4050
|
-
custom: updatedSession.metadata?.custom
|
|
4051
|
-
}) : void 0;
|
|
4052
|
-
const streamOptions = {
|
|
4053
|
-
...options,
|
|
4054
|
-
signal: this._abortController.signal,
|
|
4055
|
-
model: options?.model ?? this._currentModel,
|
|
4056
|
-
tools: runtimeTools
|
|
4057
|
-
};
|
|
4058
|
-
const stream = await this.createStreamWithRetry(adapter, sessionForAdapter, message, streamOptions);
|
|
4059
4059
|
const eventSource = this._streamTimeoutMs ? withStreamWatchdog(stream, { timeoutMs: this._streamTimeoutMs, signal: this._abortController.signal }) : stream;
|
|
4060
4060
|
for await (const event of eventSource) {
|
|
4061
4061
|
if (this._abortController.isAborted) break;
|
|
4062
4062
|
this.feedAccumulator(accumulator, event);
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
}
|
|
4068
|
-
|
|
4069
|
-
if (processedEvent) {
|
|
4070
|
-
yield processedEvent;
|
|
4071
|
-
}
|
|
4072
|
-
}
|
|
4073
|
-
if (this._state.current === "disposed") {
|
|
4074
|
-
return;
|
|
4075
|
-
}
|
|
4076
|
-
let assistantMessage = accumulator.finalize();
|
|
4077
|
-
for (const mw of this._middleware) {
|
|
4078
|
-
if (mw.onAfterReceive) {
|
|
4079
|
-
assistantMessage = await mw.onAfterReceive(assistantMessage, middlewareContext);
|
|
4063
|
+
if (event.type === "usage") {
|
|
4064
|
+
this._sessionUsage.set(cid, {
|
|
4065
|
+
promptTokens: event.promptTokens,
|
|
4066
|
+
completionTokens: event.completionTokens
|
|
4067
|
+
});
|
|
4068
|
+
this.updateContextStatsWithUsage(cid, event.promptTokens, event.completionTokens, options);
|
|
4080
4069
|
}
|
|
4070
|
+
const processed = await this.applyOnEventMiddleware(event, mwCtx);
|
|
4071
|
+
if (processed) yield processed;
|
|
4081
4072
|
}
|
|
4082
|
-
|
|
4083
|
-
this.
|
|
4073
|
+
if (this._state.current === "disposed") return;
|
|
4074
|
+
await this.finalizeAssistantMessage(cid, accumulator, mwCtx);
|
|
4084
4075
|
this._state.transition("idle");
|
|
4085
4076
|
} catch (error) {
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
sessionId: cid,
|
|
4089
|
-
signal: this._abortController?.signal ?? new AbortController().signal
|
|
4090
|
-
};
|
|
4091
|
-
for (const mw of this._middleware) {
|
|
4092
|
-
if (mw.onError) {
|
|
4093
|
-
const result = await mw.onError(processedError, middlewareContext);
|
|
4094
|
-
if (result === null) {
|
|
4095
|
-
if (this._state.canTransition("idle")) {
|
|
4096
|
-
this._state.transition("idle");
|
|
4097
|
-
}
|
|
4098
|
-
return;
|
|
4099
|
-
}
|
|
4100
|
-
processedError = result;
|
|
4101
|
-
}
|
|
4102
|
-
}
|
|
4103
|
-
if (this._state.canTransition("error")) {
|
|
4104
|
-
this._state.transition("error");
|
|
4105
|
-
}
|
|
4106
|
-
throw processedError;
|
|
4077
|
+
const result = await this.handleSendError(error, cid);
|
|
4078
|
+
if (result !== null) throw result;
|
|
4107
4079
|
} finally {
|
|
4108
4080
|
this._guard.release();
|
|
4109
4081
|
this._abortController?.dispose();
|
|
4110
4082
|
this._abortController = null;
|
|
4111
4083
|
}
|
|
4112
4084
|
}
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
// ── Backend / Model ────────────────────────────────────────
|
|
4117
|
-
get currentBackend() {
|
|
4118
|
-
return this._currentBackend;
|
|
4119
|
-
}
|
|
4120
|
-
get currentModel() {
|
|
4121
|
-
return this._currentModel;
|
|
4122
|
-
}
|
|
4123
|
-
async switchBackend(name) {
|
|
4085
|
+
// ── Send Pipeline Stages ──────────────────────────────────────
|
|
4086
|
+
/** Stage 1: Validate send inputs (message content + required fields). */
|
|
4087
|
+
validateSendInput(message, options) {
|
|
4124
4088
|
this.assertNotDisposed();
|
|
4125
|
-
if (!
|
|
4089
|
+
if (!message || message.trim().length === 0) {
|
|
4090
|
+
throw new ChatError("Message cannot be empty", { code: "INVALID_INPUT" /* INVALID_INPUT */ });
|
|
4091
|
+
}
|
|
4092
|
+
if (!options.model) {
|
|
4093
|
+
throw new ChatError(
|
|
4094
|
+
"options.model is required \u2014 caller must specify which model to use",
|
|
4095
|
+
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4096
|
+
);
|
|
4097
|
+
}
|
|
4098
|
+
if (!options.backend) {
|
|
4099
|
+
throw new ChatError(
|
|
4100
|
+
"options.backend is required \u2014 caller must specify which backend to use",
|
|
4101
|
+
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4102
|
+
);
|
|
4103
|
+
}
|
|
4104
|
+
if (!options.credentials) {
|
|
4126
4105
|
throw new ChatError(
|
|
4127
|
-
|
|
4106
|
+
"options.credentials is required \u2014 caller must provide authentication credentials",
|
|
4128
4107
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4129
4108
|
);
|
|
4130
4109
|
}
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4110
|
+
}
|
|
4111
|
+
/** Stage 2: Load session from store. */
|
|
4112
|
+
async loadSession(cid) {
|
|
4113
|
+
const session = await this._sessionStore.getSession(cid);
|
|
4114
|
+
if (!session) {
|
|
4115
|
+
throw new ChatError(
|
|
4116
|
+
`Session "${cid}" not found`,
|
|
4117
|
+
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
4118
|
+
);
|
|
4119
|
+
}
|
|
4120
|
+
return session;
|
|
4121
|
+
}
|
|
4122
|
+
/** Stage 3: Apply onBeforeSend middleware pipeline. Returns null if middleware rejected the send. */
|
|
4123
|
+
async applyBeforeSendMiddleware(userMessage, ctx) {
|
|
4124
|
+
let msg = userMessage;
|
|
4125
|
+
for (const mw of this._middleware) {
|
|
4126
|
+
if (mw.onBeforeSend && msg) {
|
|
4127
|
+
msg = await mw.onBeforeSend(msg, ctx);
|
|
4128
|
+
if (msg === null) return null;
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
return msg;
|
|
4132
|
+
}
|
|
4133
|
+
/** Stage 4: Persist user message and reload session with full history. */
|
|
4134
|
+
async persistAndReload(cid, userMessage) {
|
|
4135
|
+
await this._sessionStore.appendMessage(cid, userMessage);
|
|
4136
|
+
return await this._sessionStore.getSession(cid);
|
|
4137
|
+
}
|
|
4138
|
+
/** Stage 5: Auto-trim context window if configured. Returns session snapshot for adapter. */
|
|
4139
|
+
async trimSessionContext(cid, session, model) {
|
|
4140
|
+
if (!this._contextConfig) return session;
|
|
4141
|
+
const ctxManager = new ContextWindowManager(this._contextConfig);
|
|
4142
|
+
const lastUsage = this._sessionUsage.get(cid);
|
|
4143
|
+
const modelContextWindow = model ? this._modelContextWindows.get(model) : void 0;
|
|
4144
|
+
if (lastUsage && modelContextWindow) {
|
|
4145
|
+
const result2 = ctxManager.fitMessagesWithUsage(
|
|
4146
|
+
session.messages,
|
|
4147
|
+
lastUsage.promptTokens,
|
|
4148
|
+
modelContextWindow
|
|
4149
|
+
);
|
|
4150
|
+
this._contextStats.set(cid, {
|
|
4151
|
+
totalTokens: result2.totalTokens,
|
|
4152
|
+
removedCount: result2.removedCount,
|
|
4153
|
+
wasTruncated: result2.wasTruncated,
|
|
4154
|
+
availableBudget: Math.max(0, modelContextWindow - result2.totalTokens),
|
|
4155
|
+
realPromptTokens: lastUsage.promptTokens,
|
|
4156
|
+
realCompletionTokens: lastUsage.completionTokens,
|
|
4157
|
+
modelContextWindow
|
|
4158
|
+
});
|
|
4159
|
+
if (result2.wasTruncated && this._onContextTrimmed) {
|
|
4160
|
+
const keptIds = new Set(result2.messages.map((m) => m.id));
|
|
4161
|
+
const removed = session.messages.filter((m) => !keptIds.has(m.id));
|
|
4162
|
+
if (removed.length > 0) {
|
|
4163
|
+
try {
|
|
4164
|
+
this._onContextTrimmed(cid, removed);
|
|
4165
|
+
} catch {
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
return { ...session, messages: result2.messages };
|
|
4170
|
+
}
|
|
4171
|
+
const result = await ctxManager.fitMessagesAsync(session.messages);
|
|
4172
|
+
this._contextStats.set(cid, {
|
|
4173
|
+
totalTokens: result.totalTokens,
|
|
4174
|
+
removedCount: result.removedCount,
|
|
4175
|
+
wasTruncated: result.wasTruncated,
|
|
4176
|
+
availableBudget: ctxManager.availableBudget,
|
|
4177
|
+
modelContextWindow
|
|
4178
|
+
});
|
|
4179
|
+
if (result.wasTruncated && this._onContextTrimmed) {
|
|
4180
|
+
const keptIds = new Set(result.messages.map((m) => m.id));
|
|
4181
|
+
const removed = session.messages.filter((m) => !keptIds.has(m.id));
|
|
4182
|
+
if (removed.length > 0) {
|
|
4183
|
+
try {
|
|
4184
|
+
this._onContextTrimmed(cid, removed);
|
|
4185
|
+
} catch {
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
return { ...session, messages: result.messages };
|
|
4190
|
+
}
|
|
4191
|
+
/** Update context stats with real usage data from a usage event. */
|
|
4192
|
+
updateContextStatsWithUsage(cid, promptTokens, completionTokens, options) {
|
|
4193
|
+
const modelContextWindow = options.model ? this._modelContextWindows.get(options.model) : void 0;
|
|
4194
|
+
const existing = this._contextStats.get(cid);
|
|
4195
|
+
this._contextStats.set(cid, {
|
|
4196
|
+
totalTokens: promptTokens,
|
|
4197
|
+
removedCount: existing?.removedCount ?? 0,
|
|
4198
|
+
wasTruncated: existing?.wasTruncated ?? false,
|
|
4199
|
+
availableBudget: modelContextWindow ? Math.max(0, modelContextWindow - promptTokens) : existing?.availableBudget ?? 0,
|
|
4200
|
+
realPromptTokens: promptTokens,
|
|
4201
|
+
realCompletionTokens: completionTokens,
|
|
4202
|
+
modelContextWindow
|
|
4203
|
+
});
|
|
4204
|
+
}
|
|
4205
|
+
/** Stage 6: Prepare event stream — adapter with retry, tool injection. */
|
|
4206
|
+
async prepareEventStream(cid, sessionForAdapter, fullSession, message, options) {
|
|
4207
|
+
const adapter = await this.getOrCreateAdapterWithRetry(options.backend, options.credentials);
|
|
4208
|
+
const runtimeTools = this._tools.size > 0 ? this.injectToolContext([...this._tools.values()], {
|
|
4209
|
+
sessionId: cid,
|
|
4210
|
+
custom: fullSession.metadata?.custom
|
|
4211
|
+
}) : void 0;
|
|
4212
|
+
const streamOptions = {
|
|
4213
|
+
signal: this._abortController.signal,
|
|
4214
|
+
model: options.model,
|
|
4215
|
+
systemPrompt: options.systemPrompt,
|
|
4216
|
+
tools: runtimeTools
|
|
4217
|
+
};
|
|
4218
|
+
return this.createStreamWithRetry(
|
|
4219
|
+
adapter,
|
|
4220
|
+
sessionForAdapter,
|
|
4221
|
+
message,
|
|
4222
|
+
streamOptions,
|
|
4223
|
+
options.backend,
|
|
4224
|
+
options.credentials
|
|
4225
|
+
);
|
|
4226
|
+
}
|
|
4227
|
+
/** Stage 7: Apply onEvent middleware pipeline (sequential transform/suppress). */
|
|
4228
|
+
async applyOnEventMiddleware(event, ctx) {
|
|
4229
|
+
let processed = event;
|
|
4230
|
+
for (const mw of this._middleware) {
|
|
4231
|
+
if (mw.onEvent && processed) {
|
|
4232
|
+
processed = await mw.onEvent(processed, ctx);
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
return processed;
|
|
4236
|
+
}
|
|
4237
|
+
/** Stage 8: Finalize accumulator, apply afterReceive middleware, persist assistant message. */
|
|
4238
|
+
async finalizeAssistantMessage(cid, accumulator, ctx) {
|
|
4239
|
+
let assistantMessage = accumulator.finalize();
|
|
4240
|
+
for (const mw of this._middleware) {
|
|
4241
|
+
if (mw.onAfterReceive) {
|
|
4242
|
+
assistantMessage = await mw.onAfterReceive(assistantMessage, ctx);
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
await this._sessionStore.appendMessage(cid, assistantMessage);
|
|
4246
|
+
this._notifySessionChange();
|
|
4247
|
+
}
|
|
4248
|
+
/** Stage 9: Error handling — apply onError middleware, transition state. Returns null if suppressed. */
|
|
4249
|
+
async handleSendError(error, cid) {
|
|
4250
|
+
let processedError = error instanceof Error ? error : new Error(String(error));
|
|
4251
|
+
const ctx = {
|
|
4252
|
+
sessionId: cid,
|
|
4253
|
+
signal: this._abortController?.signal ?? new AbortController().signal
|
|
4254
|
+
};
|
|
4255
|
+
for (const mw of this._middleware) {
|
|
4256
|
+
if (mw.onError) {
|
|
4257
|
+
const result = await mw.onError(processedError, ctx);
|
|
4258
|
+
if (result === null) {
|
|
4259
|
+
if (this._state.canTransition("idle")) {
|
|
4260
|
+
this._state.transition("idle");
|
|
4261
|
+
}
|
|
4262
|
+
return null;
|
|
4263
|
+
}
|
|
4264
|
+
processedError = result;
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
if (this._state.canTransition("error")) {
|
|
4268
|
+
this._state.transition("error");
|
|
4134
4269
|
}
|
|
4135
|
-
|
|
4270
|
+
return processedError;
|
|
4271
|
+
}
|
|
4272
|
+
abort() {
|
|
4273
|
+
this._abortController?.abort("User abort");
|
|
4136
4274
|
}
|
|
4137
|
-
|
|
4275
|
+
// ── Backend / Model ────────────────────────────────────────
|
|
4276
|
+
async listModels(options) {
|
|
4138
4277
|
this.assertNotDisposed();
|
|
4139
|
-
|
|
4278
|
+
let models = [];
|
|
4279
|
+
const firstAdapter = [...this._adapterPool.values()][0];
|
|
4280
|
+
if (firstAdapter) {
|
|
4281
|
+
try {
|
|
4282
|
+
models = await firstAdapter.listModels();
|
|
4283
|
+
} catch {
|
|
4284
|
+
return [];
|
|
4285
|
+
}
|
|
4286
|
+
} else if (options?.backend && options?.credentials) {
|
|
4287
|
+
try {
|
|
4288
|
+
const adapter = await this.getOrCreateAdapter(options.backend, options.credentials);
|
|
4289
|
+
models = await adapter.listModels();
|
|
4290
|
+
} catch {
|
|
4291
|
+
return [];
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
for (const model of models) {
|
|
4295
|
+
if (model.contextWindow != null) {
|
|
4296
|
+
this._modelContextWindows.set(model.id, model.contextWindow);
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
return models;
|
|
4140
4300
|
}
|
|
4141
|
-
async
|
|
4301
|
+
async listBackends() {
|
|
4142
4302
|
this.assertNotDisposed();
|
|
4143
|
-
|
|
4144
|
-
return adapter.listModels();
|
|
4303
|
+
return Object.keys(this._backends).map((name) => ({ name }));
|
|
4145
4304
|
}
|
|
4146
4305
|
// ── Tools ──────────────────────────────────────────────────
|
|
4147
4306
|
get registeredTools() {
|
|
@@ -4166,37 +4325,46 @@ var ChatRuntime = class {
|
|
|
4166
4325
|
if (idx >= 0) this._middleware.splice(idx, 1);
|
|
4167
4326
|
}
|
|
4168
4327
|
// ── Context Stats ─────────────────────────────────────────
|
|
4169
|
-
getContextStats(sessionId) {
|
|
4328
|
+
async getContextStats(sessionId) {
|
|
4170
4329
|
const cid = toChatId(sessionId);
|
|
4171
4330
|
return this._contextStats.get(cid) ?? null;
|
|
4172
4331
|
}
|
|
4173
4332
|
// ── Session Subscription ──────────────────────────────────
|
|
4174
4333
|
onSessionChange(callback) {
|
|
4175
|
-
this._sessionListeners.add(callback);
|
|
4176
|
-
return () => {
|
|
4177
|
-
this._sessionListeners.delete(callback);
|
|
4178
|
-
};
|
|
4334
|
+
return this._sessionListeners.add(callback);
|
|
4179
4335
|
}
|
|
4180
4336
|
_notifySessionChange() {
|
|
4181
|
-
|
|
4182
|
-
try {
|
|
4183
|
-
cb();
|
|
4184
|
-
} catch {
|
|
4185
|
-
}
|
|
4186
|
-
}
|
|
4337
|
+
this._sessionListeners.notify();
|
|
4187
4338
|
}
|
|
4188
4339
|
// ── Private Helpers ────────────────────────────────────────
|
|
4189
|
-
async getOrCreateAdapter() {
|
|
4190
|
-
|
|
4191
|
-
const
|
|
4340
|
+
async getOrCreateAdapter(backend, credentials) {
|
|
4341
|
+
const key = this.getPoolKey(backend, credentials);
|
|
4342
|
+
const existing = this._adapterPool.get(key);
|
|
4343
|
+
if (existing) return existing;
|
|
4344
|
+
for (const [oldKey, oldAdapter] of this._adapterPool) {
|
|
4345
|
+
if (oldKey.startsWith(backend + ":")) {
|
|
4346
|
+
try {
|
|
4347
|
+
await oldAdapter.dispose();
|
|
4348
|
+
} catch {
|
|
4349
|
+
}
|
|
4350
|
+
this._adapterPool.delete(oldKey);
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4353
|
+
const factory = this._backends[backend];
|
|
4192
4354
|
if (!factory) {
|
|
4193
4355
|
throw new ChatError(
|
|
4194
|
-
`Backend "${
|
|
4356
|
+
`Backend "${backend}" not found`,
|
|
4195
4357
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4196
4358
|
);
|
|
4197
4359
|
}
|
|
4198
|
-
|
|
4199
|
-
|
|
4360
|
+
const adapter = await factory(credentials);
|
|
4361
|
+
this._adapterPool.set(key, adapter);
|
|
4362
|
+
return adapter;
|
|
4363
|
+
}
|
|
4364
|
+
getPoolKey(backend, credentials) {
|
|
4365
|
+
const token = credentials.accessToken;
|
|
4366
|
+
const hash = token.length > 16 ? token.slice(0, 8) + token.slice(-8) : token;
|
|
4367
|
+
return `${backend}:${hash}`;
|
|
4200
4368
|
}
|
|
4201
4369
|
/** Wrap each tool's execute to inject ToolContext as 2nd argument */
|
|
4202
4370
|
injectToolContext(tools, context) {
|
|
@@ -4228,17 +4396,25 @@ var ChatRuntime = class {
|
|
|
4228
4396
|
}
|
|
4229
4397
|
}
|
|
4230
4398
|
/** Get or create adapter with retry on connection errors */
|
|
4231
|
-
async getOrCreateAdapterWithRetry() {
|
|
4399
|
+
async getOrCreateAdapterWithRetry(backend, credentials) {
|
|
4232
4400
|
const maxAttempts = this._retryConfig?.maxAttempts ?? 1;
|
|
4233
4401
|
const delayMs = this._retryConfig?.delayMs ?? 0;
|
|
4234
4402
|
let lastError;
|
|
4235
4403
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
4236
4404
|
try {
|
|
4237
|
-
return await this.getOrCreateAdapter();
|
|
4405
|
+
return await this.getOrCreateAdapter(backend, credentials);
|
|
4238
4406
|
} catch (err) {
|
|
4239
4407
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
4240
4408
|
if (attempt < maxAttempts) {
|
|
4241
|
-
this.
|
|
4409
|
+
const key = this.getPoolKey(backend, credentials);
|
|
4410
|
+
const old = this._adapterPool.get(key);
|
|
4411
|
+
if (old) {
|
|
4412
|
+
try {
|
|
4413
|
+
await old.dispose();
|
|
4414
|
+
} catch {
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
4417
|
+
this._adapterPool.delete(key);
|
|
4242
4418
|
await delay(delayMs);
|
|
4243
4419
|
}
|
|
4244
4420
|
}
|
|
@@ -4251,7 +4427,7 @@ var ChatRuntime = class {
|
|
|
4251
4427
|
* retries with a fresh adapter. Once first event is received,
|
|
4252
4428
|
* the stream is committed (no more retries).
|
|
4253
4429
|
*/
|
|
4254
|
-
async createStreamWithRetry(adapter, session, message, options) {
|
|
4430
|
+
async createStreamWithRetry(adapter, session, message, options, backend, credentials) {
|
|
4255
4431
|
const maxAttempts = this._retryConfig?.maxAttempts ?? 1;
|
|
4256
4432
|
const delayMs = this._retryConfig?.delayMs ?? 0;
|
|
4257
4433
|
let lastError;
|
|
@@ -4272,13 +4448,14 @@ var ChatRuntime = class {
|
|
|
4272
4448
|
} catch (err) {
|
|
4273
4449
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
4274
4450
|
if (attempt < maxAttempts) {
|
|
4275
|
-
|
|
4276
|
-
await
|
|
4277
|
-
|
|
4451
|
+
try {
|
|
4452
|
+
await currentAdapter.dispose();
|
|
4453
|
+
} catch {
|
|
4278
4454
|
}
|
|
4279
|
-
this.
|
|
4455
|
+
const key = this.getPoolKey(backend, credentials);
|
|
4456
|
+
this._adapterPool.delete(key);
|
|
4280
4457
|
await delay(delayMs);
|
|
4281
|
-
currentAdapter = await this.getOrCreateAdapter();
|
|
4458
|
+
currentAdapter = await this.getOrCreateAdapter(backend, credentials);
|
|
4282
4459
|
}
|
|
4283
4460
|
}
|
|
4284
4461
|
}
|
|
@@ -4286,16 +4463,17 @@ var ChatRuntime = class {
|
|
|
4286
4463
|
}
|
|
4287
4464
|
};
|
|
4288
4465
|
function delay(ms) {
|
|
4289
|
-
return new Promise((
|
|
4466
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4290
4467
|
}
|
|
4291
4468
|
function createChatRuntime(options) {
|
|
4292
4469
|
return new ChatRuntime(options);
|
|
4293
4470
|
}
|
|
4294
4471
|
|
|
4295
4472
|
// src/chat/storage.ts
|
|
4473
|
+
init_errors2();
|
|
4296
4474
|
init_errors();
|
|
4297
4475
|
var StorageError = class extends AgentSDKError {
|
|
4298
|
-
/** Machine-readable error code */
|
|
4476
|
+
/** Machine-readable error code from the unified ErrorCode enum */
|
|
4299
4477
|
code;
|
|
4300
4478
|
constructor(message, code) {
|
|
4301
4479
|
super(message);
|
|
@@ -4332,7 +4510,7 @@ var InMemoryStorage = class {
|
|
|
4332
4510
|
if (this.data.has(key)) {
|
|
4333
4511
|
throw new StorageError(
|
|
4334
4512
|
`Item with key "${key}" already exists`,
|
|
4335
|
-
"
|
|
4513
|
+
"STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
|
|
4336
4514
|
);
|
|
4337
4515
|
}
|
|
4338
4516
|
this.data.set(key, structuredClone(item));
|
|
@@ -4342,7 +4520,7 @@ var InMemoryStorage = class {
|
|
|
4342
4520
|
if (!this.data.has(key)) {
|
|
4343
4521
|
throw new StorageError(
|
|
4344
4522
|
`Item with key "${key}" not found`,
|
|
4345
|
-
"
|
|
4523
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4346
4524
|
);
|
|
4347
4525
|
}
|
|
4348
4526
|
this.data.set(key, structuredClone(item));
|
|
@@ -4352,7 +4530,7 @@ var InMemoryStorage = class {
|
|
|
4352
4530
|
if (!this.data.has(key)) {
|
|
4353
4531
|
throw new StorageError(
|
|
4354
4532
|
`Item with key "${key}" not found`,
|
|
4355
|
-
"
|
|
4533
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4356
4534
|
);
|
|
4357
4535
|
}
|
|
4358
4536
|
this.data.delete(key);
|
|
@@ -4417,7 +4595,7 @@ var FileStorage = class {
|
|
|
4417
4595
|
if (fs.existsSync(filePath)) {
|
|
4418
4596
|
throw new StorageError(
|
|
4419
4597
|
`Item with key "${key}" already exists`,
|
|
4420
|
-
"
|
|
4598
|
+
"STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
|
|
4421
4599
|
);
|
|
4422
4600
|
}
|
|
4423
4601
|
this.writeFile(filePath, item);
|
|
@@ -4428,7 +4606,7 @@ var FileStorage = class {
|
|
|
4428
4606
|
if (!fs.existsSync(filePath)) {
|
|
4429
4607
|
throw new StorageError(
|
|
4430
4608
|
`Item with key "${key}" not found`,
|
|
4431
|
-
"
|
|
4609
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4432
4610
|
);
|
|
4433
4611
|
}
|
|
4434
4612
|
this.writeFile(filePath, item);
|
|
@@ -4439,7 +4617,7 @@ var FileStorage = class {
|
|
|
4439
4617
|
if (!fs.existsSync(filePath)) {
|
|
4440
4618
|
throw new StorageError(
|
|
4441
4619
|
`Item with key "${key}" not found`,
|
|
4442
|
-
"
|
|
4620
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4443
4621
|
);
|
|
4444
4622
|
}
|
|
4445
4623
|
fs.unlinkSync(filePath);
|
|
@@ -4485,12 +4663,12 @@ var FileStorage = class {
|
|
|
4485
4663
|
if (error instanceof SyntaxError) {
|
|
4486
4664
|
throw new StorageError(
|
|
4487
4665
|
`Failed to parse file: ${filePath}`,
|
|
4488
|
-
"
|
|
4666
|
+
"STORAGE_SERIALIZATION_ERROR" /* STORAGE_SERIALIZATION_ERROR */
|
|
4489
4667
|
);
|
|
4490
4668
|
}
|
|
4491
4669
|
throw new StorageError(
|
|
4492
4670
|
`Failed to read file: ${filePath}`,
|
|
4493
|
-
"
|
|
4671
|
+
"STORAGE_IO_ERROR" /* STORAGE_IO_ERROR */
|
|
4494
4672
|
);
|
|
4495
4673
|
}
|
|
4496
4674
|
}
|
|
@@ -4501,13 +4679,14 @@ var FileStorage = class {
|
|
|
4501
4679
|
} catch {
|
|
4502
4680
|
throw new StorageError(
|
|
4503
4681
|
`Failed to write file: ${filePath}`,
|
|
4504
|
-
"
|
|
4682
|
+
"STORAGE_IO_ERROR" /* STORAGE_IO_ERROR */
|
|
4505
4683
|
);
|
|
4506
4684
|
}
|
|
4507
4685
|
}
|
|
4508
4686
|
};
|
|
4509
4687
|
|
|
4510
4688
|
// src/chat/sessions.ts
|
|
4689
|
+
init_errors();
|
|
4511
4690
|
var BaseSessionStore = class {
|
|
4512
4691
|
constructor(adapter) {
|
|
4513
4692
|
this.adapter = adapter;
|
|
@@ -4546,7 +4725,7 @@ var BaseSessionStore = class {
|
|
|
4546
4725
|
async updateTitle(id, title) {
|
|
4547
4726
|
const session = await this.adapter.get(id);
|
|
4548
4727
|
if (!session) {
|
|
4549
|
-
throw new StorageError(`Session "${id}" not found`, "
|
|
4728
|
+
throw new StorageError(`Session "${id}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4550
4729
|
}
|
|
4551
4730
|
session.title = title;
|
|
4552
4731
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4555,7 +4734,7 @@ var BaseSessionStore = class {
|
|
|
4555
4734
|
async updateConfig(id, config) {
|
|
4556
4735
|
const session = await this.adapter.get(id);
|
|
4557
4736
|
if (!session) {
|
|
4558
|
-
throw new StorageError(`Session "${id}" not found`, "
|
|
4737
|
+
throw new StorageError(`Session "${id}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4559
4738
|
}
|
|
4560
4739
|
session.config = { ...session.config, ...config };
|
|
4561
4740
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4567,7 +4746,7 @@ var BaseSessionStore = class {
|
|
|
4567
4746
|
async appendMessage(sessionId, message) {
|
|
4568
4747
|
const session = await this.adapter.get(sessionId);
|
|
4569
4748
|
if (!session) {
|
|
4570
|
-
throw new StorageError(`Session "${sessionId}" not found`, "
|
|
4749
|
+
throw new StorageError(`Session "${sessionId}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4571
4750
|
}
|
|
4572
4751
|
session.messages.push(structuredClone(message));
|
|
4573
4752
|
session.metadata.messageCount = session.messages.length;
|
|
@@ -4578,7 +4757,7 @@ var BaseSessionStore = class {
|
|
|
4578
4757
|
if (messages.length === 0) return;
|
|
4579
4758
|
const session = await this.adapter.get(sessionId);
|
|
4580
4759
|
if (!session) {
|
|
4581
|
-
throw new StorageError(`Session "${sessionId}" not found`, "
|
|
4760
|
+
throw new StorageError(`Session "${sessionId}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4582
4761
|
}
|
|
4583
4762
|
for (const msg of messages) {
|
|
4584
4763
|
session.messages.push(structuredClone(msg));
|
|
@@ -4590,7 +4769,7 @@ var BaseSessionStore = class {
|
|
|
4590
4769
|
async loadMessages(sessionId, options) {
|
|
4591
4770
|
const session = await this.adapter.get(sessionId);
|
|
4592
4771
|
if (!session) {
|
|
4593
|
-
throw new StorageError(`Session "${sessionId}" not found`, "
|
|
4772
|
+
throw new StorageError(`Session "${sessionId}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4594
4773
|
}
|
|
4595
4774
|
const total = session.messages.length;
|
|
4596
4775
|
const offset = options?.offset ?? 0;
|
|
@@ -4602,24 +4781,6 @@ var BaseSessionStore = class {
|
|
|
4602
4781
|
hasMore: offset + limit < total
|
|
4603
4782
|
};
|
|
4604
4783
|
}
|
|
4605
|
-
async archiveSession(id) {
|
|
4606
|
-
const session = await this.adapter.get(id);
|
|
4607
|
-
if (!session) {
|
|
4608
|
-
throw new StorageError(`Session "${id}" not found`, "NOT_FOUND");
|
|
4609
|
-
}
|
|
4610
|
-
session.status = "archived";
|
|
4611
|
-
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4612
|
-
await this.adapter.update(id, session);
|
|
4613
|
-
}
|
|
4614
|
-
async unarchiveSession(id) {
|
|
4615
|
-
const session = await this.adapter.get(id);
|
|
4616
|
-
if (!session) {
|
|
4617
|
-
throw new StorageError(`Session "${id}" not found`, "NOT_FOUND");
|
|
4618
|
-
}
|
|
4619
|
-
session.status = "active";
|
|
4620
|
-
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4621
|
-
await this.adapter.update(id, session);
|
|
4622
|
-
}
|
|
4623
4784
|
async searchSessions(options) {
|
|
4624
4785
|
const query = options.query.toLowerCase();
|
|
4625
4786
|
const limit = options.limit ?? 20;
|
|
@@ -4641,15 +4802,6 @@ var BaseSessionStore = class {
|
|
|
4641
4802
|
async clear() {
|
|
4642
4803
|
return this.adapter.clear();
|
|
4643
4804
|
}
|
|
4644
|
-
// ── Deprecated Aliases ──────────────────────────────────────
|
|
4645
|
-
/** @deprecated Use `appendMessage()` instead */
|
|
4646
|
-
async addMessage(sessionId, message) {
|
|
4647
|
-
return this.appendMessage(sessionId, message);
|
|
4648
|
-
}
|
|
4649
|
-
/** @deprecated Use `loadMessages()` instead */
|
|
4650
|
-
async getMessages(sessionId, options) {
|
|
4651
|
-
return this.loadMessages(sessionId, options);
|
|
4652
|
-
}
|
|
4653
4805
|
};
|
|
4654
4806
|
var InMemorySessionStore = class extends BaseSessionStore {
|
|
4655
4807
|
constructor() {
|
|
@@ -4662,28 +4814,59 @@ var FileSessionStore = class extends BaseSessionStore {
|
|
|
4662
4814
|
}
|
|
4663
4815
|
};
|
|
4664
4816
|
|
|
4817
|
+
// src/chat/backends/types.ts
|
|
4818
|
+
function isResumableBackend(adapter) {
|
|
4819
|
+
return "canResume" in adapter && typeof adapter.canResume === "function";
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4665
4822
|
// src/chat/backends/base.ts
|
|
4666
4823
|
var BaseBackendAdapter = class {
|
|
4667
4824
|
name;
|
|
4668
|
-
_agentService;
|
|
4669
|
-
|
|
4825
|
+
_agentService = null;
|
|
4826
|
+
_agentServiceFactory = null;
|
|
4670
4827
|
_disposed = false;
|
|
4671
4828
|
_agentConfig;
|
|
4672
4829
|
_ownsService;
|
|
4830
|
+
// Agent lifecycle: tracks current agent and the model it was created with.
|
|
4831
|
+
// For persistent sessions, reused across calls when model matches.
|
|
4832
|
+
// For non-persistent, recreated every call.
|
|
4833
|
+
_currentAgent = null;
|
|
4673
4834
|
constructor(name, options) {
|
|
4674
4835
|
this.name = name;
|
|
4675
4836
|
this._agentConfig = options.agentConfig;
|
|
4676
4837
|
if (options.agentService) {
|
|
4677
4838
|
this._agentService = options.agentService;
|
|
4678
4839
|
this._ownsService = false;
|
|
4840
|
+
} else if (options.agentServiceFactory) {
|
|
4841
|
+
this._agentServiceFactory = options.agentServiceFactory;
|
|
4842
|
+
this._ownsService = true;
|
|
4679
4843
|
} else {
|
|
4680
4844
|
this._agentService = this.createService();
|
|
4681
4845
|
this._ownsService = true;
|
|
4682
4846
|
}
|
|
4683
4847
|
}
|
|
4684
4848
|
get agentService() {
|
|
4849
|
+
if (!this._agentService) {
|
|
4850
|
+
if (this._agentServiceFactory) {
|
|
4851
|
+
this._agentService = this._agentServiceFactory();
|
|
4852
|
+
this._agentServiceFactory = null;
|
|
4853
|
+
} else {
|
|
4854
|
+
throw new ChatError("Agent service not available", {
|
|
4855
|
+
code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */
|
|
4856
|
+
});
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4685
4859
|
return this._agentService;
|
|
4686
4860
|
}
|
|
4861
|
+
get currentModel() {
|
|
4862
|
+
return this._agentConfig.model;
|
|
4863
|
+
}
|
|
4864
|
+
/**
|
|
4865
|
+
* @deprecated No-op. Tools are passed per-call via SendMessageOptions.tools.
|
|
4866
|
+
* Kept for backward compatibility with code that calls setTools() directly.
|
|
4867
|
+
*/
|
|
4868
|
+
setTools() {
|
|
4869
|
+
}
|
|
4687
4870
|
async sendMessage(session, message, options) {
|
|
4688
4871
|
this.assertNotDisposed();
|
|
4689
4872
|
const events = this.streamMessage(session, message, options);
|
|
@@ -4721,9 +4904,13 @@ var BaseBackendAdapter = class {
|
|
|
4721
4904
|
*/
|
|
4722
4905
|
async *streamAgentEvents(agent, messages, options) {
|
|
4723
4906
|
const messageId = createChatId();
|
|
4907
|
+
const model = options?.model ?? this._agentConfig.model ?? "";
|
|
4724
4908
|
const agentEvents = agent.streamWithContext(messages, {
|
|
4909
|
+
model,
|
|
4725
4910
|
signal: options?.signal,
|
|
4726
|
-
context: options?.context
|
|
4911
|
+
context: options?.context,
|
|
4912
|
+
tools: options?.tools,
|
|
4913
|
+
...options?.systemPrompt ? { systemMessage: options.systemPrompt } : {}
|
|
4727
4914
|
});
|
|
4728
4915
|
yield { type: "message:start", messageId, role: "assistant" };
|
|
4729
4916
|
let text = "";
|
|
@@ -4749,31 +4936,45 @@ var BaseBackendAdapter = class {
|
|
|
4749
4936
|
}
|
|
4750
4937
|
async listModels() {
|
|
4751
4938
|
this.assertNotDisposed();
|
|
4752
|
-
return this.
|
|
4939
|
+
return this.agentService.listModels();
|
|
4753
4940
|
}
|
|
4754
4941
|
async validate() {
|
|
4755
4942
|
this.assertNotDisposed();
|
|
4756
|
-
return this.
|
|
4943
|
+
return this.agentService.validate();
|
|
4757
4944
|
}
|
|
4758
4945
|
async dispose() {
|
|
4759
4946
|
if (this._disposed) return;
|
|
4760
4947
|
this._disposed = true;
|
|
4761
|
-
this.
|
|
4762
|
-
|
|
4763
|
-
|
|
4948
|
+
if (this._currentAgent) {
|
|
4949
|
+
this._currentAgent.instance.dispose();
|
|
4950
|
+
this._currentAgent = null;
|
|
4951
|
+
}
|
|
4952
|
+
if (this._ownsService && this._agentService && typeof this._agentService.dispose === "function") {
|
|
4764
4953
|
await this._agentService.dispose();
|
|
4765
4954
|
}
|
|
4766
4955
|
}
|
|
4767
|
-
/** Get or create an agent
|
|
4956
|
+
/** Get or create an agent. Model is passed per-call via RunOptions.
|
|
4957
|
+
* Tools are passed per-call via SendMessageOptions — not baked into config.
|
|
4958
|
+
* For persistent sessions, reuses agent when model matches. */
|
|
4768
4959
|
getOrCreateAgent(options) {
|
|
4769
|
-
const
|
|
4770
|
-
if (this._agentConfig.sessionMode === "persistent" && this.
|
|
4771
|
-
|
|
4960
|
+
const model = options?.model ?? this._agentConfig.model;
|
|
4961
|
+
if (this._agentConfig.sessionMode === "persistent" && this._currentAgent) {
|
|
4962
|
+
if (this._currentAgent.model === model) {
|
|
4963
|
+
return this._currentAgent.instance;
|
|
4964
|
+
}
|
|
4965
|
+
this._currentAgent.instance.dispose();
|
|
4966
|
+
this._currentAgent = null;
|
|
4772
4967
|
}
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
this.
|
|
4968
|
+
if (this._currentAgent) {
|
|
4969
|
+
this._currentAgent.instance.dispose();
|
|
4970
|
+
this._currentAgent = null;
|
|
4776
4971
|
}
|
|
4972
|
+
const config = {
|
|
4973
|
+
...this._agentConfig,
|
|
4974
|
+
...model !== void 0 && { model }
|
|
4975
|
+
};
|
|
4976
|
+
const agent = this.agentService.createAgent(config);
|
|
4977
|
+
this._currentAgent = { instance: agent, model };
|
|
4777
4978
|
return agent;
|
|
4778
4979
|
}
|
|
4779
4980
|
assertNotDisposed() {
|
|
@@ -4798,8 +4999,8 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
4798
4999
|
this._copilotOptions = options.copilotOptions;
|
|
4799
5000
|
}
|
|
4800
5001
|
createService() {
|
|
4801
|
-
const {
|
|
4802
|
-
return
|
|
5002
|
+
const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
|
|
5003
|
+
return createCopilotService2(this._copilotOptions || {});
|
|
4803
5004
|
}
|
|
4804
5005
|
get backendSessionId() {
|
|
4805
5006
|
return this._backendSessionId;
|
|
@@ -4851,8 +5052,8 @@ var ClaudeChatAdapter = class extends BaseBackendAdapter {
|
|
|
4851
5052
|
this._claudeOptions = options.claudeOptions;
|
|
4852
5053
|
}
|
|
4853
5054
|
createService() {
|
|
4854
|
-
const {
|
|
4855
|
-
return
|
|
5055
|
+
const { createClaudeService: createClaudeService2 } = (init_claude(), __toCommonJS(claude_exports));
|
|
5056
|
+
return createClaudeService2(this._claudeOptions || {});
|
|
4856
5057
|
}
|
|
4857
5058
|
get backendSessionId() {
|
|
4858
5059
|
return this._backendSessionId;
|
|
@@ -4899,20 +5100,8 @@ var VercelAIChatAdapter = class extends BaseBackendAdapter {
|
|
|
4899
5100
|
this._vercelOptions = options.vercelOptions;
|
|
4900
5101
|
}
|
|
4901
5102
|
createService() {
|
|
4902
|
-
const {
|
|
4903
|
-
return
|
|
4904
|
-
}
|
|
4905
|
-
get backendSessionId() {
|
|
4906
|
-
return null;
|
|
4907
|
-
}
|
|
4908
|
-
canResume() {
|
|
4909
|
-
return false;
|
|
4910
|
-
}
|
|
4911
|
-
async *resume(_session, _backendSessionId, _options) {
|
|
4912
|
-
throw new ChatError(
|
|
4913
|
-
"Vercel AI adapter does not support session resume (stateless)",
|
|
4914
|
-
{ code: "PROVIDER_ERROR" /* PROVIDER_ERROR */ }
|
|
4915
|
-
);
|
|
5103
|
+
const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
|
|
5104
|
+
return createVercelAIService2(this._vercelOptions || {});
|
|
4916
5105
|
}
|
|
4917
5106
|
captureSessionId(_agent) {
|
|
4918
5107
|
}
|
|
@@ -5089,9 +5278,9 @@ var InProcessChatTransport = class {
|
|
|
5089
5278
|
send(event) {
|
|
5090
5279
|
if (!this._open) return;
|
|
5091
5280
|
if (this._resolve) {
|
|
5092
|
-
const
|
|
5281
|
+
const resolve = this._resolve;
|
|
5093
5282
|
this._resolve = null;
|
|
5094
|
-
|
|
5283
|
+
resolve({ value: event, done: false });
|
|
5095
5284
|
} else {
|
|
5096
5285
|
this._buffer.push(event);
|
|
5097
5286
|
}
|
|
@@ -5100,9 +5289,9 @@ var InProcessChatTransport = class {
|
|
|
5100
5289
|
if (!this._open) return;
|
|
5101
5290
|
this._open = false;
|
|
5102
5291
|
if (this._resolve) {
|
|
5103
|
-
const
|
|
5292
|
+
const resolve = this._resolve;
|
|
5104
5293
|
this._resolve = null;
|
|
5105
|
-
|
|
5294
|
+
resolve({ value: void 0, done: true });
|
|
5106
5295
|
}
|
|
5107
5296
|
}
|
|
5108
5297
|
error(err) {
|
|
@@ -5114,9 +5303,9 @@ var InProcessChatTransport = class {
|
|
|
5114
5303
|
recoverable: false
|
|
5115
5304
|
};
|
|
5116
5305
|
if (this._resolve) {
|
|
5117
|
-
const
|
|
5306
|
+
const resolve = this._resolve;
|
|
5118
5307
|
this._resolve = null;
|
|
5119
|
-
|
|
5308
|
+
resolve({ value: errorEvent, done: false });
|
|
5120
5309
|
} else {
|
|
5121
5310
|
this._error = err;
|
|
5122
5311
|
}
|
|
@@ -5141,8 +5330,8 @@ var InProcessChatTransport = class {
|
|
|
5141
5330
|
if (!this._open) {
|
|
5142
5331
|
return Promise.resolve({ value: void 0, done: true });
|
|
5143
5332
|
}
|
|
5144
|
-
return new Promise((
|
|
5145
|
-
this._resolve =
|
|
5333
|
+
return new Promise((resolve) => {
|
|
5334
|
+
this._resolve = resolve;
|
|
5146
5335
|
});
|
|
5147
5336
|
}
|
|
5148
5337
|
};
|
|
@@ -5315,9 +5504,7 @@ var ChatEventBus = class extends TypedEventEmitter {
|
|
|
5315
5504
|
|
|
5316
5505
|
exports.BaseBackendAdapter = BaseBackendAdapter;
|
|
5317
5506
|
exports.ChatError = ChatError;
|
|
5318
|
-
exports.ChatErrorCode = ChatErrorCode;
|
|
5319
5507
|
exports.ChatEventBus = ChatEventBus;
|
|
5320
|
-
exports.ChatSDKError = ChatError;
|
|
5321
5508
|
exports.ClaudeChatAdapter = ClaudeChatAdapter;
|
|
5322
5509
|
exports.ContextWindowManager = ContextWindowManager;
|
|
5323
5510
|
exports.CopilotChatAdapter = CopilotChatAdapter;
|
|
@@ -5325,6 +5512,7 @@ exports.ExponentialBackoffStrategy = ExponentialBackoffStrategy;
|
|
|
5325
5512
|
exports.FileSessionStore = FileSessionStore;
|
|
5326
5513
|
exports.InMemorySessionStore = InMemorySessionStore;
|
|
5327
5514
|
exports.InProcessChatTransport = InProcessChatTransport;
|
|
5515
|
+
exports.ListenerSet = ListenerSet;
|
|
5328
5516
|
exports.MessageAccumulator = MessageAccumulator;
|
|
5329
5517
|
exports.SSEChatTransport = SSEChatTransport;
|
|
5330
5518
|
exports.TypedEventEmitter = TypedEventEmitter;
|
|
@@ -5335,6 +5523,7 @@ exports.agentEventToChatEvent = agentEventToChatEvent;
|
|
|
5335
5523
|
exports.classifyError = classifyError;
|
|
5336
5524
|
exports.createChatId = createChatId;
|
|
5337
5525
|
exports.createChatRuntime = createChatRuntime;
|
|
5526
|
+
exports.createTextMessage = createTextMessage;
|
|
5338
5527
|
exports.estimateTokens = estimateTokens;
|
|
5339
5528
|
exports.fromAgentMessage = fromAgentMessage;
|
|
5340
5529
|
exports.getMessageReasoning = getMessageReasoning;
|
|
@@ -5345,7 +5534,9 @@ exports.isChatMessage = isChatMessage;
|
|
|
5345
5534
|
exports.isChatSession = isChatSession;
|
|
5346
5535
|
exports.isFilePart = isFilePart;
|
|
5347
5536
|
exports.isMessagePart = isMessagePart;
|
|
5537
|
+
exports.isObservableSession = isObservableSession;
|
|
5348
5538
|
exports.isReasoningPart = isReasoningPart;
|
|
5539
|
+
exports.isResumableBackend = isResumableBackend;
|
|
5349
5540
|
exports.isRetryable = isRetryable;
|
|
5350
5541
|
exports.isSourcePart = isSourcePart;
|
|
5351
5542
|
exports.isTextPart = isTextPart;
|