@librechat/agents 3.1.83 → 3.1.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs +26 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +1 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +2 -1
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +5 -1
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -2
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/main.cjs +4 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +5 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +26 -24
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +28 -2
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +130 -56
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +7 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +52 -13
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ptcTimeout.cjs +56 -0
- package/dist/cjs/tools/ptcTimeout.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +27 -4
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +1 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +2 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +5 -1
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +3 -2
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/main.mjs +3 -3
- package/dist/esm/tools/BashExecutor.mjs +6 -3
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +26 -25
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +27 -3
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +131 -58
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +7 -5
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +54 -15
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ptcTimeout.mjs +50 -0
- package/dist/esm/tools/ptcTimeout.mjs.map +1 -0
- package/dist/types/agents/AgentContext.d.ts +3 -1
- package/dist/types/common/enum.d.ts +2 -1
- package/dist/types/tools/BashProgrammaticToolCalling.d.ts +4 -36
- package/dist/types/tools/CodeExecutor.d.ts +5 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +18 -39
- package/dist/types/tools/ptcTimeout.d.ts +25 -0
- package/dist/types/types/tools.d.ts +8 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +32 -3
- package/src/agents/__tests__/AgentContext.test.ts +36 -3
- package/src/common/enum.ts +1 -0
- package/src/events.ts +4 -1
- package/src/graphs/MultiAgentGraph.ts +3 -2
- package/src/graphs/__tests__/composition.smoke.test.ts +84 -2
- package/src/tools/BashExecutor.ts +14 -3
- package/src/tools/BashProgrammaticToolCalling.ts +37 -25
- package/src/tools/CodeExecutor.ts +36 -2
- package/src/tools/ProgrammaticToolCalling.ts +206 -53
- package/src/tools/ToolNode.ts +3 -4
- package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +424 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +31 -1
- package/src/tools/local/LocalProgrammaticToolCalling.ts +94 -13
- package/src/tools/ptcTimeout.ts +89 -0
- package/src/types/tools.ts +12 -0
|
@@ -4,8 +4,19 @@ import fetch, { RequestInit } from 'node-fetch';
|
|
|
4
4
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
5
5
|
import { tool, DynamicStructuredTool } from '@langchain/core/tools';
|
|
6
6
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
7
|
+
import type { ProgrammaticToolCallingJsonSchema } from './ptcTimeout';
|
|
7
8
|
import type * as t from '@/types';
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
buildCodeApiHttpErrorMessage,
|
|
11
|
+
emptyOutputMessage,
|
|
12
|
+
getCodeBaseURL,
|
|
13
|
+
resolveCodeApiAuthHeaders,
|
|
14
|
+
} from './CodeExecutor';
|
|
15
|
+
import {
|
|
16
|
+
clampCodeApiRunTimeoutMs,
|
|
17
|
+
createCodeApiRunTimeoutSchema,
|
|
18
|
+
resolveCodeApiRunTimeoutMs,
|
|
19
|
+
} from './ptcTimeout';
|
|
9
20
|
import { Constants } from '@/common';
|
|
10
21
|
|
|
11
22
|
config();
|
|
@@ -13,8 +24,7 @@ config();
|
|
|
13
24
|
/** Default max round-trips to prevent infinite loops */
|
|
14
25
|
const DEFAULT_MAX_ROUND_TRIPS = 20;
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
const DEFAULT_TIMEOUT = 60000;
|
|
27
|
+
const DEFAULT_RUN_TIMEOUT_MS = resolveCodeApiRunTimeoutMs();
|
|
18
28
|
|
|
19
29
|
// ============================================================================
|
|
20
30
|
// Description Components (Single Source of Truth)
|
|
@@ -30,7 +40,8 @@ const CORE_RULES = `Rules:
|
|
|
30
40
|
- Just write code with await—auto-wrapped in async context
|
|
31
41
|
- DO NOT define async def main() or call asyncio.run()
|
|
32
42
|
- Tools are pre-defined—DO NOT write function definitions
|
|
33
|
-
- Only print() output returns to the model
|
|
43
|
+
- Only print() output returns to the model
|
|
44
|
+
- timeout caps one sandbox run/replay iteration, not the total multi-round-trip workflow`;
|
|
34
45
|
|
|
35
46
|
const ADDITIONAL_RULES = `- Generated files are automatically available in /mnt/data/ for subsequent executions
|
|
36
47
|
- Tool names normalized: hyphens→underscores, keywords get \`_tool\` suffix`;
|
|
@@ -63,25 +74,25 @@ ${EXAMPLES}
|
|
|
63
74
|
|
|
64
75
|
${CORE_RULES}`;
|
|
65
76
|
|
|
66
|
-
export
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
default: DEFAULT_TIMEOUT,
|
|
79
|
-
description:
|
|
80
|
-
'Maximum execution time in milliseconds. Default: 60 seconds. Max: 5 minutes.',
|
|
77
|
+
export function createProgrammaticToolCallingSchema(
|
|
78
|
+
maxRunTimeoutMs = DEFAULT_RUN_TIMEOUT_MS
|
|
79
|
+
): ProgrammaticToolCallingJsonSchema {
|
|
80
|
+
return {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
code: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
minLength: 1,
|
|
86
|
+
description: CODE_PARAM_DESCRIPTION,
|
|
87
|
+
},
|
|
88
|
+
timeout: createCodeApiRunTimeoutSchema(maxRunTimeoutMs),
|
|
81
89
|
},
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
90
|
+
required: ['code'],
|
|
91
|
+
} as const;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const ProgrammaticToolCallingSchema =
|
|
95
|
+
createProgrammaticToolCallingSchema();
|
|
85
96
|
|
|
86
97
|
export const ProgrammaticToolCallingName = Constants.PROGRAMMATIC_TOOL_CALLING;
|
|
87
98
|
|
|
@@ -147,6 +158,113 @@ const PYTHON_KEYWORDS = new Set([
|
|
|
147
158
|
'yield',
|
|
148
159
|
]);
|
|
149
160
|
|
|
161
|
+
export type FetchSessionFilesScope =
|
|
162
|
+
| { kind: 'skill'; id: string; version: number }
|
|
163
|
+
| { kind: 'agent' | 'user'; id: string; version?: never };
|
|
164
|
+
|
|
165
|
+
type CodeApiSessionFileWire = {
|
|
166
|
+
id?: unknown;
|
|
167
|
+
name?: unknown;
|
|
168
|
+
metadata?: unknown;
|
|
169
|
+
resource_id?: unknown;
|
|
170
|
+
storage_session_id?: unknown;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
type CodeApiSessionFileMetadata = {
|
|
174
|
+
'original-filename'?: unknown;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
function isFetchSessionFilesScope(
|
|
178
|
+
value: unknown
|
|
179
|
+
): value is FetchSessionFilesScope {
|
|
180
|
+
if (value == null || typeof value !== 'object') {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const scope = value as { kind?: unknown; id?: unknown; version?: unknown };
|
|
184
|
+
if (
|
|
185
|
+
(scope.kind === 'agent' || scope.kind === 'user') &&
|
|
186
|
+
typeof scope.id === 'string'
|
|
187
|
+
) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return (
|
|
191
|
+
scope.kind === 'skill' &&
|
|
192
|
+
typeof scope.id === 'string' &&
|
|
193
|
+
typeof scope.version === 'number'
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function isCodeApiAuthHeaders(
|
|
198
|
+
value: string | t.CodeApiAuthHeaders | undefined
|
|
199
|
+
): value is t.CodeApiAuthHeaders {
|
|
200
|
+
return value != null && typeof value !== 'string';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function isCodeApiSessionFileWire(
|
|
204
|
+
value: unknown
|
|
205
|
+
): value is CodeApiSessionFileWire {
|
|
206
|
+
return value != null && typeof value === 'object';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function isCodeApiSessionFileMetadata(
|
|
210
|
+
value: unknown
|
|
211
|
+
): value is CodeApiSessionFileMetadata {
|
|
212
|
+
return value != null && typeof value === 'object';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function normalizeSessionFile(
|
|
216
|
+
file: CodeApiSessionFileWire,
|
|
217
|
+
sessionId: string,
|
|
218
|
+
scope?: FetchSessionFilesScope
|
|
219
|
+
): t.CodeEnvFile {
|
|
220
|
+
const metadata = isCodeApiSessionFileMetadata(file.metadata)
|
|
221
|
+
? file.metadata
|
|
222
|
+
: undefined;
|
|
223
|
+
const rawName = typeof file.name === 'string' ? file.name : '';
|
|
224
|
+
const nameParts = rawName.split('/');
|
|
225
|
+
const fallbackId = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
|
|
226
|
+
const id =
|
|
227
|
+
typeof file.id === 'string' && file.id !== '' ? file.id : fallbackId;
|
|
228
|
+
const originalFilename = metadata?.['original-filename'];
|
|
229
|
+
const name =
|
|
230
|
+
typeof originalFilename === 'string' ? originalFilename : rawName;
|
|
231
|
+
const storage_session_id =
|
|
232
|
+
typeof file.storage_session_id === 'string'
|
|
233
|
+
? file.storage_session_id
|
|
234
|
+
: sessionId;
|
|
235
|
+
const resource_id =
|
|
236
|
+
typeof file.resource_id === 'string' && file.resource_id !== ''
|
|
237
|
+
? file.resource_id
|
|
238
|
+
: (scope?.id ?? id);
|
|
239
|
+
|
|
240
|
+
if (scope?.kind === 'skill') {
|
|
241
|
+
return {
|
|
242
|
+
storage_session_id,
|
|
243
|
+
kind: 'skill',
|
|
244
|
+
id,
|
|
245
|
+
resource_id,
|
|
246
|
+
name,
|
|
247
|
+
version: scope.version,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (scope != null) {
|
|
251
|
+
return {
|
|
252
|
+
storage_session_id,
|
|
253
|
+
kind: scope.kind,
|
|
254
|
+
id,
|
|
255
|
+
resource_id,
|
|
256
|
+
name,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
storage_session_id,
|
|
261
|
+
kind: 'user',
|
|
262
|
+
id,
|
|
263
|
+
resource_id: id,
|
|
264
|
+
name,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
150
268
|
/**
|
|
151
269
|
* Normalizes a tool name to Python identifier format.
|
|
152
270
|
* Must match the Code API's `normalizePythonFunctionName` exactly:
|
|
@@ -250,20 +368,62 @@ export function filterToolsByUsage(
|
|
|
250
368
|
* Files are returned as CodeEnvFile references to be included in the request.
|
|
251
369
|
* @param baseUrl - The base URL for the Code API
|
|
252
370
|
* @param sessionId - The session ID to fetch files from
|
|
371
|
+
* @param scope - Resource scope used by CodeAPI to authorize the session
|
|
253
372
|
* @param proxy - Optional HTTP proxy URL
|
|
254
373
|
* @returns Array of CodeEnvFile references, or empty array if fetch fails
|
|
255
374
|
*/
|
|
256
375
|
export async function fetchSessionFiles(
|
|
257
376
|
baseUrl: string,
|
|
258
377
|
sessionId: string,
|
|
259
|
-
proxy?: string
|
|
378
|
+
proxy?: string,
|
|
379
|
+
authHeaders?: t.CodeApiAuthHeaders
|
|
380
|
+
): Promise<t.CodeEnvFile[]>;
|
|
381
|
+
export async function fetchSessionFiles(
|
|
382
|
+
baseUrl: string,
|
|
383
|
+
sessionId: string,
|
|
384
|
+
scope: FetchSessionFilesScope,
|
|
385
|
+
proxyOrAuthHeaders?: string | t.CodeApiAuthHeaders,
|
|
386
|
+
authHeaders?: t.CodeApiAuthHeaders
|
|
387
|
+
): Promise<t.CodeEnvFile[]>;
|
|
388
|
+
export async function fetchSessionFiles(
|
|
389
|
+
baseUrl: string,
|
|
390
|
+
sessionId: string,
|
|
391
|
+
scopeOrProxy?: FetchSessionFilesScope | string,
|
|
392
|
+
proxyOrAuthHeaders?: string | t.CodeApiAuthHeaders,
|
|
393
|
+
scopedAuthHeaders?: t.CodeApiAuthHeaders
|
|
260
394
|
): Promise<t.CodeEnvFile[]> {
|
|
261
395
|
try {
|
|
262
|
-
const
|
|
396
|
+
const scope = isFetchSessionFilesScope(scopeOrProxy)
|
|
397
|
+
? scopeOrProxy
|
|
398
|
+
: undefined;
|
|
399
|
+
let proxy: string | undefined;
|
|
400
|
+
let authHeaders: t.CodeApiAuthHeaders | undefined;
|
|
401
|
+
if (scope == null) {
|
|
402
|
+
proxy = typeof scopeOrProxy === 'string' ? scopeOrProxy : undefined;
|
|
403
|
+
authHeaders = isCodeApiAuthHeaders(proxyOrAuthHeaders)
|
|
404
|
+
? proxyOrAuthHeaders
|
|
405
|
+
: undefined;
|
|
406
|
+
} else if (typeof proxyOrAuthHeaders === 'string') {
|
|
407
|
+
proxy = proxyOrAuthHeaders;
|
|
408
|
+
authHeaders = scopedAuthHeaders;
|
|
409
|
+
} else {
|
|
410
|
+
authHeaders = proxyOrAuthHeaders ?? scopedAuthHeaders;
|
|
411
|
+
}
|
|
412
|
+
const query = new URLSearchParams({ detail: 'full' });
|
|
413
|
+
if (scope != null) {
|
|
414
|
+
query.set('kind', scope.kind);
|
|
415
|
+
query.set('id', scope.id);
|
|
416
|
+
if (scope.kind === 'skill') {
|
|
417
|
+
query.set('version', String(scope.version));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const filesEndpoint = `${baseUrl}/files/${encodeURIComponent(sessionId)}?${query.toString()}`;
|
|
421
|
+
const resolvedAuthHeaders = await resolveCodeApiAuthHeaders(authHeaders);
|
|
263
422
|
const fetchOptions: RequestInit = {
|
|
264
423
|
method: 'GET',
|
|
265
424
|
headers: {
|
|
266
425
|
'User-Agent': 'LibreChat/1.0',
|
|
426
|
+
...resolvedAuthHeaders,
|
|
267
427
|
},
|
|
268
428
|
};
|
|
269
429
|
|
|
@@ -273,7 +433,9 @@ export async function fetchSessionFiles(
|
|
|
273
433
|
|
|
274
434
|
const response = await fetch(filesEndpoint, fetchOptions);
|
|
275
435
|
if (!response.ok) {
|
|
276
|
-
throw new Error(
|
|
436
|
+
throw new Error(
|
|
437
|
+
await buildCodeApiHttpErrorMessage('GET', filesEndpoint, response)
|
|
438
|
+
);
|
|
277
439
|
}
|
|
278
440
|
|
|
279
441
|
const files = await response.json();
|
|
@@ -281,25 +443,9 @@ export async function fetchSessionFiles(
|
|
|
281
443
|
return [];
|
|
282
444
|
}
|
|
283
445
|
|
|
284
|
-
return files
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const id = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
storage_session_id: sessionId,
|
|
291
|
-
/* `/files` fallback returns code-output files belonging to
|
|
292
|
-
* the user; tag them user-private. */
|
|
293
|
-
kind: 'user' as const,
|
|
294
|
-
id,
|
|
295
|
-
/* `resource_id` informational for `kind: 'user'` —
|
|
296
|
-
* codeapi derives sessionKey from auth context. */
|
|
297
|
-
resource_id: id,
|
|
298
|
-
name: (file.metadata as Record<string, unknown>)[
|
|
299
|
-
'original-filename'
|
|
300
|
-
] as string,
|
|
301
|
-
};
|
|
302
|
-
});
|
|
446
|
+
return files
|
|
447
|
+
.filter(isCodeApiSessionFileWire)
|
|
448
|
+
.map((file) => normalizeSessionFile(file, sessionId, scope));
|
|
303
449
|
} catch (error) {
|
|
304
450
|
// eslint-disable-next-line no-console
|
|
305
451
|
console.warn(
|
|
@@ -319,13 +465,16 @@ export async function fetchSessionFiles(
|
|
|
319
465
|
export async function makeRequest(
|
|
320
466
|
endpoint: string,
|
|
321
467
|
body: Record<string, unknown>,
|
|
322
|
-
proxy?: string
|
|
468
|
+
proxy?: string,
|
|
469
|
+
authHeaders?: t.CodeApiAuthHeaders
|
|
323
470
|
): Promise<t.ProgrammaticExecutionResponse> {
|
|
471
|
+
const resolvedAuthHeaders = await resolveCodeApiAuthHeaders(authHeaders);
|
|
324
472
|
const fetchOptions: RequestInit = {
|
|
325
473
|
method: 'POST',
|
|
326
474
|
headers: {
|
|
327
475
|
'Content-Type': 'application/json',
|
|
328
476
|
'User-Agent': 'LibreChat/1.0',
|
|
477
|
+
...resolvedAuthHeaders,
|
|
329
478
|
},
|
|
330
479
|
body: JSON.stringify(body),
|
|
331
480
|
};
|
|
@@ -337,9 +486,8 @@ export async function makeRequest(
|
|
|
337
486
|
const response = await fetch(endpoint, fetchOptions);
|
|
338
487
|
|
|
339
488
|
if (!response.ok) {
|
|
340
|
-
const errorText = await response.text();
|
|
341
489
|
throw new Error(
|
|
342
|
-
|
|
490
|
+
await buildCodeApiHttpErrorMessage('POST', endpoint, response)
|
|
343
491
|
);
|
|
344
492
|
}
|
|
345
493
|
|
|
@@ -486,7 +634,8 @@ export function unwrapToolResponse(
|
|
|
486
634
|
*/
|
|
487
635
|
export async function executeTools(
|
|
488
636
|
toolCalls: t.PTCToolCall[],
|
|
489
|
-
toolMap: t.ToolMap
|
|
637
|
+
toolMap: t.ToolMap,
|
|
638
|
+
programmaticToolName = Constants.PROGRAMMATIC_TOOL_CALLING
|
|
490
639
|
): Promise<t.PTCToolResult[]> {
|
|
491
640
|
const executions = toolCalls.map(async (call): Promise<t.PTCToolResult> => {
|
|
492
641
|
const tool = toolMap.get(call.name);
|
|
@@ -502,7 +651,7 @@ export async function executeTools(
|
|
|
502
651
|
|
|
503
652
|
try {
|
|
504
653
|
const result = await tool.invoke(call.input, {
|
|
505
|
-
metadata: { [
|
|
654
|
+
metadata: { [programmaticToolName]: true },
|
|
506
655
|
});
|
|
507
656
|
|
|
508
657
|
const isMCPTool = tool.mcp === true;
|
|
@@ -588,6 +737,7 @@ export function createProgrammaticToolCallingTool(
|
|
|
588
737
|
): DynamicStructuredTool {
|
|
589
738
|
const baseUrl = initParams.baseUrl ?? getCodeBaseURL();
|
|
590
739
|
const maxRoundTrips = initParams.maxRoundTrips ?? DEFAULT_MAX_ROUND_TRIPS;
|
|
740
|
+
const maxRunTimeoutMs = resolveCodeApiRunTimeoutMs(initParams.runTimeoutMs);
|
|
591
741
|
const proxy = initParams.proxy ?? process.env.PROXY;
|
|
592
742
|
const debug = initParams.debug ?? process.env.PTC_DEBUG === 'true';
|
|
593
743
|
const EXEC_ENDPOINT = `${baseUrl}/exec/programmatic`;
|
|
@@ -595,7 +745,8 @@ export function createProgrammaticToolCallingTool(
|
|
|
595
745
|
return tool(
|
|
596
746
|
async (rawParams, config) => {
|
|
597
747
|
const params = rawParams as { code: string; timeout?: number };
|
|
598
|
-
const { code
|
|
748
|
+
const { code } = params;
|
|
749
|
+
const timeout = clampCodeApiRunTimeoutMs(params.timeout, maxRunTimeoutMs);
|
|
599
750
|
|
|
600
751
|
// Extra params injected by ToolNode (follows web_search pattern).
|
|
601
752
|
const toolCall = (config.toolCall ?? {}) as ToolCall &
|
|
@@ -661,7 +812,8 @@ export function createProgrammaticToolCallingTool(
|
|
|
661
812
|
timeout,
|
|
662
813
|
...(files && files.length > 0 ? { files } : {}),
|
|
663
814
|
},
|
|
664
|
-
proxy
|
|
815
|
+
proxy,
|
|
816
|
+
initParams.authHeaders
|
|
665
817
|
);
|
|
666
818
|
|
|
667
819
|
// ====================================================================
|
|
@@ -697,7 +849,8 @@ export function createProgrammaticToolCallingTool(
|
|
|
697
849
|
continuation_token: response.continuation_token,
|
|
698
850
|
tool_results: toolResults,
|
|
699
851
|
},
|
|
700
|
-
proxy
|
|
852
|
+
proxy,
|
|
853
|
+
initParams.authHeaders
|
|
701
854
|
);
|
|
702
855
|
}
|
|
703
856
|
|
|
@@ -728,7 +881,7 @@ export function createProgrammaticToolCallingTool(
|
|
|
728
881
|
{
|
|
729
882
|
name: Constants.PROGRAMMATIC_TOOL_CALLING,
|
|
730
883
|
description: ProgrammaticToolCallingDescription,
|
|
731
|
-
schema:
|
|
884
|
+
schema: createProgrammaticToolCallingSchema(maxRunTimeoutMs),
|
|
732
885
|
responseFormat: Constants.CONTENT_AND_ARTIFACT,
|
|
733
886
|
}
|
|
734
887
|
);
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -844,10 +844,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
844
844
|
// Plumb the hook context into the programmatic-tool path so
|
|
845
845
|
// inner tool calls made via the in-process bridge can run
|
|
846
846
|
// through `PreToolUse` (deny / updatedInput) before reaching
|
|
847
|
-
// the underlying tool. Without this,
|
|
848
|
-
//
|
|
849
|
-
//
|
|
850
|
-
// `write_file` / `edit_file` (manual review finding A).
|
|
847
|
+
// the underlying tool. Without this, programmatic tool calls
|
|
848
|
+
// bypass every PreToolUse hook the host registered for the tools
|
|
849
|
+
// they dispatch — including HITL gates on `write_file` / `edit_file`.
|
|
851
850
|
hookContext: {
|
|
852
851
|
registry: this.hookRegistry,
|
|
853
852
|
runId: (config.configurable?.run_id as string | undefined) ?? '',
|