@witqq/agent-sdk 0.6.1 → 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 +539 -6
- package/dist/{types-BvwNzZCj.d.cts → agent-CW9XbmG_.d.ts} +148 -95
- package/dist/{types-BvwNzZCj.d.ts → agent-DxY68NZL.d.cts} +148 -95
- package/dist/auth/index.cjs +260 -2
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +21 -138
- package/dist/auth/index.d.ts +21 -138
- package/dist/auth/index.js +260 -3
- package/dist/auth/index.js.map +1 -1
- package/dist/backends/claude.cjs +653 -140
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +4 -1
- package/dist/backends/claude.d.ts +4 -1
- package/dist/backends/claude.js +653 -140
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +428 -88
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +13 -4
- package/dist/backends/copilot.d.ts +13 -4
- package/dist/backends/copilot.js +428 -88
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/vercel-ai.cjs +349 -77
- 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 +349 -77
- 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 +147 -0
- package/dist/chat/accumulator.cjs.map +1 -0
- package/dist/chat/accumulator.d.cts +64 -0
- package/dist/chat/accumulator.d.ts +64 -0
- package/dist/chat/accumulator.js +145 -0
- package/dist/chat/accumulator.js.map +1 -0
- package/dist/chat/backends.cjs +3524 -0
- package/dist/chat/backends.cjs.map +1 -0
- package/dist/chat/backends.d.cts +66 -0
- package/dist/chat/backends.d.ts +66 -0
- package/dist/chat/backends.js +3512 -0
- package/dist/chat/backends.js.map +1 -0
- package/dist/chat/context.cjs +280 -0
- package/dist/chat/context.cjs.map +1 -0
- package/dist/chat/context.d.cts +191 -0
- package/dist/chat/context.d.ts +191 -0
- package/dist/chat/context.js +277 -0
- package/dist/chat/context.js.map +1 -0
- package/dist/chat/core.cjs +305 -0
- package/dist/chat/core.cjs.map +1 -0
- package/dist/chat/core.d.cts +84 -0
- package/dist/chat/core.d.ts +84 -0
- package/dist/chat/core.js +282 -0
- package/dist/chat/core.js.map +1 -0
- package/dist/chat/errors.cjs +273 -0
- package/dist/chat/errors.cjs.map +1 -0
- package/dist/chat/errors.d.cts +97 -0
- package/dist/chat/errors.d.ts +97 -0
- package/dist/chat/errors.js +266 -0
- package/dist/chat/errors.js.map +1 -0
- package/dist/chat/events.cjs +203 -0
- package/dist/chat/events.cjs.map +1 -0
- package/dist/chat/events.d.cts +245 -0
- package/dist/chat/events.d.ts +245 -0
- package/dist/chat/events.js +196 -0
- package/dist/chat/events.js.map +1 -0
- package/dist/chat/index.cjs +5550 -0
- package/dist/chat/index.cjs.map +1 -0
- package/dist/chat/index.d.cts +77 -0
- package/dist/chat/index.d.ts +77 -0
- package/dist/chat/index.js +5505 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/react/theme.css +2517 -0
- package/dist/chat/react.cjs +3589 -0
- package/dist/chat/react.cjs.map +1 -0
- package/dist/chat/react.d.cts +1088 -0
- package/dist/chat/react.d.ts +1088 -0
- package/dist/chat/react.js +3547 -0
- package/dist/chat/react.js.map +1 -0
- package/dist/chat/runtime.cjs +1245 -0
- package/dist/chat/runtime.cjs.map +1 -0
- package/dist/chat/runtime.d.cts +182 -0
- package/dist/chat/runtime.d.ts +182 -0
- package/dist/chat/runtime.js +1243 -0
- package/dist/chat/runtime.js.map +1 -0
- package/dist/chat/server.cjs +2668 -0
- package/dist/chat/server.cjs.map +1 -0
- package/dist/chat/server.d.cts +648 -0
- package/dist/chat/server.d.ts +648 -0
- package/dist/chat/server.js +2628 -0
- package/dist/chat/server.js.map +1 -0
- package/dist/chat/sessions.cjs +380 -0
- package/dist/chat/sessions.cjs.map +1 -0
- package/dist/chat/sessions.d.cts +158 -0
- package/dist/chat/sessions.d.ts +158 -0
- package/dist/chat/sessions.js +376 -0
- package/dist/chat/sessions.js.map +1 -0
- 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 +190 -0
- package/dist/chat/state.cjs.map +1 -0
- package/dist/chat/state.d.cts +95 -0
- package/dist/chat/state.d.ts +95 -0
- package/dist/chat/state.js +180 -0
- package/dist/chat/state.js.map +1 -0
- package/dist/chat/storage.cjs +249 -0
- package/dist/chat/storage.cjs.map +1 -0
- package/dist/chat/storage.d.cts +197 -0
- package/dist/chat/storage.d.ts +197 -0
- package/dist/chat/storage.js +245 -0
- package/dist/chat/storage.js.map +1 -0
- 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-C1JnJGVR.d.ts +228 -0
- package/dist/in-process-transport-C7DSqPyX.d.cts +228 -0
- package/dist/index.cjs +365 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +322 -125
- package/dist/index.d.ts +322 -125
- package/dist/index.js +359 -60
- package/dist/index.js.map +1 -1
- package/dist/provider-types-PTSlRPNB.d.cts +39 -0
- package/dist/provider-types-PTSlRPNB.d.ts +39 -0
- package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
- package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
- package/dist/testing.cjs +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-Cdh3M0tS.d.cts +68 -0
- package/dist/transport-Ciap4PWK.d.ts +68 -0
- package/dist/types-4vbcmPTp.d.cts +143 -0
- package/dist/types-BxggH0Yh.d.ts +143 -0
- package/dist/types-DRgd_9R7.d.cts +363 -0
- package/dist/types-ajANVzf7.d.ts +363 -0
- package/package.json +178 -6
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// src/types.ts
|
|
3
|
+
// src/types/errors.ts
|
|
4
|
+
var RECOVERABLE_CODES = /* @__PURE__ */ new Set([
|
|
5
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
6
|
+
"RATE_LIMIT" /* RATE_LIMIT */,
|
|
7
|
+
"NETWORK" /* NETWORK */,
|
|
8
|
+
"TOOL_EXECUTION" /* TOOL_EXECUTION */,
|
|
9
|
+
"MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
|
|
10
|
+
"PROVIDER_ERROR" /* PROVIDER_ERROR */
|
|
11
|
+
]);
|
|
12
|
+
function isRecoverableErrorCode(code) {
|
|
13
|
+
return RECOVERABLE_CODES.has(code);
|
|
14
|
+
}
|
|
15
|
+
function classifyAgentError(error) {
|
|
16
|
+
const msg = (error instanceof Error ? error.message : error).toLowerCase();
|
|
17
|
+
if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
|
|
18
|
+
return "TIMEOUT" /* TIMEOUT */;
|
|
19
|
+
}
|
|
20
|
+
if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
|
|
21
|
+
return "RATE_LIMIT" /* RATE_LIMIT */;
|
|
22
|
+
}
|
|
23
|
+
if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
|
|
24
|
+
return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
|
|
25
|
+
}
|
|
26
|
+
if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
|
|
27
|
+
return "NETWORK" /* NETWORK */;
|
|
28
|
+
}
|
|
29
|
+
if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
|
|
30
|
+
return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
|
|
31
|
+
}
|
|
32
|
+
if (msg.includes("abort") || msg.includes("cancel")) {
|
|
33
|
+
return "ABORTED" /* ABORTED */;
|
|
34
|
+
}
|
|
35
|
+
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")) {
|
|
36
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
37
|
+
}
|
|
38
|
+
return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/types/guards.ts
|
|
4
42
|
function getTextContent(content) {
|
|
5
43
|
if (typeof content === "string") return content;
|
|
6
44
|
return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
@@ -8,41 +46,71 @@ function getTextContent(content) {
|
|
|
8
46
|
|
|
9
47
|
// src/errors.ts
|
|
10
48
|
var AgentSDKError = class extends Error {
|
|
49
|
+
/** @internal Marker for cross-bundle identity checks */
|
|
50
|
+
_agentSDKError = true;
|
|
51
|
+
/** Machine-readable error code. Prefer values from the ErrorCode enum. */
|
|
52
|
+
code;
|
|
53
|
+
/** Whether this error is safe to retry */
|
|
54
|
+
retryable;
|
|
55
|
+
/** HTTP status code hint for error classification */
|
|
56
|
+
httpStatus;
|
|
11
57
|
constructor(message, options) {
|
|
12
58
|
super(message, options);
|
|
13
59
|
this.name = "AgentSDKError";
|
|
60
|
+
this.code = options?.code;
|
|
61
|
+
this.retryable = options?.retryable ?? false;
|
|
62
|
+
this.httpStatus = options?.httpStatus;
|
|
63
|
+
}
|
|
64
|
+
/** Check if an error is an AgentSDKError (works across bundled copies) */
|
|
65
|
+
static is(error) {
|
|
66
|
+
return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
|
|
14
67
|
}
|
|
15
68
|
};
|
|
16
69
|
var ReentrancyError = class extends AgentSDKError {
|
|
17
70
|
constructor() {
|
|
18
|
-
super("Agent is already running. Await the current run before starting another."
|
|
71
|
+
super("Agent is already running. Await the current run before starting another.", {
|
|
72
|
+
code: "REENTRANCY" /* REENTRANCY */
|
|
73
|
+
});
|
|
19
74
|
this.name = "ReentrancyError";
|
|
20
75
|
}
|
|
21
76
|
};
|
|
22
77
|
var DisposedError = class extends AgentSDKError {
|
|
23
78
|
constructor(entity) {
|
|
24
|
-
super(`${entity} has been disposed and cannot be used
|
|
79
|
+
super(`${entity} has been disposed and cannot be used.`, {
|
|
80
|
+
code: "DISPOSED" /* DISPOSED */
|
|
81
|
+
});
|
|
25
82
|
this.name = "DisposedError";
|
|
26
83
|
}
|
|
27
84
|
};
|
|
28
85
|
var SubprocessError = class extends AgentSDKError {
|
|
29
86
|
constructor(message, options) {
|
|
30
|
-
super(message, options);
|
|
87
|
+
super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
|
|
31
88
|
this.name = "SubprocessError";
|
|
32
89
|
}
|
|
33
90
|
};
|
|
34
91
|
var AbortError = class extends AgentSDKError {
|
|
35
92
|
constructor() {
|
|
36
|
-
super("Agent run was aborted.");
|
|
93
|
+
super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
|
|
37
94
|
this.name = "AbortError";
|
|
38
95
|
}
|
|
39
96
|
};
|
|
97
|
+
var ActivityTimeoutError = class extends AgentSDKError {
|
|
98
|
+
constructor(timeoutMs) {
|
|
99
|
+
super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
|
|
100
|
+
code: "TIMEOUT" /* TIMEOUT */,
|
|
101
|
+
retryable: true
|
|
102
|
+
});
|
|
103
|
+
this.name = "ActivityTimeoutError";
|
|
104
|
+
}
|
|
105
|
+
};
|
|
40
106
|
|
|
41
107
|
// src/base-agent.ts
|
|
42
108
|
var BaseAgent = class {
|
|
43
109
|
state = "idle";
|
|
44
110
|
abortController = null;
|
|
45
111
|
config;
|
|
112
|
+
_cleanupExternalSignal = null;
|
|
113
|
+
_streamMiddleware = [];
|
|
46
114
|
/** CLI session ID for persistent mode. Override in backends that support it. */
|
|
47
115
|
get sessionId() {
|
|
48
116
|
return void 0;
|
|
@@ -58,12 +126,14 @@ var BaseAgent = class {
|
|
|
58
126
|
this.state = "running";
|
|
59
127
|
try {
|
|
60
128
|
const messages = [{ role: "user", content: prompt }];
|
|
61
|
-
const result = await this.
|
|
62
|
-
|
|
129
|
+
const result = await this.withRetry(
|
|
130
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
131
|
+
options
|
|
132
|
+
);
|
|
133
|
+
this.enrichAndNotifyUsage(result, options);
|
|
63
134
|
return result;
|
|
64
135
|
} finally {
|
|
65
|
-
this.
|
|
66
|
-
this.abortController = null;
|
|
136
|
+
this.cleanupRun();
|
|
67
137
|
}
|
|
68
138
|
}
|
|
69
139
|
async runWithContext(messages, options) {
|
|
@@ -72,12 +142,14 @@ var BaseAgent = class {
|
|
|
72
142
|
const ac = this.createAbortController(options?.signal);
|
|
73
143
|
this.state = "running";
|
|
74
144
|
try {
|
|
75
|
-
const result = await this.
|
|
76
|
-
|
|
145
|
+
const result = await this.withRetry(
|
|
146
|
+
() => this.executeRun(messages, options, ac.signal),
|
|
147
|
+
options
|
|
148
|
+
);
|
|
149
|
+
this.enrichAndNotifyUsage(result, options);
|
|
77
150
|
return result;
|
|
78
151
|
} finally {
|
|
79
|
-
this.
|
|
80
|
-
this.abortController = null;
|
|
152
|
+
this.cleanupRun();
|
|
81
153
|
}
|
|
82
154
|
}
|
|
83
155
|
async runStructured(prompt, schema, options) {
|
|
@@ -87,17 +159,14 @@ var BaseAgent = class {
|
|
|
87
159
|
this.state = "running";
|
|
88
160
|
try {
|
|
89
161
|
const messages = [{ role: "user", content: prompt }];
|
|
90
|
-
const result = await this.
|
|
91
|
-
messages,
|
|
92
|
-
|
|
93
|
-
options,
|
|
94
|
-
ac.signal
|
|
162
|
+
const result = await this.withRetry(
|
|
163
|
+
() => this.executeRunStructured(messages, schema, options, ac.signal),
|
|
164
|
+
options
|
|
95
165
|
);
|
|
96
|
-
this.enrichAndNotifyUsage(result);
|
|
166
|
+
this.enrichAndNotifyUsage(result, options);
|
|
97
167
|
return result;
|
|
98
168
|
} finally {
|
|
99
|
-
this.
|
|
100
|
-
this.abortController = null;
|
|
169
|
+
this.cleanupRun();
|
|
101
170
|
}
|
|
102
171
|
}
|
|
103
172
|
async *stream(prompt, options) {
|
|
@@ -107,11 +176,12 @@ var BaseAgent = class {
|
|
|
107
176
|
this.state = "streaming";
|
|
108
177
|
try {
|
|
109
178
|
const messages = [{ role: "user", content: prompt }];
|
|
110
|
-
|
|
111
|
-
|
|
179
|
+
yield* this.streamWithRetry(
|
|
180
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
181
|
+
options
|
|
182
|
+
);
|
|
112
183
|
} finally {
|
|
113
|
-
this.
|
|
114
|
-
this.abortController = null;
|
|
184
|
+
this.cleanupRun();
|
|
115
185
|
}
|
|
116
186
|
}
|
|
117
187
|
async *streamWithContext(messages, options) {
|
|
@@ -120,13 +190,37 @@ var BaseAgent = class {
|
|
|
120
190
|
const ac = this.createAbortController(options?.signal);
|
|
121
191
|
this.state = "streaming";
|
|
122
192
|
try {
|
|
123
|
-
|
|
124
|
-
|
|
193
|
+
yield* this.streamWithRetry(
|
|
194
|
+
() => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
|
|
195
|
+
options
|
|
196
|
+
);
|
|
125
197
|
} finally {
|
|
126
|
-
this.
|
|
127
|
-
this.abortController = null;
|
|
198
|
+
this.cleanupRun();
|
|
128
199
|
}
|
|
129
200
|
}
|
|
201
|
+
/** Register a stream middleware. Applied in registration order after built-in transforms. */
|
|
202
|
+
addStreamMiddleware(middleware) {
|
|
203
|
+
this.guardDisposed();
|
|
204
|
+
this._streamMiddleware.push(middleware);
|
|
205
|
+
}
|
|
206
|
+
/** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
|
|
207
|
+
async *applyStreamPipeline(source, options, ac) {
|
|
208
|
+
let stream = this.enrichStream(source, options);
|
|
209
|
+
stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
|
|
210
|
+
stream = this.heartbeatStream(stream);
|
|
211
|
+
if (this._streamMiddleware.length > 0) {
|
|
212
|
+
const ctx = {
|
|
213
|
+
model: options.model,
|
|
214
|
+
backend: this.backendName,
|
|
215
|
+
abortController: ac,
|
|
216
|
+
config: Object.freeze({ ...this.config })
|
|
217
|
+
};
|
|
218
|
+
for (const mw of this._streamMiddleware) {
|
|
219
|
+
stream = mw(stream, ctx);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
yield* stream;
|
|
223
|
+
}
|
|
130
224
|
abort() {
|
|
131
225
|
if (this.abortController) {
|
|
132
226
|
this.abortController.abort();
|
|
@@ -144,29 +238,114 @@ var BaseAgent = class {
|
|
|
144
238
|
}
|
|
145
239
|
/** Mark agent as disposed. Override to add cleanup. */
|
|
146
240
|
dispose() {
|
|
241
|
+
this._cleanupExternalSignal?.();
|
|
242
|
+
this._cleanupExternalSignal = null;
|
|
147
243
|
this.abort();
|
|
148
244
|
this.state = "disposed";
|
|
149
245
|
}
|
|
246
|
+
// ─── Retry Logic ─────────────────────────────────────────────
|
|
247
|
+
/** Check if an error should be retried given the retry configuration. */
|
|
248
|
+
isRetryableError(error, retry) {
|
|
249
|
+
if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
if (AgentSDKError.is(error)) {
|
|
253
|
+
if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
|
|
254
|
+
return retry.retryableErrors.includes(error.code);
|
|
255
|
+
}
|
|
256
|
+
if (error.retryable) return true;
|
|
257
|
+
if (error.code) return isRecoverableErrorCode(error.code);
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
/** Execute a function with retry logic per RetryConfig. */
|
|
262
|
+
async withRetry(fn, options) {
|
|
263
|
+
const retry = options?.retry;
|
|
264
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
265
|
+
return fn();
|
|
266
|
+
}
|
|
267
|
+
const maxRetries = retry.maxRetries;
|
|
268
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
269
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
270
|
+
let lastError;
|
|
271
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
272
|
+
try {
|
|
273
|
+
return await fn();
|
|
274
|
+
} catch (err) {
|
|
275
|
+
lastError = err;
|
|
276
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
const delay = initialDelay * Math.pow(multiplier, attempt);
|
|
280
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
281
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
throw lastError;
|
|
287
|
+
}
|
|
288
|
+
/** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
|
|
289
|
+
async *streamWithRetry(factory, options) {
|
|
290
|
+
const retry = options?.retry;
|
|
291
|
+
if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
|
|
292
|
+
yield* factory();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const maxRetries = retry.maxRetries;
|
|
296
|
+
const initialDelay = retry.initialDelayMs ?? 1e3;
|
|
297
|
+
const multiplier = retry.backoffMultiplier ?? 2;
|
|
298
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
299
|
+
try {
|
|
300
|
+
const stream = factory();
|
|
301
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
302
|
+
const first = await iterator.next();
|
|
303
|
+
if (first.done) return;
|
|
304
|
+
yield first.value;
|
|
305
|
+
while (true) {
|
|
306
|
+
const next = await iterator.next();
|
|
307
|
+
if (next.done) break;
|
|
308
|
+
yield next.value;
|
|
309
|
+
}
|
|
310
|
+
return;
|
|
311
|
+
} catch (err) {
|
|
312
|
+
if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
const delay = initialDelay * Math.pow(multiplier, attempt);
|
|
316
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
317
|
+
if (options?.signal?.aborted || this.abortController?.signal.aborted) {
|
|
318
|
+
throw err;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// ─── CallOptions Resolution ──────────────────────────────────
|
|
324
|
+
/** Resolve tools to use for this call (per-call override > config default) */
|
|
325
|
+
resolveTools(options) {
|
|
326
|
+
return options?.tools ?? this.config.tools ?? [];
|
|
327
|
+
}
|
|
150
328
|
// ─── Usage Enrichment ───────────────────────────────────────────
|
|
151
329
|
/** Enrich result usage with model/backend and fire onUsage callback */
|
|
152
|
-
enrichAndNotifyUsage(result) {
|
|
330
|
+
enrichAndNotifyUsage(result, options) {
|
|
153
331
|
if (result.usage) {
|
|
154
332
|
result.usage = {
|
|
155
333
|
...result.usage,
|
|
156
|
-
model:
|
|
334
|
+
model: options.model,
|
|
157
335
|
backend: this.backendName
|
|
158
336
|
};
|
|
159
337
|
this.callOnUsage(result.usage);
|
|
160
338
|
}
|
|
161
339
|
}
|
|
162
340
|
/** Wrap a stream to enrich usage_update events and fire onUsage callback */
|
|
163
|
-
async *enrichStream(source) {
|
|
341
|
+
async *enrichStream(source, options) {
|
|
342
|
+
const model = options.model;
|
|
164
343
|
for await (const event of source) {
|
|
165
344
|
if (event.type === "usage_update") {
|
|
166
345
|
const usage = {
|
|
167
346
|
promptTokens: event.promptTokens,
|
|
168
347
|
completionTokens: event.completionTokens,
|
|
169
|
-
model
|
|
348
|
+
model,
|
|
170
349
|
backend: this.backendName
|
|
171
350
|
};
|
|
172
351
|
this.callOnUsage(usage);
|
|
@@ -236,6 +415,35 @@ var BaseAgent = class {
|
|
|
236
415
|
heartbeatResolve = null;
|
|
237
416
|
}
|
|
238
417
|
}
|
|
418
|
+
// ─── Activity Timeout ────────────────────────────────────────
|
|
419
|
+
/** Wrap a stream to abort on inactivity. Resets timer on every event.
|
|
420
|
+
* When timeoutMs is not set, passes through directly. */
|
|
421
|
+
async *activityTimeoutStream(source, timeoutMs, ac) {
|
|
422
|
+
if (!timeoutMs || timeoutMs <= 0) {
|
|
423
|
+
yield* source;
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
427
|
+
let timerId;
|
|
428
|
+
try {
|
|
429
|
+
while (true) {
|
|
430
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
431
|
+
timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
|
|
432
|
+
});
|
|
433
|
+
const result = await Promise.race([iterator.next(), timeoutPromise]);
|
|
434
|
+
clearTimeout(timerId);
|
|
435
|
+
if (result.done) break;
|
|
436
|
+
yield result.value;
|
|
437
|
+
}
|
|
438
|
+
} catch (err) {
|
|
439
|
+
if (err instanceof ActivityTimeoutError) {
|
|
440
|
+
ac.abort(err);
|
|
441
|
+
}
|
|
442
|
+
throw err;
|
|
443
|
+
} finally {
|
|
444
|
+
clearTimeout(timerId);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
239
447
|
// ─── Guards ───────────────────────────────────────────────────
|
|
240
448
|
guardReentrancy() {
|
|
241
449
|
if (this.state === "running" || this.state === "streaming") {
|
|
@@ -254,16 +462,24 @@ var BaseAgent = class {
|
|
|
254
462
|
}
|
|
255
463
|
}
|
|
256
464
|
// ─── Internal Helpers ─────────────────────────────────────────
|
|
465
|
+
/** Clean up after a run completes (success, error, or abort). */
|
|
466
|
+
cleanupRun() {
|
|
467
|
+
this._cleanupExternalSignal?.();
|
|
468
|
+
this._cleanupExternalSignal = null;
|
|
469
|
+
this.state = "idle";
|
|
470
|
+
this.abortController = null;
|
|
471
|
+
}
|
|
257
472
|
createAbortController(externalSignal) {
|
|
258
473
|
const ac = new AbortController();
|
|
259
474
|
this.abortController = ac;
|
|
475
|
+
this._cleanupExternalSignal = null;
|
|
260
476
|
if (externalSignal) {
|
|
261
477
|
if (externalSignal.aborted) {
|
|
262
478
|
ac.abort();
|
|
263
479
|
} else {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
480
|
+
const listener = () => ac.abort();
|
|
481
|
+
externalSignal.addEventListener("abort", listener, { once: true });
|
|
482
|
+
this._cleanupExternalSignal = () => externalSignal.removeEventListener("abort", listener);
|
|
267
483
|
}
|
|
268
484
|
}
|
|
269
485
|
return ac;
|
|
@@ -326,13 +542,67 @@ function extractSchemaFromDef(schema) {
|
|
|
326
542
|
}
|
|
327
543
|
}
|
|
328
544
|
|
|
545
|
+
// src/backends/shared.ts
|
|
546
|
+
function extractLastUserPrompt(messages) {
|
|
547
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
548
|
+
const msg = messages[i];
|
|
549
|
+
if (msg.role === "user") {
|
|
550
|
+
return getTextContent(msg.content);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return "";
|
|
554
|
+
}
|
|
555
|
+
function serializeToolCall(tc) {
|
|
556
|
+
const args = typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args);
|
|
557
|
+
return ` Tool call: ${tc.name}(${args})`;
|
|
558
|
+
}
|
|
559
|
+
function serializeToolResult(tr) {
|
|
560
|
+
const result = typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
|
|
561
|
+
const prefix = tr.isError ? "[ERROR] " : "";
|
|
562
|
+
return ` ${tr.name} \u2192 ${prefix}${result}`;
|
|
563
|
+
}
|
|
564
|
+
function buildContextualPrompt(messages) {
|
|
565
|
+
if (messages.length <= 1) {
|
|
566
|
+
return extractLastUserPrompt(messages);
|
|
567
|
+
}
|
|
568
|
+
const history = messages.slice(0, -1).map((msg) => {
|
|
569
|
+
if (msg.role === "user") {
|
|
570
|
+
return `User: ${msg.content ? getTextContent(msg.content) : ""}`;
|
|
571
|
+
}
|
|
572
|
+
if (msg.role === "tool" && msg.toolResults) {
|
|
573
|
+
const results = msg.toolResults.map(serializeToolResult).join("\n");
|
|
574
|
+
return `Tool results:
|
|
575
|
+
${results}`;
|
|
576
|
+
}
|
|
577
|
+
if (msg.role === "assistant") {
|
|
578
|
+
const parts = [];
|
|
579
|
+
const thinking = msg.thinking;
|
|
580
|
+
if (thinking) {
|
|
581
|
+
parts.push(`[reasoning: ${thinking}]`);
|
|
582
|
+
}
|
|
583
|
+
const text2 = msg.content ? getTextContent(msg.content) : "";
|
|
584
|
+
if (text2) parts.push(text2);
|
|
585
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
586
|
+
parts.push(msg.toolCalls.map(serializeToolCall).join("\n"));
|
|
587
|
+
}
|
|
588
|
+
return `Assistant: ${parts.join("\n")}`;
|
|
589
|
+
}
|
|
590
|
+
const text = msg.content ? getTextContent(msg.content) : "";
|
|
591
|
+
return `${msg.role}: ${text}`;
|
|
592
|
+
}).join("\n");
|
|
593
|
+
const lastPrompt = extractLastUserPrompt(messages);
|
|
594
|
+
return `Conversation history:
|
|
595
|
+
${history}
|
|
596
|
+
|
|
597
|
+
User: ${lastPrompt}`;
|
|
598
|
+
}
|
|
599
|
+
|
|
329
600
|
// src/backends/copilot.ts
|
|
330
|
-
var
|
|
601
|
+
var _sdkMock = null;
|
|
331
602
|
async function loadSDK() {
|
|
332
|
-
if (
|
|
603
|
+
if (_sdkMock) return _sdkMock;
|
|
333
604
|
try {
|
|
334
|
-
|
|
335
|
-
return sdkModule;
|
|
605
|
+
return await import('@github/copilot-sdk');
|
|
336
606
|
} catch {
|
|
337
607
|
throw new SubprocessError(
|
|
338
608
|
"@github/copilot-sdk is not installed. Install it: npm install @github/copilot-sdk"
|
|
@@ -340,18 +610,34 @@ async function loadSDK() {
|
|
|
340
610
|
}
|
|
341
611
|
}
|
|
342
612
|
function _injectSDK(mock) {
|
|
343
|
-
|
|
613
|
+
_sdkMock = mock;
|
|
344
614
|
}
|
|
345
615
|
function _resetSDK() {
|
|
346
|
-
|
|
616
|
+
_sdkMock = null;
|
|
347
617
|
}
|
|
348
618
|
function mapToolsToSDK(tools) {
|
|
349
619
|
return tools.map((tool) => ({
|
|
350
620
|
name: tool.name,
|
|
351
621
|
description: tool.description,
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
622
|
+
parameters: convertParameters(tool.parameters),
|
|
623
|
+
handler: async (args) => {
|
|
624
|
+
const result = await tool.execute(args);
|
|
625
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
626
|
+
}
|
|
627
|
+
}));
|
|
628
|
+
}
|
|
629
|
+
function convertParameters(params) {
|
|
630
|
+
if (!params) return void 0;
|
|
631
|
+
if (params && typeof params === "object" && "_def" in params) {
|
|
632
|
+
return zodToJsonSchema(params);
|
|
633
|
+
}
|
|
634
|
+
return params;
|
|
635
|
+
}
|
|
636
|
+
async function mapToolsToSDKAsync(tools) {
|
|
637
|
+
return tools.map((tool) => ({
|
|
638
|
+
name: tool.name,
|
|
639
|
+
description: tool.description,
|
|
640
|
+
parameters: convertParameters(tool.parameters),
|
|
355
641
|
handler: async (args) => {
|
|
356
642
|
const result = await tool.execute(args);
|
|
357
643
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
@@ -372,6 +658,7 @@ function buildPermissionHandler(config) {
|
|
|
372
658
|
const unifiedRequest = {
|
|
373
659
|
toolName,
|
|
374
660
|
toolArgs: { ...request },
|
|
661
|
+
toolCallId: request.toolCallId,
|
|
375
662
|
rawSDKRequest: request
|
|
376
663
|
};
|
|
377
664
|
const ac = new AbortController();
|
|
@@ -514,15 +801,21 @@ function mapSessionEvent(event, tracker, thinkingTracker) {
|
|
|
514
801
|
};
|
|
515
802
|
case "session.error":
|
|
516
803
|
console.error("[copilot] mapSessionEvent error:", JSON.stringify(data));
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
804
|
+
{
|
|
805
|
+
const errorMsg = String(data.message ?? "Unknown error");
|
|
806
|
+
const code = classifyAgentError(errorMsg);
|
|
807
|
+
return {
|
|
808
|
+
type: "error",
|
|
809
|
+
error: errorMsg,
|
|
810
|
+
recoverable: isRecoverableErrorCode(code),
|
|
811
|
+
code
|
|
812
|
+
};
|
|
813
|
+
}
|
|
522
814
|
case "assistant.message": {
|
|
523
815
|
const doneEvent = {
|
|
524
816
|
type: "done",
|
|
525
|
-
finalOutput:
|
|
817
|
+
finalOutput: null,
|
|
818
|
+
streamed: true
|
|
526
819
|
};
|
|
527
820
|
if (thinkingTracker.endThinking()) {
|
|
528
821
|
return [{ type: "thinking_end" }, doneEvent];
|
|
@@ -542,13 +835,16 @@ var CopilotAgent = class extends BaseAgent {
|
|
|
542
835
|
isPersistent;
|
|
543
836
|
persistentSession = null;
|
|
544
837
|
_sessionId;
|
|
838
|
+
_persistentModel;
|
|
545
839
|
activeSession = null;
|
|
546
|
-
|
|
840
|
+
_resumeSessionId;
|
|
841
|
+
_toolsReady = null;
|
|
842
|
+
constructor(config, getClient, sendAndWaitTimeout, resumeSessionId) {
|
|
547
843
|
super(config);
|
|
548
844
|
this.getClient = getClient;
|
|
549
845
|
this.sendAndWaitTimeout = sendAndWaitTimeout;
|
|
550
846
|
this.isPersistent = config.sessionMode === "persistent";
|
|
551
|
-
this.sdkTools = mapToolsToSDK(config.tools);
|
|
847
|
+
this.sdkTools = mapToolsToSDK(config.tools ?? []);
|
|
552
848
|
this.sessionConfig = {
|
|
553
849
|
model: config.model,
|
|
554
850
|
tools: this.sdkTools,
|
|
@@ -558,8 +854,16 @@ var CopilotAgent = class extends BaseAgent {
|
|
|
558
854
|
},
|
|
559
855
|
onPermissionRequest: buildPermissionHandler(config),
|
|
560
856
|
onUserInputRequest: buildUserInputHandler(config),
|
|
561
|
-
...config.availableTools ? { availableTools: config.availableTools } : {}
|
|
857
|
+
...config.availableTools?.length ? { availableTools: config.availableTools } : {}
|
|
562
858
|
};
|
|
859
|
+
this._toolsReady = this._initToolsAsync(config);
|
|
860
|
+
this._resumeSessionId = resumeSessionId;
|
|
861
|
+
}
|
|
862
|
+
/** Pre-convert Zod schemas to JSON Schema asynchronously.
|
|
863
|
+
* Updates sdkTools and sessionConfig.tools before first session creation. */
|
|
864
|
+
async _initToolsAsync(config) {
|
|
865
|
+
this.sdkTools = await mapToolsToSDKAsync(config.tools ?? []);
|
|
866
|
+
this.sessionConfig.tools = this.sdkTools;
|
|
563
867
|
}
|
|
564
868
|
get sessionId() {
|
|
565
869
|
return this._sessionId;
|
|
@@ -582,27 +886,63 @@ var CopilotAgent = class extends BaseAgent {
|
|
|
582
886
|
});
|
|
583
887
|
this.persistentSession = null;
|
|
584
888
|
this._sessionId = void 0;
|
|
889
|
+
this._persistentModel = void 0;
|
|
585
890
|
}
|
|
586
891
|
}
|
|
587
|
-
async getOrCreateSession(streaming) {
|
|
892
|
+
async getOrCreateSession(streaming, options) {
|
|
588
893
|
if (this.isPersistent && this.persistentSession) {
|
|
589
|
-
|
|
894
|
+
if (options.model !== this._persistentModel) {
|
|
895
|
+
this.persistentSession.destroy().catch(() => {
|
|
896
|
+
});
|
|
897
|
+
this.persistentSession = null;
|
|
898
|
+
this._sessionId = void 0;
|
|
899
|
+
} else {
|
|
900
|
+
return { session: this.persistentSession, isNew: false };
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
if (this._toolsReady) {
|
|
904
|
+
await this._toolsReady;
|
|
905
|
+
this._toolsReady = null;
|
|
906
|
+
}
|
|
907
|
+
const sessionConfig = { ...this.sessionConfig };
|
|
908
|
+
sessionConfig.model = options.model;
|
|
909
|
+
const resolvedTools = this.resolveTools(options);
|
|
910
|
+
if (options?.tools) {
|
|
911
|
+
sessionConfig.tools = mapToolsToSDK(resolvedTools);
|
|
590
912
|
}
|
|
591
913
|
const client = await this.getClient();
|
|
914
|
+
if (this._resumeSessionId) {
|
|
915
|
+
const storedId = this._resumeSessionId;
|
|
916
|
+
this._resumeSessionId = void 0;
|
|
917
|
+
try {
|
|
918
|
+
const session2 = await client.resumeSession(storedId, {
|
|
919
|
+
...sessionConfig,
|
|
920
|
+
streaming: this.isPersistent ? true : streaming
|
|
921
|
+
});
|
|
922
|
+
if (this.isPersistent) {
|
|
923
|
+
this.persistentSession = session2;
|
|
924
|
+
this._sessionId = session2.sessionId;
|
|
925
|
+
this._persistentModel = options.model;
|
|
926
|
+
}
|
|
927
|
+
return { session: session2, isNew: false };
|
|
928
|
+
} catch {
|
|
929
|
+
}
|
|
930
|
+
}
|
|
592
931
|
const session = await client.createSession({
|
|
593
|
-
...
|
|
932
|
+
...sessionConfig,
|
|
594
933
|
streaming: this.isPersistent ? true : streaming
|
|
595
934
|
});
|
|
596
935
|
if (this.isPersistent) {
|
|
597
936
|
this.persistentSession = session;
|
|
598
937
|
this._sessionId = session.sessionId;
|
|
938
|
+
this._persistentModel = options.model;
|
|
599
939
|
}
|
|
600
940
|
return { session, isNew: true };
|
|
601
941
|
}
|
|
602
942
|
// ─── executeRun ─────────────────────────────────────────────────
|
|
603
|
-
async executeRun(messages,
|
|
943
|
+
async executeRun(messages, options, signal) {
|
|
604
944
|
this.checkAbort(signal);
|
|
605
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(false);
|
|
945
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(false, options);
|
|
606
946
|
this.activeSession = session;
|
|
607
947
|
const prompt = this.isPersistent && !isNewSession ? extractLastUserPrompt(messages) : buildContextualPrompt(messages);
|
|
608
948
|
const tracker = new ToolCallTracker();
|
|
@@ -699,9 +1039,9 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
699
1039
|
};
|
|
700
1040
|
}
|
|
701
1041
|
// ─── executeStream ──────────────────────────────────────────────
|
|
702
|
-
async *executeStream(messages,
|
|
1042
|
+
async *executeStream(messages, options, signal) {
|
|
703
1043
|
this.checkAbort(signal);
|
|
704
|
-
const { session, isNew: isNewSession } = await this.getOrCreateSession(true);
|
|
1044
|
+
const { session, isNew: isNewSession } = await this.getOrCreateSession(true, options);
|
|
705
1045
|
this.activeSession = session;
|
|
706
1046
|
if (isNewSession) {
|
|
707
1047
|
yield this.emitSessionInfo(session.sessionId);
|
|
@@ -787,28 +1127,20 @@ You MUST respond with ONLY valid JSON matching this schema:
|
|
|
787
1127
|
super.dispose();
|
|
788
1128
|
}
|
|
789
1129
|
};
|
|
790
|
-
function
|
|
791
|
-
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
const text = msg.content ? getTextContent(msg.content) : "";
|
|
805
|
-
return msg.role === "user" ? `User: ${text}` : `Assistant: ${text}`;
|
|
806
|
-
}).join("\n");
|
|
807
|
-
const lastPrompt = extractLastUserPrompt(messages);
|
|
808
|
-
return `Conversation history:
|
|
809
|
-
${history}
|
|
810
|
-
|
|
811
|
-
User: ${lastPrompt}`;
|
|
1130
|
+
function withTimeout(promise, ms, message) {
|
|
1131
|
+
return new Promise((resolve, reject) => {
|
|
1132
|
+
const timer = setTimeout(() => reject(new SubprocessError(message)), ms);
|
|
1133
|
+
promise.then(
|
|
1134
|
+
(val) => {
|
|
1135
|
+
clearTimeout(timer);
|
|
1136
|
+
resolve(val);
|
|
1137
|
+
},
|
|
1138
|
+
(err) => {
|
|
1139
|
+
clearTimeout(timer);
|
|
1140
|
+
reject(err);
|
|
1141
|
+
}
|
|
1142
|
+
);
|
|
1143
|
+
});
|
|
812
1144
|
}
|
|
813
1145
|
var CopilotAgentService = class {
|
|
814
1146
|
name = "copilot";
|
|
@@ -834,12 +1166,17 @@ var CopilotAgentService = class {
|
|
|
834
1166
|
autoRestart: true,
|
|
835
1167
|
logLevel: "error",
|
|
836
1168
|
githubToken: this.options.githubToken,
|
|
837
|
-
useLoggedInUser: this.options.useLoggedInUser ??
|
|
1169
|
+
useLoggedInUser: this.options.useLoggedInUser ?? !this.options.githubToken,
|
|
838
1170
|
...this.options.cliArgs ? { cliArgs: this.options.cliArgs } : {},
|
|
839
1171
|
...this.options.env ? { env: { ...process.env, ...this.options.env } } : {}
|
|
840
1172
|
});
|
|
841
|
-
|
|
842
|
-
|
|
1173
|
+
const startupTimeout = this.options.startupTimeoutMs ?? 3e4;
|
|
1174
|
+
await withTimeout(client.start(), startupTimeout, "CLI startup timed out");
|
|
1175
|
+
const auth = await withTimeout(
|
|
1176
|
+
client.getAuthStatus(),
|
|
1177
|
+
startupTimeout,
|
|
1178
|
+
"Auth status check timed out \u2014 token may be expired"
|
|
1179
|
+
);
|
|
843
1180
|
if (!auth.isAuthenticated) {
|
|
844
1181
|
await client.stop();
|
|
845
1182
|
throw new SubprocessError(
|
|
@@ -857,7 +1194,7 @@ var CopilotAgentService = class {
|
|
|
857
1194
|
}
|
|
858
1195
|
createAgent(config) {
|
|
859
1196
|
if (this.disposed) throw new DisposedError("CopilotAgentService");
|
|
860
|
-
return new CopilotAgent(config, () => this.ensureClient(), this.options.timeout);
|
|
1197
|
+
return new CopilotAgent(config, () => this.ensureClient(), this.options.timeout, this.options.resumeSessionId);
|
|
861
1198
|
}
|
|
862
1199
|
async listModels() {
|
|
863
1200
|
const client = await this.ensureClient();
|
|
@@ -865,7 +1202,10 @@ var CopilotAgentService = class {
|
|
|
865
1202
|
return models.map((m) => ({
|
|
866
1203
|
id: m.id,
|
|
867
1204
|
name: m.name,
|
|
868
|
-
provider: "copilot"
|
|
1205
|
+
provider: "copilot",
|
|
1206
|
+
...m.capabilities?.limits?.max_context_window_tokens != null && {
|
|
1207
|
+
contextWindow: m.capabilities.limits.max_context_window_tokens
|
|
1208
|
+
}
|
|
869
1209
|
}));
|
|
870
1210
|
}
|
|
871
1211
|
async validate() {
|