@librechat/agents 3.1.80-dev.1 → 3.1.80-dev.2

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.
@@ -176,30 +176,53 @@ function toInjectedFileRef(file, execSessionId) {
176
176
  }
177
177
  return { ...base, kind: 'user' };
178
178
  }
179
+ /* Stable file identity = `(storage_session_id, id)`. Same name in
180
+ * different storage sessions are distinct files. */
181
+ function fileIdentityKey(file) {
182
+ return `${file.storage_session_id ?? ''}\0${file.id}`;
183
+ }
179
184
  function updateCodeSession(sessions, execSessionId, files) {
180
185
  const newFiles = files ?? [];
181
186
  const existingSession = sessions.get(_enum.Constants.EXECUTE_CODE);
182
187
  const existingFiles = existingSession?.files ?? [];
183
- if (newFiles.length > 0) {
184
- const filesWithSession = newFiles.map((file) => ({
185
- ...file,
186
- storage_session_id: file.storage_session_id ?? execSessionId,
187
- }));
188
- const newFileNames = new Set(filesWithSession.map((f) => f.name));
189
- const filteredExisting = existingFiles.filter((f) => !newFileNames.has(f.name));
190
- sessions.set(_enum.Constants.EXECUTE_CODE, {
191
- session_id: execSessionId,
192
- files: [...filteredExisting, ...filesWithSession],
193
- lastUpdated: Date.now(),
194
- });
195
- }
196
- else {
188
+ if (newFiles.length === 0) {
197
189
  sessions.set(_enum.Constants.EXECUTE_CODE, {
198
190
  session_id: execSessionId,
199
191
  files: existingFiles,
200
192
  lastUpdated: Date.now(),
201
193
  });
194
+ return;
195
+ }
196
+ /* Worker echoes lack ownership identity (kind/resource_id/version) —
197
+ * sandbox doesn't re-attest; that's signed at upload. Merge by
198
+ * (storage_session_id, id) so prior identity survives the echo. */
199
+ const filesWithSession = [];
200
+ const newFileNames = new Set();
201
+ const incomingByIdentity = new Map();
202
+ for (const file of newFiles) {
203
+ const withSession = {
204
+ ...file,
205
+ storage_session_id: file.storage_session_id ?? execSessionId,
206
+ };
207
+ incomingByIdentity.set(fileIdentityKey(withSession), filesWithSession.length);
208
+ newFileNames.add(withSession.name);
209
+ filesWithSession.push(withSession);
210
+ }
211
+ const filteredExisting = [];
212
+ for (const e of existingFiles) {
213
+ const idx = incomingByIdentity.get(fileIdentityKey(e));
214
+ if (idx !== undefined) {
215
+ filesWithSession[idx] = { ...e, ...filesWithSession[idx] };
216
+ }
217
+ if (!newFileNames.has(e.name)) {
218
+ filteredExisting.push(e);
219
+ }
202
220
  }
221
+ sessions.set(_enum.Constants.EXECUTE_CODE, {
222
+ session_id: execSessionId,
223
+ files: [...filteredExisting, ...filesWithSession],
224
+ lastUpdated: Date.now(),
225
+ });
203
226
  }
204
227
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
205
228
  class ToolNode extends run.RunnableCallable {