@librechat/agents 3.1.84 → 3.1.86
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 +7 -2
- 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/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 +2 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +23 -21
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +23 -22
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +4 -1
- 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 +7 -2
- 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/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 +2 -2
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +23 -22
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +23 -23
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +4 -1
- 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/common/enum.d.ts +2 -1
- package/dist/types/tools/BashProgrammaticToolCalling.d.ts +4 -36
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +4 -36
- package/dist/types/tools/ptcTimeout.d.ts +25 -0
- package/dist/types/types/tools.d.ts +2 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +7 -2
- package/src/agents/__tests__/AgentContext.test.ts +254 -5
- package/src/common/enum.ts +1 -0
- package/src/graphs/MultiAgentGraph.ts +3 -2
- package/src/graphs/__tests__/composition.smoke.test.ts +84 -2
- package/src/tools/BashProgrammaticToolCalling.ts +31 -22
- package/src/tools/ProgrammaticToolCalling.ts +31 -23
- package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +103 -0
- package/src/tools/local/LocalProgrammaticToolCalling.ts +94 -13
- package/src/tools/ptcTimeout.ts +89 -0
- package/src/types/tools.ts +2 -0
|
@@ -13,6 +13,14 @@ import {
|
|
|
13
13
|
makeRequest,
|
|
14
14
|
} from '../ProgrammaticToolCalling';
|
|
15
15
|
import { createBashProgrammaticToolCallingTool } from '../BashProgrammaticToolCalling';
|
|
16
|
+
import {
|
|
17
|
+
clampCodeApiRunTimeoutMs,
|
|
18
|
+
createCodeApiRunTimeoutSchema,
|
|
19
|
+
} from '../ptcTimeout';
|
|
20
|
+
import {
|
|
21
|
+
createLocalProgrammaticToolCallingTool,
|
|
22
|
+
createLocalBashProgrammaticToolCallingTool,
|
|
23
|
+
} from '../local/LocalProgrammaticToolCalling';
|
|
16
24
|
|
|
17
25
|
jest.mock('node-fetch', () => ({
|
|
18
26
|
__esModule: true,
|
|
@@ -23,8 +31,33 @@ type FetchMock = jest.MockedFunction<
|
|
|
23
31
|
(url: unknown, init?: unknown) => Promise<unknown>
|
|
24
32
|
>;
|
|
25
33
|
|
|
34
|
+
type CodeApiRequestBody = {
|
|
35
|
+
timeout?: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type TimeoutSchemaForTest = {
|
|
39
|
+
default: number;
|
|
40
|
+
maximum: number;
|
|
41
|
+
description: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type ToolSchemaForTest = {
|
|
45
|
+
properties: {
|
|
46
|
+
timeout: TimeoutSchemaForTest;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
26
50
|
const fetchMock = fetch as unknown as FetchMock;
|
|
27
51
|
|
|
52
|
+
function requestBodyAt(callIndex: number): CodeApiRequestBody {
|
|
53
|
+
const init = fetchMock.mock.calls[callIndex]?.[1] as RequestInit;
|
|
54
|
+
return JSON.parse(init.body as string) as CodeApiRequestBody;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function timeoutSchemaForTest(toolSchema: unknown): TimeoutSchemaForTest {
|
|
58
|
+
return (toolSchema as ToolSchemaForTest).properties.timeout;
|
|
59
|
+
}
|
|
60
|
+
|
|
28
61
|
function jsonResponse(body: unknown): unknown {
|
|
29
62
|
return {
|
|
30
63
|
ok: true,
|
|
@@ -203,6 +236,76 @@ describe('CodeAPI auth header injection', () => {
|
|
|
203
236
|
}
|
|
204
237
|
});
|
|
205
238
|
|
|
239
|
+
it('defaults programmatic timeout to the configured CodeAPI run cap', async () => {
|
|
240
|
+
const tool = createProgrammaticToolCallingTool({
|
|
241
|
+
runTimeoutMs: 15000,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
await tool.invoke(
|
|
245
|
+
{ code: 'result = await lookup_user()\nprint(result)' },
|
|
246
|
+
{
|
|
247
|
+
toolCall: {
|
|
248
|
+
name: 'programmatic_code_execution',
|
|
249
|
+
args: {},
|
|
250
|
+
toolMap: toolMap(),
|
|
251
|
+
toolDefs,
|
|
252
|
+
},
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
expect(requestBodyAt(0).timeout).toBe(15000);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('defaults bash programmatic timeout to the configured CodeAPI run cap', async () => {
|
|
260
|
+
const tool = createBashProgrammaticToolCallingTool({
|
|
261
|
+
runTimeoutMs: 15000,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
await tool.invoke(
|
|
265
|
+
{ code: 'lookup_user "{}"' },
|
|
266
|
+
{
|
|
267
|
+
toolCall: {
|
|
268
|
+
name: 'bash_programmatic_code_execution',
|
|
269
|
+
args: {},
|
|
270
|
+
toolMap: toolMap(),
|
|
271
|
+
toolDefs,
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
expect(requestBodyAt(0).timeout).toBe(15000);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('describes the PTC timeout as a single sandbox run cap', () => {
|
|
280
|
+
const schema = createCodeApiRunTimeoutSchema(15000);
|
|
281
|
+
|
|
282
|
+
expect(clampCodeApiRunTimeoutMs(60000, 15000)).toBe(15000);
|
|
283
|
+
expect(schema.default).toBe(15000);
|
|
284
|
+
expect(schema.maximum).toBe(15000);
|
|
285
|
+
expect(schema.description).toContain('one sandbox run');
|
|
286
|
+
expect(schema.description).toContain('not the total multi-round-trip');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('keeps local programmatic timeout schemas aligned with local execution defaults', () => {
|
|
290
|
+
const pythonTimeout = timeoutSchemaForTest(
|
|
291
|
+
createLocalProgrammaticToolCallingTool().schema
|
|
292
|
+
);
|
|
293
|
+
const bashTimeout = timeoutSchemaForTest(
|
|
294
|
+
createLocalBashProgrammaticToolCallingTool().schema
|
|
295
|
+
);
|
|
296
|
+
const configuredTimeout = timeoutSchemaForTest(
|
|
297
|
+
createLocalProgrammaticToolCallingTool({ timeoutMs: 120000 }).schema
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
expect(pythonTimeout.default).toBe(60000);
|
|
301
|
+
expect(pythonTimeout.maximum).toBe(300000);
|
|
302
|
+
expect(pythonTimeout.description).toContain('local execution time');
|
|
303
|
+
expect(bashTimeout.default).toBe(60000);
|
|
304
|
+
expect(bashTimeout.maximum).toBe(300000);
|
|
305
|
+
expect(configuredTimeout.default).toBe(120000);
|
|
306
|
+
expect(configuredTimeout.maximum).toBe(300000);
|
|
307
|
+
});
|
|
308
|
+
|
|
206
309
|
it('forwards Authorization for bash programmatic requests', async () => {
|
|
207
310
|
const tool = createBashProgrammaticToolCallingTool({
|
|
208
311
|
authHeaders: { Authorization: 'Bearer bash-ptc-token' },
|
|
@@ -30,19 +30,100 @@ import {
|
|
|
30
30
|
import { Constants } from '@/common';
|
|
31
31
|
|
|
32
32
|
const DEFAULT_TIMEOUT = 60000;
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const LOCAL_MIN_TIMEOUT = 1000;
|
|
34
|
+
const LOCAL_MAX_TIMEOUT = 300000;
|
|
35
|
+
|
|
36
|
+
type LocalTimeoutSchema = {
|
|
37
|
+
type: 'integer';
|
|
38
|
+
minimum: number;
|
|
39
|
+
maximum: number;
|
|
40
|
+
default: number;
|
|
41
|
+
description: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type LocalProgrammaticToolCallingJsonSchema = {
|
|
45
|
+
type: 'object';
|
|
46
|
+
properties: typeof ProgrammaticToolCallingSchema.properties & {
|
|
47
|
+
timeout: LocalTimeoutSchema;
|
|
37
48
|
lang: {
|
|
38
|
-
type: 'string'
|
|
39
|
-
enum: ['py', 'python', 'bash', 'sh']
|
|
40
|
-
default: 'bash'
|
|
41
|
-
description:
|
|
42
|
-
|
|
49
|
+
type: 'string';
|
|
50
|
+
enum: readonly ['py', 'python', 'bash', 'sh'];
|
|
51
|
+
default: 'bash';
|
|
52
|
+
description: string;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
required: readonly ['code'];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type LocalBashProgrammaticToolCallingJsonSchema = {
|
|
59
|
+
type: 'object';
|
|
60
|
+
properties: typeof BashProgrammaticToolCallingSchema.properties & {
|
|
61
|
+
timeout: LocalTimeoutSchema;
|
|
62
|
+
};
|
|
63
|
+
required: readonly ['code'];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function normalizeLocalTimeout(timeoutMs: number | undefined): number {
|
|
67
|
+
if (timeoutMs == null || !Number.isFinite(timeoutMs)) {
|
|
68
|
+
return DEFAULT_TIMEOUT;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return Math.max(LOCAL_MIN_TIMEOUT, Math.floor(timeoutMs));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatLocalTimeout(timeoutMs: number): string {
|
|
75
|
+
return timeoutMs % 1000 === 0
|
|
76
|
+
? `${timeoutMs / 1000} seconds`
|
|
77
|
+
: `${timeoutMs} milliseconds`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createLocalTimeoutSchema(timeoutMs?: number): LocalTimeoutSchema {
|
|
81
|
+
const defaultTimeout = normalizeLocalTimeout(timeoutMs);
|
|
82
|
+
const maxTimeout = Math.max(LOCAL_MAX_TIMEOUT, defaultTimeout);
|
|
83
|
+
const formattedDefault = formatLocalTimeout(defaultTimeout);
|
|
84
|
+
const formattedMax = formatLocalTimeout(maxTimeout);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
type: 'integer',
|
|
88
|
+
minimum: LOCAL_MIN_TIMEOUT,
|
|
89
|
+
maximum: maxTimeout,
|
|
90
|
+
default: defaultTimeout,
|
|
91
|
+
description:
|
|
92
|
+
'Maximum local execution time in milliseconds. ' +
|
|
93
|
+
`Default: ${formattedDefault}. Max: ${formattedMax}.`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createLocalProgrammaticToolCallingSchema(
|
|
98
|
+
localConfig: t.LocalExecutionConfig = {}
|
|
99
|
+
): LocalProgrammaticToolCallingJsonSchema {
|
|
100
|
+
return {
|
|
101
|
+
...ProgrammaticToolCallingSchema,
|
|
102
|
+
properties: {
|
|
103
|
+
...ProgrammaticToolCallingSchema.properties,
|
|
104
|
+
timeout: createLocalTimeoutSchema(localConfig.timeoutMs),
|
|
105
|
+
lang: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
enum: ['py', 'python', 'bash', 'sh'],
|
|
108
|
+
default: 'bash',
|
|
109
|
+
description:
|
|
110
|
+
'Local engine runtime for orchestration code. Defaults to bash; use py/python for Python orchestration.',
|
|
111
|
+
},
|
|
43
112
|
},
|
|
44
|
-
}
|
|
45
|
-
}
|
|
113
|
+
} as const;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function createLocalBashProgrammaticToolCallingSchema(
|
|
117
|
+
localConfig: t.LocalExecutionConfig = {}
|
|
118
|
+
): LocalBashProgrammaticToolCallingJsonSchema {
|
|
119
|
+
return {
|
|
120
|
+
...BashProgrammaticToolCallingSchema,
|
|
121
|
+
properties: {
|
|
122
|
+
...BashProgrammaticToolCallingSchema.properties,
|
|
123
|
+
timeout: createLocalTimeoutSchema(localConfig.timeoutMs),
|
|
124
|
+
},
|
|
125
|
+
} as const;
|
|
126
|
+
}
|
|
46
127
|
|
|
47
128
|
type ToolBridge = {
|
|
48
129
|
url: string;
|
|
@@ -582,7 +663,7 @@ export function createLocalProgrammaticToolCallingTool(
|
|
|
582
663
|
{
|
|
583
664
|
name: ProgrammaticToolCallingName,
|
|
584
665
|
description: `${ProgrammaticToolCallingDescription}\n\nLocal engine: runs bash by default, or Python when \`lang\` is \`py\` or \`python\`, on the host machine and calls tools through an in-process localhost bridge.`,
|
|
585
|
-
schema:
|
|
666
|
+
schema: createLocalProgrammaticToolCallingSchema(localConfig),
|
|
586
667
|
responseFormat: Constants.CONTENT_AND_ARTIFACT,
|
|
587
668
|
}
|
|
588
669
|
);
|
|
@@ -604,7 +685,7 @@ export function createLocalBashProgrammaticToolCallingTool(
|
|
|
604
685
|
{
|
|
605
686
|
name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
|
|
606
687
|
description: `${BashProgrammaticToolCallingDescription}\n\nLocal engine: runs this bash orchestration code on the host machine and calls tools through an in-process localhost bridge.`,
|
|
607
|
-
schema:
|
|
688
|
+
schema: createLocalBashProgrammaticToolCallingSchema(localConfig),
|
|
608
689
|
responseFormat: Constants.CONTENT_AND_ARTIFACT,
|
|
609
690
|
}
|
|
610
691
|
);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { EnvVar } from '@/common';
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_CODE_API_RUN_TIMEOUT_MS = 15_000;
|
|
4
|
+
export const MIN_CODE_API_RUN_TIMEOUT_MS = 1_000;
|
|
5
|
+
|
|
6
|
+
type TimeoutSchema = {
|
|
7
|
+
type: 'integer';
|
|
8
|
+
minimum: number;
|
|
9
|
+
maximum: number;
|
|
10
|
+
default: number;
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ProgrammaticToolCallingJsonSchema = {
|
|
15
|
+
type: 'object';
|
|
16
|
+
properties: {
|
|
17
|
+
code: {
|
|
18
|
+
type: 'string';
|
|
19
|
+
minLength: number;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
timeout: TimeoutSchema;
|
|
23
|
+
};
|
|
24
|
+
required: readonly ['code'];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function normalizeTimeoutMs(value: number | undefined): number | undefined {
|
|
28
|
+
if (value == null || !Number.isFinite(value)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return Math.max(MIN_CODE_API_RUN_TIMEOUT_MS, Math.floor(value));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parseTimeoutMs(value: string | undefined): number | undefined {
|
|
36
|
+
if (value == null || value.trim() === '') {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return normalizeTimeoutMs(Number(value));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function formatTimeout(timeoutMs: number): string {
|
|
44
|
+
return timeoutMs % 1000 === 0
|
|
45
|
+
? `${timeoutMs / 1000} seconds`
|
|
46
|
+
: `${timeoutMs} milliseconds`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function resolveCodeApiRunTimeoutMs(override?: number): number {
|
|
50
|
+
return (
|
|
51
|
+
normalizeTimeoutMs(override) ??
|
|
52
|
+
parseTimeoutMs(process.env[EnvVar.CODE_API_RUN_TIMEOUT_MS]) ??
|
|
53
|
+
DEFAULT_CODE_API_RUN_TIMEOUT_MS
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function clampCodeApiRunTimeoutMs(
|
|
58
|
+
timeoutMs: number | undefined,
|
|
59
|
+
maxRunTimeoutMs = resolveCodeApiRunTimeoutMs()
|
|
60
|
+
): number {
|
|
61
|
+
const normalizedMaxRunTimeoutMs =
|
|
62
|
+
normalizeTimeoutMs(maxRunTimeoutMs) ?? DEFAULT_CODE_API_RUN_TIMEOUT_MS;
|
|
63
|
+
const normalizedTimeoutMs = normalizeTimeoutMs(timeoutMs);
|
|
64
|
+
|
|
65
|
+
if (normalizedTimeoutMs == null) {
|
|
66
|
+
return normalizedMaxRunTimeoutMs;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return Math.min(normalizedTimeoutMs, normalizedMaxRunTimeoutMs);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createCodeApiRunTimeoutSchema(
|
|
73
|
+
maxRunTimeoutMs = resolveCodeApiRunTimeoutMs()
|
|
74
|
+
): TimeoutSchema {
|
|
75
|
+
const normalizedMaxRunTimeoutMs =
|
|
76
|
+
normalizeTimeoutMs(maxRunTimeoutMs) ?? DEFAULT_CODE_API_RUN_TIMEOUT_MS;
|
|
77
|
+
const formattedTimeout = formatTimeout(normalizedMaxRunTimeoutMs);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
type: 'integer',
|
|
81
|
+
minimum: MIN_CODE_API_RUN_TIMEOUT_MS,
|
|
82
|
+
maximum: normalizedMaxRunTimeoutMs,
|
|
83
|
+
default: normalizedMaxRunTimeoutMs,
|
|
84
|
+
description:
|
|
85
|
+
'Maximum wall-clock time in milliseconds for one sandbox run or replay iteration. ' +
|
|
86
|
+
'This is not the total multi-round-trip task budget. ' +
|
|
87
|
+
`Default: ${formattedTimeout}. Max: ${formattedTimeout}.`,
|
|
88
|
+
};
|
|
89
|
+
}
|
package/src/types/tools.ts
CHANGED
|
@@ -900,6 +900,8 @@ export type ProgrammaticToolCallingParams = {
|
|
|
900
900
|
baseUrl?: string;
|
|
901
901
|
/** Safety limit for round-trips (default: 20) */
|
|
902
902
|
maxRoundTrips?: number;
|
|
903
|
+
/** Maximum per-sandbox-run timeout for PTC's legacy `timeout` field. */
|
|
904
|
+
runTimeoutMs?: number;
|
|
903
905
|
/** HTTP proxy URL */
|
|
904
906
|
proxy?: string;
|
|
905
907
|
/** Enable debug logging (or set PTC_DEBUG=true env var) */
|