llm-cli-gateway 1.0.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/CHANGELOG.md +541 -0
- package/LICENSE +21 -0
- package/README.md +545 -0
- package/dist/approval-manager.d.ts +43 -0
- package/dist/approval-manager.js +156 -0
- package/dist/async-job-manager.d.ts +57 -0
- package/dist/async-job-manager.js +334 -0
- package/dist/claude-mcp-config.d.ts +8 -0
- package/dist/claude-mcp-config.js +161 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.js +56 -0
- package/dist/db.d.ts +48 -0
- package/dist/db.js +170 -0
- package/dist/executor.d.ts +30 -0
- package/dist/executor.js +315 -0
- package/dist/health.d.ts +20 -0
- package/dist/health.js +32 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +1503 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.js +5 -0
- package/dist/metrics.d.ts +23 -0
- package/dist/metrics.js +57 -0
- package/dist/migrate-sessions.d.ts +12 -0
- package/dist/migrate-sessions.js +145 -0
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.js +100 -0
- package/dist/model-registry.d.ts +10 -0
- package/dist/model-registry.js +346 -0
- package/dist/optimizer.d.ts +3 -0
- package/dist/optimizer.js +183 -0
- package/dist/process-monitor.d.ts +54 -0
- package/dist/process-monitor.js +146 -0
- package/dist/request-helpers.d.ts +25 -0
- package/dist/request-helpers.js +32 -0
- package/dist/resources.d.ts +26 -0
- package/dist/resources.js +201 -0
- package/dist/retry.d.ts +72 -0
- package/dist/retry.js +146 -0
- package/dist/review-integrity.d.ts +50 -0
- package/dist/review-integrity.js +283 -0
- package/dist/session-manager-pg.d.ts +76 -0
- package/dist/session-manager-pg.js +383 -0
- package/dist/session-manager.d.ts +62 -0
- package/dist/session-manager.js +223 -0
- package/dist/stream-json-parser.d.ts +35 -0
- package/dist/stream-json-parser.js +94 -0
- package/package.json +90 -0
package/dist/executor.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { readdirSync, existsSync } from "fs";
|
|
5
|
+
import { createCircuitBreaker, withRetry } from "./retry.js";
|
|
6
|
+
const MAX_OUTPUT_SIZE = 50 * 1024 * 1024;
|
|
7
|
+
const circuitBreakers = new Map();
|
|
8
|
+
let cachedNvmPath;
|
|
9
|
+
function getCircuitBreaker(command) {
|
|
10
|
+
const existing = circuitBreakers.get(command);
|
|
11
|
+
if (existing) {
|
|
12
|
+
return existing;
|
|
13
|
+
}
|
|
14
|
+
const circuitBreaker = createCircuitBreaker();
|
|
15
|
+
circuitBreakers.set(command, circuitBreaker);
|
|
16
|
+
return circuitBreaker;
|
|
17
|
+
}
|
|
18
|
+
function getNvmPath() {
|
|
19
|
+
if (cachedNvmPath !== undefined) {
|
|
20
|
+
return cachedNvmPath;
|
|
21
|
+
}
|
|
22
|
+
const home = homedir();
|
|
23
|
+
const nvmVersionsDir = join(home, ".nvm/versions/node");
|
|
24
|
+
if (!existsSync(nvmVersionsDir)) {
|
|
25
|
+
cachedNvmPath = null;
|
|
26
|
+
return cachedNvmPath;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const versions = readdirSync(nvmVersionsDir);
|
|
30
|
+
cachedNvmPath = versions.length
|
|
31
|
+
? versions.map((version) => join(nvmVersionsDir, version, "bin")).join(":")
|
|
32
|
+
: null;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
cachedNvmPath = null;
|
|
36
|
+
}
|
|
37
|
+
return cachedNvmPath;
|
|
38
|
+
}
|
|
39
|
+
// Extend PATH to include common locations for CLI tools
|
|
40
|
+
export function getExtendedPath() {
|
|
41
|
+
const home = homedir();
|
|
42
|
+
const additionalPaths = [
|
|
43
|
+
join(home, ".local/bin"),
|
|
44
|
+
dirname(process.execPath), // Current node's bin directory
|
|
45
|
+
"/usr/local/bin",
|
|
46
|
+
"/usr/bin"
|
|
47
|
+
];
|
|
48
|
+
// Add all nvm node version bin directories
|
|
49
|
+
const nvmPath = getNvmPath();
|
|
50
|
+
if (nvmPath) {
|
|
51
|
+
additionalPaths.push(nvmPath);
|
|
52
|
+
}
|
|
53
|
+
const currentPath = process.env.PATH || "";
|
|
54
|
+
return [...additionalPaths, currentPath].join(":");
|
|
55
|
+
}
|
|
56
|
+
/** Registry of active detached process groups for shutdown cleanup. */
|
|
57
|
+
const activeProcessGroups = new Set();
|
|
58
|
+
export function registerProcessGroup(pid) {
|
|
59
|
+
activeProcessGroups.add(pid);
|
|
60
|
+
}
|
|
61
|
+
export function unregisterProcessGroup(pid) {
|
|
62
|
+
activeProcessGroups.delete(pid);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Kill all active process groups. Called on gateway shutdown.
|
|
66
|
+
* Sends SIGTERM to all groups, waits 3s, then SIGKILL survivors.
|
|
67
|
+
* Returns a Promise that resolves after SIGKILL escalation completes.
|
|
68
|
+
* The returned Promise keeps the event loop alive (no .unref()),
|
|
69
|
+
* ensuring the process does NOT exit before SIGKILL fires.
|
|
70
|
+
*/
|
|
71
|
+
export function killAllProcessGroups() {
|
|
72
|
+
if (activeProcessGroups.size === 0)
|
|
73
|
+
return Promise.resolve();
|
|
74
|
+
for (const pid of activeProcessGroups) {
|
|
75
|
+
try {
|
|
76
|
+
process.kill(-pid, "SIGTERM");
|
|
77
|
+
}
|
|
78
|
+
catch { /* ESRCH ok */ }
|
|
79
|
+
}
|
|
80
|
+
return new Promise(resolve => {
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
for (const pid of activeProcessGroups) {
|
|
83
|
+
try {
|
|
84
|
+
process.kill(-pid, "SIGKILL");
|
|
85
|
+
}
|
|
86
|
+
catch { /* ESRCH ok */ }
|
|
87
|
+
}
|
|
88
|
+
activeProcessGroups.clear();
|
|
89
|
+
resolve();
|
|
90
|
+
}, 3000); // No .unref() — keeps event loop alive through escalation
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Kill an entire process group. Falls back to killing just the process
|
|
95
|
+
* if the group kill fails (e.g., pid not yet assigned).
|
|
96
|
+
*/
|
|
97
|
+
export function killProcessGroup(proc, signal) {
|
|
98
|
+
if (proc.pid) {
|
|
99
|
+
try {
|
|
100
|
+
process.kill(-proc.pid, signal);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
// ESRCH = process/group already dead — not an error
|
|
105
|
+
if (err.code !== "ESRCH") {
|
|
106
|
+
try {
|
|
107
|
+
return proc.kill(signal);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
return proc.kill(signal);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export async function executeCli(command, args, options = {}) {
|
|
124
|
+
const { timeout, idleTimeout, cwd } = options;
|
|
125
|
+
const extendedPath = getExtendedPath();
|
|
126
|
+
const circuitBreaker = getCircuitBreaker(command);
|
|
127
|
+
const runOnce = () => new Promise((resolve, reject) => {
|
|
128
|
+
const proc = spawn(command, args, {
|
|
129
|
+
cwd,
|
|
130
|
+
detached: true,
|
|
131
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
132
|
+
env: { ...process.env, PATH: extendedPath }
|
|
133
|
+
});
|
|
134
|
+
if (proc.pid)
|
|
135
|
+
registerProcessGroup(proc.pid);
|
|
136
|
+
// Prevent detached process from keeping parent alive when not needed
|
|
137
|
+
proc.unref();
|
|
138
|
+
let stdout = "";
|
|
139
|
+
let stderr = "";
|
|
140
|
+
let timedOut = false;
|
|
141
|
+
let idledOut = false;
|
|
142
|
+
let overflowed = false;
|
|
143
|
+
let exited = false;
|
|
144
|
+
let outputSize = 0;
|
|
145
|
+
let settled = false;
|
|
146
|
+
// Single cleanup flag to prevent double-unregister
|
|
147
|
+
let groupCleaned = false;
|
|
148
|
+
const cleanupProcessGroup = () => {
|
|
149
|
+
if (groupCleaned)
|
|
150
|
+
return;
|
|
151
|
+
groupCleaned = true;
|
|
152
|
+
if (proc.pid)
|
|
153
|
+
unregisterProcessGroup(proc.pid);
|
|
154
|
+
};
|
|
155
|
+
const timeoutMs = typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0 ? timeout : undefined;
|
|
156
|
+
const timeoutId = timeoutMs
|
|
157
|
+
? setTimeout(() => {
|
|
158
|
+
timedOut = true;
|
|
159
|
+
killProcessGroup(proc, "SIGTERM");
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
if (!exited)
|
|
162
|
+
killProcessGroup(proc, "SIGKILL");
|
|
163
|
+
cleanupProcessGroup();
|
|
164
|
+
}, 5000);
|
|
165
|
+
}, timeoutMs)
|
|
166
|
+
: undefined;
|
|
167
|
+
// Idle timeout: kill process if no stdout/stderr activity for idleMs
|
|
168
|
+
const idleMs = typeof idleTimeout === "number" && Number.isFinite(idleTimeout) && idleTimeout > 0
|
|
169
|
+
? idleTimeout : undefined;
|
|
170
|
+
let idleTimerId;
|
|
171
|
+
const resetIdleTimer = () => {
|
|
172
|
+
if (!idleMs)
|
|
173
|
+
return;
|
|
174
|
+
if (idleTimerId)
|
|
175
|
+
clearTimeout(idleTimerId);
|
|
176
|
+
idleTimerId = setTimeout(() => {
|
|
177
|
+
idledOut = true;
|
|
178
|
+
if (timeoutId)
|
|
179
|
+
clearTimeout(timeoutId);
|
|
180
|
+
killProcessGroup(proc, "SIGTERM");
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
if (!exited)
|
|
183
|
+
killProcessGroup(proc, "SIGKILL");
|
|
184
|
+
cleanupProcessGroup();
|
|
185
|
+
}, 5000);
|
|
186
|
+
}, idleMs);
|
|
187
|
+
};
|
|
188
|
+
// Start idle timer immediately (covers case where process never outputs)
|
|
189
|
+
resetIdleTimer();
|
|
190
|
+
const finalizeReject = (error) => {
|
|
191
|
+
if (settled) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
settled = true;
|
|
195
|
+
if (timeoutId) {
|
|
196
|
+
clearTimeout(timeoutId);
|
|
197
|
+
}
|
|
198
|
+
if (idleTimerId) {
|
|
199
|
+
clearTimeout(idleTimerId);
|
|
200
|
+
}
|
|
201
|
+
reject(error);
|
|
202
|
+
};
|
|
203
|
+
const handleOutputChunk = (data, stream) => {
|
|
204
|
+
outputSize += data.length;
|
|
205
|
+
if (outputSize > MAX_OUTPUT_SIZE) {
|
|
206
|
+
overflowed = true;
|
|
207
|
+
killProcessGroup(proc, "SIGTERM");
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
if (!exited)
|
|
210
|
+
killProcessGroup(proc, "SIGKILL");
|
|
211
|
+
cleanupProcessGroup();
|
|
212
|
+
}, 5000);
|
|
213
|
+
finalizeReject(new Error("Output exceeded maximum size (50MB)"));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
resetIdleTimer();
|
|
217
|
+
const text = data.toString();
|
|
218
|
+
if (stream === "stdout") {
|
|
219
|
+
stdout += text;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
stderr += text;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
proc.stdout.on("data", (data) => {
|
|
226
|
+
if (settled) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
handleOutputChunk(data, "stdout");
|
|
230
|
+
});
|
|
231
|
+
proc.stderr.on("data", (data) => {
|
|
232
|
+
if (settled) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
handleOutputChunk(data, "stderr");
|
|
236
|
+
});
|
|
237
|
+
proc.on("close", (code) => {
|
|
238
|
+
exited = true;
|
|
239
|
+
if (idleTimerId) {
|
|
240
|
+
clearTimeout(idleTimerId);
|
|
241
|
+
}
|
|
242
|
+
// Unregister process group on clean exit (no kill was issued)
|
|
243
|
+
if (!timedOut && !idledOut && !overflowed) {
|
|
244
|
+
cleanupProcessGroup();
|
|
245
|
+
}
|
|
246
|
+
if (settled) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (timeoutId) {
|
|
250
|
+
clearTimeout(timeoutId);
|
|
251
|
+
}
|
|
252
|
+
if (timedOut) {
|
|
253
|
+
const result = {
|
|
254
|
+
stdout,
|
|
255
|
+
stderr: stderr + `\nProcess timed out after ${timeoutMs}ms`,
|
|
256
|
+
code: 124 // Standard timeout exit code
|
|
257
|
+
};
|
|
258
|
+
const error = new Error(result.stderr);
|
|
259
|
+
error.code = 124;
|
|
260
|
+
error.result = result;
|
|
261
|
+
reject(error);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (idledOut) {
|
|
265
|
+
const result = {
|
|
266
|
+
stdout,
|
|
267
|
+
stderr: stderr + `\nProcess killed after ${idleMs}ms of inactivity`,
|
|
268
|
+
code: 125
|
|
269
|
+
};
|
|
270
|
+
const error = new Error(result.stderr);
|
|
271
|
+
error.code = 125;
|
|
272
|
+
error.result = result;
|
|
273
|
+
reject(error);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const result = { stdout, stderr, code: code ?? 0 };
|
|
277
|
+
if (result.code !== 0) {
|
|
278
|
+
const error = new Error(`Process exited with code ${result.code}`);
|
|
279
|
+
error.code = result.code;
|
|
280
|
+
error.result = result;
|
|
281
|
+
reject(error);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
resolve(result);
|
|
285
|
+
});
|
|
286
|
+
proc.on("error", (err) => {
|
|
287
|
+
exited = true;
|
|
288
|
+
if (idleTimerId) {
|
|
289
|
+
clearTimeout(idleTimerId);
|
|
290
|
+
}
|
|
291
|
+
cleanupProcessGroup();
|
|
292
|
+
if (settled) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (timeoutId) {
|
|
296
|
+
clearTimeout(timeoutId);
|
|
297
|
+
}
|
|
298
|
+
settled = true;
|
|
299
|
+
reject(err);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
try {
|
|
303
|
+
return await withRetry(runOnce, circuitBreaker, undefined, options.logger);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
if (error?.cause?.message === "Output exceeded maximum size (50MB)") {
|
|
307
|
+
throw error.cause;
|
|
308
|
+
}
|
|
309
|
+
const result = error?.result ?? error?.cause?.result;
|
|
310
|
+
if (result) {
|
|
311
|
+
return result;
|
|
312
|
+
}
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DatabaseConnection } from "./db.js";
|
|
2
|
+
export interface HealthStatus {
|
|
3
|
+
status: "healthy" | "degraded" | "unhealthy";
|
|
4
|
+
postgres: {
|
|
5
|
+
status: "up" | "down";
|
|
6
|
+
latency: number;
|
|
7
|
+
};
|
|
8
|
+
redis: {
|
|
9
|
+
status: "up" | "down";
|
|
10
|
+
latency: number;
|
|
11
|
+
};
|
|
12
|
+
timestamp: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check health status of PostgreSQL and Redis
|
|
16
|
+
* - Both up → healthy
|
|
17
|
+
* - Only PostgreSQL up → degraded (Redis down but DB works)
|
|
18
|
+
* - PostgreSQL down → unhealthy (critical failure)
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkHealth(db: DatabaseConnection): Promise<HealthStatus>;
|
package/dist/health.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check health status of PostgreSQL and Redis
|
|
3
|
+
* - Both up → healthy
|
|
4
|
+
* - Only PostgreSQL up → degraded (Redis down but DB works)
|
|
5
|
+
* - PostgreSQL down → unhealthy (critical failure)
|
|
6
|
+
*/
|
|
7
|
+
export async function checkHealth(db) {
|
|
8
|
+
const result = await db.healthCheck();
|
|
9
|
+
const health = {
|
|
10
|
+
status: "unhealthy",
|
|
11
|
+
postgres: {
|
|
12
|
+
status: result.postgres.connected ? "up" : "down",
|
|
13
|
+
latency: result.postgres.latency
|
|
14
|
+
},
|
|
15
|
+
redis: {
|
|
16
|
+
status: result.redis.connected ? "up" : "down",
|
|
17
|
+
latency: result.redis.latency
|
|
18
|
+
},
|
|
19
|
+
timestamp: new Date().toISOString()
|
|
20
|
+
};
|
|
21
|
+
// Determine overall health status
|
|
22
|
+
if (result.postgres.connected && result.redis.connected) {
|
|
23
|
+
health.status = "healthy";
|
|
24
|
+
}
|
|
25
|
+
else if (result.postgres.connected && !result.redis.connected) {
|
|
26
|
+
health.status = "degraded";
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
health.status = "unhealthy";
|
|
30
|
+
}
|
|
31
|
+
return health;
|
|
32
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { ISessionManager } from "./session-manager.js";
|
|
3
|
+
import { AsyncJobManager } from "./async-job-manager.js";
|
|
4
|
+
import { ApprovalRecord } from "./approval-manager.js";
|
|
5
|
+
import { ReviewIntegrityResult } from "./review-integrity.js";
|
|
6
|
+
import { ClaudeMcpServerName } from "./claude-mcp-config.js";
|
|
7
|
+
type ExtendedToolResponse = {
|
|
8
|
+
content: {
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}[];
|
|
12
|
+
isError?: boolean;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
resumable?: boolean;
|
|
15
|
+
approval?: ApprovalRecord | null;
|
|
16
|
+
mcpServers?: {
|
|
17
|
+
requested: ClaudeMcpServerName[];
|
|
18
|
+
enabled?: ClaudeMcpServerName[];
|
|
19
|
+
missing?: ClaudeMcpServerName[];
|
|
20
|
+
};
|
|
21
|
+
reviewIntegrity?: ReviewIntegrityResult;
|
|
22
|
+
};
|
|
23
|
+
export interface GeminiRequestParams {
|
|
24
|
+
prompt: string;
|
|
25
|
+
model?: string;
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
resumeLatest: boolean;
|
|
28
|
+
createNewSession: boolean;
|
|
29
|
+
approvalMode?: string;
|
|
30
|
+
approvalStrategy: "legacy" | "mcp_managed";
|
|
31
|
+
approvalPolicy?: string;
|
|
32
|
+
mcpServers?: ClaudeMcpServerName[];
|
|
33
|
+
allowedTools?: string[];
|
|
34
|
+
includeDirs?: string[];
|
|
35
|
+
correlationId?: string;
|
|
36
|
+
optimizePrompt: boolean;
|
|
37
|
+
optimizeResponse?: boolean;
|
|
38
|
+
idleTimeoutMs?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface HandlerDeps {
|
|
41
|
+
sessionManager: ISessionManager;
|
|
42
|
+
logger: {
|
|
43
|
+
info: (...args: any[]) => void;
|
|
44
|
+
error: (...args: any[]) => void;
|
|
45
|
+
debug: (...args: any[]) => void;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export interface AsyncHandlerDeps extends HandlerDeps {
|
|
49
|
+
asyncJobManager: AsyncJobManager;
|
|
50
|
+
}
|
|
51
|
+
export declare function handleGeminiRequest(deps: HandlerDeps, params: GeminiRequestParams): Promise<ExtendedToolResponse>;
|
|
52
|
+
export declare function handleGeminiRequestAsync(deps: AsyncHandlerDeps, params: Omit<GeminiRequestParams, "optimizeResponse">): Promise<ExtendedToolResponse>;
|
|
53
|
+
export declare function handleCodexRequestAsync(deps: AsyncHandlerDeps, params: {
|
|
54
|
+
prompt: string;
|
|
55
|
+
model?: string;
|
|
56
|
+
fullAuto: boolean;
|
|
57
|
+
dangerouslyBypassApprovalsAndSandbox: boolean;
|
|
58
|
+
approvalStrategy: "legacy" | "mcp_managed";
|
|
59
|
+
approvalPolicy?: string;
|
|
60
|
+
mcpServers?: ClaudeMcpServerName[];
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
createNewSession: boolean;
|
|
63
|
+
correlationId?: string;
|
|
64
|
+
optimizePrompt: boolean;
|
|
65
|
+
idleTimeoutMs?: number;
|
|
66
|
+
}): Promise<ExtendedToolResponse>;
|
|
67
|
+
export {};
|