@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.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
1
|
import { existsSync, readdirSync, unlinkSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
2
|
import { join } from 'path';
|
|
5
|
-
import * as os from 'os';
|
|
6
3
|
|
|
7
4
|
var __defProp = Object.defineProperty;
|
|
8
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -25,16 +22,100 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
25
22
|
};
|
|
26
23
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
24
|
|
|
28
|
-
// src/errors.ts
|
|
29
|
-
|
|
25
|
+
// src/types/errors.ts
|
|
26
|
+
function isRecoverableErrorCode(code) {
|
|
27
|
+
return RECOVERABLE_CODES.has(code);
|
|
28
|
+
}
|
|
29
|
+
function classifyAgentError(error) {
|
|
30
|
+
const msg = (error instanceof Error ? error.message : error).toLowerCase();
|
|
31
|
+
if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
|
|
32
|
+
return "TIMEOUT" /* TIMEOUT */;
|
|
33
|
+
}
|
|
34
|
+
if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
|
|
35
|
+
return "RATE_LIMIT" /* RATE_LIMIT */;
|
|
36
|
+
}
|
|
37
|
+
if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
|
|
38
|
+
return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
|
|
39
|
+
}
|
|
40
|
+
if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
|
|
41
|
+
return "NETWORK" /* NETWORK */;
|
|
42
|
+
}
|
|
43
|
+
if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
|
|
44
|
+
return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
|
|
45
|
+
}
|
|
46
|
+
if (msg.includes("abort") || msg.includes("cancel")) {
|
|
47
|
+
return "ABORTED" /* ABORTED */;
|
|
48
|
+
}
|
|
49
|
+
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")) {
|
|
50
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
51
|
+
}
|
|
52
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
53
|
+
}
|
|
54
|
+
var ErrorCode, RECOVERABLE_CODES;
|
|
30
55
|
var init_errors = __esm({
|
|
56
|
+
"src/types/errors.ts"() {
|
|
57
|
+
ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
58
|
+
ErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
|
|
59
|
+
ErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
|
|
60
|
+
ErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
|
|
61
|
+
ErrorCode2["NETWORK"] = "NETWORK";
|
|
62
|
+
ErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
63
|
+
ErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
|
|
64
|
+
ErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
|
|
65
|
+
ErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
|
|
66
|
+
ErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
|
|
67
|
+
ErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
|
|
68
|
+
ErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
|
|
69
|
+
ErrorCode2["REENTRANCY"] = "REENTRANCY";
|
|
70
|
+
ErrorCode2["DISPOSED"] = "DISPOSED";
|
|
71
|
+
ErrorCode2["ABORTED"] = "ABORTED";
|
|
72
|
+
ErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
|
|
73
|
+
ErrorCode2["DEPENDENCY_MISSING"] = "DEPENDENCY_MISSING";
|
|
74
|
+
ErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
|
|
75
|
+
ErrorCode2["TOOL_EXECUTION"] = "TOOL_EXECUTION";
|
|
76
|
+
ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
77
|
+
ErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
|
|
78
|
+
ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
|
|
79
|
+
ErrorCode2["PROVIDER_NOT_FOUND"] = "PROVIDER_NOT_FOUND";
|
|
80
|
+
ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
|
|
81
|
+
ErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
|
|
82
|
+
ErrorCode2["STORAGE_NOT_FOUND"] = "STORAGE_NOT_FOUND";
|
|
83
|
+
ErrorCode2["STORAGE_DUPLICATE_KEY"] = "STORAGE_DUPLICATE_KEY";
|
|
84
|
+
ErrorCode2["STORAGE_IO_ERROR"] = "STORAGE_IO_ERROR";
|
|
85
|
+
ErrorCode2["STORAGE_SERIALIZATION_ERROR"] = "STORAGE_SERIALIZATION_ERROR";
|
|
86
|
+
return ErrorCode2;
|
|
87
|
+
})(ErrorCode || {});
|
|
88
|
+
RECOVERABLE_CODES = /* @__PURE__ */ new Set([
|
|
89
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
90
|
+
"RATE_LIMIT" /* RATE_LIMIT */,
|
|
91
|
+
"NETWORK" /* NETWORK */,
|
|
92
|
+
"TOOL_EXECUTION" /* TOOL_EXECUTION */,
|
|
93
|
+
"MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
|
|
94
|
+
"PROVIDER_ERROR" /* PROVIDER_ERROR */
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// src/errors.ts
|
|
100
|
+
var AgentSDKError, ReentrancyError, DisposedError, SubprocessError, DependencyError, AbortError, ToolExecutionError, ActivityTimeoutError;
|
|
101
|
+
var init_errors2 = __esm({
|
|
31
102
|
"src/errors.ts"() {
|
|
103
|
+
init_errors();
|
|
32
104
|
AgentSDKError = class extends Error {
|
|
33
105
|
/** @internal Marker for cross-bundle identity checks */
|
|
34
106
|
_agentSDKError = true;
|
|
107
|
+
/** Machine-readable error code. Prefer values from the ErrorCode enum. */
|
|
108
|
+
code;
|
|
109
|
+
/** Whether this error is safe to retry */
|
|
110
|
+
retryable;
|
|
111
|
+
/** HTTP status code hint for error classification */
|
|
112
|
+
httpStatus;
|
|
35
113
|
constructor(message, options) {
|
|
36
114
|
super(message, options);
|
|
37
115
|
this.name = "AgentSDKError";
|
|
116
|
+
this.code = options?.code;
|
|
117
|
+
this.retryable = options?.retryable ?? false;
|
|
118
|
+
this.httpStatus = options?.httpStatus;
|
|
38
119
|
}
|
|
39
120
|
/** Check if an error is an AgentSDKError (works across bundled copies) */
|
|
40
121
|
static is(error) {
|
|
@@ -43,83 +124,84 @@ var init_errors = __esm({
|
|
|
43
124
|
};
|
|
44
125
|
ReentrancyError = class extends AgentSDKError {
|
|
45
126
|
constructor() {
|
|
46
|
-
super("Agent is already running. Await the current run before starting another."
|
|
127
|
+
super("Agent is already running. Await the current run before starting another.", {
|
|
128
|
+
code: "REENTRANCY" /* REENTRANCY */
|
|
129
|
+
});
|
|
47
130
|
this.name = "ReentrancyError";
|
|
48
131
|
}
|
|
49
132
|
};
|
|
50
133
|
DisposedError = class extends AgentSDKError {
|
|
51
134
|
constructor(entity) {
|
|
52
|
-
super(`${entity} has been disposed and cannot be used
|
|
135
|
+
super(`${entity} has been disposed and cannot be used.`, {
|
|
136
|
+
code: "DISPOSED" /* DISPOSED */
|
|
137
|
+
});
|
|
53
138
|
this.name = "DisposedError";
|
|
54
139
|
}
|
|
55
140
|
};
|
|
56
|
-
BackendNotFoundError = class extends AgentSDKError {
|
|
57
|
-
constructor(backend) {
|
|
58
|
-
super(
|
|
59
|
-
`Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`
|
|
60
|
-
);
|
|
61
|
-
this.name = "BackendNotFoundError";
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
BackendAlreadyRegisteredError = class extends AgentSDKError {
|
|
65
|
-
constructor(backend) {
|
|
66
|
-
super(`Backend "${backend}" is already registered. Use a different name or unregister first.`);
|
|
67
|
-
this.name = "BackendAlreadyRegisteredError";
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
141
|
SubprocessError = class extends AgentSDKError {
|
|
71
142
|
constructor(message, options) {
|
|
72
|
-
super(message, options);
|
|
143
|
+
super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
|
|
73
144
|
this.name = "SubprocessError";
|
|
74
145
|
}
|
|
75
146
|
};
|
|
76
147
|
DependencyError = class extends AgentSDKError {
|
|
77
148
|
packageName;
|
|
78
149
|
constructor(packageName) {
|
|
79
|
-
super(`${packageName} is not installed. Install it: npm install ${packageName}
|
|
150
|
+
super(`${packageName} is not installed. Install it: npm install ${packageName}`, {
|
|
151
|
+
code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */
|
|
152
|
+
});
|
|
80
153
|
this.name = "DependencyError";
|
|
81
154
|
this.packageName = packageName;
|
|
82
155
|
}
|
|
83
156
|
};
|
|
84
157
|
AbortError = class extends AgentSDKError {
|
|
85
158
|
constructor() {
|
|
86
|
-
super("Agent run was aborted.");
|
|
159
|
+
super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
|
|
87
160
|
this.name = "AbortError";
|
|
88
161
|
}
|
|
89
162
|
};
|
|
90
163
|
ToolExecutionError = class extends AgentSDKError {
|
|
91
164
|
toolName;
|
|
92
165
|
constructor(toolName, message, options) {
|
|
93
|
-
super(`Tool "${toolName}" failed: ${message}`, options);
|
|
166
|
+
super(`Tool "${toolName}" failed: ${message}`, { ...options, code: "TOOL_EXECUTION" /* TOOL_EXECUTION */ });
|
|
94
167
|
this.name = "ToolExecutionError";
|
|
95
168
|
this.toolName = toolName;
|
|
96
169
|
}
|
|
97
170
|
};
|
|
98
|
-
|
|
99
|
-
constructor(
|
|
100
|
-
super(`
|
|
101
|
-
|
|
171
|
+
ActivityTimeoutError = class extends AgentSDKError {
|
|
172
|
+
constructor(timeoutMs) {
|
|
173
|
+
super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
|
|
174
|
+
code: "TIMEOUT" /* TIMEOUT */,
|
|
175
|
+
retryable: true
|
|
176
|
+
});
|
|
177
|
+
this.name = "ActivityTimeoutError";
|
|
102
178
|
}
|
|
103
179
|
};
|
|
104
180
|
}
|
|
105
181
|
});
|
|
106
182
|
|
|
107
|
-
// src/types.ts
|
|
108
|
-
function isToolDefinition(tool) {
|
|
109
|
-
return "execute" in tool && typeof tool.execute === "function";
|
|
110
|
-
}
|
|
111
|
-
function isTextContent(content) {
|
|
112
|
-
return typeof content === "string";
|
|
113
|
-
}
|
|
114
|
-
function isMultiPartContent(content) {
|
|
115
|
-
return Array.isArray(content);
|
|
116
|
-
}
|
|
183
|
+
// src/types/guards.ts
|
|
117
184
|
function getTextContent(content) {
|
|
118
185
|
if (typeof content === "string") return content;
|
|
119
186
|
return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
120
187
|
}
|
|
188
|
+
var init_guards = __esm({
|
|
189
|
+
"src/types/guards.ts"() {
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// src/types/index.ts
|
|
121
194
|
var init_types = __esm({
|
|
195
|
+
"src/types/index.ts"() {
|
|
196
|
+
init_errors();
|
|
197
|
+
init_guards();
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// src/types.ts
|
|
202
|
+
var init_types2 = __esm({
|
|
122
203
|
"src/types.ts"() {
|
|
204
|
+
init_types();
|
|
123
205
|
}
|
|
124
206
|
});
|
|
125
207
|
|
|
@@ -127,12 +209,15 @@ var init_types = __esm({
|
|
|
127
209
|
var BaseAgent;
|
|
128
210
|
var init_base_agent = __esm({
|
|
129
211
|
"src/base-agent.ts"() {
|
|
212
|
+
init_errors2();
|
|
213
|
+
init_errors2();
|
|
130
214
|
init_errors();
|
|
131
215
|
BaseAgent = class {
|
|
132
216
|
state = "idle";
|
|
133
217
|
abortController = null;
|
|
134
218
|
config;
|
|
135
219
|
_cleanupExternalSignal = null;
|
|
220
|
+
_streamMiddleware = [];
|
|
136
221
|
/** CLI session ID for persistent mode. Override in backends that support it. */
|
|
137
222
|
get sessionId() {
|
|
138
223
|
return void 0;
|
|
@@ -148,8 +233,11 @@ var init_base_agent = __esm({
|
|
|
148
233
|
this.state = "running";
|
|
149
234
|
try {
|
|
150
235
|
const messages = [{ role: "user", content: prompt }];
|
|
151
|
-
const result = await this.
|
|
152
|
-
|
|
236
|
+
const result = await this.withRetry(
|
|
237
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
238
|
+
options
|
|
239
|
+
);
|
|
240
|
+
this.enrichAndNotifyUsage(result, options);
|
|
153
241
|
return result;
|
|
154
242
|
} finally {
|
|
155
243
|
this.cleanupRun();
|
|
@@ -161,8 +249,11 @@ var init_base_agent = __esm({
|
|
|
161
249
|
const ac = this.createAbortController(options?.signal);
|
|
162
250
|
this.state = "running";
|
|
163
251
|
try {
|
|
164
|
-
const result = await this.
|
|
165
|
-
|
|
252
|
+
const result = await this.withRetry(
|
|
253
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
254
|
+
options
|
|
255
|
+
);
|
|
256
|
+
this.enrichAndNotifyUsage(result, options);
|
|
166
257
|
return result;
|
|
167
258
|
} finally {
|
|
168
259
|
this.cleanupRun();
|
|
@@ -175,13 +266,11 @@ var init_base_agent = __esm({
|
|
|
175
266
|
this.state = "running";
|
|
176
267
|
try {
|
|
177
268
|
const messages = [{ role: "user", content: prompt }];
|
|
178
|
-
const result = await this.
|
|
179
|
-
messages,
|
|
180
|
-
|
|
181
|
-
options,
|
|
182
|
-
ac.signal
|
|
269
|
+
const result = await this.withRetry(
|
|
270
|
+
() => this.executeRunStructured(messages, schema, options, ac.signal),
|
|
271
|
+
options
|
|
183
272
|
);
|
|
184
|
-
this.enrichAndNotifyUsage(result);
|
|
273
|
+
this.enrichAndNotifyUsage(result, options);
|
|
185
274
|
return result;
|
|
186
275
|
} finally {
|
|
187
276
|
this.cleanupRun();
|
|
@@ -194,8 +283,10 @@ var init_base_agent = __esm({
|
|
|
194
283
|
this.state = "streaming";
|
|
195
284
|
try {
|
|
196
285
|
const messages = [{ role: "user", content: prompt }];
|
|
197
|
-
|
|
198
|
-
|
|
286
|
+
yield* this.streamWithRetry(
|
|
287
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
288
|
+
options
|
|
289
|
+
);
|
|
199
290
|
} finally {
|
|
200
291
|
this.cleanupRun();
|
|
201
292
|
}
|
|
@@ -206,12 +297,37 @@ var init_base_agent = __esm({
|
|
|
206
297
|
const ac = this.createAbortController(options?.signal);
|
|
207
298
|
this.state = "streaming";
|
|
208
299
|
try {
|
|
209
|
-
|
|
210
|
-
|
|
300
|
+
yield* this.streamWithRetry(
|
|
301
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
302
|
+
options
|
|
303
|
+
);
|
|
211
304
|
} finally {
|
|
212
305
|
this.cleanupRun();
|
|
213
306
|
}
|
|
214
307
|
}
|
|
308
|
+
/** Register a stream middleware. Applied in registration order after built-in transforms. */
|
|
309
|
+
addStreamMiddleware(middleware) {
|
|
310
|
+
this.guardDisposed();
|
|
311
|
+
this._streamMiddleware.push(middleware);
|
|
312
|
+
}
|
|
313
|
+
/** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
|
|
314
|
+
async *applyStreamPipeline(source, options, ac) {
|
|
315
|
+
let stream = this.enrichStream(source, options);
|
|
316
|
+
stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
|
|
317
|
+
stream = this.heartbeatStream(stream);
|
|
318
|
+
if (this._streamMiddleware.length > 0) {
|
|
319
|
+
const ctx = {
|
|
320
|
+
model: options.model,
|
|
321
|
+
backend: this.backendName,
|
|
322
|
+
abortController: ac,
|
|
323
|
+
config: Object.freeze({ ...this.config })
|
|
324
|
+
};
|
|
325
|
+
for (const mw of this._streamMiddleware) {
|
|
326
|
+
stream = mw(stream, ctx);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
yield* stream;
|
|
330
|
+
}
|
|
215
331
|
abort() {
|
|
216
332
|
if (this.abortController) {
|
|
217
333
|
this.abortController.abort();
|
|
@@ -234,26 +350,109 @@ var init_base_agent = __esm({
|
|
|
234
350
|
this.abort();
|
|
235
351
|
this.state = "disposed";
|
|
236
352
|
}
|
|
353
|
+
// ─── Retry Logic ─────────────────────────────────────────────
|
|
354
|
+
/** Check if an error should be retried given the retry configuration. */
|
|
355
|
+
isRetryableError(error, retry) {
|
|
356
|
+
if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
if (AgentSDKError.is(error)) {
|
|
360
|
+
if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
|
|
361
|
+
return retry.retryableErrors.includes(error.code);
|
|
362
|
+
}
|
|
363
|
+
if (error.retryable) return true;
|
|
364
|
+
if (error.code) return isRecoverableErrorCode(error.code);
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
/** Execute a function with retry logic per RetryConfig. */
|
|
369
|
+
async withRetry(fn, options) {
|
|
370
|
+
const retry = options?.retry;
|
|
371
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
372
|
+
return fn();
|
|
373
|
+
}
|
|
374
|
+
const maxRetries = retry.maxRetries;
|
|
375
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
376
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
377
|
+
let lastError;
|
|
378
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
379
|
+
try {
|
|
380
|
+
return await fn();
|
|
381
|
+
} catch (err) {
|
|
382
|
+
lastError = err;
|
|
383
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
384
|
+
throw err;
|
|
385
|
+
}
|
|
386
|
+
const delay2 = initialDelay * Math.pow(multiplier, attempt);
|
|
387
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
388
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
389
|
+
throw err;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
throw lastError;
|
|
394
|
+
}
|
|
395
|
+
/** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
|
|
396
|
+
async *streamWithRetry(factory, options) {
|
|
397
|
+
const retry = options?.retry;
|
|
398
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
399
|
+
yield* factory();
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const maxRetries = retry.maxRetries;
|
|
403
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
404
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
405
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
406
|
+
try {
|
|
407
|
+
const stream = factory();
|
|
408
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
409
|
+
const first = await iterator.next();
|
|
410
|
+
if (first.done) return;
|
|
411
|
+
yield first.value;
|
|
412
|
+
while (true) {
|
|
413
|
+
const next = await iterator.next();
|
|
414
|
+
if (next.done) break;
|
|
415
|
+
yield next.value;
|
|
416
|
+
}
|
|
417
|
+
return;
|
|
418
|
+
} catch (err) {
|
|
419
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
const delay2 = initialDelay * Math.pow(multiplier, attempt);
|
|
423
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
424
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
425
|
+
throw err;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
// ─── CallOptions Resolution ──────────────────────────────────
|
|
431
|
+
/** Resolve tools to use for this call (per-call override > config default) */
|
|
432
|
+
resolveTools(options) {
|
|
433
|
+
return options?.tools ?? this.config.tools ?? [];
|
|
434
|
+
}
|
|
237
435
|
// ─── Usage Enrichment ───────────────────────────────────────────
|
|
238
436
|
/** Enrich result usage with model/backend and fire onUsage callback */
|
|
239
|
-
enrichAndNotifyUsage(result) {
|
|
437
|
+
enrichAndNotifyUsage(result, options) {
|
|
240
438
|
if (result.usage) {
|
|
241
439
|
result.usage = {
|
|
242
440
|
...result.usage,
|
|
243
|
-
model:
|
|
441
|
+
model: options.model,
|
|
244
442
|
backend: this.backendName
|
|
245
443
|
};
|
|
246
444
|
this.callOnUsage(result.usage);
|
|
247
445
|
}
|
|
248
446
|
}
|
|
249
447
|
/** Wrap a stream to enrich usage_update events and fire onUsage callback */
|
|
250
|
-
async *enrichStream(source) {
|
|
448
|
+
async *enrichStream(source, options) {
|
|
449
|
+
const model = options.model;
|
|
251
450
|
for await (const event of source) {
|
|
252
451
|
if (event.type === "usage_update") {
|
|
253
452
|
const usage = {
|
|
254
453
|
promptTokens: event.promptTokens,
|
|
255
454
|
completionTokens: event.completionTokens,
|
|
256
|
-
model
|
|
455
|
+
model,
|
|
257
456
|
backend: this.backendName
|
|
258
457
|
};
|
|
259
458
|
this.callOnUsage(usage);
|
|
@@ -289,9 +488,9 @@ var init_base_agent = __esm({
|
|
|
289
488
|
let heartbeatResolve = null;
|
|
290
489
|
const timer = setInterval(() => {
|
|
291
490
|
if (heartbeatResolve) {
|
|
292
|
-
const
|
|
491
|
+
const resolve = heartbeatResolve;
|
|
293
492
|
heartbeatResolve = null;
|
|
294
|
-
|
|
493
|
+
resolve();
|
|
295
494
|
}
|
|
296
495
|
}, interval);
|
|
297
496
|
try {
|
|
@@ -299,8 +498,8 @@ var init_base_agent = __esm({
|
|
|
299
498
|
if (!pendingEvent) {
|
|
300
499
|
pendingEvent = iterator.next();
|
|
301
500
|
}
|
|
302
|
-
const heartbeatPromise = new Promise((
|
|
303
|
-
heartbeatResolve =
|
|
501
|
+
const heartbeatPromise = new Promise((resolve) => {
|
|
502
|
+
heartbeatResolve = resolve;
|
|
304
503
|
});
|
|
305
504
|
const eventDone = pendingEvent.then(
|
|
306
505
|
(r) => ({ kind: "event", result: r })
|
|
@@ -323,6 +522,35 @@ var init_base_agent = __esm({
|
|
|
323
522
|
heartbeatResolve = null;
|
|
324
523
|
}
|
|
325
524
|
}
|
|
525
|
+
// ─── Activity Timeout ────────────────────────────────────────
|
|
526
|
+
/** Wrap a stream to abort on inactivity. Resets timer on every event.
|
|
527
|
+
* When timeoutMs is not set, passes through directly. */
|
|
528
|
+
async *activityTimeoutStream(source, timeoutMs, ac) {
|
|
529
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
530
|
+
yield* source;
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
534
|
+
let timerId;
|
|
535
|
+
try {
|
|
536
|
+
while (true) {
|
|
537
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
538
|
+
timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
|
|
539
|
+
});
|
|
540
|
+
const result = await Promise.race([iterator.next(), timeoutPromise]);
|
|
541
|
+
clearTimeout(timerId);
|
|
542
|
+
if (result.done) break;
|
|
543
|
+
yield result.value;
|
|
544
|
+
}
|
|
545
|
+
} catch (err) {
|
|
546
|
+
if (err instanceof ActivityTimeoutError) {
|
|
547
|
+
ac.abort(err);
|
|
548
|
+
}
|
|
549
|
+
throw err;
|
|
550
|
+
} finally {
|
|
551
|
+
clearTimeout(timerId);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
326
554
|
// ─── Guards ───────────────────────────────────────────────────
|
|
327
555
|
guardReentrancy() {
|
|
328
556
|
if (this.state === "running" || this.state === "streaming") {
|
|
@@ -427,6 +655,66 @@ var init_schema = __esm({
|
|
|
427
655
|
}
|
|
428
656
|
});
|
|
429
657
|
|
|
658
|
+
// src/backends/shared.ts
|
|
659
|
+
function extractLastUserPrompt(messages) {
|
|
660
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
661
|
+
const msg = messages[i];
|
|
662
|
+
if (msg.role === "user") {
|
|
663
|
+
return getTextContent(msg.content);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return "";
|
|
667
|
+
}
|
|
668
|
+
function serializeToolCall(tc) {
|
|
669
|
+
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
670
|
+
return ` Tool call: ${tc.name}(${args})`;
|
|
671
|
+
}
|
|
672
|
+
function serializeToolResult(tr) {
|
|
673
|
+
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
674
|
+
const prefix = tr.isError ? "[ERROR] " : "";
|
|
675
|
+
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
676
|
+
}
|
|
677
|
+
function buildContextualPrompt(messages) {
|
|
678
|
+
if (messages.length <= 1) {
|
|
679
|
+
return extractLastUserPrompt(messages);
|
|
680
|
+
}
|
|
681
|
+
const history = messages.slice(0, -1).map((msg) => {
|
|
682
|
+
if (msg.role === "user") {
|
|
683
|
+
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
684
|
+
}
|
|
685
|
+
if (msg.role === "tool" && msg.toolResults) {
|
|
686
|
+
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
687
|
+
return `Tool results:
|
|
688
|
+
${results}`;
|
|
689
|
+
}
|
|
690
|
+
if (msg.role === "assistant") {
|
|
691
|
+
const parts = [];
|
|
692
|
+
const thinking = msg.thinking;
|
|
693
|
+
if (thinking) {
|
|
694
|
+
parts.push(`[reasoning: ${thinking}]`);
|
|
695
|
+
}
|
|
696
|
+
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
697
|
+
if (text2) parts.push(text2);
|
|
698
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
699
|
+
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
700
|
+
}
|
|
701
|
+
return `Assistant: ${parts.join("\n")}`;
|
|
702
|
+
}
|
|
703
|
+
const text = msg.content ? getTextContent(msg.content) : "";
|
|
704
|
+
return `${msg.role}: ${text}`;
|
|
705
|
+
}).join("\n");
|
|
706
|
+
const lastPrompt = extractLastUserPrompt(messages);
|
|
707
|
+
return `Conversation history:
|
|
708
|
+
${history}
|
|
709
|
+
|
|
710
|
+
User: ${lastPrompt}`;
|
|
711
|
+
}
|
|
712
|
+
var init_shared = __esm({
|
|
713
|
+
"src/backends/shared.ts"() {
|
|
714
|
+
init_types2();
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
|
|
430
718
|
// src/backends/copilot.ts
|
|
431
719
|
var copilot_exports = {};
|
|
432
720
|
__export(copilot_exports, {
|
|
@@ -435,10 +723,9 @@ __export(copilot_exports, {
|
|
|
435
723
|
createCopilotService: () => createCopilotService
|
|
436
724
|
});
|
|
437
725
|
async function loadSDK() {
|
|
438
|
-
if (
|
|
726
|
+
if (_sdkMock) return _sdkMock;
|
|
439
727
|
try {
|
|
440
|
-
|
|
441
|
-
return sdkModule;
|
|
728
|
+
return await import('@github/copilot-sdk');
|
|
442
729
|
} catch {
|
|
443
730
|
throw new SubprocessError(
|
|
444
731
|
"@github/copilot-sdk is not installed. Install it: npm install @github/copilot-sdk"
|
|
@@ -446,10 +733,10 @@ async function loadSDK() {
|
|
|
446
733
|
}
|
|
447
734
|
}
|
|
448
735
|
function _injectSDK(mock) {
|
|
449
|
-
|
|
736
|
+
_sdkMock = mock;
|
|
450
737
|
}
|
|
451
738
|
function _resetSDK() {
|
|
452
|
-
|
|
739
|
+
_sdkMock = null;
|
|
453
740
|
}
|
|
454
741
|
function mapToolsToSDK(tools) {
|
|
455
742
|
return tools.map((tool) => ({
|
|
@@ -494,6 +781,7 @@ function buildPermissionHandler(config) {
|
|
|
494
781
|
const unifiedRequest = {
|
|
495
782
|
toolName,
|
|
496
783
|
toolArgs: { ...request },
|
|
784
|
+
toolCallId: request.toolCallId,
|
|
497
785
|
rawSDKRequest: request
|
|
498
786
|
};
|
|
499
787
|
const ac = new AbortController();
|
|
@@ -598,15 +886,21 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
598
886
|
};
|
|
599
887
|
case "session.error":
|
|
600
888
|
console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
889
|
+
{
|
|
890
|
+
const errorMsg = String(data.message ?? "Unknown error");
|
|
891
|
+
const code = classifyAgentError(errorMsg);
|
|
892
|
+
return {
|
|
893
|
+
type: "error",
|
|
894
|
+
error: errorMsg,
|
|
895
|
+
recoverable: isRecoverableErrorCode(code),
|
|
896
|
+
code
|
|
897
|
+
};
|
|
898
|
+
}
|
|
606
899
|
case "assistant.message": {
|
|
607
900
|
const doneEvent = {
|
|
608
901
|
type: "done",
|
|
609
|
-
finalOutput:
|
|
902
|
+
finalOutput: null,
|
|
903
|
+
streamed: true
|
|
610
904
|
};
|
|
611
905
|
if (thinkingTracker.endThinking()) {
|
|
612
906
|
return [{ type: "thinking_end" }, doneEvent];
|
|
@@ -617,66 +911,13 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
617
911
|
return null;
|
|
618
912
|
}
|
|
619
913
|
}
|
|
620
|
-
function extractLastUserPrompt(messages) {
|
|
621
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
622
|
-
const msg = messages[i];
|
|
623
|
-
if (msg.role === "user") {
|
|
624
|
-
return getTextContent(msg.content);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
return "";
|
|
628
|
-
}
|
|
629
|
-
function serializeToolCall(tc) {
|
|
630
|
-
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
631
|
-
return ` Tool call: ${tc.name}(${args})`;
|
|
632
|
-
}
|
|
633
|
-
function serializeToolResult(tr) {
|
|
634
|
-
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
635
|
-
const prefix = tr.isError ? "[ERROR] " : "";
|
|
636
|
-
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
637
|
-
}
|
|
638
|
-
function buildContextualPrompt(messages) {
|
|
639
|
-
if (messages.length <= 1) {
|
|
640
|
-
return extractLastUserPrompt(messages);
|
|
641
|
-
}
|
|
642
|
-
const history = messages.slice(0, -1).map((msg) => {
|
|
643
|
-
if (msg.role === "user") {
|
|
644
|
-
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
645
|
-
}
|
|
646
|
-
if (msg.role === "tool" && msg.toolResults) {
|
|
647
|
-
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
648
|
-
return `Tool results:
|
|
649
|
-
${results}`;
|
|
650
|
-
}
|
|
651
|
-
if (msg.role === "assistant") {
|
|
652
|
-
const parts = [];
|
|
653
|
-
const thinking = msg.thinking;
|
|
654
|
-
if (thinking) {
|
|
655
|
-
parts.push(`[reasoning: ${thinking}]`);
|
|
656
|
-
}
|
|
657
|
-
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
658
|
-
if (text2) parts.push(text2);
|
|
659
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
660
|
-
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
661
|
-
}
|
|
662
|
-
return `Assistant: ${parts.join("\n")}`;
|
|
663
|
-
}
|
|
664
|
-
const text = msg.content ? getTextContent(msg.content) : "";
|
|
665
|
-
return `${msg.role}: ${text}`;
|
|
666
|
-
}).join("\n");
|
|
667
|
-
const lastPrompt = extractLastUserPrompt(messages);
|
|
668
|
-
return `Conversation history:
|
|
669
|
-
${history}
|
|
670
|
-
|
|
671
|
-
User: ${lastPrompt}`;
|
|
672
|
-
}
|
|
673
914
|
function withTimeout(promise, ms, message) {
|
|
674
|
-
return new Promise((
|
|
915
|
+
return new Promise((resolve, reject) => {
|
|
675
916
|
const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
|
|
676
917
|
promise.then(
|
|
677
918
|
(val) => {
|
|
678
919
|
clearTimeout(timer);
|
|
679
|
-
|
|
920
|
+
resolve(val);
|
|
680
921
|
},
|
|
681
922
|
(err) => {
|
|
682
923
|
clearTimeout(timer);
|
|
@@ -688,14 +929,15 @@ function withTimeout(promise, ms, message) {
|
|
|
688
929
|
function createCopilotService(options) {
|
|
689
930
|
return new CopilotAgentService(options);
|
|
690
931
|
}
|
|
691
|
-
var
|
|
932
|
+
var _sdkMock, ToolCallTracker, ThinkingTracker, CopilotAgent, CopilotAgentService;
|
|
692
933
|
var init_copilot = __esm({
|
|
693
934
|
"src/backends/copilot.ts"() {
|
|
694
|
-
|
|
935
|
+
init_types2();
|
|
695
936
|
init_base_agent();
|
|
696
|
-
|
|
937
|
+
init_errors2();
|
|
697
938
|
init_schema();
|
|
698
|
-
|
|
939
|
+
init_shared();
|
|
940
|
+
_sdkMock = null;
|
|
699
941
|
ToolCallTracker = class {
|
|
700
942
|
map = /* @__PURE__ */ new Map();
|
|
701
943
|
trackStart(toolCallId, toolName, args) {
|
|
@@ -743,6 +985,7 @@ var init_copilot = __esm({
|
|
|
743
985
|
isPersistent;
|
|
744
986
|
persistentSession = null;
|
|
745
987
|
_sessionId;
|
|
988
|
+
_persistentModel;
|
|
746
989
|
activeSession = null;
|
|
747
990
|
_resumeSessionId;
|
|
748
991
|
_toolsReady = null;
|
|
@@ -793,47 +1036,63 @@ var init_copilot = __esm({
|
|
|
793
1036
|
});
|
|
794
1037
|
this.persistentSession = null;
|
|
795
1038
|
this._sessionId = void 0;
|
|
1039
|
+
this._persistentModel = void 0;
|
|
796
1040
|
}
|
|
797
1041
|
}
|
|
798
|
-
async getOrCreateSession(streaming) {
|
|
1042
|
+
async getOrCreateSession(streaming, options) {
|
|
799
1043
|
if (this.isPersistent && this.persistentSession) {
|
|
800
|
-
|
|
1044
|
+
if (options.model !== this._persistentModel) {
|
|
1045
|
+
this.persistentSession.destroy().catch(() => {
|
|
1046
|
+
});
|
|
1047
|
+
this.persistentSession = null;
|
|
1048
|
+
this._sessionId = void 0;
|
|
1049
|
+
} else {
|
|
1050
|
+
return { session: this.persistentSession, isNew: false };
|
|
1051
|
+
}
|
|
801
1052
|
}
|
|
802
1053
|
if (this._toolsReady) {
|
|
803
1054
|
await this._toolsReady;
|
|
804
1055
|
this._toolsReady = null;
|
|
805
1056
|
}
|
|
1057
|
+
const sessionConfig = { ...this.sessionConfig };
|
|
1058
|
+
sessionConfig.model = options.model;
|
|
1059
|
+
const resolvedTools = this.resolveTools(options);
|
|
1060
|
+
if (options?.tools) {
|
|
1061
|
+
sessionConfig.tools = mapToolsToSDK(resolvedTools);
|
|
1062
|
+
}
|
|
806
1063
|
const client = await this.getClient();
|
|
807
1064
|
if (this._resumeSessionId) {
|
|
808
1065
|
const storedId = this._resumeSessionId;
|
|
809
1066
|
this._resumeSessionId = void 0;
|
|
810
1067
|
try {
|
|
811
1068
|
const session2 = await client.resumeSession(storedId, {
|
|
812
|
-
...
|
|
1069
|
+
...sessionConfig,
|
|
813
1070
|
streaming: this.isPersistent ? true : streaming
|
|
814
1071
|
});
|
|
815
1072
|
if (this.isPersistent) {
|
|
816
1073
|
this.persistentSession = session2;
|
|
817
1074
|
this._sessionId = session2.sessionId;
|
|
1075
|
+
this._persistentModel = options.model;
|
|
818
1076
|
}
|
|
819
1077
|
return { session: session2, isNew: false };
|
|
820
1078
|
} catch {
|
|
821
1079
|
}
|
|
822
1080
|
}
|
|
823
1081
|
const session = await client.createSession({
|
|
824
|
-
...
|
|
1082
|
+
...sessionConfig,
|
|
825
1083
|
streaming: this.isPersistent ? true : streaming
|
|
826
1084
|
});
|
|
827
1085
|
if (this.isPersistent) {
|
|
828
1086
|
this.persistentSession = session;
|
|
829
1087
|
this._sessionId = session.sessionId;
|
|
1088
|
+
this._persistentModel = options.model;
|
|
830
1089
|
}
|
|
831
1090
|
return { session, isNew: true };
|
|
832
1091
|
}
|
|
833
1092
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
834
|
-
async executeRun(messages,
|
|
1093
|
+
async executeRun(messages, options, signal) {
|
|
835
1094
|
this.checkAbort(signal);
|
|
836
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
|
|
1095
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(false, options);
|
|
837
1096
|
this.activeSession = session;
|
|
838
1097
|
const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
839
1098
|
const tracker = new ToolCallTracker();
|
|
@@ -930,9 +1189,9 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
930
1189
|
};
|
|
931
1190
|
}
|
|
932
1191
|
// ─── executeStream ──────────────────────────────────────────────
|
|
933
|
-
async *executeStream(messages,
|
|
1192
|
+
async *executeStream(messages, options, signal) {
|
|
934
1193
|
this.checkAbort(signal);
|
|
935
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
|
|
1194
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(true, options);
|
|
936
1195
|
this.activeSession = session;
|
|
937
1196
|
if (isNewSession) {
|
|
938
1197
|
yield this.emitSessionInfo(session.sessionId);
|
|
@@ -949,8 +1208,8 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
949
1208
|
notify = null;
|
|
950
1209
|
}
|
|
951
1210
|
};
|
|
952
|
-
const waitForItem = () => new Promise((
|
|
953
|
-
notify =
|
|
1211
|
+
const waitForItem = () => new Promise((resolve) => {
|
|
1212
|
+
notify = resolve;
|
|
954
1213
|
});
|
|
955
1214
|
const unsubscribe = session.on((event) => {
|
|
956
1215
|
const mapped = mapSessionEvent(event, tracker, thinkingTracker);
|
|
@@ -1078,7 +1337,10 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
1078
1337
|
return models.map((m) => ({
|
|
1079
1338
|
id: m.id,
|
|
1080
1339
|
name: m.name,
|
|
1081
|
-
provider: "copilot"
|
|
1340
|
+
provider: "copilot",
|
|
1341
|
+
...m.capabilities?.limits?.max_context_window_tokens != null && {
|
|
1342
|
+
contextWindow: m.capabilities.limits.max_context_window_tokens
|
|
1343
|
+
}
|
|
1082
1344
|
}));
|
|
1083
1345
|
}
|
|
1084
1346
|
async validate() {
|
|
@@ -1131,10 +1393,9 @@ function stripMcpPrefix(name) {
|
|
|
1131
1393
|
return name.startsWith(MCP_TOOL_PREFIX) ? name.slice(MCP_TOOL_PREFIX.length) : name;
|
|
1132
1394
|
}
|
|
1133
1395
|
async function loadSDK2() {
|
|
1134
|
-
if (
|
|
1396
|
+
if (_sdkMock2) return _sdkMock2;
|
|
1135
1397
|
try {
|
|
1136
|
-
|
|
1137
|
-
return sdkModule2;
|
|
1398
|
+
return await import('@anthropic-ai/claude-agent-sdk');
|
|
1138
1399
|
} catch {
|
|
1139
1400
|
throw new SubprocessError(
|
|
1140
1401
|
"@anthropic-ai/claude-agent-sdk is not installed. Install it: npm install @anthropic-ai/claude-agent-sdk"
|
|
@@ -1142,13 +1403,32 @@ async function loadSDK2() {
|
|
|
1142
1403
|
}
|
|
1143
1404
|
}
|
|
1144
1405
|
function _injectSDK2(mock) {
|
|
1145
|
-
|
|
1406
|
+
_sdkMock2 = mock;
|
|
1146
1407
|
}
|
|
1147
1408
|
function _resetSDK2() {
|
|
1148
|
-
|
|
1409
|
+
_sdkMock2 = null;
|
|
1149
1410
|
}
|
|
1150
|
-
function
|
|
1151
|
-
if (
|
|
1411
|
+
function normalizeAskUserInput(args) {
|
|
1412
|
+
if (typeof args.question === "string") {
|
|
1413
|
+
return {
|
|
1414
|
+
question: args.question,
|
|
1415
|
+
choices: Array.isArray(args.choices) ? args.choices : void 0,
|
|
1416
|
+
allowFreeform: args.allowFreeform !== false
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
const questions = args.questions;
|
|
1420
|
+
if (questions && questions.length > 0) {
|
|
1421
|
+
const first = questions[0];
|
|
1422
|
+
return {
|
|
1423
|
+
question: first.question,
|
|
1424
|
+
choices: first.options?.map((o) => o.label),
|
|
1425
|
+
allowFreeform: true
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
return { question: JSON.stringify(args), allowFreeform: true };
|
|
1429
|
+
}
|
|
1430
|
+
function buildMcpServer(sdk, tools, toolResultCapture, onAskUser) {
|
|
1431
|
+
if (tools.length === 0 && !onAskUser) return void 0;
|
|
1152
1432
|
const mcpTools = tools.map((tool) => {
|
|
1153
1433
|
const zodSchema = tool.parameters;
|
|
1154
1434
|
const inputSchema = zodSchema.shape ?? zodToJsonSchema(tool.parameters);
|
|
@@ -1172,6 +1452,39 @@ function buildMcpServer(sdk, tools, toolResultCapture) {
|
|
|
1172
1452
|
}
|
|
1173
1453
|
);
|
|
1174
1454
|
});
|
|
1455
|
+
if (onAskUser) {
|
|
1456
|
+
const askUserTool = sdk.tool(
|
|
1457
|
+
"ask_user",
|
|
1458
|
+
"Ask the user a question and wait for their response",
|
|
1459
|
+
{
|
|
1460
|
+
question: { type: "string", description: "The question to ask the user" },
|
|
1461
|
+
choices: {
|
|
1462
|
+
type: "array",
|
|
1463
|
+
items: { type: "string" },
|
|
1464
|
+
description: "Optional list of choices for multiple choice"
|
|
1465
|
+
},
|
|
1466
|
+
questions: {
|
|
1467
|
+
type: "array",
|
|
1468
|
+
items: {
|
|
1469
|
+
type: "object",
|
|
1470
|
+
properties: {
|
|
1471
|
+
question: { type: "string" },
|
|
1472
|
+
options: { type: "array", items: { type: "object", properties: { label: { type: "string" } } } }
|
|
1473
|
+
}
|
|
1474
|
+
},
|
|
1475
|
+
description: "Alternative nested question format"
|
|
1476
|
+
}
|
|
1477
|
+
},
|
|
1478
|
+
async (args) => {
|
|
1479
|
+
const normalized = normalizeAskUserInput(args);
|
|
1480
|
+
const response = await onAskUser(normalized, AbortSignal.timeout(3e5));
|
|
1481
|
+
return {
|
|
1482
|
+
content: [{ type: "text", text: response.answer }]
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
);
|
|
1486
|
+
mcpTools.push(askUserTool);
|
|
1487
|
+
}
|
|
1175
1488
|
return sdk.createSdkMcpServer({
|
|
1176
1489
|
name: MCP_SERVER_NAME,
|
|
1177
1490
|
version: "1.0.0",
|
|
@@ -1221,6 +1534,7 @@ function buildCanUseTool(config) {
|
|
|
1221
1534
|
const unifiedRequest = {
|
|
1222
1535
|
toolName,
|
|
1223
1536
|
toolArgs: input,
|
|
1537
|
+
toolCallId: options.toolUseID,
|
|
1224
1538
|
suggestedScope: extractSuggestedScope(options.suggestions),
|
|
1225
1539
|
rawSDKRequest: { toolName, input, ...options }
|
|
1226
1540
|
};
|
|
@@ -1273,6 +1587,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1273
1587
|
if (block.type === "tool_use") {
|
|
1274
1588
|
const toolCallId = String(block.id ?? "");
|
|
1275
1589
|
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1590
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1276
1591
|
if (toolCallTracker) {
|
|
1277
1592
|
toolCallTracker.trackStart(toolCallId, toolName);
|
|
1278
1593
|
}
|
|
@@ -1296,6 +1611,7 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1296
1611
|
case "tool_use_summary": {
|
|
1297
1612
|
const summary = msg.summary;
|
|
1298
1613
|
const toolName = stripMcpPrefix(msg.tool_name ?? "unknown");
|
|
1614
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) return null;
|
|
1299
1615
|
const precedingIds = msg.preceding_tool_use_ids;
|
|
1300
1616
|
let toolCallId = "";
|
|
1301
1617
|
if (precedingIds && precedingIds.length > 0) {
|
|
@@ -1349,10 +1665,13 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1349
1665
|
}
|
|
1350
1666
|
if (msg.is_error) {
|
|
1351
1667
|
const r = msg;
|
|
1668
|
+
const errorMsg = r.errors?.join("; ") ?? "Unknown error";
|
|
1669
|
+
const code = classifyAgentError(errorMsg);
|
|
1352
1670
|
return {
|
|
1353
1671
|
type: "error",
|
|
1354
|
-
error:
|
|
1355
|
-
recoverable:
|
|
1672
|
+
error: errorMsg,
|
|
1673
|
+
recoverable: isRecoverableErrorCode(code),
|
|
1674
|
+
code
|
|
1356
1675
|
};
|
|
1357
1676
|
}
|
|
1358
1677
|
return null;
|
|
@@ -1361,72 +1680,21 @@ function mapSDKMessage(msg, thinkingBlockIndices, toolCallTracker) {
|
|
|
1361
1680
|
return null;
|
|
1362
1681
|
}
|
|
1363
1682
|
}
|
|
1364
|
-
function extractLastUserPrompt2(messages) {
|
|
1365
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1366
|
-
const msg = messages[i];
|
|
1367
|
-
if (msg.role === "user") {
|
|
1368
|
-
return getTextContent(msg.content);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
return "";
|
|
1372
|
-
}
|
|
1373
|
-
function serializeToolCall2(tc) {
|
|
1374
|
-
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
1375
|
-
return ` Tool call: ${tc.name}(${args})`;
|
|
1376
|
-
}
|
|
1377
|
-
function serializeToolResult2(tr) {
|
|
1378
|
-
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
1379
|
-
const prefix = tr.isError ? "[ERROR] " : "";
|
|
1380
|
-
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
1381
|
-
}
|
|
1382
|
-
function buildContextualPrompt2(messages) {
|
|
1383
|
-
if (messages.length <= 1) {
|
|
1384
|
-
return extractLastUserPrompt2(messages);
|
|
1385
|
-
}
|
|
1386
|
-
const history = messages.slice(0, -1).map((msg) => {
|
|
1387
|
-
if (msg.role === "user") {
|
|
1388
|
-
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
1389
|
-
}
|
|
1390
|
-
if (msg.role === "tool" && msg.toolResults) {
|
|
1391
|
-
const results = msg.toolResults.map(serializeToolResult2).join("\n");
|
|
1392
|
-
return `Tool results:
|
|
1393
|
-
${results}`;
|
|
1394
|
-
}
|
|
1395
|
-
if (msg.role === "assistant") {
|
|
1396
|
-
const parts = [];
|
|
1397
|
-
const thinking = msg.thinking;
|
|
1398
|
-
if (thinking) {
|
|
1399
|
-
parts.push(`[reasoning: ${thinking}]`);
|
|
1400
|
-
}
|
|
1401
|
-
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
1402
|
-
if (text2) parts.push(text2);
|
|
1403
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
1404
|
-
parts.push(msg.toolCalls.map(serializeToolCall2).join("\n"));
|
|
1405
|
-
}
|
|
1406
|
-
return `Assistant: ${parts.join("\n")}`;
|
|
1407
|
-
}
|
|
1408
|
-
const text = msg.content ? getTextContent(msg.content) : "";
|
|
1409
|
-
return `${msg.role}: ${text}`;
|
|
1410
|
-
}).join("\n");
|
|
1411
|
-
const lastPrompt = extractLastUserPrompt2(messages);
|
|
1412
|
-
return `Conversation history:
|
|
1413
|
-
${history}
|
|
1414
|
-
|
|
1415
|
-
User: ${lastPrompt}`;
|
|
1416
|
-
}
|
|
1417
1683
|
function createClaudeService(options) {
|
|
1418
1684
|
return new ClaudeAgentService(options);
|
|
1419
1685
|
}
|
|
1420
|
-
var MCP_SERVER_NAME, MCP_TOOL_PREFIX,
|
|
1686
|
+
var MCP_SERVER_NAME, MCP_TOOL_PREFIX, CLAUDE_INTERNAL_TOOL_NAMES, _sdkMock2, ANTHROPIC_MODELS_URL, ANTHROPIC_API_VERSION, ANTHROPIC_OAUTH_BETA, ClaudeToolCallTracker, ClaudeAgent, ClaudeAgentService;
|
|
1421
1687
|
var init_claude = __esm({
|
|
1422
1688
|
"src/backends/claude.ts"() {
|
|
1423
|
-
|
|
1689
|
+
init_types2();
|
|
1424
1690
|
init_base_agent();
|
|
1425
|
-
|
|
1691
|
+
init_errors2();
|
|
1426
1692
|
init_schema();
|
|
1693
|
+
init_shared();
|
|
1427
1694
|
MCP_SERVER_NAME = "agent-sdk-tools";
|
|
1428
1695
|
MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
1429
|
-
|
|
1696
|
+
CLAUDE_INTERNAL_TOOL_NAMES = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1697
|
+
_sdkMock2 = null;
|
|
1430
1698
|
ANTHROPIC_MODELS_URL = "https://api.anthropic.com/v1/models";
|
|
1431
1699
|
ANTHROPIC_API_VERSION = "2023-06-01";
|
|
1432
1700
|
ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
@@ -1471,11 +1739,6 @@ var init_claude = __esm({
|
|
|
1471
1739
|
if (options.resumeSessionId) {
|
|
1472
1740
|
this._sessionId = options.resumeSessionId;
|
|
1473
1741
|
}
|
|
1474
|
-
if (config.supervisor?.onAskUser) {
|
|
1475
|
-
console.warn(
|
|
1476
|
-
"[agent-sdk/claude] supervisor.onAskUser is not supported by the Claude CLI backend. User interaction requests from the model will not be forwarded."
|
|
1477
|
-
);
|
|
1478
|
-
}
|
|
1479
1742
|
}
|
|
1480
1743
|
get sessionId() {
|
|
1481
1744
|
return this._sessionId;
|
|
@@ -1499,12 +1762,12 @@ var init_claude = __esm({
|
|
|
1499
1762
|
const transcriptPath = home ? `${home}/.claude/projects/.session/sessions/${sessionId}/conversation.jsonl` : void 0;
|
|
1500
1763
|
return { type: "session_info", sessionId, transcriptPath, backend: "claude" };
|
|
1501
1764
|
}
|
|
1502
|
-
buildQueryOptions(signal) {
|
|
1765
|
+
buildQueryOptions(signal, options) {
|
|
1503
1766
|
const ac = new AbortController();
|
|
1504
1767
|
signal.addEventListener("abort", () => ac.abort(), { once: true });
|
|
1505
1768
|
const opts = {
|
|
1506
1769
|
abortController: ac,
|
|
1507
|
-
model:
|
|
1770
|
+
model: options.model,
|
|
1508
1771
|
maxTurns: this.options.maxTurns,
|
|
1509
1772
|
cwd: this.options.workingDirectory,
|
|
1510
1773
|
pathToClaudeCodeExecutable: this.options.cliPath,
|
|
@@ -1534,25 +1797,85 @@ var init_claude = __esm({
|
|
|
1534
1797
|
return opts;
|
|
1535
1798
|
}
|
|
1536
1799
|
async buildMcpConfig(opts, toolResultCapture) {
|
|
1537
|
-
|
|
1800
|
+
const onAskUser = this.config.supervisor?.onAskUser;
|
|
1801
|
+
if (this.tools.length === 0 && !onAskUser) return opts;
|
|
1538
1802
|
const sdk = await loadSDK2();
|
|
1539
|
-
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture);
|
|
1803
|
+
const mcpServer = buildMcpServer(sdk, this.tools, toolResultCapture, onAskUser);
|
|
1540
1804
|
if (mcpServer) {
|
|
1541
1805
|
opts.mcpServers = {
|
|
1542
1806
|
[MCP_SERVER_NAME]: mcpServer
|
|
1543
1807
|
};
|
|
1544
1808
|
const mcpToolNames = this.tools.map((t) => mcpToolName(t.name));
|
|
1809
|
+
if (onAskUser) {
|
|
1810
|
+
mcpToolNames.push(mcpToolName("ask_user"));
|
|
1811
|
+
}
|
|
1545
1812
|
opts.allowedTools = [...opts.allowedTools ?? [], ...mcpToolNames];
|
|
1546
1813
|
}
|
|
1814
|
+
if (onAskUser) {
|
|
1815
|
+
opts.disallowedTools = [...opts.disallowedTools ?? [], "AskUserQuestion"];
|
|
1816
|
+
}
|
|
1547
1817
|
return opts;
|
|
1548
1818
|
}
|
|
1819
|
+
// ─── Retry Helpers (shared across executeRun/RunStructured/Stream) ──
|
|
1820
|
+
/** Setup a retry query: clear session, rebuild with full history */
|
|
1821
|
+
async prepareRetryQuery(sdk, messages, signal, options, toolResultCapture, modifyOpts) {
|
|
1822
|
+
this.clearPersistentSession();
|
|
1823
|
+
const retryPrompt = buildContextualPrompt(messages);
|
|
1824
|
+
let retryOpts = this.buildQueryOptions(signal, options);
|
|
1825
|
+
toolResultCapture.clear();
|
|
1826
|
+
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1827
|
+
modifyOpts?.(retryOpts);
|
|
1828
|
+
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1829
|
+
this.activeQuery = retryQ;
|
|
1830
|
+
return retryQ;
|
|
1831
|
+
}
|
|
1832
|
+
/** Extract tool_use blocks from an assistant SDK message into toolCalls array */
|
|
1833
|
+
collectToolCallsFromMessage(msg, toolCalls, toolResultCapture) {
|
|
1834
|
+
if (msg.type !== "assistant") return;
|
|
1835
|
+
const betaMessage = msg.message;
|
|
1836
|
+
if (!betaMessage?.content) return;
|
|
1837
|
+
for (const block of betaMessage.content) {
|
|
1838
|
+
if (block.type === "tool_use") {
|
|
1839
|
+
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1840
|
+
if (CLAUDE_INTERNAL_TOOL_NAMES.has(toolName)) continue;
|
|
1841
|
+
toolCalls.push({
|
|
1842
|
+
toolName,
|
|
1843
|
+
args: block.input ?? {},
|
|
1844
|
+
result: toolResultCapture.get(toolName) ?? null,
|
|
1845
|
+
approved: true
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
/** Back-fill tool results from capture map on summary/result messages */
|
|
1851
|
+
backfillToolResults(msg, toolCalls, toolResultCapture) {
|
|
1852
|
+
if (msg.type !== "tool_use_summary" && msg.type !== "result") return;
|
|
1853
|
+
for (const tc of toolCalls) {
|
|
1854
|
+
if (tc.result === null) {
|
|
1855
|
+
const captured = toolResultCapture.get(tc.toolName);
|
|
1856
|
+
if (captured !== void 0) tc.result = captured;
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
/** Wrap retry inner loop with shared error handling */
|
|
1861
|
+
async withRetryErrorHandling(signal, fn) {
|
|
1862
|
+
try {
|
|
1863
|
+
return await fn();
|
|
1864
|
+
} catch (retryError) {
|
|
1865
|
+
if (this.isPersistent) this.clearPersistentSession();
|
|
1866
|
+
if (signal.aborted) throw new AbortError();
|
|
1867
|
+
throw retryError;
|
|
1868
|
+
} finally {
|
|
1869
|
+
this.activeQuery = null;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1549
1872
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
1550
|
-
async executeRun(messages,
|
|
1873
|
+
async executeRun(messages, options, signal) {
|
|
1551
1874
|
this.checkAbort(signal);
|
|
1552
1875
|
const sdk = await loadSDK2();
|
|
1553
1876
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1554
|
-
const prompt = isResuming ?
|
|
1555
|
-
let opts = this.buildQueryOptions(signal);
|
|
1877
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1878
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1556
1879
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1557
1880
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1558
1881
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1562,30 +1885,8 @@ var init_claude = __esm({
|
|
|
1562
1885
|
let usage;
|
|
1563
1886
|
try {
|
|
1564
1887
|
for await (const msg of q) {
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
if (betaMessage?.content) {
|
|
1568
|
-
for (const block of betaMessage.content) {
|
|
1569
|
-
if (block.type === "tool_use") {
|
|
1570
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1571
|
-
toolCalls.push({
|
|
1572
|
-
toolName,
|
|
1573
|
-
args: block.input ?? {},
|
|
1574
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1575
|
-
approved: true
|
|
1576
|
-
});
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1582
|
-
for (const tc of toolCalls) {
|
|
1583
|
-
if (tc.result === null) {
|
|
1584
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1585
|
-
if (captured !== void 0) tc.result = captured;
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1888
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1889
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1589
1890
|
if (msg.type === "result") {
|
|
1590
1891
|
if (msg.subtype === "success") {
|
|
1591
1892
|
const r = msg;
|
|
@@ -1605,41 +1906,13 @@ var init_claude = __esm({
|
|
|
1605
1906
|
} catch (e) {
|
|
1606
1907
|
if (signal.aborted) throw new AbortError();
|
|
1607
1908
|
if (isResuming && this.isPersistent) {
|
|
1608
|
-
this.
|
|
1609
|
-
const retryPrompt = buildContextualPrompt2(messages);
|
|
1610
|
-
let retryOpts = this.buildQueryOptions(signal);
|
|
1611
|
-
toolResultCapture.clear();
|
|
1612
|
-
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1613
|
-
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1614
|
-
this.activeQuery = retryQ;
|
|
1909
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1615
1910
|
toolCalls.length = 0;
|
|
1616
1911
|
output = null;
|
|
1617
|
-
|
|
1912
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1618
1913
|
for await (const msg of retryQ) {
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
if (betaMessage?.content) {
|
|
1622
|
-
for (const block of betaMessage.content) {
|
|
1623
|
-
if (block.type === "tool_use") {
|
|
1624
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1625
|
-
toolCalls.push({
|
|
1626
|
-
toolName,
|
|
1627
|
-
args: block.input ?? {},
|
|
1628
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1629
|
-
approved: true
|
|
1630
|
-
});
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1636
|
-
for (const tc of toolCalls) {
|
|
1637
|
-
if (tc.result === null) {
|
|
1638
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1639
|
-
if (captured !== void 0) tc.result = captured;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1914
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1915
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1643
1916
|
if (msg.type === "result") {
|
|
1644
1917
|
if (msg.subtype === "success") {
|
|
1645
1918
|
const r = msg;
|
|
@@ -1656,23 +1929,17 @@ var init_claude = __esm({
|
|
|
1656
1929
|
}
|
|
1657
1930
|
}
|
|
1658
1931
|
}
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
messages: [
|
|
1671
|
-
...messages,
|
|
1672
|
-
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1673
|
-
],
|
|
1674
|
-
usage
|
|
1675
|
-
};
|
|
1932
|
+
return {
|
|
1933
|
+
output,
|
|
1934
|
+
structuredOutput: void 0,
|
|
1935
|
+
toolCalls,
|
|
1936
|
+
messages: [
|
|
1937
|
+
...messages,
|
|
1938
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1939
|
+
],
|
|
1940
|
+
usage
|
|
1941
|
+
};
|
|
1942
|
+
});
|
|
1676
1943
|
}
|
|
1677
1944
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1678
1945
|
throw e;
|
|
@@ -1691,12 +1958,12 @@ var init_claude = __esm({
|
|
|
1691
1958
|
};
|
|
1692
1959
|
}
|
|
1693
1960
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
1694
|
-
async executeRunStructured(messages, schema,
|
|
1961
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
1695
1962
|
this.checkAbort(signal);
|
|
1696
1963
|
const sdk = await loadSDK2();
|
|
1697
1964
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1698
|
-
const prompt = isResuming ?
|
|
1699
|
-
let opts = this.buildQueryOptions(signal);
|
|
1965
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
1966
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1700
1967
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1701
1968
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1702
1969
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
@@ -1712,30 +1979,8 @@ var init_claude = __esm({
|
|
|
1712
1979
|
let usage;
|
|
1713
1980
|
try {
|
|
1714
1981
|
for await (const msg of q) {
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
if (betaMessage?.content) {
|
|
1718
|
-
for (const block of betaMessage.content) {
|
|
1719
|
-
if (block.type === "tool_use") {
|
|
1720
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1721
|
-
toolCalls.push({
|
|
1722
|
-
toolName,
|
|
1723
|
-
args: block.input ?? {},
|
|
1724
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1725
|
-
approved: true
|
|
1726
|
-
});
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1732
|
-
for (const tc of toolCalls) {
|
|
1733
|
-
if (tc.result === null) {
|
|
1734
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1735
|
-
if (captured !== void 0) tc.result = captured;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1982
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
1983
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1739
1984
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1740
1985
|
const r = msg;
|
|
1741
1986
|
output = r.result;
|
|
@@ -1770,46 +2015,23 @@ var init_claude = __esm({
|
|
|
1770
2015
|
} catch (e) {
|
|
1771
2016
|
if (signal.aborted) throw new AbortError();
|
|
1772
2017
|
if (isResuming && this.isPersistent) {
|
|
1773
|
-
this.
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
this.activeQuery = retryQ;
|
|
2018
|
+
const retryQ = await this.prepareRetryQuery(
|
|
2019
|
+
sdk,
|
|
2020
|
+
messages,
|
|
2021
|
+
signal,
|
|
2022
|
+
options,
|
|
2023
|
+
toolResultCapture,
|
|
2024
|
+
(opts2) => {
|
|
2025
|
+
opts2.outputFormat = { type: "json_schema", schema: jsonSchema };
|
|
2026
|
+
}
|
|
2027
|
+
);
|
|
1784
2028
|
toolCalls.length = 0;
|
|
1785
2029
|
output = null;
|
|
1786
2030
|
structuredOutput = void 0;
|
|
1787
|
-
|
|
2031
|
+
return this.withRetryErrorHandling(signal, async () => {
|
|
1788
2032
|
for await (const msg of retryQ) {
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
if (betaMessage?.content) {
|
|
1792
|
-
for (const block of betaMessage.content) {
|
|
1793
|
-
if (block.type === "tool_use") {
|
|
1794
|
-
const toolName = stripMcpPrefix(block.name ?? "unknown");
|
|
1795
|
-
toolCalls.push({
|
|
1796
|
-
toolName,
|
|
1797
|
-
args: block.input ?? {},
|
|
1798
|
-
result: toolResultCapture.get(toolName) ?? null,
|
|
1799
|
-
approved: true
|
|
1800
|
-
});
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
if (msg.type === "tool_use_summary" || msg.type === "result") {
|
|
1806
|
-
for (const tc of toolCalls) {
|
|
1807
|
-
if (tc.result === null) {
|
|
1808
|
-
const captured = toolResultCapture.get(tc.toolName);
|
|
1809
|
-
if (captured !== void 0) tc.result = captured;
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
2033
|
+
this.collectToolCallsFromMessage(msg, toolCalls, toolResultCapture);
|
|
2034
|
+
this.backfillToolResults(msg, toolCalls, toolResultCapture);
|
|
1813
2035
|
if (msg.type === "result" && msg.subtype === "success") {
|
|
1814
2036
|
const r = msg;
|
|
1815
2037
|
output = r.result;
|
|
@@ -1841,23 +2063,17 @@ var init_claude = __esm({
|
|
|
1841
2063
|
);
|
|
1842
2064
|
}
|
|
1843
2065
|
}
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
messages: [
|
|
1856
|
-
...messages,
|
|
1857
|
-
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
1858
|
-
],
|
|
1859
|
-
usage
|
|
1860
|
-
};
|
|
2066
|
+
return {
|
|
2067
|
+
output,
|
|
2068
|
+
structuredOutput,
|
|
2069
|
+
toolCalls,
|
|
2070
|
+
messages: [
|
|
2071
|
+
...messages,
|
|
2072
|
+
...output !== null ? [{ role: "assistant", content: output }] : []
|
|
2073
|
+
],
|
|
2074
|
+
usage
|
|
2075
|
+
};
|
|
2076
|
+
});
|
|
1861
2077
|
}
|
|
1862
2078
|
if (this.isPersistent) this.clearPersistentSession();
|
|
1863
2079
|
throw e;
|
|
@@ -1876,12 +2092,12 @@ var init_claude = __esm({
|
|
|
1876
2092
|
};
|
|
1877
2093
|
}
|
|
1878
2094
|
// ─── executeStream ──────────────────────────────────────────────
|
|
1879
|
-
async *executeStream(messages,
|
|
2095
|
+
async *executeStream(messages, options, signal) {
|
|
1880
2096
|
this.checkAbort(signal);
|
|
1881
2097
|
const sdk = await loadSDK2();
|
|
1882
2098
|
const isResuming = this.isPersistent && this._sessionId !== void 0;
|
|
1883
|
-
const prompt = isResuming ?
|
|
1884
|
-
let opts = this.buildQueryOptions(signal);
|
|
2099
|
+
const prompt = isResuming ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
2100
|
+
let opts = this.buildQueryOptions(signal, options);
|
|
1885
2101
|
const toolResultCapture = /* @__PURE__ */ new Map();
|
|
1886
2102
|
opts = await this.buildMcpConfig(opts, toolResultCapture);
|
|
1887
2103
|
const q = sdk.query({ prompt, options: opts });
|
|
@@ -1889,6 +2105,7 @@ var init_claude = __esm({
|
|
|
1889
2105
|
const thinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1890
2106
|
const toolCallTracker = new ClaudeToolCallTracker();
|
|
1891
2107
|
const pendingStreamToolCalls = /* @__PURE__ */ new Map();
|
|
2108
|
+
let hasStreamedText = false;
|
|
1892
2109
|
try {
|
|
1893
2110
|
for await (const msg of q) {
|
|
1894
2111
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1906,6 +2123,7 @@ var init_claude = __esm({
|
|
|
1906
2123
|
} else if (e.type === "tool_call_end") {
|
|
1907
2124
|
pendingStreamToolCalls.delete(e.toolCallId);
|
|
1908
2125
|
}
|
|
2126
|
+
if (e.type === "text_delta") hasStreamedText = true;
|
|
1909
2127
|
yield e;
|
|
1910
2128
|
}
|
|
1911
2129
|
}
|
|
@@ -1929,22 +2147,21 @@ var init_claude = __esm({
|
|
|
1929
2147
|
}
|
|
1930
2148
|
yield this.emitSessionInfo(r.session_id);
|
|
1931
2149
|
}
|
|
1932
|
-
yield {
|
|
2150
|
+
yield {
|
|
2151
|
+
type: "done",
|
|
2152
|
+
finalOutput: hasStreamedText ? null : r.result,
|
|
2153
|
+
...hasStreamedText ? { streamed: true } : {}
|
|
2154
|
+
};
|
|
1933
2155
|
}
|
|
1934
2156
|
}
|
|
1935
2157
|
} catch (e) {
|
|
1936
2158
|
if (signal.aborted) throw new AbortError();
|
|
1937
2159
|
if (isResuming && this.isPersistent) {
|
|
1938
|
-
this.
|
|
1939
|
-
const retryPrompt = buildContextualPrompt2(messages);
|
|
1940
|
-
let retryOpts = this.buildQueryOptions(signal);
|
|
1941
|
-
toolResultCapture.clear();
|
|
1942
|
-
retryOpts = await this.buildMcpConfig(retryOpts, toolResultCapture);
|
|
1943
|
-
const retryQ = sdk.query({ prompt: retryPrompt, options: retryOpts });
|
|
1944
|
-
this.activeQuery = retryQ;
|
|
2160
|
+
const retryQ = await this.prepareRetryQuery(sdk, messages, signal, options, toolResultCapture);
|
|
1945
2161
|
const retryThinkingBlockIndices = /* @__PURE__ */ new Set();
|
|
1946
2162
|
const retryToolCallTracker = new ClaudeToolCallTracker();
|
|
1947
2163
|
const retryPendingToolCalls = /* @__PURE__ */ new Map();
|
|
2164
|
+
let retryHasStreamedText = false;
|
|
1948
2165
|
try {
|
|
1949
2166
|
for await (const msg of retryQ) {
|
|
1950
2167
|
if (signal.aborted) throw new AbortError();
|
|
@@ -1962,6 +2179,7 @@ var init_claude = __esm({
|
|
|
1962
2179
|
} else if (ev.type === "tool_call_end") {
|
|
1963
2180
|
retryPendingToolCalls.delete(ev.toolCallId);
|
|
1964
2181
|
}
|
|
2182
|
+
if (ev.type === "text_delta") retryHasStreamedText = true;
|
|
1965
2183
|
yield ev;
|
|
1966
2184
|
}
|
|
1967
2185
|
}
|
|
@@ -1985,7 +2203,11 @@ var init_claude = __esm({
|
|
|
1985
2203
|
}
|
|
1986
2204
|
yield this.emitSessionInfo(r.session_id);
|
|
1987
2205
|
}
|
|
1988
|
-
yield {
|
|
2206
|
+
yield {
|
|
2207
|
+
type: "done",
|
|
2208
|
+
finalOutput: retryHasStreamedText ? null : r.result,
|
|
2209
|
+
...retryHasStreamedText ? { streamed: true } : {}
|
|
2210
|
+
};
|
|
1989
2211
|
}
|
|
1990
2212
|
}
|
|
1991
2213
|
} catch (retryError) {
|
|
@@ -2047,7 +2269,8 @@ var init_claude = __esm({
|
|
|
2047
2269
|
this.cachedModels = body.data.map((m) => ({
|
|
2048
2270
|
id: m.id,
|
|
2049
2271
|
name: m.display_name,
|
|
2050
|
-
provider: "claude"
|
|
2272
|
+
provider: "claude",
|
|
2273
|
+
...m.max_input_tokens != null && { contextWindow: m.max_input_tokens }
|
|
2051
2274
|
}));
|
|
2052
2275
|
return this.cachedModels;
|
|
2053
2276
|
}
|
|
@@ -2105,32 +2328,30 @@ __export(vercel_ai_exports, {
|
|
|
2105
2328
|
createVercelAIService: () => createVercelAIService
|
|
2106
2329
|
});
|
|
2107
2330
|
async function loadSDK3() {
|
|
2108
|
-
if (
|
|
2331
|
+
if (_sdkMock3) return _sdkMock3;
|
|
2109
2332
|
try {
|
|
2110
|
-
|
|
2111
|
-
return sdkModule3;
|
|
2333
|
+
return await import('ai');
|
|
2112
2334
|
} catch {
|
|
2113
2335
|
throw new DependencyError("ai");
|
|
2114
2336
|
}
|
|
2115
2337
|
}
|
|
2116
2338
|
async function loadCompat() {
|
|
2117
|
-
if (
|
|
2339
|
+
if (_compatMock) return _compatMock;
|
|
2118
2340
|
try {
|
|
2119
|
-
|
|
2120
|
-
return compatModule;
|
|
2341
|
+
return await import('@ai-sdk/openai-compatible');
|
|
2121
2342
|
} catch {
|
|
2122
2343
|
throw new DependencyError("@ai-sdk/openai-compatible");
|
|
2123
2344
|
}
|
|
2124
2345
|
}
|
|
2125
2346
|
function _injectSDK3(mock) {
|
|
2126
|
-
|
|
2347
|
+
_sdkMock3 = mock;
|
|
2127
2348
|
}
|
|
2128
2349
|
function _injectCompat(mock) {
|
|
2129
|
-
|
|
2350
|
+
_compatMock = mock;
|
|
2130
2351
|
}
|
|
2131
2352
|
function _resetSDK3() {
|
|
2132
|
-
|
|
2133
|
-
|
|
2353
|
+
_sdkMock3 = null;
|
|
2354
|
+
_compatMock = null;
|
|
2134
2355
|
}
|
|
2135
2356
|
function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, signal) {
|
|
2136
2357
|
const toolMap = {};
|
|
@@ -2173,13 +2394,14 @@ function mapToolsToSDK2(sdk, tools, config, sessionApprovals, permissionStore, s
|
|
|
2173
2394
|
return toolMap;
|
|
2174
2395
|
}
|
|
2175
2396
|
function wrapToolExecute(ourTool, supervisor, sessionApprovals, permissionStore, signal) {
|
|
2176
|
-
return async (args) => {
|
|
2397
|
+
return async (args, options) => {
|
|
2177
2398
|
if (ourTool.needsApproval && supervisor?.onPermission) {
|
|
2178
2399
|
const storeApproved = permissionStore && await permissionStore.isApproved(ourTool.name);
|
|
2179
2400
|
if (!storeApproved && !sessionApprovals.has(ourTool.name)) {
|
|
2180
2401
|
const request = {
|
|
2181
2402
|
toolName: ourTool.name,
|
|
2182
|
-
toolArgs: args ?? {}
|
|
2403
|
+
toolArgs: args ?? {},
|
|
2404
|
+
toolCallId: options?.toolCallId
|
|
2183
2405
|
};
|
|
2184
2406
|
const decision = await supervisor.onPermission(
|
|
2185
2407
|
request,
|
|
@@ -2286,7 +2508,8 @@ function mapStreamPart(part) {
|
|
|
2286
2508
|
return {
|
|
2287
2509
|
type: "error",
|
|
2288
2510
|
error: p.error instanceof Error ? p.error.message : String(p.error ?? "Tool execution failed"),
|
|
2289
|
-
recoverable: true
|
|
2511
|
+
recoverable: true,
|
|
2512
|
+
code: "TOOL_EXECUTION" /* TOOL_EXECUTION */
|
|
2290
2513
|
};
|
|
2291
2514
|
}
|
|
2292
2515
|
case "reasoning-start":
|
|
@@ -2307,10 +2530,13 @@ function mapStreamPart(part) {
|
|
|
2307
2530
|
}
|
|
2308
2531
|
case "error": {
|
|
2309
2532
|
const p = part;
|
|
2533
|
+
const errorMsg = p.error instanceof Error ? p.error.message : String(p.error ?? "Unknown error");
|
|
2534
|
+
const code = classifyAgentError(errorMsg);
|
|
2310
2535
|
return {
|
|
2311
2536
|
type: "error",
|
|
2312
|
-
error:
|
|
2313
|
-
recoverable:
|
|
2537
|
+
error: errorMsg,
|
|
2538
|
+
recoverable: isRecoverableErrorCode(code),
|
|
2539
|
+
code
|
|
2314
2540
|
};
|
|
2315
2541
|
}
|
|
2316
2542
|
default:
|
|
@@ -2320,15 +2546,15 @@ function mapStreamPart(part) {
|
|
|
2320
2546
|
function createVercelAIService(options) {
|
|
2321
2547
|
return new VercelAIAgentService(options);
|
|
2322
2548
|
}
|
|
2323
|
-
var
|
|
2549
|
+
var _sdkMock3, _compatMock, DEFAULT_BASE_URL, DEFAULT_PROVIDER, DEFAULT_MAX_TURNS, VercelAIAgent, VercelAIAgentService;
|
|
2324
2550
|
var init_vercel_ai = __esm({
|
|
2325
2551
|
"src/backends/vercel-ai.ts"() {
|
|
2326
|
-
|
|
2552
|
+
init_types2();
|
|
2327
2553
|
init_base_agent();
|
|
2328
|
-
|
|
2554
|
+
init_errors2();
|
|
2329
2555
|
init_schema();
|
|
2330
|
-
|
|
2331
|
-
|
|
2556
|
+
_sdkMock3 = null;
|
|
2557
|
+
_compatMock = null;
|
|
2332
2558
|
DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
2333
2559
|
DEFAULT_PROVIDER = "openrouter";
|
|
2334
2560
|
DEFAULT_MAX_TURNS = 10;
|
|
@@ -2341,28 +2567,33 @@ var init_vercel_ai = __esm({
|
|
|
2341
2567
|
super(config);
|
|
2342
2568
|
this.backendOptions = backendOptions;
|
|
2343
2569
|
}
|
|
2344
|
-
async getModel() {
|
|
2345
|
-
|
|
2570
|
+
async getModel(options) {
|
|
2571
|
+
const requestedModel = options.model;
|
|
2572
|
+
const defaultModel = this.config.model;
|
|
2573
|
+
if (requestedModel === defaultModel && this.model) return this.model;
|
|
2346
2574
|
const compat = await loadCompat();
|
|
2347
2575
|
const provider = compat.createOpenAICompatible({
|
|
2348
2576
|
name: this.backendOptions.provider ?? DEFAULT_PROVIDER,
|
|
2349
2577
|
baseURL: this.backendOptions.baseUrl ?? DEFAULT_BASE_URL,
|
|
2350
2578
|
apiKey: this.backendOptions.apiKey
|
|
2351
2579
|
});
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2354
|
-
|
|
2580
|
+
const model = provider.chatModel(requestedModel);
|
|
2581
|
+
if (requestedModel === defaultModel) {
|
|
2582
|
+
this.model = model;
|
|
2583
|
+
}
|
|
2584
|
+
return model;
|
|
2355
2585
|
}
|
|
2356
|
-
async getSDKTools(signal) {
|
|
2586
|
+
async getSDKTools(signal, options) {
|
|
2357
2587
|
const sdk = await loadSDK3();
|
|
2358
|
-
|
|
2588
|
+
const tools = this.resolveTools(options);
|
|
2589
|
+
return mapToolsToSDK2(sdk, tools, this.config, this.sessionApprovals, this.config.permissionStore, signal);
|
|
2359
2590
|
}
|
|
2360
2591
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
2361
|
-
async executeRun(messages,
|
|
2592
|
+
async executeRun(messages, options, signal) {
|
|
2362
2593
|
this.checkAbort(signal);
|
|
2363
2594
|
const sdk = await loadSDK3();
|
|
2364
|
-
const model = await this.getModel();
|
|
2365
|
-
const tools = await this.getSDKTools(signal);
|
|
2595
|
+
const model = await this.getModel(options);
|
|
2596
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2366
2597
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2367
2598
|
const sdkMessages = messagesToSDK(messages);
|
|
2368
2599
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2418,10 +2649,10 @@ var init_vercel_ai = __esm({
|
|
|
2418
2649
|
};
|
|
2419
2650
|
}
|
|
2420
2651
|
// ─── executeRunStructured ───────────────────────────────────────
|
|
2421
|
-
async executeRunStructured(messages, schema,
|
|
2652
|
+
async executeRunStructured(messages, schema, options, signal) {
|
|
2422
2653
|
this.checkAbort(signal);
|
|
2423
2654
|
const sdk = await loadSDK3();
|
|
2424
|
-
const model = await this.getModel();
|
|
2655
|
+
const model = await this.getModel(options);
|
|
2425
2656
|
const sdkMessages = messagesToSDK(messages);
|
|
2426
2657
|
const jsonSchema = zodToJsonSchema(schema.schema);
|
|
2427
2658
|
const result = await sdk.generateObject({
|
|
@@ -2463,11 +2694,11 @@ var init_vercel_ai = __esm({
|
|
|
2463
2694
|
};
|
|
2464
2695
|
}
|
|
2465
2696
|
// ─── executeStream ──────────────────────────────────────────────
|
|
2466
|
-
async *executeStream(messages,
|
|
2697
|
+
async *executeStream(messages, options, signal) {
|
|
2467
2698
|
this.checkAbort(signal);
|
|
2468
2699
|
const sdk = await loadSDK3();
|
|
2469
|
-
const model = await this.getModel();
|
|
2470
|
-
const tools = await this.getSDKTools(signal);
|
|
2700
|
+
const model = await this.getModel(options);
|
|
2701
|
+
const tools = await this.getSDKTools(signal, options);
|
|
2471
2702
|
const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
2472
2703
|
const sdkMessages = messagesToSDK(messages);
|
|
2473
2704
|
const hasTools = Object.keys(tools).length > 0;
|
|
@@ -2513,9 +2744,11 @@ var init_vercel_ai = __esm({
|
|
|
2513
2744
|
promptTokens: Number(totalUsage?.inputTokens ?? 0),
|
|
2514
2745
|
completionTokens: Number(totalUsage?.outputTokens ?? 0)
|
|
2515
2746
|
};
|
|
2747
|
+
const hasStreamed = finalText.length > 0;
|
|
2516
2748
|
yield {
|
|
2517
2749
|
type: "done",
|
|
2518
|
-
finalOutput: finalText || null
|
|
2750
|
+
finalOutput: hasStreamed ? null : finalText || null,
|
|
2751
|
+
...hasStreamed ? { streamed: true } : {}
|
|
2519
2752
|
};
|
|
2520
2753
|
} catch (e) {
|
|
2521
2754
|
if (signal.aborted) throw new AbortError();
|
|
@@ -2544,16 +2777,33 @@ var init_vercel_ai = __esm({
|
|
|
2544
2777
|
const baseUrl = (this.options.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
2545
2778
|
try {
|
|
2546
2779
|
const res = await globalThis.fetch(`${baseUrl}/models`, {
|
|
2547
|
-
headers: {
|
|
2780
|
+
headers: {
|
|
2781
|
+
Authorization: `Bearer ${this.options.apiKey}`,
|
|
2782
|
+
// OpenRouter requires HTTP-Referer for API access
|
|
2783
|
+
"HTTP-Referer": "https://github.com/nicepkg/agent-sdk"
|
|
2784
|
+
}
|
|
2548
2785
|
});
|
|
2549
2786
|
if (!res.ok) {
|
|
2550
2787
|
return [];
|
|
2551
2788
|
}
|
|
2552
2789
|
const body = await res.json();
|
|
2553
|
-
if (
|
|
2554
|
-
return
|
|
2790
|
+
if (body.data && Array.isArray(body.data)) {
|
|
2791
|
+
return body.data.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2792
|
+
id: m.id,
|
|
2793
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2794
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2795
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2796
|
+
}));
|
|
2797
|
+
}
|
|
2798
|
+
if (Array.isArray(body)) {
|
|
2799
|
+
return body.filter((m) => typeof m.id === "string").map((m) => ({
|
|
2800
|
+
id: m.id,
|
|
2801
|
+
...typeof m.name === "string" && { name: m.name },
|
|
2802
|
+
...typeof m.description === "string" && { description: m.description },
|
|
2803
|
+
...typeof m.context_length === "number" && { contextWindow: m.context_length }
|
|
2804
|
+
}));
|
|
2555
2805
|
}
|
|
2556
|
-
return
|
|
2806
|
+
return [];
|
|
2557
2807
|
} catch {
|
|
2558
2808
|
return [];
|
|
2559
2809
|
}
|
|
@@ -2567,280 +2817,24 @@ var init_vercel_ai = __esm({
|
|
|
2567
2817
|
try {
|
|
2568
2818
|
await loadSDK3();
|
|
2569
2819
|
} catch (e) {
|
|
2570
|
-
errors.push(e instanceof Error ? e.message : String(e));
|
|
2571
|
-
}
|
|
2572
|
-
try {
|
|
2573
|
-
await loadCompat();
|
|
2574
|
-
} catch (e) {
|
|
2575
|
-
errors.push(e instanceof Error ? e.message : String(e));
|
|
2576
|
-
}
|
|
2577
|
-
return { valid: errors.length === 0, errors };
|
|
2578
|
-
}
|
|
2579
|
-
async dispose() {
|
|
2580
|
-
if (this.disposed) return;
|
|
2581
|
-
this.disposed = true;
|
|
2582
|
-
}
|
|
2583
|
-
};
|
|
2584
|
-
}
|
|
2585
|
-
});
|
|
2586
|
-
|
|
2587
|
-
// src/registry.ts
|
|
2588
|
-
function registerBackend(name, factory) {
|
|
2589
|
-
if (registry.has(name)) {
|
|
2590
|
-
throw new BackendAlreadyRegisteredError(name);
|
|
2591
|
-
}
|
|
2592
|
-
registry.set(name, { factory, builtin: false });
|
|
2593
|
-
}
|
|
2594
|
-
function unregisterBackend(name) {
|
|
2595
|
-
return registry.delete(name);
|
|
2596
|
-
}
|
|
2597
|
-
function hasBackend(name) {
|
|
2598
|
-
return registry.has(name) || isBuiltinName(name);
|
|
2599
|
-
}
|
|
2600
|
-
function listBackends() {
|
|
2601
|
-
const names = new Set(registry.keys());
|
|
2602
|
-
for (const builtin of BUILTIN_BACKENDS) {
|
|
2603
|
-
names.add(builtin);
|
|
2604
|
-
}
|
|
2605
|
-
return [...names];
|
|
2606
|
-
}
|
|
2607
|
-
function resetRegistry() {
|
|
2608
|
-
registry.clear();
|
|
2609
|
-
}
|
|
2610
|
-
function isBuiltinName(name) {
|
|
2611
|
-
return BUILTIN_BACKENDS.has(name);
|
|
2612
|
-
}
|
|
2613
|
-
async function loadBuiltinFactory(name) {
|
|
2614
|
-
switch (name) {
|
|
2615
|
-
case "copilot": {
|
|
2616
|
-
const mod = await Promise.resolve().then(() => (init_copilot(), copilot_exports));
|
|
2617
|
-
return (opts) => mod.createCopilotService(opts);
|
|
2618
|
-
}
|
|
2619
|
-
case "claude": {
|
|
2620
|
-
const mod = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
2621
|
-
return (opts) => mod.createClaudeService(opts);
|
|
2622
|
-
}
|
|
2623
|
-
case "vercel-ai": {
|
|
2624
|
-
const mod = await Promise.resolve().then(() => (init_vercel_ai(), vercel_ai_exports));
|
|
2625
|
-
return (opts) => mod.createVercelAIService(opts);
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
async function createAgentService(name, options) {
|
|
2630
|
-
const entry = registry.get(name);
|
|
2631
|
-
if (entry) {
|
|
2632
|
-
return entry.factory(options);
|
|
2633
|
-
}
|
|
2634
|
-
if (isBuiltinName(name)) {
|
|
2635
|
-
const factory = await loadBuiltinFactory(name);
|
|
2636
|
-
registry.set(name, { factory, builtin: true });
|
|
2637
|
-
return factory(options);
|
|
2638
|
-
}
|
|
2639
|
-
throw new BackendNotFoundError(name);
|
|
2640
|
-
}
|
|
2641
|
-
var registry, BUILTIN_BACKENDS;
|
|
2642
|
-
var init_registry = __esm({
|
|
2643
|
-
"src/registry.ts"() {
|
|
2644
|
-
init_errors();
|
|
2645
|
-
registry = /* @__PURE__ */ new Map();
|
|
2646
|
-
BUILTIN_BACKENDS = /* @__PURE__ */ new Set([
|
|
2647
|
-
"copilot",
|
|
2648
|
-
"claude",
|
|
2649
|
-
"vercel-ai"
|
|
2650
|
-
]);
|
|
2651
|
-
}
|
|
2652
|
-
});
|
|
2653
|
-
|
|
2654
|
-
// src/utils/messages.ts
|
|
2655
|
-
function messagesToPrompt(messages) {
|
|
2656
|
-
return messages.map((msg) => {
|
|
2657
|
-
switch (msg.role) {
|
|
2658
|
-
case "user":
|
|
2659
|
-
return contentToText(msg.content);
|
|
2660
|
-
case "assistant":
|
|
2661
|
-
return contentToText(msg.content);
|
|
2662
|
-
case "system":
|
|
2663
|
-
return msg.content;
|
|
2664
|
-
case "tool":
|
|
2665
|
-
return msg.content ?? "";
|
|
2666
|
-
}
|
|
2667
|
-
}).filter(Boolean).join("\n\n");
|
|
2668
|
-
}
|
|
2669
|
-
function contentToText(content) {
|
|
2670
|
-
return getTextContent(content);
|
|
2671
|
-
}
|
|
2672
|
-
function buildSystemPrompt(base, schemaInstruction) {
|
|
2673
|
-
if (!schemaInstruction) return base;
|
|
2674
|
-
return `${base}
|
|
2675
|
-
|
|
2676
|
-
${schemaInstruction}`;
|
|
2677
|
-
}
|
|
2678
|
-
var init_messages = __esm({
|
|
2679
|
-
"src/utils/messages.ts"() {
|
|
2680
|
-
init_types();
|
|
2681
|
-
}
|
|
2682
|
-
});
|
|
2683
|
-
function createDefaultPermissionStore(projectDir) {
|
|
2684
|
-
const sessionStore = new InMemoryPermissionStore();
|
|
2685
|
-
const projectPath = projectDir ? path.join(projectDir, ".agent-sdk", "permissions.json") : path.join(process.cwd(), ".agent-sdk", "permissions.json");
|
|
2686
|
-
const userPath = path.join(os.homedir(), ".agent-sdk", "permissions.json");
|
|
2687
|
-
const projectStore = new FilePermissionStore(projectPath);
|
|
2688
|
-
const userStore = new FilePermissionStore(userPath);
|
|
2689
|
-
return new CompositePermissionStore(sessionStore, projectStore, userStore);
|
|
2690
|
-
}
|
|
2691
|
-
var InMemoryPermissionStore, FilePermissionStore, CompositePermissionStore;
|
|
2692
|
-
var init_permission_store = __esm({
|
|
2693
|
-
"src/permission-store.ts"() {
|
|
2694
|
-
InMemoryPermissionStore = class {
|
|
2695
|
-
approvals = /* @__PURE__ */ new Map();
|
|
2696
|
-
async isApproved(toolName) {
|
|
2697
|
-
return this.approvals.has(toolName);
|
|
2698
|
-
}
|
|
2699
|
-
async approve(toolName, scope) {
|
|
2700
|
-
if (scope === "once") return;
|
|
2701
|
-
this.approvals.set(toolName, scope);
|
|
2702
|
-
}
|
|
2703
|
-
async revoke(toolName) {
|
|
2704
|
-
this.approvals.delete(toolName);
|
|
2705
|
-
}
|
|
2706
|
-
async clear() {
|
|
2707
|
-
this.approvals.clear();
|
|
2708
|
-
}
|
|
2709
|
-
async dispose() {
|
|
2710
|
-
this.approvals.clear();
|
|
2711
|
-
}
|
|
2712
|
-
};
|
|
2713
|
-
FilePermissionStore = class {
|
|
2714
|
-
filePath;
|
|
2715
|
-
constructor(filePath) {
|
|
2716
|
-
this.filePath = path.resolve(filePath);
|
|
2717
|
-
}
|
|
2718
|
-
async isApproved(toolName) {
|
|
2719
|
-
const data = this.readFile();
|
|
2720
|
-
return toolName in data.approvals;
|
|
2721
|
-
}
|
|
2722
|
-
async approve(toolName, scope) {
|
|
2723
|
-
if (scope === "once") return;
|
|
2724
|
-
const data = this.readFile();
|
|
2725
|
-
data.approvals[toolName] = { scope, timestamp: Date.now() };
|
|
2726
|
-
this.writeFileAtomic(data);
|
|
2727
|
-
}
|
|
2728
|
-
async revoke(toolName) {
|
|
2729
|
-
const data = this.readFile();
|
|
2730
|
-
delete data.approvals[toolName];
|
|
2731
|
-
this.writeFileAtomic(data);
|
|
2732
|
-
}
|
|
2733
|
-
async clear() {
|
|
2734
|
-
this.writeFileAtomic({ approvals: {} });
|
|
2735
|
-
}
|
|
2736
|
-
async dispose() {
|
|
2737
|
-
}
|
|
2738
|
-
readFile() {
|
|
2739
|
-
try {
|
|
2740
|
-
const raw = fs.readFileSync(this.filePath, "utf-8");
|
|
2741
|
-
const parsed = JSON.parse(raw);
|
|
2742
|
-
if (parsed && typeof parsed.approvals === "object") return parsed;
|
|
2743
|
-
} catch {
|
|
2744
|
-
}
|
|
2745
|
-
return { approvals: {} };
|
|
2746
|
-
}
|
|
2747
|
-
writeFileAtomic(data) {
|
|
2748
|
-
const dir = path.dirname(this.filePath);
|
|
2749
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
2750
|
-
const tmpPath = this.filePath + `.tmp.${process.pid}.${Date.now()}`;
|
|
2751
|
-
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
2752
|
-
fs.renameSync(tmpPath, this.filePath);
|
|
2753
|
-
}
|
|
2754
|
-
};
|
|
2755
|
-
CompositePermissionStore = class {
|
|
2756
|
-
sessionStore;
|
|
2757
|
-
projectStore;
|
|
2758
|
-
userStore;
|
|
2759
|
-
constructor(sessionStore, projectStore, userStore) {
|
|
2760
|
-
this.sessionStore = sessionStore;
|
|
2761
|
-
this.projectStore = projectStore;
|
|
2762
|
-
this.userStore = userStore ?? projectStore;
|
|
2763
|
-
}
|
|
2764
|
-
async isApproved(toolName) {
|
|
2765
|
-
return await this.sessionStore.isApproved(toolName) || await this.projectStore.isApproved(toolName) || await this.userStore.isApproved(toolName);
|
|
2766
|
-
}
|
|
2767
|
-
async approve(toolName, scope) {
|
|
2768
|
-
if (scope === "once") return;
|
|
2769
|
-
if (scope === "session") {
|
|
2770
|
-
await this.sessionStore.approve(toolName, scope);
|
|
2771
|
-
} else if (scope === "project") {
|
|
2772
|
-
await this.projectStore.approve(toolName, scope);
|
|
2773
|
-
} else {
|
|
2774
|
-
await this.userStore.approve(toolName, scope);
|
|
2820
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
2775
2821
|
}
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
async clear() {
|
|
2783
|
-
await this.sessionStore.clear();
|
|
2784
|
-
await this.projectStore.clear();
|
|
2785
|
-
await this.userStore.clear();
|
|
2822
|
+
try {
|
|
2823
|
+
await loadCompat();
|
|
2824
|
+
} catch (e) {
|
|
2825
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
2826
|
+
}
|
|
2827
|
+
return { valid: errors.length === 0, errors };
|
|
2786
2828
|
}
|
|
2787
2829
|
async dispose() {
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
if (this.userStore !== this.projectStore) {
|
|
2791
|
-
await this.userStore.dispose();
|
|
2792
|
-
}
|
|
2830
|
+
if (this.disposed) return;
|
|
2831
|
+
this.disposed = true;
|
|
2793
2832
|
}
|
|
2794
2833
|
};
|
|
2795
2834
|
}
|
|
2796
2835
|
});
|
|
2797
2836
|
|
|
2798
|
-
// src/
|
|
2799
|
-
var src_exports = {};
|
|
2800
|
-
__export(src_exports, {
|
|
2801
|
-
AbortError: () => AbortError,
|
|
2802
|
-
AgentSDKError: () => AgentSDKError,
|
|
2803
|
-
BackendAlreadyRegisteredError: () => BackendAlreadyRegisteredError,
|
|
2804
|
-
BackendNotFoundError: () => BackendNotFoundError,
|
|
2805
|
-
BaseAgent: () => BaseAgent,
|
|
2806
|
-
CompositePermissionStore: () => CompositePermissionStore,
|
|
2807
|
-
DependencyError: () => DependencyError,
|
|
2808
|
-
DisposedError: () => DisposedError,
|
|
2809
|
-
FilePermissionStore: () => FilePermissionStore,
|
|
2810
|
-
InMemoryPermissionStore: () => InMemoryPermissionStore,
|
|
2811
|
-
ReentrancyError: () => ReentrancyError,
|
|
2812
|
-
StructuredOutputError: () => StructuredOutputError,
|
|
2813
|
-
SubprocessError: () => SubprocessError,
|
|
2814
|
-
ToolExecutionError: () => ToolExecutionError,
|
|
2815
|
-
buildSystemPrompt: () => buildSystemPrompt,
|
|
2816
|
-
contentToText: () => contentToText,
|
|
2817
|
-
createAgentService: () => createAgentService,
|
|
2818
|
-
createDefaultPermissionStore: () => createDefaultPermissionStore,
|
|
2819
|
-
getTextContent: () => getTextContent,
|
|
2820
|
-
hasBackend: () => hasBackend,
|
|
2821
|
-
isMultiPartContent: () => isMultiPartContent,
|
|
2822
|
-
isTextContent: () => isTextContent,
|
|
2823
|
-
isToolDefinition: () => isToolDefinition,
|
|
2824
|
-
listBackends: () => listBackends,
|
|
2825
|
-
messagesToPrompt: () => messagesToPrompt,
|
|
2826
|
-
registerBackend: () => registerBackend,
|
|
2827
|
-
resetRegistry: () => resetRegistry,
|
|
2828
|
-
unregisterBackend: () => unregisterBackend,
|
|
2829
|
-
zodToJsonSchema: () => zodToJsonSchema
|
|
2830
|
-
});
|
|
2831
|
-
var init_src = __esm({
|
|
2832
|
-
"src/index.ts"() {
|
|
2833
|
-
init_types();
|
|
2834
|
-
init_errors();
|
|
2835
|
-
init_registry();
|
|
2836
|
-
init_base_agent();
|
|
2837
|
-
init_schema();
|
|
2838
|
-
init_messages();
|
|
2839
|
-
init_permission_store();
|
|
2840
|
-
}
|
|
2841
|
-
});
|
|
2842
|
-
|
|
2843
|
-
// src/chat/core.ts
|
|
2837
|
+
// src/chat/types.ts
|
|
2844
2838
|
function createChatId() {
|
|
2845
2839
|
return crypto.randomUUID();
|
|
2846
2840
|
}
|
|
@@ -2851,6 +2845,20 @@ function toChatId(value) {
|
|
|
2851
2845
|
}
|
|
2852
2846
|
return value;
|
|
2853
2847
|
}
|
|
2848
|
+
function createTextMessage(text, role = "user") {
|
|
2849
|
+
return {
|
|
2850
|
+
id: createChatId(),
|
|
2851
|
+
role,
|
|
2852
|
+
parts: [{ type: "text", text, status: "complete" }],
|
|
2853
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2854
|
+
status: "complete"
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
function isObservableSession(session) {
|
|
2858
|
+
return "subscribe" in session && typeof session.subscribe === "function" && "getSnapshot" in session && typeof session.getSnapshot === "function";
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
// src/chat/chat-utils.ts
|
|
2854
2862
|
function getMessageText(message) {
|
|
2855
2863
|
return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
2856
2864
|
}
|
|
@@ -2860,6 +2868,8 @@ function getMessageToolCalls(message) {
|
|
|
2860
2868
|
function getMessageReasoning(message) {
|
|
2861
2869
|
return message.parts.filter((p) => p.type === "reasoning").map((p) => p.text).join("");
|
|
2862
2870
|
}
|
|
2871
|
+
|
|
2872
|
+
// src/chat/guards.ts
|
|
2863
2873
|
function isChatMessage(value) {
|
|
2864
2874
|
if (typeof value !== "object" || value === null) return false;
|
|
2865
2875
|
const obj = value;
|
|
@@ -2925,6 +2935,8 @@ function isChatEvent(value) {
|
|
|
2925
2935
|
];
|
|
2926
2936
|
return validTypes.includes(obj.type);
|
|
2927
2937
|
}
|
|
2938
|
+
|
|
2939
|
+
// src/chat/bridge.ts
|
|
2928
2940
|
function agentEventToChatEvent(event, messageId) {
|
|
2929
2941
|
switch (event.type) {
|
|
2930
2942
|
case "text_delta":
|
|
@@ -2977,6 +2989,7 @@ function agentEventToChatEvent(event, messageId) {
|
|
|
2977
2989
|
type: "error",
|
|
2978
2990
|
error: event.error,
|
|
2979
2991
|
recoverable: event.recoverable,
|
|
2992
|
+
code: event.code,
|
|
2980
2993
|
messageId
|
|
2981
2994
|
};
|
|
2982
2995
|
case "heartbeat":
|
|
@@ -3023,11 +3036,13 @@ function chatEventToAgentEvent(event) {
|
|
|
3023
3036
|
result: event.result
|
|
3024
3037
|
};
|
|
3025
3038
|
case "error":
|
|
3026
|
-
return { type: "error", error: event.error, recoverable: event.recoverable };
|
|
3039
|
+
return { type: "error", error: event.error, recoverable: event.recoverable, code: event.code };
|
|
3027
3040
|
default:
|
|
3028
3041
|
return null;
|
|
3029
3042
|
}
|
|
3030
3043
|
}
|
|
3044
|
+
|
|
3045
|
+
// src/chat/conversion.ts
|
|
3031
3046
|
function toAgentMessage(message) {
|
|
3032
3047
|
const textContent = getMessageText(message);
|
|
3033
3048
|
const toolCallParts = getMessageToolCalls(message);
|
|
@@ -3198,6 +3213,56 @@ var ContextWindowManager = class {
|
|
|
3198
3213
|
});
|
|
3199
3214
|
return { ...result, messages: updatedMessages };
|
|
3200
3215
|
}
|
|
3216
|
+
/**
|
|
3217
|
+
* Trim messages using real token usage data from the previous API call.
|
|
3218
|
+
* Uses average-based algorithm: `avgTokensPerMessage = lastPromptTokens / messageCount`.
|
|
3219
|
+
* Removes oldest non-system messages until freed budget brings usage under modelContextWindow.
|
|
3220
|
+
*
|
|
3221
|
+
* @param messages - All messages in the session
|
|
3222
|
+
* @param lastPromptTokens - Real prompt tokens from the last API response
|
|
3223
|
+
* @param modelContextWindow - Model's total context window size in tokens
|
|
3224
|
+
* @returns Result with fitted messages and metadata
|
|
3225
|
+
*/
|
|
3226
|
+
fitMessagesWithUsage(messages, lastPromptTokens, modelContextWindow) {
|
|
3227
|
+
if (messages.length === 0) {
|
|
3228
|
+
return { messages: [], totalTokens: 0, removedCount: 0, wasTruncated: false };
|
|
3229
|
+
}
|
|
3230
|
+
const budget = modelContextWindow - this.config.reservedTokens;
|
|
3231
|
+
if (budget <= 0 || lastPromptTokens <= budget) {
|
|
3232
|
+
return {
|
|
3233
|
+
messages: [...messages],
|
|
3234
|
+
totalTokens: lastPromptTokens,
|
|
3235
|
+
removedCount: 0,
|
|
3236
|
+
wasTruncated: false
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3239
|
+
const avgTokensPerMessage = lastPromptTokens / messages.length;
|
|
3240
|
+
const tokensToFree = lastPromptTokens - budget;
|
|
3241
|
+
const messagesToRemove = Math.ceil(tokensToFree / avgTokensPerMessage);
|
|
3242
|
+
const nonSystemIndices = [];
|
|
3243
|
+
for (let i = 0; i < messages.length; i++) {
|
|
3244
|
+
if (messages[i].role === "system") ; else {
|
|
3245
|
+
nonSystemIndices.push(i);
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
const removableCount = Math.min(messagesToRemove, nonSystemIndices.length);
|
|
3249
|
+
const removedIndices = new Set(nonSystemIndices.slice(0, removableCount));
|
|
3250
|
+
const result = [];
|
|
3251
|
+
for (let i = 0; i < messages.length; i++) {
|
|
3252
|
+
if (!removedIndices.has(i)) {
|
|
3253
|
+
result.push(messages[i]);
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
const estimatedTokens = Math.round(
|
|
3257
|
+
lastPromptTokens * (result.length / messages.length)
|
|
3258
|
+
);
|
|
3259
|
+
return {
|
|
3260
|
+
messages: result,
|
|
3261
|
+
totalTokens: estimatedTokens,
|
|
3262
|
+
removedCount: removableCount,
|
|
3263
|
+
wasTruncated: removableCount > 0
|
|
3264
|
+
};
|
|
3265
|
+
}
|
|
3201
3266
|
/**
|
|
3202
3267
|
* Truncate oldest: keeps system messages, removes oldest non-system messages first.
|
|
3203
3268
|
* Always keeps the most recent user message.
|
|
@@ -3315,37 +3380,19 @@ var ContextWindowManager = class {
|
|
|
3315
3380
|
};
|
|
3316
3381
|
|
|
3317
3382
|
// src/chat/errors.ts
|
|
3383
|
+
init_errors2();
|
|
3318
3384
|
init_errors();
|
|
3319
|
-
var ChatErrorCode = /* @__PURE__ */ ((ChatErrorCode2) => {
|
|
3320
|
-
ChatErrorCode2["NETWORK"] = "NETWORK";
|
|
3321
|
-
ChatErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
3322
|
-
ChatErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
|
|
3323
|
-
ChatErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
|
|
3324
|
-
ChatErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
|
|
3325
|
-
ChatErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
|
|
3326
|
-
ChatErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
|
|
3327
|
-
ChatErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
|
|
3328
|
-
ChatErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
|
|
3329
|
-
ChatErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
|
|
3330
|
-
ChatErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
|
|
3331
|
-
ChatErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
3332
|
-
ChatErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
|
|
3333
|
-
ChatErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
|
|
3334
|
-
ChatErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
|
|
3335
|
-
ChatErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
|
|
3336
|
-
ChatErrorCode2["DISPOSED"] = "DISPOSED";
|
|
3337
|
-
ChatErrorCode2["ABORTED"] = "ABORTED";
|
|
3338
|
-
ChatErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
|
|
3339
|
-
ChatErrorCode2["REENTRANCY"] = "REENTRANCY";
|
|
3340
|
-
return ChatErrorCode2;
|
|
3341
|
-
})(ChatErrorCode || {});
|
|
3342
3385
|
var ChatError = class extends AgentSDKError {
|
|
3343
3386
|
code;
|
|
3344
3387
|
retryable;
|
|
3345
3388
|
retryAfter;
|
|
3346
3389
|
timestamp;
|
|
3347
3390
|
constructor(message, options) {
|
|
3348
|
-
super(message, {
|
|
3391
|
+
super(message, {
|
|
3392
|
+
cause: options.cause,
|
|
3393
|
+
code: options.code,
|
|
3394
|
+
retryable: options.retryable
|
|
3395
|
+
});
|
|
3349
3396
|
this.name = "ChatError";
|
|
3350
3397
|
this.code = options.code;
|
|
3351
3398
|
this.retryable = options.retryable ?? false;
|
|
@@ -3524,12 +3571,12 @@ function isRetryable(error) {
|
|
|
3524
3571
|
return classified.retryable;
|
|
3525
3572
|
}
|
|
3526
3573
|
function sleep(ms, signal) {
|
|
3527
|
-
return new Promise((
|
|
3574
|
+
return new Promise((resolve, reject) => {
|
|
3528
3575
|
if (signal?.aborted) {
|
|
3529
3576
|
reject(new ChatError("Retry aborted", { code: "ABORTED" /* ABORTED */ }));
|
|
3530
3577
|
return;
|
|
3531
3578
|
}
|
|
3532
|
-
const timer = setTimeout(
|
|
3579
|
+
const timer = setTimeout(resolve, ms);
|
|
3533
3580
|
signal?.addEventListener(
|
|
3534
3581
|
"abort",
|
|
3535
3582
|
() => {
|
|
@@ -3853,6 +3900,35 @@ var CancellableTimeout = class {
|
|
|
3853
3900
|
}
|
|
3854
3901
|
};
|
|
3855
3902
|
|
|
3903
|
+
// src/chat/listener-set.ts
|
|
3904
|
+
var ListenerSet = class {
|
|
3905
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
3906
|
+
/** Add a listener. Returns an unsubscribe function. */
|
|
3907
|
+
add(callback) {
|
|
3908
|
+
this._listeners.add(callback);
|
|
3909
|
+
return () => {
|
|
3910
|
+
this._listeners.delete(callback);
|
|
3911
|
+
};
|
|
3912
|
+
}
|
|
3913
|
+
/** Notify all listeners with the given arguments. Errors are isolated per listener. */
|
|
3914
|
+
notify(...args) {
|
|
3915
|
+
for (const cb of this._listeners) {
|
|
3916
|
+
try {
|
|
3917
|
+
cb(...args);
|
|
3918
|
+
} catch {
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
/** Remove all listeners. */
|
|
3923
|
+
clear() {
|
|
3924
|
+
this._listeners.clear();
|
|
3925
|
+
}
|
|
3926
|
+
/** Current number of listeners. */
|
|
3927
|
+
get size() {
|
|
3928
|
+
return this._listeners.size;
|
|
3929
|
+
}
|
|
3930
|
+
};
|
|
3931
|
+
|
|
3856
3932
|
// src/chat/runtime.ts
|
|
3857
3933
|
var ChatRuntime = class {
|
|
3858
3934
|
_state;
|
|
@@ -3864,20 +3940,19 @@ var ChatRuntime = class {
|
|
|
3864
3940
|
_tools = /* @__PURE__ */ new Map();
|
|
3865
3941
|
_retryConfig;
|
|
3866
3942
|
_contextStats = /* @__PURE__ */ new Map();
|
|
3943
|
+
_sessionUsage = /* @__PURE__ */ new Map();
|
|
3944
|
+
_modelContextWindows = /* @__PURE__ */ new Map();
|
|
3867
3945
|
_onContextTrimmed;
|
|
3868
3946
|
_streamTimeoutMs;
|
|
3869
|
-
_sessionListeners =
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
_currentModel;
|
|
3873
|
-
_activeSessionId = null;
|
|
3947
|
+
_sessionListeners = new ListenerSet();
|
|
3948
|
+
_adapterPool = /* @__PURE__ */ new Map();
|
|
3949
|
+
_defaultBackend;
|
|
3874
3950
|
_abortController = null;
|
|
3875
3951
|
constructor(options) {
|
|
3876
3952
|
this._state = new StateMachine("idle", RUNTIME_TRANSITIONS);
|
|
3877
3953
|
this._guard = new ChatReentrancyGuard();
|
|
3878
3954
|
this._backends = options.backends;
|
|
3879
|
-
this.
|
|
3880
|
-
this._currentModel = options.defaultModel;
|
|
3955
|
+
this._defaultBackend = options.defaultBackend;
|
|
3881
3956
|
this._sessionStore = options.sessionStore;
|
|
3882
3957
|
this._contextConfig = options.context;
|
|
3883
3958
|
this._middleware = [...options.middleware ?? []];
|
|
@@ -3890,6 +3965,11 @@ var ChatRuntime = class {
|
|
|
3890
3965
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
3891
3966
|
);
|
|
3892
3967
|
}
|
|
3968
|
+
if (options.tools) {
|
|
3969
|
+
for (const tool of options.tools) {
|
|
3970
|
+
this._tools.set(tool.name, tool);
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3893
3973
|
}
|
|
3894
3974
|
// ── Lifecycle ──────────────────────────────────────────────
|
|
3895
3975
|
get status() {
|
|
@@ -3901,24 +3981,23 @@ var ChatRuntime = class {
|
|
|
3901
3981
|
this._abortController?.dispose();
|
|
3902
3982
|
this._abortController = null;
|
|
3903
3983
|
this._state.transition("disposed");
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3984
|
+
for (const adapter of this._adapterPool.values()) {
|
|
3985
|
+
try {
|
|
3986
|
+
await adapter.dispose();
|
|
3987
|
+
} catch {
|
|
3988
|
+
}
|
|
3907
3989
|
}
|
|
3990
|
+
this._adapterPool.clear();
|
|
3908
3991
|
}
|
|
3909
3992
|
// ── Sessions ───────────────────────────────────────────────
|
|
3910
|
-
get activeSessionId() {
|
|
3911
|
-
return this._activeSessionId;
|
|
3912
|
-
}
|
|
3913
3993
|
async createSession(options) {
|
|
3914
3994
|
this.assertNotDisposed();
|
|
3915
3995
|
const config = {
|
|
3916
|
-
model: options.config?.model ??
|
|
3917
|
-
backend: options.config?.backend ?? this.
|
|
3996
|
+
model: options.config?.model ?? "",
|
|
3997
|
+
backend: options.config?.backend ?? this._defaultBackend,
|
|
3918
3998
|
...options.config
|
|
3919
3999
|
};
|
|
3920
4000
|
const session = await this._sessionStore.createSession({ ...options, config });
|
|
3921
|
-
this._activeSessionId = session.id;
|
|
3922
4001
|
this._notifySessionChange();
|
|
3923
4002
|
return session;
|
|
3924
4003
|
}
|
|
@@ -3938,36 +4017,12 @@ var ChatRuntime = class {
|
|
|
3938
4017
|
if (!session) return;
|
|
3939
4018
|
await this._sessionStore.deleteSession(cid);
|
|
3940
4019
|
this._contextStats.delete(cid);
|
|
3941
|
-
|
|
3942
|
-
this._activeSessionId = null;
|
|
3943
|
-
}
|
|
3944
|
-
this._notifySessionChange();
|
|
3945
|
-
}
|
|
3946
|
-
async archiveSession(id) {
|
|
3947
|
-
this.assertNotDisposed();
|
|
3948
|
-
const cid = toChatId(id);
|
|
3949
|
-
await this._sessionStore.archiveSession(cid);
|
|
4020
|
+
this._sessionUsage.delete(cid);
|
|
3950
4021
|
this._notifySessionChange();
|
|
3951
4022
|
}
|
|
3952
|
-
async switchSession(id) {
|
|
3953
|
-
this.assertNotDisposed();
|
|
3954
|
-
const cid = toChatId(id);
|
|
3955
|
-
const session = await this._sessionStore.getSession(cid);
|
|
3956
|
-
if (!session) {
|
|
3957
|
-
throw new ChatError(
|
|
3958
|
-
`Session "${id}" not found`,
|
|
3959
|
-
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
3960
|
-
);
|
|
3961
|
-
}
|
|
3962
|
-
this._activeSessionId = session.id;
|
|
3963
|
-
return session;
|
|
3964
|
-
}
|
|
3965
4023
|
// ── Messaging ──────────────────────────────────────────────
|
|
3966
4024
|
async *send(sessionId, message, options) {
|
|
3967
|
-
this.
|
|
3968
|
-
if (!message || message.trim().length === 0) {
|
|
3969
|
-
throw new ChatError("Message cannot be empty", { code: "INVALID_INPUT" /* INVALID_INPUT */ });
|
|
3970
|
-
}
|
|
4025
|
+
this.validateSendInput(message, options);
|
|
3971
4026
|
this._guard.acquire();
|
|
3972
4027
|
const cid = toChatId(sessionId);
|
|
3973
4028
|
this._abortController = new ChatAbortController(options?.signal);
|
|
@@ -3976,150 +4031,274 @@ var ChatRuntime = class {
|
|
|
3976
4031
|
this._state.transition("idle");
|
|
3977
4032
|
}
|
|
3978
4033
|
this._state.transition("streaming");
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
throw new ChatError(
|
|
3982
|
-
`Session "${cid}" not found`,
|
|
3983
|
-
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
3984
|
-
);
|
|
3985
|
-
}
|
|
3986
|
-
const middlewareContext = {
|
|
4034
|
+
await this.loadSession(cid);
|
|
4035
|
+
const mwCtx = {
|
|
3987
4036
|
sessionId: cid,
|
|
3988
4037
|
signal: this._abortController.signal
|
|
3989
4038
|
};
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
const updatedSession = await this._sessionStore.getSession(cid);
|
|
3998
|
-
let messagesToSend = updatedSession.messages;
|
|
3999
|
-
if (this._contextConfig) {
|
|
4000
|
-
const ctxManager = new ContextWindowManager(this._contextConfig);
|
|
4001
|
-
const result = await ctxManager.fitMessagesAsync(messagesToSend);
|
|
4002
|
-
this._contextStats.set(cid, {
|
|
4003
|
-
totalTokens: result.totalTokens,
|
|
4004
|
-
removedCount: result.removedCount,
|
|
4005
|
-
wasTruncated: result.wasTruncated,
|
|
4006
|
-
availableBudget: ctxManager.availableBudget
|
|
4007
|
-
});
|
|
4008
|
-
if (result.wasTruncated && this._onContextTrimmed) {
|
|
4009
|
-
const keptIds = new Set(result.messages.map((m) => m.id));
|
|
4010
|
-
const removed = messagesToSend.filter((m) => !keptIds.has(m.id));
|
|
4011
|
-
if (removed.length > 0) {
|
|
4012
|
-
try {
|
|
4013
|
-
this._onContextTrimmed(cid, removed);
|
|
4014
|
-
} catch {
|
|
4015
|
-
}
|
|
4016
|
-
}
|
|
4017
|
-
}
|
|
4018
|
-
messagesToSend = result.messages;
|
|
4039
|
+
const userMessage = await this.applyBeforeSendMiddleware(
|
|
4040
|
+
this.createUserMessage(message),
|
|
4041
|
+
mwCtx
|
|
4042
|
+
);
|
|
4043
|
+
if (userMessage === null) {
|
|
4044
|
+
this._state.transition("idle");
|
|
4045
|
+
return;
|
|
4019
4046
|
}
|
|
4020
|
-
const
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4047
|
+
const updatedSession = await this.persistAndReload(cid, userMessage);
|
|
4048
|
+
const sessionForAdapter = await this.trimSessionContext(cid, updatedSession, options.model);
|
|
4049
|
+
const stream = await this.prepareEventStream(
|
|
4050
|
+
cid,
|
|
4051
|
+
sessionForAdapter,
|
|
4052
|
+
updatedSession,
|
|
4053
|
+
message,
|
|
4054
|
+
options
|
|
4055
|
+
);
|
|
4025
4056
|
const accumulator = new MessageAccumulator();
|
|
4026
|
-
const runtimeTools = this._tools.size > 0 ? this.injectToolContext([...this._tools.values()], {
|
|
4027
|
-
sessionId: cid,
|
|
4028
|
-
custom: updatedSession.metadata?.custom
|
|
4029
|
-
}) : void 0;
|
|
4030
|
-
const streamOptions = {
|
|
4031
|
-
...options,
|
|
4032
|
-
signal: this._abortController.signal,
|
|
4033
|
-
model: options?.model ?? this._currentModel,
|
|
4034
|
-
tools: runtimeTools
|
|
4035
|
-
};
|
|
4036
|
-
const stream = await this.createStreamWithRetry(adapter, sessionForAdapter, message, streamOptions);
|
|
4037
4057
|
const eventSource = this._streamTimeoutMs ? withStreamWatchdog(stream, { timeoutMs: this._streamTimeoutMs, signal: this._abortController.signal }) : stream;
|
|
4038
4058
|
for await (const event of eventSource) {
|
|
4039
4059
|
if (this._abortController.isAborted) break;
|
|
4040
4060
|
this.feedAccumulator(accumulator, event);
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
}
|
|
4046
|
-
|
|
4047
|
-
if (processedEvent) {
|
|
4048
|
-
yield processedEvent;
|
|
4049
|
-
}
|
|
4050
|
-
}
|
|
4051
|
-
if (this._state.current === "disposed") {
|
|
4052
|
-
return;
|
|
4053
|
-
}
|
|
4054
|
-
let assistantMessage = accumulator.finalize();
|
|
4055
|
-
for (const mw of this._middleware) {
|
|
4056
|
-
if (mw.onAfterReceive) {
|
|
4057
|
-
assistantMessage = await mw.onAfterReceive(assistantMessage, middlewareContext);
|
|
4061
|
+
if (event.type === "usage") {
|
|
4062
|
+
this._sessionUsage.set(cid, {
|
|
4063
|
+
promptTokens: event.promptTokens,
|
|
4064
|
+
completionTokens: event.completionTokens
|
|
4065
|
+
});
|
|
4066
|
+
this.updateContextStatsWithUsage(cid, event.promptTokens, event.completionTokens, options);
|
|
4058
4067
|
}
|
|
4068
|
+
const processed = await this.applyOnEventMiddleware(event, mwCtx);
|
|
4069
|
+
if (processed) yield processed;
|
|
4059
4070
|
}
|
|
4060
|
-
|
|
4061
|
-
this.
|
|
4071
|
+
if (this._state.current === "disposed") return;
|
|
4072
|
+
await this.finalizeAssistantMessage(cid, accumulator, mwCtx);
|
|
4062
4073
|
this._state.transition("idle");
|
|
4063
4074
|
} catch (error) {
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
sessionId: cid,
|
|
4067
|
-
signal: this._abortController?.signal ?? new AbortController().signal
|
|
4068
|
-
};
|
|
4069
|
-
for (const mw of this._middleware) {
|
|
4070
|
-
if (mw.onError) {
|
|
4071
|
-
const result = await mw.onError(processedError, middlewareContext);
|
|
4072
|
-
if (result === null) {
|
|
4073
|
-
if (this._state.canTransition("idle")) {
|
|
4074
|
-
this._state.transition("idle");
|
|
4075
|
-
}
|
|
4076
|
-
return;
|
|
4077
|
-
}
|
|
4078
|
-
processedError = result;
|
|
4079
|
-
}
|
|
4080
|
-
}
|
|
4081
|
-
if (this._state.canTransition("error")) {
|
|
4082
|
-
this._state.transition("error");
|
|
4083
|
-
}
|
|
4084
|
-
throw processedError;
|
|
4075
|
+
const result = await this.handleSendError(error, cid);
|
|
4076
|
+
if (result !== null) throw result;
|
|
4085
4077
|
} finally {
|
|
4086
4078
|
this._guard.release();
|
|
4087
4079
|
this._abortController?.dispose();
|
|
4088
4080
|
this._abortController = null;
|
|
4089
4081
|
}
|
|
4090
4082
|
}
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
// ── Backend / Model ────────────────────────────────────────
|
|
4095
|
-
get currentBackend() {
|
|
4096
|
-
return this._currentBackend;
|
|
4097
|
-
}
|
|
4098
|
-
get currentModel() {
|
|
4099
|
-
return this._currentModel;
|
|
4100
|
-
}
|
|
4101
|
-
async switchBackend(name) {
|
|
4083
|
+
// ── Send Pipeline Stages ──────────────────────────────────────
|
|
4084
|
+
/** Stage 1: Validate send inputs (message content + required fields). */
|
|
4085
|
+
validateSendInput(message, options) {
|
|
4102
4086
|
this.assertNotDisposed();
|
|
4103
|
-
if (!
|
|
4087
|
+
if (!message || message.trim().length === 0) {
|
|
4088
|
+
throw new ChatError("Message cannot be empty", { code: "INVALID_INPUT" /* INVALID_INPUT */ });
|
|
4089
|
+
}
|
|
4090
|
+
if (!options.model) {
|
|
4091
|
+
throw new ChatError(
|
|
4092
|
+
"options.model is required \u2014 caller must specify which model to use",
|
|
4093
|
+
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4094
|
+
);
|
|
4095
|
+
}
|
|
4096
|
+
if (!options.backend) {
|
|
4097
|
+
throw new ChatError(
|
|
4098
|
+
"options.backend is required \u2014 caller must specify which backend to use",
|
|
4099
|
+
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4100
|
+
);
|
|
4101
|
+
}
|
|
4102
|
+
if (!options.credentials) {
|
|
4104
4103
|
throw new ChatError(
|
|
4105
|
-
|
|
4104
|
+
"options.credentials is required \u2014 caller must provide authentication credentials",
|
|
4106
4105
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4107
4106
|
);
|
|
4108
4107
|
}
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4108
|
+
}
|
|
4109
|
+
/** Stage 2: Load session from store. */
|
|
4110
|
+
async loadSession(cid) {
|
|
4111
|
+
const session = await this._sessionStore.getSession(cid);
|
|
4112
|
+
if (!session) {
|
|
4113
|
+
throw new ChatError(
|
|
4114
|
+
`Session "${cid}" not found`,
|
|
4115
|
+
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
4116
|
+
);
|
|
4117
|
+
}
|
|
4118
|
+
return session;
|
|
4119
|
+
}
|
|
4120
|
+
/** Stage 3: Apply onBeforeSend middleware pipeline. Returns null if middleware rejected the send. */
|
|
4121
|
+
async applyBeforeSendMiddleware(userMessage, ctx) {
|
|
4122
|
+
let msg = userMessage;
|
|
4123
|
+
for (const mw of this._middleware) {
|
|
4124
|
+
if (mw.onBeforeSend && msg) {
|
|
4125
|
+
msg = await mw.onBeforeSend(msg, ctx);
|
|
4126
|
+
if (msg === null) return null;
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
return msg;
|
|
4130
|
+
}
|
|
4131
|
+
/** Stage 4: Persist user message and reload session with full history. */
|
|
4132
|
+
async persistAndReload(cid, userMessage) {
|
|
4133
|
+
await this._sessionStore.appendMessage(cid, userMessage);
|
|
4134
|
+
return await this._sessionStore.getSession(cid);
|
|
4135
|
+
}
|
|
4136
|
+
/** Stage 5: Auto-trim context window if configured. Returns session snapshot for adapter. */
|
|
4137
|
+
async trimSessionContext(cid, session, model) {
|
|
4138
|
+
if (!this._contextConfig) return session;
|
|
4139
|
+
const ctxManager = new ContextWindowManager(this._contextConfig);
|
|
4140
|
+
const lastUsage = this._sessionUsage.get(cid);
|
|
4141
|
+
const modelContextWindow = model ? this._modelContextWindows.get(model) : void 0;
|
|
4142
|
+
if (lastUsage && modelContextWindow) {
|
|
4143
|
+
const result2 = ctxManager.fitMessagesWithUsage(
|
|
4144
|
+
session.messages,
|
|
4145
|
+
lastUsage.promptTokens,
|
|
4146
|
+
modelContextWindow
|
|
4147
|
+
);
|
|
4148
|
+
this._contextStats.set(cid, {
|
|
4149
|
+
totalTokens: result2.totalTokens,
|
|
4150
|
+
removedCount: result2.removedCount,
|
|
4151
|
+
wasTruncated: result2.wasTruncated,
|
|
4152
|
+
availableBudget: Math.max(0, modelContextWindow - result2.totalTokens),
|
|
4153
|
+
realPromptTokens: lastUsage.promptTokens,
|
|
4154
|
+
realCompletionTokens: lastUsage.completionTokens,
|
|
4155
|
+
modelContextWindow
|
|
4156
|
+
});
|
|
4157
|
+
if (result2.wasTruncated && this._onContextTrimmed) {
|
|
4158
|
+
const keptIds = new Set(result2.messages.map((m) => m.id));
|
|
4159
|
+
const removed = session.messages.filter((m) => !keptIds.has(m.id));
|
|
4160
|
+
if (removed.length > 0) {
|
|
4161
|
+
try {
|
|
4162
|
+
this._onContextTrimmed(cid, removed);
|
|
4163
|
+
} catch {
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
return { ...session, messages: result2.messages };
|
|
4168
|
+
}
|
|
4169
|
+
const result = await ctxManager.fitMessagesAsync(session.messages);
|
|
4170
|
+
this._contextStats.set(cid, {
|
|
4171
|
+
totalTokens: result.totalTokens,
|
|
4172
|
+
removedCount: result.removedCount,
|
|
4173
|
+
wasTruncated: result.wasTruncated,
|
|
4174
|
+
availableBudget: ctxManager.availableBudget,
|
|
4175
|
+
modelContextWindow
|
|
4176
|
+
});
|
|
4177
|
+
if (result.wasTruncated && this._onContextTrimmed) {
|
|
4178
|
+
const keptIds = new Set(result.messages.map((m) => m.id));
|
|
4179
|
+
const removed = session.messages.filter((m) => !keptIds.has(m.id));
|
|
4180
|
+
if (removed.length > 0) {
|
|
4181
|
+
try {
|
|
4182
|
+
this._onContextTrimmed(cid, removed);
|
|
4183
|
+
} catch {
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
return { ...session, messages: result.messages };
|
|
4188
|
+
}
|
|
4189
|
+
/** Update context stats with real usage data from a usage event. */
|
|
4190
|
+
updateContextStatsWithUsage(cid, promptTokens, completionTokens, options) {
|
|
4191
|
+
const modelContextWindow = options.model ? this._modelContextWindows.get(options.model) : void 0;
|
|
4192
|
+
const existing = this._contextStats.get(cid);
|
|
4193
|
+
this._contextStats.set(cid, {
|
|
4194
|
+
totalTokens: promptTokens,
|
|
4195
|
+
removedCount: existing?.removedCount ?? 0,
|
|
4196
|
+
wasTruncated: existing?.wasTruncated ?? false,
|
|
4197
|
+
availableBudget: modelContextWindow ? Math.max(0, modelContextWindow - promptTokens) : existing?.availableBudget ?? 0,
|
|
4198
|
+
realPromptTokens: promptTokens,
|
|
4199
|
+
realCompletionTokens: completionTokens,
|
|
4200
|
+
modelContextWindow
|
|
4201
|
+
});
|
|
4202
|
+
}
|
|
4203
|
+
/** Stage 6: Prepare event stream — adapter with retry, tool injection. */
|
|
4204
|
+
async prepareEventStream(cid, sessionForAdapter, fullSession, message, options) {
|
|
4205
|
+
const adapter = await this.getOrCreateAdapterWithRetry(options.backend, options.credentials);
|
|
4206
|
+
const runtimeTools = this._tools.size > 0 ? this.injectToolContext([...this._tools.values()], {
|
|
4207
|
+
sessionId: cid,
|
|
4208
|
+
custom: fullSession.metadata?.custom
|
|
4209
|
+
}) : void 0;
|
|
4210
|
+
const streamOptions = {
|
|
4211
|
+
signal: this._abortController.signal,
|
|
4212
|
+
model: options.model,
|
|
4213
|
+
systemPrompt: options.systemPrompt,
|
|
4214
|
+
tools: runtimeTools
|
|
4215
|
+
};
|
|
4216
|
+
return this.createStreamWithRetry(
|
|
4217
|
+
adapter,
|
|
4218
|
+
sessionForAdapter,
|
|
4219
|
+
message,
|
|
4220
|
+
streamOptions,
|
|
4221
|
+
options.backend,
|
|
4222
|
+
options.credentials
|
|
4223
|
+
);
|
|
4224
|
+
}
|
|
4225
|
+
/** Stage 7: Apply onEvent middleware pipeline (sequential transform/suppress). */
|
|
4226
|
+
async applyOnEventMiddleware(event, ctx) {
|
|
4227
|
+
let processed = event;
|
|
4228
|
+
for (const mw of this._middleware) {
|
|
4229
|
+
if (mw.onEvent && processed) {
|
|
4230
|
+
processed = await mw.onEvent(processed, ctx);
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
return processed;
|
|
4234
|
+
}
|
|
4235
|
+
/** Stage 8: Finalize accumulator, apply afterReceive middleware, persist assistant message. */
|
|
4236
|
+
async finalizeAssistantMessage(cid, accumulator, ctx) {
|
|
4237
|
+
let assistantMessage = accumulator.finalize();
|
|
4238
|
+
for (const mw of this._middleware) {
|
|
4239
|
+
if (mw.onAfterReceive) {
|
|
4240
|
+
assistantMessage = await mw.onAfterReceive(assistantMessage, ctx);
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
await this._sessionStore.appendMessage(cid, assistantMessage);
|
|
4244
|
+
this._notifySessionChange();
|
|
4245
|
+
}
|
|
4246
|
+
/** Stage 9: Error handling — apply onError middleware, transition state. Returns null if suppressed. */
|
|
4247
|
+
async handleSendError(error, cid) {
|
|
4248
|
+
let processedError = error instanceof Error ? error : new Error(String(error));
|
|
4249
|
+
const ctx = {
|
|
4250
|
+
sessionId: cid,
|
|
4251
|
+
signal: this._abortController?.signal ?? new AbortController().signal
|
|
4252
|
+
};
|
|
4253
|
+
for (const mw of this._middleware) {
|
|
4254
|
+
if (mw.onError) {
|
|
4255
|
+
const result = await mw.onError(processedError, ctx);
|
|
4256
|
+
if (result === null) {
|
|
4257
|
+
if (this._state.canTransition("idle")) {
|
|
4258
|
+
this._state.transition("idle");
|
|
4259
|
+
}
|
|
4260
|
+
return null;
|
|
4261
|
+
}
|
|
4262
|
+
processedError = result;
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
if (this._state.canTransition("error")) {
|
|
4266
|
+
this._state.transition("error");
|
|
4112
4267
|
}
|
|
4113
|
-
|
|
4268
|
+
return processedError;
|
|
4269
|
+
}
|
|
4270
|
+
abort() {
|
|
4271
|
+
this._abortController?.abort("User abort");
|
|
4114
4272
|
}
|
|
4115
|
-
|
|
4273
|
+
// ── Backend / Model ────────────────────────────────────────
|
|
4274
|
+
async listModels(options) {
|
|
4116
4275
|
this.assertNotDisposed();
|
|
4117
|
-
|
|
4276
|
+
let models = [];
|
|
4277
|
+
const firstAdapter = [...this._adapterPool.values()][0];
|
|
4278
|
+
if (firstAdapter) {
|
|
4279
|
+
try {
|
|
4280
|
+
models = await firstAdapter.listModels();
|
|
4281
|
+
} catch {
|
|
4282
|
+
return [];
|
|
4283
|
+
}
|
|
4284
|
+
} else if (options?.backend && options?.credentials) {
|
|
4285
|
+
try {
|
|
4286
|
+
const adapter = await this.getOrCreateAdapter(options.backend, options.credentials);
|
|
4287
|
+
models = await adapter.listModels();
|
|
4288
|
+
} catch {
|
|
4289
|
+
return [];
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
for (const model of models) {
|
|
4293
|
+
if (model.contextWindow != null) {
|
|
4294
|
+
this._modelContextWindows.set(model.id, model.contextWindow);
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
return models;
|
|
4118
4298
|
}
|
|
4119
|
-
async
|
|
4299
|
+
async listBackends() {
|
|
4120
4300
|
this.assertNotDisposed();
|
|
4121
|
-
|
|
4122
|
-
return adapter.listModels();
|
|
4301
|
+
return Object.keys(this._backends).map((name) => ({ name }));
|
|
4123
4302
|
}
|
|
4124
4303
|
// ── Tools ──────────────────────────────────────────────────
|
|
4125
4304
|
get registeredTools() {
|
|
@@ -4144,37 +4323,46 @@ var ChatRuntime = class {
|
|
|
4144
4323
|
if (idx >= 0) this._middleware.splice(idx, 1);
|
|
4145
4324
|
}
|
|
4146
4325
|
// ── Context Stats ─────────────────────────────────────────
|
|
4147
|
-
getContextStats(sessionId) {
|
|
4326
|
+
async getContextStats(sessionId) {
|
|
4148
4327
|
const cid = toChatId(sessionId);
|
|
4149
4328
|
return this._contextStats.get(cid) ?? null;
|
|
4150
4329
|
}
|
|
4151
4330
|
// ── Session Subscription ──────────────────────────────────
|
|
4152
4331
|
onSessionChange(callback) {
|
|
4153
|
-
this._sessionListeners.add(callback);
|
|
4154
|
-
return () => {
|
|
4155
|
-
this._sessionListeners.delete(callback);
|
|
4156
|
-
};
|
|
4332
|
+
return this._sessionListeners.add(callback);
|
|
4157
4333
|
}
|
|
4158
4334
|
_notifySessionChange() {
|
|
4159
|
-
|
|
4160
|
-
try {
|
|
4161
|
-
cb();
|
|
4162
|
-
} catch {
|
|
4163
|
-
}
|
|
4164
|
-
}
|
|
4335
|
+
this._sessionListeners.notify();
|
|
4165
4336
|
}
|
|
4166
4337
|
// ── Private Helpers ────────────────────────────────────────
|
|
4167
|
-
async getOrCreateAdapter() {
|
|
4168
|
-
|
|
4169
|
-
const
|
|
4338
|
+
async getOrCreateAdapter(backend, credentials) {
|
|
4339
|
+
const key = this.getPoolKey(backend, credentials);
|
|
4340
|
+
const existing = this._adapterPool.get(key);
|
|
4341
|
+
if (existing) return existing;
|
|
4342
|
+
for (const [oldKey, oldAdapter] of this._adapterPool) {
|
|
4343
|
+
if (oldKey.startsWith(backend + ":")) {
|
|
4344
|
+
try {
|
|
4345
|
+
await oldAdapter.dispose();
|
|
4346
|
+
} catch {
|
|
4347
|
+
}
|
|
4348
|
+
this._adapterPool.delete(oldKey);
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
const factory = this._backends[backend];
|
|
4170
4352
|
if (!factory) {
|
|
4171
4353
|
throw new ChatError(
|
|
4172
|
-
`Backend "${
|
|
4354
|
+
`Backend "${backend}" not found`,
|
|
4173
4355
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
4174
4356
|
);
|
|
4175
4357
|
}
|
|
4176
|
-
|
|
4177
|
-
|
|
4358
|
+
const adapter = await factory(credentials);
|
|
4359
|
+
this._adapterPool.set(key, adapter);
|
|
4360
|
+
return adapter;
|
|
4361
|
+
}
|
|
4362
|
+
getPoolKey(backend, credentials) {
|
|
4363
|
+
const token = credentials.accessToken;
|
|
4364
|
+
const hash = token.length > 16 ? token.slice(0, 8) + token.slice(-8) : token;
|
|
4365
|
+
return `${backend}:${hash}`;
|
|
4178
4366
|
}
|
|
4179
4367
|
/** Wrap each tool's execute to inject ToolContext as 2nd argument */
|
|
4180
4368
|
injectToolContext(tools, context) {
|
|
@@ -4206,17 +4394,25 @@ var ChatRuntime = class {
|
|
|
4206
4394
|
}
|
|
4207
4395
|
}
|
|
4208
4396
|
/** Get or create adapter with retry on connection errors */
|
|
4209
|
-
async getOrCreateAdapterWithRetry() {
|
|
4397
|
+
async getOrCreateAdapterWithRetry(backend, credentials) {
|
|
4210
4398
|
const maxAttempts = this._retryConfig?.maxAttempts ?? 1;
|
|
4211
4399
|
const delayMs = this._retryConfig?.delayMs ?? 0;
|
|
4212
4400
|
let lastError;
|
|
4213
4401
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
4214
4402
|
try {
|
|
4215
|
-
return await this.getOrCreateAdapter();
|
|
4403
|
+
return await this.getOrCreateAdapter(backend, credentials);
|
|
4216
4404
|
} catch (err) {
|
|
4217
4405
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
4218
4406
|
if (attempt < maxAttempts) {
|
|
4219
|
-
this.
|
|
4407
|
+
const key = this.getPoolKey(backend, credentials);
|
|
4408
|
+
const old = this._adapterPool.get(key);
|
|
4409
|
+
if (old) {
|
|
4410
|
+
try {
|
|
4411
|
+
await old.dispose();
|
|
4412
|
+
} catch {
|
|
4413
|
+
}
|
|
4414
|
+
}
|
|
4415
|
+
this._adapterPool.delete(key);
|
|
4220
4416
|
await delay(delayMs);
|
|
4221
4417
|
}
|
|
4222
4418
|
}
|
|
@@ -4229,7 +4425,7 @@ var ChatRuntime = class {
|
|
|
4229
4425
|
* retries with a fresh adapter. Once first event is received,
|
|
4230
4426
|
* the stream is committed (no more retries).
|
|
4231
4427
|
*/
|
|
4232
|
-
async createStreamWithRetry(adapter, session, message, options) {
|
|
4428
|
+
async createStreamWithRetry(adapter, session, message, options, backend, credentials) {
|
|
4233
4429
|
const maxAttempts = this._retryConfig?.maxAttempts ?? 1;
|
|
4234
4430
|
const delayMs = this._retryConfig?.delayMs ?? 0;
|
|
4235
4431
|
let lastError;
|
|
@@ -4250,13 +4446,14 @@ var ChatRuntime = class {
|
|
|
4250
4446
|
} catch (err) {
|
|
4251
4447
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
4252
4448
|
if (attempt < maxAttempts) {
|
|
4253
|
-
|
|
4254
|
-
await
|
|
4255
|
-
|
|
4449
|
+
try {
|
|
4450
|
+
await currentAdapter.dispose();
|
|
4451
|
+
} catch {
|
|
4256
4452
|
}
|
|
4257
|
-
this.
|
|
4453
|
+
const key = this.getPoolKey(backend, credentials);
|
|
4454
|
+
this._adapterPool.delete(key);
|
|
4258
4455
|
await delay(delayMs);
|
|
4259
|
-
currentAdapter = await this.getOrCreateAdapter();
|
|
4456
|
+
currentAdapter = await this.getOrCreateAdapter(backend, credentials);
|
|
4260
4457
|
}
|
|
4261
4458
|
}
|
|
4262
4459
|
}
|
|
@@ -4264,16 +4461,17 @@ var ChatRuntime = class {
|
|
|
4264
4461
|
}
|
|
4265
4462
|
};
|
|
4266
4463
|
function delay(ms) {
|
|
4267
|
-
return new Promise((
|
|
4464
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4268
4465
|
}
|
|
4269
4466
|
function createChatRuntime(options) {
|
|
4270
4467
|
return new ChatRuntime(options);
|
|
4271
4468
|
}
|
|
4272
4469
|
|
|
4273
4470
|
// src/chat/storage.ts
|
|
4471
|
+
init_errors2();
|
|
4274
4472
|
init_errors();
|
|
4275
4473
|
var StorageError = class extends AgentSDKError {
|
|
4276
|
-
/** Machine-readable error code */
|
|
4474
|
+
/** Machine-readable error code from the unified ErrorCode enum */
|
|
4277
4475
|
code;
|
|
4278
4476
|
constructor(message, code) {
|
|
4279
4477
|
super(message);
|
|
@@ -4310,7 +4508,7 @@ var InMemoryStorage = class {
|
|
|
4310
4508
|
if (this.data.has(key)) {
|
|
4311
4509
|
throw new StorageError(
|
|
4312
4510
|
`Item with key "${key}" already exists`,
|
|
4313
|
-
"
|
|
4511
|
+
"STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
|
|
4314
4512
|
);
|
|
4315
4513
|
}
|
|
4316
4514
|
this.data.set(key, structuredClone(item));
|
|
@@ -4320,7 +4518,7 @@ var InMemoryStorage = class {
|
|
|
4320
4518
|
if (!this.data.has(key)) {
|
|
4321
4519
|
throw new StorageError(
|
|
4322
4520
|
`Item with key "${key}" not found`,
|
|
4323
|
-
"
|
|
4521
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4324
4522
|
);
|
|
4325
4523
|
}
|
|
4326
4524
|
this.data.set(key, structuredClone(item));
|
|
@@ -4330,7 +4528,7 @@ var InMemoryStorage = class {
|
|
|
4330
4528
|
if (!this.data.has(key)) {
|
|
4331
4529
|
throw new StorageError(
|
|
4332
4530
|
`Item with key "${key}" not found`,
|
|
4333
|
-
"
|
|
4531
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4334
4532
|
);
|
|
4335
4533
|
}
|
|
4336
4534
|
this.data.delete(key);
|
|
@@ -4395,7 +4593,7 @@ var FileStorage = class {
|
|
|
4395
4593
|
if (existsSync(filePath)) {
|
|
4396
4594
|
throw new StorageError(
|
|
4397
4595
|
`Item with key "${key}" already exists`,
|
|
4398
|
-
"
|
|
4596
|
+
"STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
|
|
4399
4597
|
);
|
|
4400
4598
|
}
|
|
4401
4599
|
this.writeFile(filePath, item);
|
|
@@ -4406,7 +4604,7 @@ var FileStorage = class {
|
|
|
4406
4604
|
if (!existsSync(filePath)) {
|
|
4407
4605
|
throw new StorageError(
|
|
4408
4606
|
`Item with key "${key}" not found`,
|
|
4409
|
-
"
|
|
4607
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4410
4608
|
);
|
|
4411
4609
|
}
|
|
4412
4610
|
this.writeFile(filePath, item);
|
|
@@ -4417,7 +4615,7 @@ var FileStorage = class {
|
|
|
4417
4615
|
if (!existsSync(filePath)) {
|
|
4418
4616
|
throw new StorageError(
|
|
4419
4617
|
`Item with key "${key}" not found`,
|
|
4420
|
-
"
|
|
4618
|
+
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
4421
4619
|
);
|
|
4422
4620
|
}
|
|
4423
4621
|
unlinkSync(filePath);
|
|
@@ -4463,12 +4661,12 @@ var FileStorage = class {
|
|
|
4463
4661
|
if (error instanceof SyntaxError) {
|
|
4464
4662
|
throw new StorageError(
|
|
4465
4663
|
`Failed to parse file: ${filePath}`,
|
|
4466
|
-
"
|
|
4664
|
+
"STORAGE_SERIALIZATION_ERROR" /* STORAGE_SERIALIZATION_ERROR */
|
|
4467
4665
|
);
|
|
4468
4666
|
}
|
|
4469
4667
|
throw new StorageError(
|
|
4470
4668
|
`Failed to read file: ${filePath}`,
|
|
4471
|
-
"
|
|
4669
|
+
"STORAGE_IO_ERROR" /* STORAGE_IO_ERROR */
|
|
4472
4670
|
);
|
|
4473
4671
|
}
|
|
4474
4672
|
}
|
|
@@ -4479,13 +4677,14 @@ var FileStorage = class {
|
|
|
4479
4677
|
} catch {
|
|
4480
4678
|
throw new StorageError(
|
|
4481
4679
|
`Failed to write file: ${filePath}`,
|
|
4482
|
-
"
|
|
4680
|
+
"STORAGE_IO_ERROR" /* STORAGE_IO_ERROR */
|
|
4483
4681
|
);
|
|
4484
4682
|
}
|
|
4485
4683
|
}
|
|
4486
4684
|
};
|
|
4487
4685
|
|
|
4488
4686
|
// src/chat/sessions.ts
|
|
4687
|
+
init_errors();
|
|
4489
4688
|
var BaseSessionStore = class {
|
|
4490
4689
|
constructor(adapter) {
|
|
4491
4690
|
this.adapter = adapter;
|
|
@@ -4524,7 +4723,7 @@ var BaseSessionStore = class {
|
|
|
4524
4723
|
async updateTitle(id, title) {
|
|
4525
4724
|
const session = await this.adapter.get(id);
|
|
4526
4725
|
if (!session) {
|
|
4527
|
-
throw new StorageError(`Session "${id}" not found`, "
|
|
4726
|
+
throw new StorageError(`Session "${id}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4528
4727
|
}
|
|
4529
4728
|
session.title = title;
|
|
4530
4729
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4533,7 +4732,7 @@ var BaseSessionStore = class {
|
|
|
4533
4732
|
async updateConfig(id, config) {
|
|
4534
4733
|
const session = await this.adapter.get(id);
|
|
4535
4734
|
if (!session) {
|
|
4536
|
-
throw new StorageError(`Session "${id}" not found`, "
|
|
4735
|
+
throw new StorageError(`Session "${id}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4537
4736
|
}
|
|
4538
4737
|
session.config = { ...session.config, ...config };
|
|
4539
4738
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4545,7 +4744,7 @@ var BaseSessionStore = class {
|
|
|
4545
4744
|
async appendMessage(sessionId, message) {
|
|
4546
4745
|
const session = await this.adapter.get(sessionId);
|
|
4547
4746
|
if (!session) {
|
|
4548
|
-
throw new StorageError(`Session "${sessionId}" not found`, "
|
|
4747
|
+
throw new StorageError(`Session "${sessionId}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4549
4748
|
}
|
|
4550
4749
|
session.messages.push(structuredClone(message));
|
|
4551
4750
|
session.metadata.messageCount = session.messages.length;
|
|
@@ -4556,7 +4755,7 @@ var BaseSessionStore = class {
|
|
|
4556
4755
|
if (messages.length === 0) return;
|
|
4557
4756
|
const session = await this.adapter.get(sessionId);
|
|
4558
4757
|
if (!session) {
|
|
4559
|
-
throw new StorageError(`Session "${sessionId}" not found`, "
|
|
4758
|
+
throw new StorageError(`Session "${sessionId}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4560
4759
|
}
|
|
4561
4760
|
for (const msg of messages) {
|
|
4562
4761
|
session.messages.push(structuredClone(msg));
|
|
@@ -4568,7 +4767,7 @@ var BaseSessionStore = class {
|
|
|
4568
4767
|
async loadMessages(sessionId, options) {
|
|
4569
4768
|
const session = await this.adapter.get(sessionId);
|
|
4570
4769
|
if (!session) {
|
|
4571
|
-
throw new StorageError(`Session "${sessionId}" not found`, "
|
|
4770
|
+
throw new StorageError(`Session "${sessionId}" not found`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
|
|
4572
4771
|
}
|
|
4573
4772
|
const total = session.messages.length;
|
|
4574
4773
|
const offset = options?.offset ?? 0;
|
|
@@ -4580,24 +4779,6 @@ var BaseSessionStore = class {
|
|
|
4580
4779
|
hasMore: offset + limit < total
|
|
4581
4780
|
};
|
|
4582
4781
|
}
|
|
4583
|
-
async archiveSession(id) {
|
|
4584
|
-
const session = await this.adapter.get(id);
|
|
4585
|
-
if (!session) {
|
|
4586
|
-
throw new StorageError(`Session "${id}" not found`, "NOT_FOUND");
|
|
4587
|
-
}
|
|
4588
|
-
session.status = "archived";
|
|
4589
|
-
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4590
|
-
await this.adapter.update(id, session);
|
|
4591
|
-
}
|
|
4592
|
-
async unarchiveSession(id) {
|
|
4593
|
-
const session = await this.adapter.get(id);
|
|
4594
|
-
if (!session) {
|
|
4595
|
-
throw new StorageError(`Session "${id}" not found`, "NOT_FOUND");
|
|
4596
|
-
}
|
|
4597
|
-
session.status = "active";
|
|
4598
|
-
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4599
|
-
await this.adapter.update(id, session);
|
|
4600
|
-
}
|
|
4601
4782
|
async searchSessions(options) {
|
|
4602
4783
|
const query = options.query.toLowerCase();
|
|
4603
4784
|
const limit = options.limit ?? 20;
|
|
@@ -4619,15 +4800,6 @@ var BaseSessionStore = class {
|
|
|
4619
4800
|
async clear() {
|
|
4620
4801
|
return this.adapter.clear();
|
|
4621
4802
|
}
|
|
4622
|
-
// ── Deprecated Aliases ──────────────────────────────────────
|
|
4623
|
-
/** @deprecated Use `appendMessage()` instead */
|
|
4624
|
-
async addMessage(sessionId, message) {
|
|
4625
|
-
return this.appendMessage(sessionId, message);
|
|
4626
|
-
}
|
|
4627
|
-
/** @deprecated Use `loadMessages()` instead */
|
|
4628
|
-
async getMessages(sessionId, options) {
|
|
4629
|
-
return this.loadMessages(sessionId, options);
|
|
4630
|
-
}
|
|
4631
4803
|
};
|
|
4632
4804
|
var InMemorySessionStore = class extends BaseSessionStore {
|
|
4633
4805
|
constructor() {
|
|
@@ -4640,28 +4812,59 @@ var FileSessionStore = class extends BaseSessionStore {
|
|
|
4640
4812
|
}
|
|
4641
4813
|
};
|
|
4642
4814
|
|
|
4815
|
+
// src/chat/backends/types.ts
|
|
4816
|
+
function isResumableBackend(adapter) {
|
|
4817
|
+
return "canResume" in adapter && typeof adapter.canResume === "function";
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4643
4820
|
// src/chat/backends/base.ts
|
|
4644
4821
|
var BaseBackendAdapter = class {
|
|
4645
4822
|
name;
|
|
4646
|
-
_agentService;
|
|
4647
|
-
|
|
4823
|
+
_agentService = null;
|
|
4824
|
+
_agentServiceFactory = null;
|
|
4648
4825
|
_disposed = false;
|
|
4649
4826
|
_agentConfig;
|
|
4650
4827
|
_ownsService;
|
|
4828
|
+
// Agent lifecycle: tracks current agent and the model it was created with.
|
|
4829
|
+
// For persistent sessions, reused across calls when model matches.
|
|
4830
|
+
// For non-persistent, recreated every call.
|
|
4831
|
+
_currentAgent = null;
|
|
4651
4832
|
constructor(name, options) {
|
|
4652
4833
|
this.name = name;
|
|
4653
4834
|
this._agentConfig = options.agentConfig;
|
|
4654
4835
|
if (options.agentService) {
|
|
4655
4836
|
this._agentService = options.agentService;
|
|
4656
4837
|
this._ownsService = false;
|
|
4838
|
+
} else if (options.agentServiceFactory) {
|
|
4839
|
+
this._agentServiceFactory = options.agentServiceFactory;
|
|
4840
|
+
this._ownsService = true;
|
|
4657
4841
|
} else {
|
|
4658
4842
|
this._agentService = this.createService();
|
|
4659
4843
|
this._ownsService = true;
|
|
4660
4844
|
}
|
|
4661
4845
|
}
|
|
4662
4846
|
get agentService() {
|
|
4847
|
+
if (!this._agentService) {
|
|
4848
|
+
if (this._agentServiceFactory) {
|
|
4849
|
+
this._agentService = this._agentServiceFactory();
|
|
4850
|
+
this._agentServiceFactory = null;
|
|
4851
|
+
} else {
|
|
4852
|
+
throw new ChatError("Agent service not available", {
|
|
4853
|
+
code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */
|
|
4854
|
+
});
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4663
4857
|
return this._agentService;
|
|
4664
4858
|
}
|
|
4859
|
+
get currentModel() {
|
|
4860
|
+
return this._agentConfig.model;
|
|
4861
|
+
}
|
|
4862
|
+
/**
|
|
4863
|
+
* @deprecated No-op. Tools are passed per-call via SendMessageOptions.tools.
|
|
4864
|
+
* Kept for backward compatibility with code that calls setTools() directly.
|
|
4865
|
+
*/
|
|
4866
|
+
setTools() {
|
|
4867
|
+
}
|
|
4665
4868
|
async sendMessage(session, message, options) {
|
|
4666
4869
|
this.assertNotDisposed();
|
|
4667
4870
|
const events = this.streamMessage(session, message, options);
|
|
@@ -4699,9 +4902,13 @@ var BaseBackendAdapter = class {
|
|
|
4699
4902
|
*/
|
|
4700
4903
|
async *streamAgentEvents(agent, messages, options) {
|
|
4701
4904
|
const messageId = createChatId();
|
|
4905
|
+
const model = options?.model ?? this._agentConfig.model ?? "";
|
|
4702
4906
|
const agentEvents = agent.streamWithContext(messages, {
|
|
4907
|
+
model,
|
|
4703
4908
|
signal: options?.signal,
|
|
4704
|
-
context: options?.context
|
|
4909
|
+
context: options?.context,
|
|
4910
|
+
tools: options?.tools,
|
|
4911
|
+
...options?.systemPrompt ? { systemMessage: options.systemPrompt } : {}
|
|
4705
4912
|
});
|
|
4706
4913
|
yield { type: "message:start", messageId, role: "assistant" };
|
|
4707
4914
|
let text = "";
|
|
@@ -4727,31 +4934,45 @@ var BaseBackendAdapter = class {
|
|
|
4727
4934
|
}
|
|
4728
4935
|
async listModels() {
|
|
4729
4936
|
this.assertNotDisposed();
|
|
4730
|
-
return this.
|
|
4937
|
+
return this.agentService.listModels();
|
|
4731
4938
|
}
|
|
4732
4939
|
async validate() {
|
|
4733
4940
|
this.assertNotDisposed();
|
|
4734
|
-
return this.
|
|
4941
|
+
return this.agentService.validate();
|
|
4735
4942
|
}
|
|
4736
4943
|
async dispose() {
|
|
4737
4944
|
if (this._disposed) return;
|
|
4738
4945
|
this._disposed = true;
|
|
4739
|
-
this.
|
|
4740
|
-
|
|
4741
|
-
|
|
4946
|
+
if (this._currentAgent) {
|
|
4947
|
+
this._currentAgent.instance.dispose();
|
|
4948
|
+
this._currentAgent = null;
|
|
4949
|
+
}
|
|
4950
|
+
if (this._ownsService && this._agentService && typeof this._agentService.dispose === "function") {
|
|
4742
4951
|
await this._agentService.dispose();
|
|
4743
4952
|
}
|
|
4744
4953
|
}
|
|
4745
|
-
/** Get or create an agent
|
|
4954
|
+
/** Get or create an agent. Model is passed per-call via RunOptions.
|
|
4955
|
+
* Tools are passed per-call via SendMessageOptions — not baked into config.
|
|
4956
|
+
* For persistent sessions, reuses agent when model matches. */
|
|
4746
4957
|
getOrCreateAgent(options) {
|
|
4747
|
-
const
|
|
4748
|
-
if (this._agentConfig.sessionMode === "persistent" && this.
|
|
4749
|
-
|
|
4958
|
+
const model = options?.model ?? this._agentConfig.model;
|
|
4959
|
+
if (this._agentConfig.sessionMode === "persistent" && this._currentAgent) {
|
|
4960
|
+
if (this._currentAgent.model === model) {
|
|
4961
|
+
return this._currentAgent.instance;
|
|
4962
|
+
}
|
|
4963
|
+
this._currentAgent.instance.dispose();
|
|
4964
|
+
this._currentAgent = null;
|
|
4750
4965
|
}
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
this.
|
|
4966
|
+
if (this._currentAgent) {
|
|
4967
|
+
this._currentAgent.instance.dispose();
|
|
4968
|
+
this._currentAgent = null;
|
|
4754
4969
|
}
|
|
4970
|
+
const config = {
|
|
4971
|
+
...this._agentConfig,
|
|
4972
|
+
...model !== void 0 && { model }
|
|
4973
|
+
};
|
|
4974
|
+
const agent = this.agentService.createAgent(config);
|
|
4975
|
+
this._currentAgent = { instance: agent, model };
|
|
4755
4976
|
return agent;
|
|
4756
4977
|
}
|
|
4757
4978
|
assertNotDisposed() {
|
|
@@ -4776,8 +4997,8 @@ var CopilotChatAdapter = class extends BaseBackendAdapter {
|
|
|
4776
4997
|
this._copilotOptions = options.copilotOptions;
|
|
4777
4998
|
}
|
|
4778
4999
|
createService() {
|
|
4779
|
-
const {
|
|
4780
|
-
return
|
|
5000
|
+
const { createCopilotService: createCopilotService2 } = (init_copilot(), __toCommonJS(copilot_exports));
|
|
5001
|
+
return createCopilotService2(this._copilotOptions || {});
|
|
4781
5002
|
}
|
|
4782
5003
|
get backendSessionId() {
|
|
4783
5004
|
return this._backendSessionId;
|
|
@@ -4829,8 +5050,8 @@ var ClaudeChatAdapter = class extends BaseBackendAdapter {
|
|
|
4829
5050
|
this._claudeOptions = options.claudeOptions;
|
|
4830
5051
|
}
|
|
4831
5052
|
createService() {
|
|
4832
|
-
const {
|
|
4833
|
-
return
|
|
5053
|
+
const { createClaudeService: createClaudeService2 } = (init_claude(), __toCommonJS(claude_exports));
|
|
5054
|
+
return createClaudeService2(this._claudeOptions || {});
|
|
4834
5055
|
}
|
|
4835
5056
|
get backendSessionId() {
|
|
4836
5057
|
return this._backendSessionId;
|
|
@@ -4877,20 +5098,8 @@ var VercelAIChatAdapter = class extends BaseBackendAdapter {
|
|
|
4877
5098
|
this._vercelOptions = options.vercelOptions;
|
|
4878
5099
|
}
|
|
4879
5100
|
createService() {
|
|
4880
|
-
const {
|
|
4881
|
-
return
|
|
4882
|
-
}
|
|
4883
|
-
get backendSessionId() {
|
|
4884
|
-
return null;
|
|
4885
|
-
}
|
|
4886
|
-
canResume() {
|
|
4887
|
-
return false;
|
|
4888
|
-
}
|
|
4889
|
-
async *resume(_session, _backendSessionId, _options) {
|
|
4890
|
-
throw new ChatError(
|
|
4891
|
-
"Vercel AI adapter does not support session resume (stateless)",
|
|
4892
|
-
{ code: "PROVIDER_ERROR" /* PROVIDER_ERROR */ }
|
|
4893
|
-
);
|
|
5101
|
+
const { createVercelAIService: createVercelAIService2 } = (init_vercel_ai(), __toCommonJS(vercel_ai_exports));
|
|
5102
|
+
return createVercelAIService2(this._vercelOptions || {});
|
|
4894
5103
|
}
|
|
4895
5104
|
captureSessionId(_agent) {
|
|
4896
5105
|
}
|
|
@@ -5067,9 +5276,9 @@ var InProcessChatTransport = class {
|
|
|
5067
5276
|
send(event) {
|
|
5068
5277
|
if (!this._open) return;
|
|
5069
5278
|
if (this._resolve) {
|
|
5070
|
-
const
|
|
5279
|
+
const resolve = this._resolve;
|
|
5071
5280
|
this._resolve = null;
|
|
5072
|
-
|
|
5281
|
+
resolve({ value: event, done: false });
|
|
5073
5282
|
} else {
|
|
5074
5283
|
this._buffer.push(event);
|
|
5075
5284
|
}
|
|
@@ -5078,9 +5287,9 @@ var InProcessChatTransport = class {
|
|
|
5078
5287
|
if (!this._open) return;
|
|
5079
5288
|
this._open = false;
|
|
5080
5289
|
if (this._resolve) {
|
|
5081
|
-
const
|
|
5290
|
+
const resolve = this._resolve;
|
|
5082
5291
|
this._resolve = null;
|
|
5083
|
-
|
|
5292
|
+
resolve({ value: void 0, done: true });
|
|
5084
5293
|
}
|
|
5085
5294
|
}
|
|
5086
5295
|
error(err) {
|
|
@@ -5092,9 +5301,9 @@ var InProcessChatTransport = class {
|
|
|
5092
5301
|
recoverable: false
|
|
5093
5302
|
};
|
|
5094
5303
|
if (this._resolve) {
|
|
5095
|
-
const
|
|
5304
|
+
const resolve = this._resolve;
|
|
5096
5305
|
this._resolve = null;
|
|
5097
|
-
|
|
5306
|
+
resolve({ value: errorEvent, done: false });
|
|
5098
5307
|
} else {
|
|
5099
5308
|
this._error = err;
|
|
5100
5309
|
}
|
|
@@ -5119,8 +5328,8 @@ var InProcessChatTransport = class {
|
|
|
5119
5328
|
if (!this._open) {
|
|
5120
5329
|
return Promise.resolve({ value: void 0, done: true });
|
|
5121
5330
|
}
|
|
5122
|
-
return new Promise((
|
|
5123
|
-
this._resolve =
|
|
5331
|
+
return new Promise((resolve) => {
|
|
5332
|
+
this._resolve = resolve;
|
|
5124
5333
|
});
|
|
5125
5334
|
}
|
|
5126
5335
|
};
|
|
@@ -5291,6 +5500,6 @@ var ChatEventBus = class extends TypedEventEmitter {
|
|
|
5291
5500
|
}
|
|
5292
5501
|
};
|
|
5293
5502
|
|
|
5294
|
-
export { BaseBackendAdapter, ChatError,
|
|
5503
|
+
export { BaseBackendAdapter, ChatError, ChatEventBus, ClaudeChatAdapter, ContextWindowManager, CopilotChatAdapter, ErrorCode, ExponentialBackoffStrategy, FileSessionStore, InMemorySessionStore, InProcessChatTransport, ListenerSet, MessageAccumulator, SSEChatTransport, TypedEventEmitter, VercelAIChatAdapter, WsChatTransport, adaptAgentEvents, agentEventToChatEvent, classifyError, createChatId, createChatRuntime, createTextMessage, estimateTokens, fromAgentMessage, getMessageReasoning, getMessageText, getMessageToolCalls, isChatEvent, isChatMessage, isChatSession, isFilePart, isMessagePart, isObservableSession, isReasoningPart, isResumableBackend, isRetryable, isSourcePart, isTextPart, isToolCallPart, streamToTransport, toAgentMessage, toChatId, withRetry, withStreamWatchdog };
|
|
5295
5504
|
//# sourceMappingURL=index.js.map
|
|
5296
5505
|
//# sourceMappingURL=index.js.map
|