@librechat/agents 3.1.79 → 3.1.80-dev.1
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/tools/BashExecutor.cjs +13 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +21 -5
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +12 -4
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +73 -40
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +13 -2
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +21 -5
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +12 -4
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +73 -40
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
- package/dist/types/types/tools.d.ts +106 -17
- package/package.json +1 -1
- package/src/scripts/code_exec_multi_session.ts +4 -4
- package/src/tools/BashExecutor.ts +14 -3
- package/src/tools/BashProgrammaticToolCalling.ts +6 -6
- package/src/tools/CodeExecutor.ts +22 -6
- package/src/tools/ProgrammaticToolCalling.ts +17 -10
- package/src/tools/ToolNode.ts +96 -48
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +9 -2
- package/src/tools/__tests__/ToolNode.session.test.ts +152 -50
- package/src/tools/local/LocalExecutionTools.ts +2 -2
- package/src/tools/local/LocalProgrammaticToolCalling.ts +23 -6
- package/src/types/tools.ts +103 -17
|
@@ -123,39 +123,79 @@ function normalizeApprovalDecisions(callIds, resumeValue) {
|
|
|
123
123
|
* - `artifact.session_id` (the `sessionId` arg here) is the EXEC session
|
|
124
124
|
* — the sandbox VM that ran the code. It's transient and torn down
|
|
125
125
|
* post-execution; subsequent calls cannot reuse it as a sandbox.
|
|
126
|
-
* - `file.
|
|
126
|
+
* - `file.storage_session_id` on each `artifact.files[i]` is the STORAGE
|
|
127
127
|
* session — the file-server bucket prefix where the artifact actually
|
|
128
128
|
* lives and is served from.
|
|
129
129
|
*
|
|
130
|
-
* Per-file `
|
|
131
|
-
* because `_injected_files` are looked up against the
|
|
132
|
-
* storage path on subsequent tool calls. Stomping the
|
|
133
|
-
* the exec id silently 404s every follow-up tool call
|
|
134
|
-
* run — `cat /mnt/data/foo.txt` reports "No such file
|
|
135
|
-
* because the worker can't mount a file at a path the
|
|
136
|
-
* know about. Fall back to
|
|
137
|
-
* absent (
|
|
130
|
+
* Per-file `storage_session_id` is preserved (not overwritten with the
|
|
131
|
+
* exec id) because `_injected_files` are looked up against the
|
|
132
|
+
* file-server's storage path on subsequent tool calls. Stomping the
|
|
133
|
+
* storage id with the exec id silently 404s every follow-up tool call
|
|
134
|
+
* within the same run — `cat /mnt/data/foo.txt` reports "No such file
|
|
135
|
+
* or directory" because the worker can't mount a file at a path the
|
|
136
|
+
* storage doesn't know about. Fall back to the exec id only when the
|
|
137
|
+
* per-file id is absent (e.g. inline `content` files have no persistent
|
|
138
|
+
* storage location).
|
|
138
139
|
*/
|
|
139
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Builds a `CodeEnvFile` ref from an arbitrary `FileRef`-like input,
|
|
142
|
+
* narrowing onto the discriminated union: `kind: 'skill'` requires
|
|
143
|
+
* `version`, other kinds forbid it.
|
|
144
|
+
*
|
|
145
|
+
* Defaults `kind` to `'user'` when unset — most ad-hoc files are
|
|
146
|
+
* user-private; shared resources (skills/agents) populate their kind
|
|
147
|
+
* upstream. A skill ref missing `version` falls back to `'user'` so
|
|
148
|
+
* the upstream contract bug surfaces as a degraded sessionKey rather
|
|
149
|
+
* than a runtime crash; primeSkillFiles is the only writer, and it
|
|
150
|
+
* always sets `version` — see LC packages/api/src/agents/skillFiles.ts.
|
|
151
|
+
*
|
|
152
|
+
* `resource_id` carries the entity-that-owns-this-file's-session
|
|
153
|
+
* identity (skill `_id` etc.); falls back to `id` (the storage
|
|
154
|
+
* file_id) for inputs that haven't been updated to send the field
|
|
155
|
+
* explicitly. The fallback degrades sessionKey resolution on the
|
|
156
|
+
* codeapi side for shared kinds (it'll match the storage nanoid
|
|
157
|
+
* against a skill _id and 403) — but won't crash, so an unmigrated
|
|
158
|
+
* client still produces a diagnosable error instead of a stack
|
|
159
|
+
* trace.
|
|
160
|
+
*/
|
|
161
|
+
function toInjectedFileRef(file, execSessionId) {
|
|
162
|
+
const base = {
|
|
163
|
+
id: file.id,
|
|
164
|
+
resource_id: file.resource_id ?? file.id,
|
|
165
|
+
name: file.name,
|
|
166
|
+
/* Inline `content` files have no persistent storage location;
|
|
167
|
+
* fall back to the execution session id for those entries. */
|
|
168
|
+
storage_session_id: file.storage_session_id ?? execSessionId,
|
|
169
|
+
};
|
|
170
|
+
const kind = file.kind ?? 'user';
|
|
171
|
+
if (kind === 'skill' && file.version != null) {
|
|
172
|
+
return { ...base, kind: 'skill', version: file.version };
|
|
173
|
+
}
|
|
174
|
+
if (kind === 'agent') {
|
|
175
|
+
return { ...base, kind: 'agent' };
|
|
176
|
+
}
|
|
177
|
+
return { ...base, kind: 'user' };
|
|
178
|
+
}
|
|
179
|
+
function updateCodeSession(sessions, execSessionId, files) {
|
|
140
180
|
const newFiles = files ?? [];
|
|
141
181
|
const existingSession = sessions.get(_enum.Constants.EXECUTE_CODE);
|
|
142
182
|
const existingFiles = existingSession?.files ?? [];
|
|
143
183
|
if (newFiles.length > 0) {
|
|
144
184
|
const filesWithSession = newFiles.map((file) => ({
|
|
145
185
|
...file,
|
|
146
|
-
|
|
186
|
+
storage_session_id: file.storage_session_id ?? execSessionId,
|
|
147
187
|
}));
|
|
148
188
|
const newFileNames = new Set(filesWithSession.map((f) => f.name));
|
|
149
189
|
const filteredExisting = existingFiles.filter((f) => !newFileNames.has(f.name));
|
|
150
190
|
sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
151
|
-
session_id:
|
|
191
|
+
session_id: execSessionId,
|
|
152
192
|
files: [...filteredExisting, ...filesWithSession],
|
|
153
193
|
lastUpdated: Date.now(),
|
|
154
194
|
});
|
|
155
195
|
}
|
|
156
196
|
else {
|
|
157
197
|
sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
158
|
-
session_id:
|
|
198
|
+
session_id: execSessionId,
|
|
159
199
|
files: existingFiles,
|
|
160
200
|
lastUpdated: Date.now(),
|
|
161
201
|
});
|
|
@@ -242,7 +282,10 @@ class ToolNode extends run.RunnableCallable {
|
|
|
242
282
|
this.loadRuntimeTools = loadRuntimeTools;
|
|
243
283
|
this.errorHandler = errorHandler;
|
|
244
284
|
this.toolUsageCount = new Map();
|
|
245
|
-
this.toolRegistry = resolveLocalExecutionTools.resolveLocalToolRegistry({
|
|
285
|
+
this.toolRegistry = resolveLocalExecutionTools.resolveLocalToolRegistry({
|
|
286
|
+
toolRegistry,
|
|
287
|
+
toolExecution,
|
|
288
|
+
});
|
|
246
289
|
this.sessions = sessions;
|
|
247
290
|
this.eventDrivenMode = eventDrivenMode ?? false;
|
|
248
291
|
this.agentId = agentId;
|
|
@@ -509,19 +552,14 @@ class ToolNode extends run.RunnableCallable {
|
|
|
509
552
|
*/
|
|
510
553
|
if (_enum.CODE_EXECUTION_TOOLS.has(call.name)) {
|
|
511
554
|
const codeSession = this.sessions?.get(_enum.Constants.EXECUTE_CODE);
|
|
512
|
-
|
|
555
|
+
const execSessionId = codeSession?.session_id;
|
|
556
|
+
if (execSessionId != null && execSessionId !== '') {
|
|
513
557
|
invokeParams = {
|
|
514
558
|
...invokeParams,
|
|
515
|
-
session_id:
|
|
559
|
+
session_id: execSessionId,
|
|
516
560
|
};
|
|
517
|
-
if (codeSession
|
|
518
|
-
|
|
519
|
-
session_id: file.session_id ?? codeSession.session_id,
|
|
520
|
-
id: file.id,
|
|
521
|
-
name: file.name,
|
|
522
|
-
...(file.entity_id != null ? { entity_id: file.entity_id } : {}),
|
|
523
|
-
}));
|
|
524
|
-
invokeParams._injected_files = fileRefs;
|
|
561
|
+
if (codeSession?.files != null && codeSession.files.length > 0) {
|
|
562
|
+
invokeParams._injected_files = codeSession.files.map((file) => toInjectedFileRef(file, execSessionId));
|
|
525
563
|
}
|
|
526
564
|
}
|
|
527
565
|
}
|
|
@@ -737,8 +775,7 @@ class ToolNode extends run.RunnableCallable {
|
|
|
737
775
|
// survives `run()`'s clear, so a resume sees the original
|
|
738
776
|
// assignment.)
|
|
739
777
|
const cachedTurn = call.id != null && call.id !== ''
|
|
740
|
-
? this.directPathTurns.get(call.id) ??
|
|
741
|
-
this.toolCallTurns.get(call.id)
|
|
778
|
+
? (this.directPathTurns.get(call.id) ?? this.toolCallTurns.get(call.id))
|
|
742
779
|
: undefined;
|
|
743
780
|
if (cachedTurn != null) {
|
|
744
781
|
usageCount = cachedTurn;
|
|
@@ -874,9 +911,7 @@ class ToolNode extends run.RunnableCallable {
|
|
|
874
911
|
return this.blockDirectCall({
|
|
875
912
|
call,
|
|
876
913
|
resolvedArgs,
|
|
877
|
-
reason: decision.reason ??
|
|
878
|
-
preResult.reason ??
|
|
879
|
-
'Rejected by user',
|
|
914
|
+
reason: decision.reason ?? preResult.reason ?? 'Rejected by user',
|
|
880
915
|
hookRegistry,
|
|
881
916
|
runId,
|
|
882
917
|
threadId,
|
|
@@ -1135,16 +1170,12 @@ class ToolNode extends run.RunnableCallable {
|
|
|
1135
1170
|
if (!codeSession) {
|
|
1136
1171
|
return undefined;
|
|
1137
1172
|
}
|
|
1173
|
+
const execSessionId = codeSession.session_id;
|
|
1138
1174
|
const context = {
|
|
1139
|
-
session_id:
|
|
1175
|
+
session_id: execSessionId,
|
|
1140
1176
|
};
|
|
1141
1177
|
if (codeSession.files && codeSession.files.length > 0) {
|
|
1142
|
-
context.files = codeSession.files.map((file) => (
|
|
1143
|
-
session_id: file.session_id ?? codeSession.session_id,
|
|
1144
|
-
id: file.id,
|
|
1145
|
-
name: file.name,
|
|
1146
|
-
...(file.entity_id != null ? { entity_id: file.entity_id } : {}),
|
|
1147
|
-
}));
|
|
1178
|
+
context.files = codeSession.files.map((file) => toInjectedFileRef(file, execSessionId));
|
|
1148
1179
|
}
|
|
1149
1180
|
return context;
|
|
1150
1181
|
}
|
|
@@ -1169,10 +1200,11 @@ class ToolNode extends run.RunnableCallable {
|
|
|
1169
1200
|
continue;
|
|
1170
1201
|
}
|
|
1171
1202
|
const artifact = result.artifact;
|
|
1172
|
-
|
|
1203
|
+
const execSessionId = artifact?.session_id;
|
|
1204
|
+
if (execSessionId == null || execSessionId === '') {
|
|
1173
1205
|
continue;
|
|
1174
1206
|
}
|
|
1175
|
-
updateCodeSession(this.sessions,
|
|
1207
|
+
updateCodeSession(this.sessions, execSessionId, artifact?.files);
|
|
1176
1208
|
}
|
|
1177
1209
|
}
|
|
1178
1210
|
/**
|
|
@@ -1205,8 +1237,9 @@ class ToolNode extends run.RunnableCallable {
|
|
|
1205
1237
|
}
|
|
1206
1238
|
if (this.sessions && _enum.CODE_EXECUTION_TOOLS.has(call.name)) {
|
|
1207
1239
|
const artifact = toolMessage.artifact;
|
|
1208
|
-
|
|
1209
|
-
|
|
1240
|
+
const execSessionId = artifact?.session_id;
|
|
1241
|
+
if (execSessionId != null && execSessionId !== '') {
|
|
1242
|
+
updateCodeSession(this.sessions, execSessionId, artifact?.files);
|
|
1210
1243
|
}
|
|
1211
1244
|
}
|
|
1212
1245
|
// Dispatch ON_RUN_STEP_COMPLETED via custom event (same path as dispatchToolEvents)
|