@librechat/agents 3.7.11 → 3.7.12
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/main.cjs +2 -0
- package/dist/cjs/messages/format.cjs +6 -34
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +22 -6
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticCallerPolicy.cjs +10 -0
- package/dist/cjs/tools/ProgrammaticCallerPolicy.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +43 -6
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +5 -3
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/messages/format.mjs +6 -34
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +23 -7
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticCallerPolicy.mjs +10 -1
- package/dist/esm/tools/ProgrammaticCallerPolicy.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +42 -7
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +5 -3
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/types/messages/format.d.ts +2 -1
- package/dist/types/tools/ProgrammaticCallerPolicy.d.ts +12 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +35 -0
- package/package.json +1 -1
- package/src/messages/format.ts +23 -70
- package/src/tools/BashProgrammaticToolCalling.ts +57 -19
- package/src/tools/ProgrammaticCallerPolicy.ts +31 -0
- package/src/tools/ProgrammaticToolCalling.ts +132 -19
- package/src/tools/local/LocalProgrammaticToolCalling.ts +19 -8
|
@@ -22,16 +22,17 @@ import {
|
|
|
22
22
|
selectRuntimeSessionHint,
|
|
23
23
|
} from './CodeExecutor';
|
|
24
24
|
import {
|
|
25
|
-
|
|
26
|
-
createCodeApiRunTimeoutSchema,
|
|
27
|
-
resolveCodeApiRunTimeoutMs,
|
|
28
|
-
} from './ptcTimeout';
|
|
29
|
-
import {
|
|
25
|
+
assertUnambiguousIdentifiers,
|
|
30
26
|
projectProgrammaticToolMap,
|
|
31
27
|
resolveProgrammaticToolDefinitions,
|
|
32
28
|
selectProgrammaticTools,
|
|
33
29
|
type ProgrammaticInvocationParams,
|
|
34
30
|
} from './ProgrammaticCallerPolicy';
|
|
31
|
+
import {
|
|
32
|
+
clampCodeApiRunTimeoutMs,
|
|
33
|
+
createCodeApiRunTimeoutSchema,
|
|
34
|
+
resolveCodeApiRunTimeoutMs,
|
|
35
|
+
} from './ptcTimeout';
|
|
35
36
|
import { resolveFetchProxyAgent } from '@/utils/proxy';
|
|
36
37
|
import { INTENT_PROPERTY } from '@/tools/intentArg';
|
|
37
38
|
import { Constants } from '@/common';
|
|
@@ -95,7 +96,7 @@ ${CORE_RULES}`;
|
|
|
95
96
|
|
|
96
97
|
const TOOL_MANIFEST_DESCRIPTION =
|
|
97
98
|
'Exact registered tool names used by the code. Required when direct-only tools are configured; ' +
|
|
98
|
-
'validated before execution starts.';
|
|
99
|
+
'validated before execution starts. Pass [] when the code calls no tools at all.';
|
|
99
100
|
|
|
100
101
|
export function createProgrammaticToolCallingSchema(
|
|
101
102
|
maxRunTimeoutMs = DEFAULT_RUN_TIMEOUT_MS
|
|
@@ -874,6 +875,84 @@ export function formatCompletedResponse(
|
|
|
874
875
|
];
|
|
875
876
|
}
|
|
876
877
|
|
|
878
|
+
/**
|
|
879
|
+
* Mirrors the Code API's programmatic Python wrapper (`wrapUserCodeInAsync`).
|
|
880
|
+
*
|
|
881
|
+
* The programmatic contract promises top-level `await` works; plain `/exec`
|
|
882
|
+
* applies no wrapper, so forwarding source unchanged would turn valid
|
|
883
|
+
* programmatic input into a SyntaxError. The wrapper is self-contained, so a
|
|
884
|
+
* later divergence in the Code API's own copy cannot break this path.
|
|
885
|
+
*/
|
|
886
|
+
export function wrapPythonForPlainExecution(userCode: string): string {
|
|
887
|
+
const indented = userCode
|
|
888
|
+
.split('\n')
|
|
889
|
+
.map((line) => (line.trim() === '' ? '' : ` ${line}`))
|
|
890
|
+
.join('\n');
|
|
891
|
+
|
|
892
|
+
return (
|
|
893
|
+
'async def __user_main__():\n' +
|
|
894
|
+
' """Auto-generated wrapper for user code to support top-level await"""\n' +
|
|
895
|
+
`${indented}\n` +
|
|
896
|
+
'\n' +
|
|
897
|
+
'if __name__ == "__main__":\n' +
|
|
898
|
+
' import asyncio\n' +
|
|
899
|
+
' asyncio.run(__user_main__())\n'
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Runs code that selected no tools through plain `/exec`.
|
|
905
|
+
*
|
|
906
|
+
* `/exec/programmatic` rejects an empty tool manifest outright, and the sandbox
|
|
907
|
+
* has nothing to inject for such a call anyway — no stubs, no replay round
|
|
908
|
+
* trips. Routing it here makes a tool-free programmatic call behave exactly like
|
|
909
|
+
* the equivalent `execute_code`, against every deployed Code API, instead of
|
|
910
|
+
* failing with a rejection the model cannot act on.
|
|
911
|
+
*/
|
|
912
|
+
export async function runPlainExecution(args: {
|
|
913
|
+
baseUrl: string;
|
|
914
|
+
lang: 'bash' | 'py';
|
|
915
|
+
code: string;
|
|
916
|
+
/**
|
|
917
|
+
* Forwarded so the model-supplied cap applies as soon as the Code API honors
|
|
918
|
+
* it on `/exec`, which does not read `timeout` today. Session affinity and
|
|
919
|
+
* input files are honored there, so those ride the same body.
|
|
920
|
+
*/
|
|
921
|
+
timeout?: number;
|
|
922
|
+
sessionId?: string;
|
|
923
|
+
files?: t.CodeEnvFile[];
|
|
924
|
+
runtimeSessionHint?: string;
|
|
925
|
+
proxy?: string;
|
|
926
|
+
authHeaders?: t.CodeApiAuthHeaders;
|
|
927
|
+
executionProfile?: t.CodeApiExecutionProfile;
|
|
928
|
+
}): Promise<[string, t.ProgrammaticExecutionArtifact]> {
|
|
929
|
+
const response = await makeRequest(
|
|
930
|
+
buildCodeApiEndpoint(args.baseUrl, 'exec'),
|
|
931
|
+
{
|
|
932
|
+
lang: args.lang,
|
|
933
|
+
code:
|
|
934
|
+
args.lang === 'py'
|
|
935
|
+
? wrapPythonForPlainExecution(args.code)
|
|
936
|
+
: args.code,
|
|
937
|
+
...(args.timeout != null ? { timeout: args.timeout } : {}),
|
|
938
|
+
...(args.sessionId != null && args.sessionId !== ''
|
|
939
|
+
? { session_id: args.sessionId }
|
|
940
|
+
: {}),
|
|
941
|
+
...(args.files != null && args.files.length > 0
|
|
942
|
+
? { files: args.files }
|
|
943
|
+
: {}),
|
|
944
|
+
...(args.runtimeSessionHint != null
|
|
945
|
+
? { runtime_session_hint: args.runtimeSessionHint }
|
|
946
|
+
: {}),
|
|
947
|
+
},
|
|
948
|
+
args.proxy,
|
|
949
|
+
args.authHeaders,
|
|
950
|
+
args.executionProfile
|
|
951
|
+
);
|
|
952
|
+
|
|
953
|
+
return formatCompletedResponse(response, args.code);
|
|
954
|
+
}
|
|
955
|
+
|
|
877
956
|
// ============================================================================
|
|
878
957
|
// Tool Factory
|
|
879
958
|
// ============================================================================
|
|
@@ -943,22 +1022,41 @@ export function createProgrammaticToolCallingTool(
|
|
|
943
1022
|
programmaticToolName,
|
|
944
1023
|
});
|
|
945
1024
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1025
|
+
/* These guard the replay path only. A call that selected no tools never
|
|
1026
|
+
* replays, and event-driven ToolNode configurations legitimately inject
|
|
1027
|
+
* an empty toolMap/toolDefs. Injected context is still required to
|
|
1028
|
+
* conclude that — with nothing injected at all, an empty selection means
|
|
1029
|
+
* the host wired the tool up wrong. */
|
|
1030
|
+
const needsNoTools =
|
|
1031
|
+
effectiveTools.length === 0 &&
|
|
1032
|
+
(params.tool_manifest?.length === 0 ||
|
|
1033
|
+
toolDefs != null ||
|
|
1034
|
+
disallowedToolDefs != null);
|
|
1035
|
+
|
|
1036
|
+
if (!needsNoTools) {
|
|
1037
|
+
if (toolMap == null || toolMap.size === 0) {
|
|
1038
|
+
throw new Error(
|
|
1039
|
+
'No toolMap provided. ' +
|
|
1040
|
+
'ToolNode should inject this from AgentContext when invoked through the graph.'
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
952
1043
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1044
|
+
if (toolDefs == null || toolDefs.length === 0) {
|
|
1045
|
+
throw new Error(
|
|
1046
|
+
'No tool definitions provided. ' +
|
|
1047
|
+
'Either pass tools in the input or ensure ToolNode injects toolDefs.'
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
958
1050
|
}
|
|
959
1051
|
|
|
1052
|
+
assertUnambiguousIdentifiers(
|
|
1053
|
+
effectiveTools,
|
|
1054
|
+
normalizeToPythonIdentifier,
|
|
1055
|
+
programmaticToolName
|
|
1056
|
+
);
|
|
1057
|
+
|
|
960
1058
|
const effectiveToolMap = projectProgrammaticToolMap(
|
|
961
|
-
toolMap,
|
|
1059
|
+
toolMap ?? new Map(),
|
|
962
1060
|
effectiveTools
|
|
963
1061
|
);
|
|
964
1062
|
|
|
@@ -973,7 +1071,7 @@ export function createProgrammaticToolCallingTool(
|
|
|
973
1071
|
// eslint-disable-next-line no-console
|
|
974
1072
|
console.log(
|
|
975
1073
|
`[PTC Debug] Sending ${effectiveTools.length} tools to API ` +
|
|
976
|
-
`(selected from ${toolDefs
|
|
1074
|
+
`(selected from ${toolDefs?.length ?? 0})`
|
|
977
1075
|
);
|
|
978
1076
|
}
|
|
979
1077
|
|
|
@@ -1008,6 +1106,21 @@ export function createProgrammaticToolCallingTool(
|
|
|
1008
1106
|
? selectedRuntimeSessionHint
|
|
1009
1107
|
: undefined;
|
|
1010
1108
|
|
|
1109
|
+
if (needsNoTools) {
|
|
1110
|
+
return await runPlainExecution({
|
|
1111
|
+
baseUrl,
|
|
1112
|
+
lang: 'py',
|
|
1113
|
+
code,
|
|
1114
|
+
timeout,
|
|
1115
|
+
sessionId: session_id,
|
|
1116
|
+
files,
|
|
1117
|
+
runtimeSessionHint,
|
|
1118
|
+
proxy,
|
|
1119
|
+
authHeaders: initParams.authHeaders,
|
|
1120
|
+
executionProfile: initParams.executionProfile,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1011
1124
|
let response = await makeRequest(
|
|
1012
1125
|
EXEC_ENDPOINT,
|
|
1013
1126
|
{
|
|
@@ -589,17 +589,28 @@ async function runLocalProgrammaticTool(args: {
|
|
|
589
589
|
programmaticToolName: runnerName,
|
|
590
590
|
});
|
|
591
591
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
592
|
+
/* The local program builder supports zero stubs, so a call that selected no
|
|
593
|
+
* tools needs neither a toolMap nor toolDefs. Injected context is still
|
|
594
|
+
* required to conclude that. */
|
|
595
|
+
const needsNoTools =
|
|
596
|
+
selectedTools.length === 0 &&
|
|
597
|
+
(args.params.tool_manifest?.length === 0 ||
|
|
598
|
+
toolDefs != null ||
|
|
599
|
+
disallowedToolDefs != null);
|
|
600
|
+
|
|
601
|
+
if (!needsNoTools) {
|
|
602
|
+
if (toolMap == null || toolMap.size === 0) {
|
|
603
|
+
throw new Error('No toolMap provided for local programmatic execution.');
|
|
604
|
+
}
|
|
605
|
+
if (toolDefs == null || toolDefs.length === 0) {
|
|
606
|
+
throw new Error(
|
|
607
|
+
'No tool definitions provided for local programmatic execution.'
|
|
608
|
+
);
|
|
609
|
+
}
|
|
599
610
|
}
|
|
600
611
|
|
|
601
612
|
const { effectiveTools, effectiveMap } = createEffectiveToolMap(
|
|
602
|
-
toolMap,
|
|
613
|
+
toolMap ?? new Map(),
|
|
603
614
|
selectedTools
|
|
604
615
|
);
|
|
605
616
|
const bridge = await createToolBridge(effectiveMap, hookContext);
|