@librechat/agents 3.1.84 → 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/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/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/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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { config } from 'dotenv';
|
|
2
2
|
import { tool, DynamicStructuredTool } from '@langchain/core/tools';
|
|
3
3
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
4
|
+
import type { ProgrammaticToolCallingJsonSchema } from './ptcTimeout';
|
|
4
5
|
import type * as t from '@/types';
|
|
5
6
|
import {
|
|
6
7
|
makeRequest,
|
|
@@ -8,6 +9,11 @@ import {
|
|
|
8
9
|
formatCompletedResponse,
|
|
9
10
|
} from './ProgrammaticToolCalling';
|
|
10
11
|
import { getCodeBaseURL } from './CodeExecutor';
|
|
12
|
+
import {
|
|
13
|
+
clampCodeApiRunTimeoutMs,
|
|
14
|
+
createCodeApiRunTimeoutSchema,
|
|
15
|
+
resolveCodeApiRunTimeoutMs,
|
|
16
|
+
} from './ptcTimeout';
|
|
11
17
|
import { Constants } from '@/common';
|
|
12
18
|
|
|
13
19
|
config();
|
|
@@ -17,7 +23,7 @@ config();
|
|
|
17
23
|
// ============================================================================
|
|
18
24
|
|
|
19
25
|
const DEFAULT_MAX_ROUND_TRIPS = 20;
|
|
20
|
-
const
|
|
26
|
+
const DEFAULT_RUN_TIMEOUT_MS = resolveCodeApiRunTimeoutMs();
|
|
21
27
|
|
|
22
28
|
/** Bash reserved words that get `_tool` suffix when used as function names */
|
|
23
29
|
const BASH_RESERVED = new Set([
|
|
@@ -60,7 +66,8 @@ const CORE_RULES = `Rules:
|
|
|
60
66
|
- Tools are pre-defined as bash functions—DO NOT redefine them
|
|
61
67
|
- Each tool function accepts a JSON string argument
|
|
62
68
|
- Only echo/printf output returns to the model
|
|
63
|
-
- Generated files are automatically available in /mnt/data/ for subsequent executions
|
|
69
|
+
- Generated files are automatically available in /mnt/data/ for subsequent executions
|
|
70
|
+
- timeout caps one sandbox run/replay iteration, not the total multi-round-trip workflow`;
|
|
64
71
|
|
|
65
72
|
const ADDITIONAL_RULES =
|
|
66
73
|
'- Tool names normalized: hyphens→underscores, reserved words get `_tool` suffix';
|
|
@@ -92,25 +99,25 @@ ${CORE_RULES}`;
|
|
|
92
99
|
// Schema
|
|
93
100
|
// ============================================================================
|
|
94
101
|
|
|
95
|
-
export
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
default: DEFAULT_TIMEOUT,
|
|
108
|
-
description:
|
|
109
|
-
'Maximum execution time in milliseconds. Default: 60 seconds. Max: 5 minutes.',
|
|
102
|
+
export function createBashProgrammaticToolCallingSchema(
|
|
103
|
+
maxRunTimeoutMs = DEFAULT_RUN_TIMEOUT_MS
|
|
104
|
+
): ProgrammaticToolCallingJsonSchema {
|
|
105
|
+
return {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
code: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
minLength: 1,
|
|
111
|
+
description: CODE_PARAM_DESCRIPTION,
|
|
112
|
+
},
|
|
113
|
+
timeout: createCodeApiRunTimeoutSchema(maxRunTimeoutMs),
|
|
110
114
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
115
|
+
required: ['code'],
|
|
116
|
+
} as const;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const BashProgrammaticToolCallingSchema =
|
|
120
|
+
createBashProgrammaticToolCallingSchema();
|
|
114
121
|
|
|
115
122
|
export const BashProgrammaticToolCallingName =
|
|
116
123
|
Constants.BASH_PROGRAMMATIC_TOOL_CALLING;
|
|
@@ -242,6 +249,7 @@ export function createBashProgrammaticToolCallingTool(
|
|
|
242
249
|
): DynamicStructuredTool {
|
|
243
250
|
const baseUrl = initParams.baseUrl ?? getCodeBaseURL();
|
|
244
251
|
const maxRoundTrips = initParams.maxRoundTrips ?? DEFAULT_MAX_ROUND_TRIPS;
|
|
252
|
+
const maxRunTimeoutMs = resolveCodeApiRunTimeoutMs(initParams.runTimeoutMs);
|
|
245
253
|
const proxy = initParams.proxy ?? process.env.PROXY;
|
|
246
254
|
const debug = initParams.debug ?? process.env.BASH_PTC_DEBUG === 'true';
|
|
247
255
|
const EXEC_ENDPOINT = `${baseUrl}/exec/programmatic`;
|
|
@@ -249,7 +257,8 @@ export function createBashProgrammaticToolCallingTool(
|
|
|
249
257
|
return tool(
|
|
250
258
|
async (rawParams, config) => {
|
|
251
259
|
const params = rawParams as { code: string; timeout?: number };
|
|
252
|
-
const { code
|
|
260
|
+
const { code } = params;
|
|
261
|
+
const timeout = clampCodeApiRunTimeoutMs(params.timeout, maxRunTimeoutMs);
|
|
253
262
|
|
|
254
263
|
const toolCall = (config.toolCall ?? {}) as ToolCall &
|
|
255
264
|
Partial<t.ProgrammaticCache> & {
|
|
@@ -382,7 +391,7 @@ export function createBashProgrammaticToolCallingTool(
|
|
|
382
391
|
{
|
|
383
392
|
name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
|
|
384
393
|
description: BashProgrammaticToolCallingDescription,
|
|
385
|
-
schema:
|
|
394
|
+
schema: createBashProgrammaticToolCallingSchema(maxRunTimeoutMs),
|
|
386
395
|
responseFormat: Constants.CONTENT_AND_ARTIFACT,
|
|
387
396
|
}
|
|
388
397
|
);
|
|
@@ -4,6 +4,7 @@ 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
9
|
import {
|
|
9
10
|
buildCodeApiHttpErrorMessage,
|
|
@@ -11,6 +12,11 @@ import {
|
|
|
11
12
|
getCodeBaseURL,
|
|
12
13
|
resolveCodeApiAuthHeaders,
|
|
13
14
|
} from './CodeExecutor';
|
|
15
|
+
import {
|
|
16
|
+
clampCodeApiRunTimeoutMs,
|
|
17
|
+
createCodeApiRunTimeoutSchema,
|
|
18
|
+
resolveCodeApiRunTimeoutMs,
|
|
19
|
+
} from './ptcTimeout';
|
|
14
20
|
import { Constants } from '@/common';
|
|
15
21
|
|
|
16
22
|
config();
|
|
@@ -18,8 +24,7 @@ config();
|
|
|
18
24
|
/** Default max round-trips to prevent infinite loops */
|
|
19
25
|
const DEFAULT_MAX_ROUND_TRIPS = 20;
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
const DEFAULT_TIMEOUT = 60000;
|
|
27
|
+
const DEFAULT_RUN_TIMEOUT_MS = resolveCodeApiRunTimeoutMs();
|
|
23
28
|
|
|
24
29
|
// ============================================================================
|
|
25
30
|
// Description Components (Single Source of Truth)
|
|
@@ -35,7 +40,8 @@ const CORE_RULES = `Rules:
|
|
|
35
40
|
- Just write code with await—auto-wrapped in async context
|
|
36
41
|
- DO NOT define async def main() or call asyncio.run()
|
|
37
42
|
- Tools are pre-defined—DO NOT write function definitions
|
|
38
|
-
- 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`;
|
|
39
45
|
|
|
40
46
|
const ADDITIONAL_RULES = `- Generated files are automatically available in /mnt/data/ for subsequent executions
|
|
41
47
|
- Tool names normalized: hyphens→underscores, keywords get \`_tool\` suffix`;
|
|
@@ -68,25 +74,25 @@ ${EXAMPLES}
|
|
|
68
74
|
|
|
69
75
|
${CORE_RULES}`;
|
|
70
76
|
|
|
71
|
-
export
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
default: DEFAULT_TIMEOUT,
|
|
84
|
-
description:
|
|
85
|
-
'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),
|
|
86
89
|
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
+
required: ['code'],
|
|
91
|
+
} as const;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const ProgrammaticToolCallingSchema =
|
|
95
|
+
createProgrammaticToolCallingSchema();
|
|
90
96
|
|
|
91
97
|
export const ProgrammaticToolCallingName = Constants.PROGRAMMATIC_TOOL_CALLING;
|
|
92
98
|
|
|
@@ -731,6 +737,7 @@ export function createProgrammaticToolCallingTool(
|
|
|
731
737
|
): DynamicStructuredTool {
|
|
732
738
|
const baseUrl = initParams.baseUrl ?? getCodeBaseURL();
|
|
733
739
|
const maxRoundTrips = initParams.maxRoundTrips ?? DEFAULT_MAX_ROUND_TRIPS;
|
|
740
|
+
const maxRunTimeoutMs = resolveCodeApiRunTimeoutMs(initParams.runTimeoutMs);
|
|
734
741
|
const proxy = initParams.proxy ?? process.env.PROXY;
|
|
735
742
|
const debug = initParams.debug ?? process.env.PTC_DEBUG === 'true';
|
|
736
743
|
const EXEC_ENDPOINT = `${baseUrl}/exec/programmatic`;
|
|
@@ -738,7 +745,8 @@ export function createProgrammaticToolCallingTool(
|
|
|
738
745
|
return tool(
|
|
739
746
|
async (rawParams, config) => {
|
|
740
747
|
const params = rawParams as { code: string; timeout?: number };
|
|
741
|
-
const { code
|
|
748
|
+
const { code } = params;
|
|
749
|
+
const timeout = clampCodeApiRunTimeoutMs(params.timeout, maxRunTimeoutMs);
|
|
742
750
|
|
|
743
751
|
// Extra params injected by ToolNode (follows web_search pattern).
|
|
744
752
|
const toolCall = (config.toolCall ?? {}) as ToolCall &
|
|
@@ -873,7 +881,7 @@ export function createProgrammaticToolCallingTool(
|
|
|
873
881
|
{
|
|
874
882
|
name: Constants.PROGRAMMATIC_TOOL_CALLING,
|
|
875
883
|
description: ProgrammaticToolCallingDescription,
|
|
876
|
-
schema:
|
|
884
|
+
schema: createProgrammaticToolCallingSchema(maxRunTimeoutMs),
|
|
877
885
|
responseFormat: Constants.CONTENT_AND_ARTIFACT,
|
|
878
886
|
}
|
|
879
887
|
);
|
|
@@ -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) */
|