@librechat/agents 3.1.80-dev.0 → 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.
@@ -144,14 +144,33 @@ export declare const CODE_ENV_KINDS: readonly ["skill", "agent", "user"];
144
144
  export type CodeEnvKind = (typeof CODE_ENV_KINDS)[number];
145
145
  type CodeEnvFileBase = {
146
146
  /**
147
- * Resource identity. Semantics depend on `kind`:
148
- * - `skill`: skill `_id` (sessionKey-meaningful, cross-user shared).
149
- * - `agent`: agent id (sessionKey-meaningful, cross-user shared).
150
- * - `user`: informational only codeapi derives sessionKey from
151
- * the auth-context user. Kept on the type for shape uniformity;
152
- * do not rely on it for routing.
147
+ * **Storage file id** the per-file uuid the file_server returns
148
+ * at upload time. Identifies the bytes at
149
+ * `<storage_session_id>/<id>` in the object bucket; used by the
150
+ * worker to fetch the file and by codeapi's auth layer for the
151
+ * upload-existence check.
152
+ *
153
+ * Distinct from `resource_id` below — that's the entity that owns
154
+ * this file's storage session (skill `_id`, agent id, etc.), used
155
+ * for sessionKey resolution. Conflating the two caused
156
+ * shared-kind authorization to fail because the sessionKey
157
+ * re-derivation used the storage nanoid where the resource id was
158
+ * required. See codeapi #1455 review.
153
159
  */
154
160
  id: string;
161
+ /**
162
+ * **Resource id** — the entity that owns this file's storage
163
+ * session. Skill `_id` for `kind: 'skill'`, agent id for `'agent'`,
164
+ * informational only for `'user'` (codeapi resolves user identity
165
+ * from auth context). Kept on the type for shape uniformity across
166
+ * kinds.
167
+ *
168
+ * Drives codeapi's `resolveSessionKey` switch — the sessionKey
169
+ * embeds this value (`<tenant>:<kind>:<resource_id>[:v:<version>]`)
170
+ * so cross-user-within-tenant sharing for shared kinds is a
171
+ * designed property of the kind switch.
172
+ */
173
+ resource_id: string;
155
174
  name: string;
156
175
  /**
157
176
  * Storage session — the long-lived bucket where this file's bytes
@@ -189,12 +208,17 @@ export type CodeExecutionToolParams = undefined | {
189
208
  };
190
209
  export type FileRef = {
191
210
  /**
192
- * Resource identity. Semantics depend on `kind` (when present):
193
- * - `skill` / `agent`: shared resource id (sessionKey-meaningful).
194
- * - `user`: informational only — codeapi derives sessionKey from
195
- * the auth-context user. Do not rely on it for routing.
211
+ * Storage file id (the per-file uuid). See `CodeEnvFile.id` for
212
+ * the full motivation behind the storage-vs-resource split.
196
213
  */
197
214
  id: string;
215
+ /**
216
+ * Resource id — the entity that owns this file's storage session.
217
+ * Optional on `FileRef` (post-execute artifact refs may not carry
218
+ * resource provenance for outputs); required on `CodeEnvFile`
219
+ * (the input wire shape).
220
+ */
221
+ resource_id?: string;
198
222
  name: string;
199
223
  path?: string;
200
224
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.1.80-dev.0",
3
+ "version": "3.1.80-dev.1",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -168,6 +168,9 @@ function createBashExecutionTool(
168
168
  * to the user; tag them user-private. */
169
169
  kind: 'user' as const,
170
170
  id,
171
+ /* `resource_id` informational for `kind: 'user'` —
172
+ * codeapi derives sessionKey from auth context. */
173
+ resource_id: id,
171
174
  name: file.metadata['original-filename'],
172
175
  };
173
176
  });
@@ -194,6 +194,11 @@ function createCodeExecutionTool(
194
194
  * to the user; tag them user-private. */
195
195
  kind: 'user' as const,
196
196
  id,
197
+ /* `resource_id` is informational for `kind: 'user'`
198
+ * (codeapi derives sessionKey from auth context); use
199
+ * the same value as `id` since the `/files` fallback
200
+ * doesn't carry separate provenance. */
201
+ resource_id: id,
197
202
  name: file.metadata['original-filename'],
198
203
  };
199
204
  });
@@ -309,6 +309,9 @@ export async function fetchSessionFiles(
309
309
  * the user; tag them user-private. */
310
310
  kind: 'user' as const,
311
311
  id,
312
+ /* `resource_id` informational for `kind: 'user'` —
313
+ * codeapi derives sessionKey from auth context. */
314
+ resource_id: id,
312
315
  name: (file.metadata as Record<string, unknown>)[
313
316
  'original-filename'
314
317
  ] as string,
@@ -274,10 +274,20 @@ function normalizeApprovalDecisions(
274
274
  * the upstream contract bug surfaces as a degraded sessionKey rather
275
275
  * than a runtime crash; primeSkillFiles is the only writer, and it
276
276
  * always sets `version` — see LC packages/api/src/agents/skillFiles.ts.
277
+ *
278
+ * `resource_id` carries the entity-that-owns-this-file's-session
279
+ * identity (skill `_id` etc.); falls back to `id` (the storage
280
+ * file_id) for inputs that haven't been updated to send the field
281
+ * explicitly. The fallback degrades sessionKey resolution on the
282
+ * codeapi side for shared kinds (it'll match the storage nanoid
283
+ * against a skill _id and 403) — but won't crash, so an unmigrated
284
+ * client still produces a diagnosable error instead of a stack
285
+ * trace.
277
286
  */
278
287
  function toInjectedFileRef(
279
288
  file: {
280
289
  id: string;
290
+ resource_id?: string;
281
291
  name: string;
282
292
  storage_session_id?: string;
283
293
  kind?: t.CodeEnvKind;
@@ -287,6 +297,7 @@ function toInjectedFileRef(
287
297
  ): t.CodeEnvFile {
288
298
  const base = {
289
299
  id: file.id,
300
+ resource_id: file.resource_id ?? file.id,
290
301
  name: file.name,
291
302
  /* Inline `content` files have no persistent storage location;
292
303
  * fall back to the execution session id for those entries. */
@@ -84,12 +84,20 @@ describe('ToolNode code execution session management', () => {
84
84
  expect(capturedConfigs[0]._injected_files).toEqual([
85
85
  {
86
86
  id: 'file1',
87
+ /* `resource_id` defaults to `id` (the storage uuid) when
88
+ * the input ref didn't supply it — informational for
89
+ * `kind: 'user'` since codeapi derives sessionKey from
90
+ * auth context. The real LC priming chain DOES supply
91
+ * resource_id explicitly; the default is a back-compat
92
+ * landing for inputs that haven't been updated. */
93
+ resource_id: 'file1',
87
94
  name: 'data.csv',
88
95
  storage_session_id: 'prev-session-abc',
89
96
  kind: 'user',
90
97
  },
91
98
  {
92
99
  id: 'file2',
100
+ resource_id: 'file2',
93
101
  name: 'chart.png',
94
102
  storage_session_id: 'prev-session-abc',
95
103
  kind: 'user',
@@ -195,6 +203,9 @@ describe('ToolNode code execution session management', () => {
195
203
  expect(files).toEqual([
196
204
  {
197
205
  id: 'skill-123',
206
+ /* Default fallback when input doesn't supply `resource_id`.
207
+ * Production LC sets it explicitly to the skill's `_id`. */
208
+ resource_id: 'skill-123',
198
209
  name: 'demo/SKILL.md',
199
210
  storage_session_id: 'session-A',
200
211
  kind: 'skill',
@@ -202,6 +213,7 @@ describe('ToolNode code execution session management', () => {
202
213
  },
203
214
  {
204
215
  id: 'user-file',
216
+ resource_id: 'user-file',
205
217
  name: 'attachment.csv',
206
218
  storage_session_id: 'session-B',
207
219
  kind: 'user',
@@ -241,6 +253,9 @@ describe('ToolNode code execution session management', () => {
241
253
  files: [
242
254
  {
243
255
  id: 'ef1',
256
+ /* `resource_id` defaults to `id` when input doesn't carry
257
+ * separate provenance — see toInjectedFileRef. */
258
+ resource_id: 'ef1',
244
259
  name: 'out.parquet',
245
260
  storage_session_id: 'evt-session',
246
261
  kind: 'user',
@@ -327,6 +342,8 @@ describe('ToolNode code execution session management', () => {
327
342
  files: [
328
343
  {
329
344
  id: 'skill-abc',
345
+ /* Default fallback when input doesn't supply `resource_id`. */
346
+ resource_id: 'skill-abc',
330
347
  name: 'demo/SKILL.md',
331
348
  storage_session_id: 'evt-session',
332
349
  kind: 'skill',
@@ -334,6 +351,7 @@ describe('ToolNode code execution session management', () => {
334
351
  },
335
352
  {
336
353
  id: 'usr1',
354
+ resource_id: 'usr1',
337
355
  name: 'data.csv',
338
356
  storage_session_id: 'evt-session',
339
357
  kind: 'user',
@@ -835,6 +853,9 @@ describe('ToolNode code execution session management', () => {
835
853
  files: [
836
854
  {
837
855
  id: 'rf1',
856
+ /* Default fallback for inputs that don't carry separate
857
+ * provenance — see toInjectedFileRef. */
858
+ resource_id: 'rf1',
838
859
  name: 'data.csv',
839
860
  storage_session_id: 'rf-session',
840
861
  kind: 'user',
@@ -158,14 +158,33 @@ export type CodeEnvKind = (typeof CODE_ENV_KINDS)[number];
158
158
 
159
159
  type CodeEnvFileBase = {
160
160
  /**
161
- * Resource identity. Semantics depend on `kind`:
162
- * - `skill`: skill `_id` (sessionKey-meaningful, cross-user shared).
163
- * - `agent`: agent id (sessionKey-meaningful, cross-user shared).
164
- * - `user`: informational only codeapi derives sessionKey from
165
- * the auth-context user. Kept on the type for shape uniformity;
166
- * do not rely on it for routing.
161
+ * **Storage file id** the per-file uuid the file_server returns
162
+ * at upload time. Identifies the bytes at
163
+ * `<storage_session_id>/<id>` in the object bucket; used by the
164
+ * worker to fetch the file and by codeapi's auth layer for the
165
+ * upload-existence check.
166
+ *
167
+ * Distinct from `resource_id` below — that's the entity that owns
168
+ * this file's storage session (skill `_id`, agent id, etc.), used
169
+ * for sessionKey resolution. Conflating the two caused
170
+ * shared-kind authorization to fail because the sessionKey
171
+ * re-derivation used the storage nanoid where the resource id was
172
+ * required. See codeapi #1455 review.
167
173
  */
168
174
  id: string;
175
+ /**
176
+ * **Resource id** — the entity that owns this file's storage
177
+ * session. Skill `_id` for `kind: 'skill'`, agent id for `'agent'`,
178
+ * informational only for `'user'` (codeapi resolves user identity
179
+ * from auth context). Kept on the type for shape uniformity across
180
+ * kinds.
181
+ *
182
+ * Drives codeapi's `resolveSessionKey` switch — the sessionKey
183
+ * embeds this value (`<tenant>:<kind>:<resource_id>[:v:<version>]`)
184
+ * so cross-user-within-tenant sharing for shared kinds is a
185
+ * designed property of the kind switch.
186
+ */
187
+ resource_id: string;
169
188
  name: string;
170
189
  /**
171
190
  * Storage session — the long-lived bucket where this file's bytes
@@ -204,12 +223,17 @@ export type CodeExecutionToolParams =
204
223
 
205
224
  export type FileRef = {
206
225
  /**
207
- * Resource identity. Semantics depend on `kind` (when present):
208
- * - `skill` / `agent`: shared resource id (sessionKey-meaningful).
209
- * - `user`: informational only — codeapi derives sessionKey from
210
- * the auth-context user. Do not rely on it for routing.
226
+ * Storage file id (the per-file uuid). See `CodeEnvFile.id` for
227
+ * the full motivation behind the storage-vs-resource split.
211
228
  */
212
229
  id: string;
230
+ /**
231
+ * Resource id — the entity that owns this file's storage session.
232
+ * Optional on `FileRef` (post-execute artifact refs may not carry
233
+ * resource provenance for outputs); required on `CodeEnvFile`
234
+ * (the input wire shape).
235
+ */
236
+ resource_id?: string;
213
237
  name: string;
214
238
  path?: string;
215
239
  /**