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