@nestm/storage 0.1.0-alpha.7 → 0.1.0-alpha.9

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/README.md +302 -18
  3. package/SECURITY.md +34 -5
  4. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +21 -3
  5. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts.map +1 -1
  6. package/dist/ai-sdk/ai-sdk-workspace-tools.js +163 -73
  7. package/dist/ai-sdk/ai-sdk-workspace-tools.js.map +1 -1
  8. package/dist/ai-sdk/index.d.ts +1 -1
  9. package/dist/ai-sdk/index.d.ts.map +1 -1
  10. package/dist/ai-sdk/index.js.map +1 -1
  11. package/dist/files-sdk/files-sdk.driver.d.ts +54 -10
  12. package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
  13. package/dist/files-sdk/files-sdk.driver.js +831 -63
  14. package/dist/files-sdk/files-sdk.driver.js.map +1 -1
  15. package/dist/files-sdk/fs/index.d.ts +4 -4
  16. package/dist/files-sdk/fs/index.d.ts.map +1 -1
  17. package/dist/files-sdk/fs/index.js +242 -9
  18. package/dist/files-sdk/fs/index.js.map +1 -1
  19. package/dist/files-sdk/index.d.ts +1 -1
  20. package/dist/files-sdk/index.d.ts.map +1 -1
  21. package/dist/files-sdk/index.js.map +1 -1
  22. package/dist/files-sdk/provider/index.d.ts +9 -5
  23. package/dist/files-sdk/provider/index.d.ts.map +1 -1
  24. package/dist/files-sdk/provider/index.js +53 -15
  25. package/dist/files-sdk/provider/index.js.map +1 -1
  26. package/dist/files-sdk/s3/construction-metadata.d.ts +7 -0
  27. package/dist/files-sdk/s3/construction-metadata.d.ts.map +1 -0
  28. package/dist/files-sdk/s3/construction-metadata.js +13 -0
  29. package/dist/files-sdk/s3/construction-metadata.js.map +1 -0
  30. package/dist/files-sdk/s3/index.d.ts +39 -19
  31. package/dist/files-sdk/s3/index.d.ts.map +1 -1
  32. package/dist/files-sdk/s3/index.js +936 -113
  33. package/dist/files-sdk/s3/index.js.map +1 -1
  34. package/dist/gateway/storage-gateway.controller.d.ts.map +1 -1
  35. package/dist/gateway/storage-gateway.controller.js +25 -5
  36. package/dist/gateway/storage-gateway.controller.js.map +1 -1
  37. package/dist/storage-etag.d.ts +13 -0
  38. package/dist/storage-etag.d.ts.map +1 -0
  39. package/dist/storage-etag.js +31 -0
  40. package/dist/storage-etag.js.map +1 -0
  41. package/dist/storage.client.d.ts +3 -1
  42. package/dist/storage.client.d.ts.map +1 -1
  43. package/dist/storage.client.js +87 -22
  44. package/dist/storage.client.js.map +1 -1
  45. package/dist/storage.driver.d.ts +21 -1
  46. package/dist/storage.driver.d.ts.map +1 -1
  47. package/dist/storage.driver.js.map +1 -1
  48. package/dist/storage.types.d.ts +90 -19
  49. package/dist/storage.types.d.ts.map +1 -1
  50. package/dist/storage.types.js.map +1 -1
  51. package/dist/testing/index.d.ts +1 -0
  52. package/dist/testing/index.d.ts.map +1 -1
  53. package/dist/testing/index.js +1 -0
  54. package/dist/testing/index.js.map +1 -1
  55. package/dist/testing/provider-conformance.d.ts +65 -0
  56. package/dist/testing/provider-conformance.d.ts.map +1 -0
  57. package/dist/testing/provider-conformance.js +853 -0
  58. package/dist/testing/provider-conformance.js.map +1 -0
  59. package/dist/workspace/index.d.ts +2 -1
  60. package/dist/workspace/index.d.ts.map +1 -1
  61. package/dist/workspace/index.js +1 -0
  62. package/dist/workspace/index.js.map +1 -1
  63. package/dist/workspace/storage-workspace.cursor.d.ts +68 -3
  64. package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -1
  65. package/dist/workspace/storage-workspace.cursor.js +402 -39
  66. package/dist/workspace/storage-workspace.cursor.js.map +1 -1
  67. package/dist/workspace/storage-workspace.d.ts.map +1 -1
  68. package/dist/workspace/storage-workspace.js +162 -62
  69. package/dist/workspace/storage-workspace.js.map +1 -1
  70. package/dist/workspace/storage-workspace.types.d.ts +31 -5
  71. package/dist/workspace/storage-workspace.types.d.ts.map +1 -1
  72. package/dist/workspace/storage-workspace.types.js +2 -0
  73. package/dist/workspace/storage-workspace.types.js.map +1 -1
  74. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import { type ToolSet } from 'ai';
1
+ import { type JSONValue, type ToolSet } from 'ai';
2
2
  import { type StorageWorkspace } from '../workspace/index.js';
3
3
  import { type StorageErrorCode as StorageErrorCodeValue } from '../storage.error.js';
4
4
  export declare const AI_SDK_WORKSPACE_TOOL_NAMES: readonly ['workspace_list', 'workspace_stat', 'workspace_read_file', 'workspace_search', 'workspace_write_file', 'workspace_copy_file', 'workspace_move_file', 'workspace_delete_file'];
@@ -9,7 +9,13 @@ export type AiSdkWorkspaceMutationToolName = Extract<AiSdkWorkspaceToolName, 'wo
9
9
  * approval, matching an omitted policy.
10
10
  */
11
11
  export type AiSdkWorkspaceApprovalConfig = boolean | Partial<Record<AiSdkWorkspaceMutationToolName, boolean>>;
12
- export interface CreateAiSdkWorkspaceToolsOptions {
12
+ export type AiSdkWorkspaceMutationMode = 'conditional' | 'last-write-wins';
13
+ export interface AiSdkWorkspaceCreateConflict {
14
+ /** The logical destination inside the mounted workspace. */
15
+ readonly path: string;
16
+ }
17
+ export type AiSdkWorkspaceCreateConflictMapper<Result extends JSONValue> = (conflict: AiSdkWorkspaceCreateConflict) => PromiseLike<Result> | Result;
18
+ export interface CreateAiSdkWorkspaceToolsOptions<CreateConflictResult extends JSONValue = never> {
13
19
  /** The already-mounted, policy-enforcing workspace exposed to the tools. */
14
20
  workspace: StorageWorkspace;
15
21
  /**
@@ -19,6 +25,18 @@ export interface CreateAiSdkWorkspaceToolsOptions {
19
25
  maxReadBytes?: number;
20
26
  /** Mutation tools require approval by default. */
21
27
  requireApproval?: AiSdkWorkspaceApprovalConfig;
28
+ /**
29
+ * Selects the mutation contract exposed to the model. Conditional mode is
30
+ * the default; last-write-wins uses the workspace's ordinary Files path.
31
+ */
32
+ mutationMode?: AiSdkWorkspaceMutationMode;
33
+ /**
34
+ * Maps an atomic create collision to an application result. When omitted,
35
+ * the collision remains an AiSdkWorkspaceToolError like every other storage
36
+ * failure. Replace conflicts are never mapped by this hook. This option is
37
+ * valid only when mutationMode is conditional.
38
+ */
39
+ mapCreateConflict?: AiSdkWorkspaceCreateConflictMapper<CreateConflictResult>;
22
40
  }
23
41
  export type AiSdkWorkspaceToolErrorCode = StorageErrorCodeValue;
24
42
  /**
@@ -58,6 +76,6 @@ export interface AiSdkWorkspacePageResult {
58
76
  * The workspace remains the enforcing boundary if a retained tool reference
59
77
  * is invoked after further narrowing.
60
78
  */
61
- export declare function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMaxReadBytes, requireApproval, }: CreateAiSdkWorkspaceToolsOptions): ToolSet;
79
+ export declare function createAiSdkWorkspaceTools<CreateConflictResult extends JSONValue = never>({ workspace, maxReadBytes: requestedMaxReadBytes, mutationMode, requireApproval, mapCreateConflict, }: CreateAiSdkWorkspaceToolsOptions<CreateConflictResult>): ToolSet;
62
80
  export declare function isAiSdkWorkspaceMutationToolName(value: string): value is AiSdkWorkspaceMutationToolName;
63
81
  //# sourceMappingURL=ai-sdk-workspace-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-sdk-workspace-tools.d.ts","sourceRoot":"","sources":["../../src/ai-sdk/ai-sdk-workspace-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAGxC,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,KAAK,gBAAgB,IAAI,qBAAqB,EAC/C,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,2BAA2B,YACtC,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,CACf,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,MAAM,8BAA8B,GAAG,OAAO,CAClD,sBAAsB,EACpB,sBAAsB,GACtB,qBAAqB,GACrB,qBAAqB,GACrB,uBAAuB,CAC1B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GACtC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,8BAA8B,EAAE,OAAO,CAAC,CAAC,CAAC;AAErE,MAAM,WAAW,gCAAgC;IAC/C,4EAA4E;IAC5E,SAAS,EAAE,gBAAgB,CAAC;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,eAAe,CAAC,EAAE,4BAA4B,CAAC;CAChD;AAED,MAAM,MAAM,2BAA2B,GAAG,qBAAqB,CAAC;AAsBhE;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAE3C,YAAY,IAAI,EAAE,2BAA2B,EAI5C;CACF;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,yBAAyB,GACnC,wBAAwB,GAAG,6BAA6B,CAAC;AAE3D,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,yBAAyB,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA2MD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,SAAS,EACT,YAAY,EAAE,qBAAqB,EACnC,eAAsB,GACvB,EAAE,gCAAgC,GAAG,OAAO,CA2R5C;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,MAAM,GACZ,KAAK,IAAI,8BAA8B,CAEzC"}
1
+ {"version":3,"file":"ai-sdk-workspace-tools.d.ts","sourceRoot":"","sources":["../../src/ai-sdk/ai-sdk-workspace-tools.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { tool } from 'ai';
2
2
  import { z } from 'zod';
3
- import { isStorageWorkspaceError, } from '../workspace/index.js';
3
+ import { STORAGE_WORKSPACE_MAX_CURSOR_BYTES, isStorageWorkspaceError, } from '../workspace/index.js';
4
4
  import { StorageErrorCode, isStorageError, } from '../storage.error.js';
5
+ import { isCanonicalStorageEtag } from '../storage-etag.js';
5
6
  export const AI_SDK_WORKSPACE_TOOL_NAMES = [
6
7
  'workspace_list',
7
8
  'workspace_stat',
@@ -15,7 +16,7 @@ export const AI_SDK_WORKSPACE_TOOL_NAMES = [
15
16
  const SAFE_ERROR_MESSAGES = {
16
17
  [StorageErrorCode.NOT_FOUND]: 'The requested workspace path was not found.',
17
18
  [StorageErrorCode.UNAUTHORIZED]: 'This operation is not permitted in the workspace.',
18
- [StorageErrorCode.CONFLICT]: 'The operation conflicts with current workspace state. Refresh metadata and retry with the current ETag or a new destination.',
19
+ [StorageErrorCode.CONFLICT]: 'The operation conflicts with current workspace state. Inspect the affected paths before retrying.',
19
20
  [StorageErrorCode.READ_ONLY]: 'This operation is not permitted in the workspace.',
20
21
  [StorageErrorCode.INVALID_ARGUMENT]: 'The workspace tool input was rejected.',
21
22
  [StorageErrorCode.NOT_SUPPORTED]: 'This workspace operation is not supported by the configured storage.',
@@ -44,7 +45,7 @@ const mutationToolNames = new Set([
44
45
  ]);
45
46
  const utf8Encoder = new TextEncoder();
46
47
  const forbiddenUnicodeCharacter = /\p{C}/u;
47
- const workspaceCursor = /^[A-Za-z0-9_-]{32}$/u;
48
+ const workspaceCursor = /^[A-Za-z0-9._-]+$/u;
48
49
  const windowsDeviceName = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/iu;
49
50
  function isLogicalPath(value) {
50
51
  if (value.length === 0 ||
@@ -87,22 +88,20 @@ function searchQuery(maxBytes) {
87
88
  })
88
89
  .describe('Path pattern or text to find inside the mounted workspace.');
89
90
  }
90
- function boundedEtag(maxBytes) {
91
+ function boundedEtag() {
91
92
  return z
92
93
  .string()
93
- .min(1)
94
- .refine((value) => !forbiddenUnicodeCharacter.test(value), {
95
- message: 'ETag contains forbidden characters.',
96
- })
97
- .refine((value) => utf8Encoder.encode(value).byteLength <= maxBytes, {
98
- message: `ETag exceeds the ${maxBytes}-byte workspace limit.`,
94
+ .refine(isCanonicalStorageEtag, {
95
+ message: 'ETag must be a canonical bare value of at most 1,024 bytes.',
99
96
  })
100
- .describe('Exact ETag returned by the latest workspace stat or read.');
97
+ .describe('Exact canonical bare ETag returned by the latest workspace stat or read.');
101
98
  }
102
- function continuationCursor(description) {
99
+ function continuationCursor(description, maxBytes) {
103
100
  return z
104
101
  .string()
105
- .regex(workspaceCursor, 'Cursor must be the opaque base64url token returned by the workspace.')
102
+ .min(1)
103
+ .max(Math.min(STORAGE_WORKSPACE_MAX_CURSOR_BYTES, maxBytes))
104
+ .regex(workspaceCursor, 'Cursor must be the bounded opaque token returned by the workspace.')
106
105
  .optional()
107
106
  .describe(description);
108
107
  }
@@ -155,7 +154,29 @@ async function executeSafely(signal, operation) {
155
154
  throw sanitizeToolError(error, signal);
156
155
  }
157
156
  }
157
+ async function executeCreateAware(signal, input, operation, mapCreateConflict) {
158
+ try {
159
+ return await operation();
160
+ }
161
+ catch (error) {
162
+ const safeError = sanitizeToolError(error, signal);
163
+ if (input.mode === 'create' &&
164
+ safeError.code === StorageErrorCode.CONFLICT &&
165
+ mapCreateConflict !== undefined) {
166
+ try {
167
+ return await mapCreateConflict({ path: input.path });
168
+ }
169
+ catch {
170
+ throw new AiSdkWorkspaceToolError(StorageErrorCode.PROVIDER);
171
+ }
172
+ }
173
+ throw safeError;
174
+ }
175
+ }
158
176
  function serializeFile(file) {
177
+ if (file.etag !== undefined && !isCanonicalStorageEtag(file.etag)) {
178
+ throw new Error('Workspace returned a malformed ETag.');
179
+ }
159
180
  return {
160
181
  kind: 'file',
161
182
  path: file.path,
@@ -189,16 +210,24 @@ function serializePage(page) {
189
210
  * The workspace remains the enforcing boundary if a retained tool reference
190
211
  * is invoked after further narrowing.
191
212
  */
192
- export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMaxReadBytes, requireApproval = true, }) {
213
+ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMaxReadBytes, mutationMode = 'conditional', requireApproval = true, mapCreateConflict, }) {
214
+ if (mutationMode !== 'conditional' && mutationMode !== 'last-write-wins') {
215
+ throw new RangeError('mutationMode must be "conditional" or "last-write-wins".');
216
+ }
217
+ if (mutationMode === 'last-write-wins' && mapCreateConflict !== undefined) {
218
+ throw new RangeError('mapCreateConflict is available only in conditional mutation mode.');
219
+ }
193
220
  const maxReadBytes = resolveReadLimit(workspace, requestedMaxReadBytes);
194
221
  const tools = {};
195
222
  const pathSchema = logicalPath('File path', workspace.limits.maxPathBytes);
196
223
  const directorySchema = logicalPath('Directory path', workspace.limits.maxPathBytes);
197
- const etagSchema = boundedEtag(workspace.limits.maxPathBytes);
224
+ const etagSchema = boundedEtag();
198
225
  if (workspace.allows('list')) {
199
226
  tools.workspace_list = tool({
200
227
  description: 'List files and directories inside the mounted workspace. Omit directory to list the workspace root.',
201
- strict: true,
228
+ // Optional pagination and directory inputs are not compatible with
229
+ // OpenAI strict function schemas, which require every property.
230
+ strict: false,
202
231
  inputSchema: z
203
232
  .object({
204
233
  directory: directorySchema.optional(),
@@ -207,7 +236,7 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
207
236
  .optional()
208
237
  .describe('Whether to include descendants recursively.'),
209
238
  limit: positiveIntegerAtMost(workspace.limits.maxPageSize, `Maximum entries to return, up to ${workspace.limits.maxPageSize}.`),
210
- cursor: continuationCursor('Opaque one-use cursor returned by the preceding list call. Repeat the same directory, recursive, and limit options when continuing.'),
239
+ cursor: continuationCursor('Opaque cursor returned by a preceding list call. It may be replayed before expiry while its provider continuation remains valid; repeat the same directory, recursive, and limit options when continuing.', workspace.limits.maxCursorBytes),
211
240
  })
212
241
  .strict(),
213
242
  execute: (input, { abortSignal }) => executeSafely(abortSignal, async () => serializePage(await workspace.list({
@@ -225,7 +254,9 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
225
254
  }
226
255
  if (workspace.allows('read')) {
227
256
  tools.workspace_stat = tool({
228
- description: 'Inspect a file inside the mounted workspace without reading its contents. Returns the ETag required for safe replace, move, and delete operations.',
257
+ description: mutationMode === 'conditional'
258
+ ? 'Inspect a file inside the mounted workspace without reading its contents. Returns the ETag required for safe replace, move, and delete operations.'
259
+ : 'Inspect a file inside the mounted workspace without reading its contents. Any returned ETag is informational in last-write-wins mode.',
229
260
  strict: true,
230
261
  inputSchema: z.object({ path: pathSchema }).strict(),
231
262
  execute: ({ path }, { abortSignal }) => executeSafely(abortSignal, async () => serializeFile(await workspace.stat(path, operationOptions(abortSignal)))),
@@ -243,7 +274,8 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
243
274
  if (workspace.allows('search')) {
244
275
  tools.workspace_search = tool({
245
276
  description: 'Search logical paths inside the mounted workspace using a bounded glob, substring, or exact match. Omit directory to search from the workspace root.',
246
- strict: true,
277
+ // Search intentionally has optional filters and cursor inputs.
278
+ strict: false,
247
279
  inputSchema: z
248
280
  .object({
249
281
  query: searchQuery(workspace.limits.maxPathBytes),
@@ -254,7 +286,7 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
254
286
  .describe('Matching strategy; defaults to glob.'),
255
287
  caseInsensitive: z.boolean().optional(),
256
288
  limit: positiveIntegerAtMost(workspace.limits.maxSearchResults, `Maximum matches to return, up to ${workspace.limits.maxSearchResults}.`),
257
- cursor: continuationCursor('Opaque one-use cursor returned by the preceding search call. Repeat the same query, directory, match, caseInsensitive, and limit options when continuing.'),
289
+ cursor: continuationCursor('Opaque cursor returned by a preceding search call. It may be replayed before expiry while its provider continuation remains valid; repeat the same query, directory, match, caseInsensitive, and limit options when continuing.', workspace.limits.maxCursorBytes),
258
290
  })
259
291
  .strict(),
260
292
  execute: ({ query, directory, match, caseInsensitive, limit, cursor }, { abortSignal }) => executeSafely(abortSignal, async () => serializePage(await workspace.search(query, {
@@ -267,61 +299,79 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
267
299
  }))),
268
300
  });
269
301
  }
270
- const canCreate = workspace.allows('create');
271
- const canReplace = workspace.allows('replace');
272
- if (canCreate || canReplace) {
273
- const commonWriteShape = {
274
- path: pathSchema,
275
- content: z
276
- .string()
277
- .refine((value) => utf8Encoder.encode(value).byteLength <=
278
- workspace.limits.maxWriteBytes, {
279
- message: `Content exceeds the ${workspace.limits.maxWriteBytes}-byte workspace write limit.`,
280
- })
281
- .describe(`UTF-8 text to write. The workspace enforces its ${workspace.limits.maxWriteBytes}-byte write limit.`),
282
- };
283
- const createSchema = z
284
- .object({ ...commonWriteShape, mode: z.literal('create') })
285
- .strict();
286
- const replaceSchema = z
287
- .object({
288
- ...commonWriteShape,
289
- mode: z.literal('replace'),
290
- etag: etagSchema,
302
+ const commonWriteShape = {
303
+ path: pathSchema,
304
+ content: z
305
+ .string()
306
+ .refine((value) => utf8Encoder.encode(value).byteLength <=
307
+ workspace.limits.maxWriteBytes, {
308
+ message: `Content exceeds the ${workspace.limits.maxWriteBytes}-byte workspace write limit.`,
291
309
  })
292
- .strict();
293
- const inputSchema = canCreate && canReplace
294
- ? z.discriminatedUnion('mode', [createSchema, replaceSchema])
295
- : canCreate
296
- ? createSchema
297
- : replaceSchema;
310
+ .describe(`UTF-8 text to write. The workspace enforces its ${workspace.limits.maxWriteBytes}-byte write limit.`),
311
+ };
312
+ if (mutationMode === 'last-write-wins' && workspace.allows('write')) {
313
+ const inputSchema = z.object(commonWriteShape).strict();
298
314
  tools.workspace_write_file = tool({
299
- description: canCreate && canReplace
300
- ? 'Create a new UTF-8 text file or replace an existing file inside the mounted workspace. Create fails if the destination exists; replace requires its current ETag.'
301
- : canCreate
302
- ? 'Create a new UTF-8 text file inside the mounted workspace. The operation fails if the destination already exists.'
303
- : 'Replace an existing UTF-8 text file inside the mounted workspace using its current ETag.',
315
+ description: 'Write a UTF-8 text file inside the mounted workspace. An existing destination is overwritten; the last successful writer wins.',
304
316
  strict: true,
305
317
  inputSchema,
306
318
  needsApproval: resolveApproval('workspace_write_file', requireApproval),
307
- execute: (input, { abortSignal }) => executeSafely(abortSignal, async () => serializeFile(input.mode === 'create'
308
- ? await workspace.writeFile(input.path, input.content, {
309
- mode: 'create',
310
- ...operationOptions(abortSignal),
311
- })
312
- : await workspace.writeFile(input.path, input.content, {
313
- mode: 'replace',
314
- etag: input.etag,
315
- ...operationOptions(abortSignal),
316
- }))),
319
+ execute: ({ path, content }, { abortSignal }) => executeSafely(abortSignal, async () => serializeFile(await workspace.writeFile(path, content, {
320
+ mode: 'overwrite',
321
+ ...operationOptions(abortSignal),
322
+ }))),
317
323
  });
318
324
  }
319
- const canCopy = workspace.allows('copy') &&
320
- workspace.allows('read') &&
321
- workspace.allows('create');
322
- if (canCopy) {
325
+ else if (mutationMode === 'conditional') {
326
+ const canCreate = workspace.allows('create');
327
+ const canReplace = workspace.allows('replace');
328
+ if (canCreate || canReplace) {
329
+ const createSchema = z
330
+ .object({ ...commonWriteShape, mode: z.literal('create') })
331
+ .strict();
332
+ const replaceSchema = z
333
+ .object({
334
+ ...commonWriteShape,
335
+ mode: z.literal('replace'),
336
+ etag: etagSchema,
337
+ })
338
+ .strict();
339
+ const inputSchema = canCreate && canReplace
340
+ ? z.discriminatedUnion('mode', [createSchema, replaceSchema])
341
+ : canCreate
342
+ ? createSchema
343
+ : replaceSchema;
344
+ tools.workspace_write_file = tool({
345
+ description: canCreate && canReplace
346
+ ? 'Create a new UTF-8 text file or replace an existing file inside the mounted workspace. Create fails if the destination exists; replace requires its current ETag.'
347
+ : canCreate
348
+ ? 'Create a new UTF-8 text file inside the mounted workspace. The operation fails if the destination already exists.'
349
+ : 'Replace an existing UTF-8 text file inside the mounted workspace using its current ETag.',
350
+ // The combined create/replace schema is a discriminated union. OpenAI
351
+ // strict function tools reject its root-level oneOf, while the runtime
352
+ // Zod schema continues to validate every tool call in non-strict mode.
353
+ strict: !(canCreate && canReplace),
354
+ inputSchema,
355
+ needsApproval: resolveApproval('workspace_write_file', requireApproval),
356
+ execute: (input, { abortSignal }) => executeCreateAware(abortSignal, input, async () => serializeFile(input.mode === 'create'
357
+ ? await workspace.writeFile(input.path, input.content, {
358
+ mode: 'create',
359
+ ...operationOptions(abortSignal),
360
+ })
361
+ : await workspace.writeFile(input.path, input.content, {
362
+ mode: 'replace',
363
+ etag: input.etag,
364
+ ...operationOptions(abortSignal),
365
+ })), mapCreateConflict),
366
+ });
367
+ }
368
+ }
369
+ const canCopy = workspace.allows('copy') && workspace.allows('read');
370
+ if (mutationMode === 'last-write-wins' &&
371
+ canCopy &&
372
+ workspace.allows('write')) {
323
373
  tools.workspace_copy_file = tool({
324
- description: 'Copy a file inside the mounted workspace. The source remains intact, and the operation fails if the destination already exists.',
374
+ description: 'Copy the latest readable contents of a file inside the mounted workspace. The source remains intact, and an existing destination is overwritten.',
325
375
  strict: true,
326
376
  inputSchema: z
327
377
  .object({
@@ -330,14 +380,37 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
330
380
  })
331
381
  .strict(),
332
382
  needsApproval: resolveApproval('workspace_copy_file', requireApproval),
333
- execute: ({ source, destination }, { abortSignal }) => executeSafely(abortSignal, async () => serializeFile(await workspace.copyFile(source, destination, operationOptions(abortSignal)))),
383
+ execute: ({ source, destination }, { abortSignal }) => executeSafely(abortSignal, async () => serializeFile(await workspace.copyFile(source, destination, {
384
+ mode: 'overwrite',
385
+ ...operationOptions(abortSignal),
386
+ }))),
387
+ });
388
+ }
389
+ else if (mutationMode === 'conditional' &&
390
+ canCopy &&
391
+ workspace.allows('create')) {
392
+ tools.workspace_copy_file = tool({
393
+ description: 'Copy an exact observed version of a file inside the mounted workspace. The source remains intact, and the operation fails if the source changed or the destination already exists.',
394
+ strict: true,
395
+ inputSchema: z
396
+ .object({
397
+ source: logicalPath('Source file path', workspace.limits.maxPathBytes),
398
+ destination: logicalPath('Destination file path', workspace.limits.maxPathBytes),
399
+ etag: etagSchema.describe('Exact ETag of the source returned by the latest workspace stat or read.'),
400
+ })
401
+ .strict(),
402
+ needsApproval: resolveApproval('workspace_copy_file', requireApproval),
403
+ execute: ({ source, destination, etag }, { abortSignal }) => executeSafely(abortSignal, async () => serializeFile(await workspace.copyFile(source, destination, {
404
+ etag,
405
+ ...operationOptions(abortSignal),
406
+ }))),
334
407
  });
335
408
  }
336
- const canMove = workspace.allows('move') &&
409
+ if (mutationMode === 'conditional' &&
410
+ workspace.allows('move') &&
337
411
  workspace.allows('read') &&
338
- workspace.allows('create') &&
339
- workspace.allows('delete');
340
- if (canMove) {
412
+ workspace.allows('delete') &&
413
+ workspace.allows('create')) {
341
414
  tools.workspace_move_file = tool({
342
415
  description: "Move a file inside the mounted workspace using the source's current ETag. The operation fails if the destination already exists. If source deletion cannot be confirmed, the destination is retained and the tool reports a conflict; inspect both paths before retrying.",
343
416
  strict: true,
@@ -355,7 +428,24 @@ export function createAiSdkWorkspaceTools({ workspace, maxReadBytes: requestedMa
355
428
  }))),
356
429
  });
357
430
  }
358
- if (workspace.allows('delete')) {
431
+ if (mutationMode === 'last-write-wins' &&
432
+ workspace.allows('delete') &&
433
+ workspace.allows('write')) {
434
+ tools.workspace_delete_file = tool({
435
+ description: 'Unconditionally delete the current file at a path inside the mounted workspace.',
436
+ strict: true,
437
+ inputSchema: z.object({ path: pathSchema }).strict(),
438
+ needsApproval: resolveApproval('workspace_delete_file', requireApproval),
439
+ execute: ({ path }, { abortSignal }) => executeSafely(abortSignal, async () => {
440
+ await workspace.deleteFile(path, {
441
+ mode: 'unconditional',
442
+ ...operationOptions(abortSignal),
443
+ });
444
+ return { deleted: true, path };
445
+ }),
446
+ });
447
+ }
448
+ else if (mutationMode === 'conditional' && workspace.allows('delete')) {
359
449
  tools.workspace_delete_file = tool({
360
450
  description: 'Delete a file inside the mounted workspace using its current ETag.',
361
451
  strict: true,
@@ -1 +1 @@
1
- {"version":3,"file":"ai-sdk-workspace-tools.js","sourceRoot":"","sources":["../../src/ai-sdk/ai-sdk-workspace-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { tool, type ToolSet } from 'ai';\nimport { z } from 'zod';\n\nimport {\n isStorageWorkspaceError,\n type StorageWorkspace,\n type StorageWorkspaceEntry,\n type StorageWorkspaceFile,\n type StorageWorkspaceTextFile,\n} from '../workspace/index.js';\nimport {\n StorageErrorCode,\n isStorageError,\n type StorageErrorCode as StorageErrorCodeValue,\n} from '../storage.error.js';\n\nexport const AI_SDK_WORKSPACE_TOOL_NAMES = [\n 'workspace_list',\n 'workspace_stat',\n 'workspace_read_file',\n 'workspace_search',\n 'workspace_write_file',\n 'workspace_copy_file',\n 'workspace_move_file',\n 'workspace_delete_file',\n] as const;\n\nexport type AiSdkWorkspaceToolName =\n (typeof AI_SDK_WORKSPACE_TOOL_NAMES)[number];\n\nexport type AiSdkWorkspaceMutationToolName = Extract<\n AiSdkWorkspaceToolName,\n | 'workspace_write_file'\n | 'workspace_copy_file'\n | 'workspace_move_file'\n | 'workspace_delete_file'\n>;\n\n/**\n * Approval policy for mutation tools. An omitted entry defaults to requiring\n * approval, matching an omitted policy.\n */\nexport type AiSdkWorkspaceApprovalConfig =\n boolean | Partial<Record<AiSdkWorkspaceMutationToolName, boolean>>;\n\nexport interface CreateAiSdkWorkspaceToolsOptions {\n /** The already-mounted, policy-enforcing workspace exposed to the tools. */\n workspace: StorageWorkspace;\n /**\n * Optional tighter read ceiling. Values above the workspace ceiling are\n * clamped; the model cannot choose or raise this value.\n */\n maxReadBytes?: number;\n /** Mutation tools require approval by default. */\n requireApproval?: AiSdkWorkspaceApprovalConfig;\n}\n\nexport type AiSdkWorkspaceToolErrorCode = StorageErrorCodeValue;\n\nconst SAFE_ERROR_MESSAGES: Readonly<\n Record<AiSdkWorkspaceToolErrorCode, string>\n> = {\n [StorageErrorCode.NOT_FOUND]: 'The requested workspace path was not found.',\n [StorageErrorCode.UNAUTHORIZED]:\n 'This operation is not permitted in the workspace.',\n [StorageErrorCode.CONFLICT]:\n 'The operation conflicts with current workspace state. Refresh metadata and retry with the current ETag or a new destination.',\n [StorageErrorCode.READ_ONLY]:\n 'This operation is not permitted in the workspace.',\n [StorageErrorCode.INVALID_ARGUMENT]: 'The workspace tool input was rejected.',\n [StorageErrorCode.NOT_SUPPORTED]:\n 'This workspace operation is not supported by the configured storage.',\n [StorageErrorCode.ABORTED]: 'The workspace operation was aborted.',\n [StorageErrorCode.TIMEOUT]: 'The workspace operation timed out.',\n [StorageErrorCode.LIMIT_EXCEEDED]:\n 'The workspace operation exceeded a configured limit.',\n [StorageErrorCode.PROVIDER]: 'The workspace operation failed.',\n};\n\n/**\n * Safe error exposed at the AI tool boundary. It deliberately carries no\n * provider error, storage key, mount prefix, store name, or cause.\n */\nexport class AiSdkWorkspaceToolError extends Error {\n readonly code: AiSdkWorkspaceToolErrorCode;\n\n constructor(code: AiSdkWorkspaceToolErrorCode) {\n super(SAFE_ERROR_MESSAGES[code]);\n this.name = 'AiSdkWorkspaceToolError';\n this.code = code;\n }\n}\n\nexport interface AiSdkWorkspaceFileResult {\n kind: 'file';\n path: string;\n name: string;\n size: number;\n contentType: string;\n etag?: string;\n lastModified?: string;\n}\n\nexport interface AiSdkWorkspaceDirectoryResult {\n kind: 'directory';\n path: string;\n name: string;\n}\n\nexport type AiSdkWorkspaceEntryResult =\n AiSdkWorkspaceFileResult | AiSdkWorkspaceDirectoryResult;\n\nexport interface AiSdkWorkspaceTextFileResult extends AiSdkWorkspaceFileResult {\n text: string;\n}\n\nexport interface AiSdkWorkspacePageResult {\n entries: AiSdkWorkspaceEntryResult[];\n cursor?: string;\n}\n\nconst mutationToolNames = new Set<AiSdkWorkspaceMutationToolName>([\n 'workspace_write_file',\n 'workspace_copy_file',\n 'workspace_move_file',\n 'workspace_delete_file',\n]);\nconst utf8Encoder = new TextEncoder();\nconst forbiddenUnicodeCharacter = /\\p{C}/u;\nconst workspaceCursor = /^[A-Za-z0-9_-]{32}$/u;\nconst windowsDeviceName = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\..*)?$/iu;\n\nfunction isLogicalPath(value: string): boolean {\n if (\n value.length === 0 ||\n value.startsWith('/') ||\n value.endsWith('/') ||\n value !== value.normalize('NFC') ||\n value.includes('\\\\') ||\n forbiddenUnicodeCharacter.test(value)\n ) {\n return false;\n }\n\n return value\n .split('/')\n .every(\n (segment) =>\n segment.length > 0 &&\n segment !== '.' &&\n segment !== '..' &&\n !segment.includes(':') &&\n !segment.endsWith('.') &&\n !segment.endsWith(' ') &&\n !windowsDeviceName.test(segment),\n );\n}\n\nfunction logicalPath(label: string, maxBytes: number) {\n return z\n .string()\n .min(1)\n .refine(isLogicalPath, {\n message: `${label} must be a portable, NFC-normalized, relative POSIX workspace path.`,\n })\n .refine((value) => utf8Encoder.encode(value).byteLength <= maxBytes, {\n message: `${label} exceeds the ${maxBytes}-byte workspace path limit.`,\n })\n .describe(\n `${label}. Use an NFC-normalized relative POSIX path inside the mounted workspace. Empty, dot, parent, colon, trailing dot or space, and Windows reserved device segments are forbidden.`,\n );\n}\n\nfunction searchQuery(maxBytes: number) {\n return z\n .string()\n .min(1)\n .refine(\n (value) =>\n !value.includes('\\\\') && !forbiddenUnicodeCharacter.test(value),\n { message: 'Search query contains forbidden characters.' },\n )\n .refine((value) => utf8Encoder.encode(value).byteLength <= maxBytes, {\n message: `Search query exceeds the ${maxBytes}-byte workspace limit.`,\n })\n .describe('Path pattern or text to find inside the mounted workspace.');\n}\n\nfunction boundedEtag(maxBytes: number) {\n return z\n .string()\n .min(1)\n .refine((value) => !forbiddenUnicodeCharacter.test(value), {\n message: 'ETag contains forbidden characters.',\n })\n .refine((value) => utf8Encoder.encode(value).byteLength <= maxBytes, {\n message: `ETag exceeds the ${maxBytes}-byte workspace limit.`,\n })\n .describe('Exact ETag returned by the latest workspace stat or read.');\n}\n\nfunction continuationCursor(description: string) {\n return z\n .string()\n .regex(\n workspaceCursor,\n 'Cursor must be the opaque base64url token returned by the workspace.',\n )\n .optional()\n .describe(description);\n}\n\nfunction positiveIntegerAtMost(maximum: number, description: string) {\n return z\n .number()\n .int()\n .positive()\n .max(maximum)\n .optional()\n .describe(description);\n}\n\nfunction operationOptions(signal: AbortSignal | undefined): {\n signal?: AbortSignal;\n} {\n return signal === undefined ? {} : { signal };\n}\n\nfunction resolveApproval(\n toolName: AiSdkWorkspaceMutationToolName,\n config: AiSdkWorkspaceApprovalConfig,\n): boolean {\n return typeof config === 'boolean' ? config : (config[toolName] ?? true);\n}\n\nfunction resolveReadLimit(\n workspace: StorageWorkspace,\n requested: number | undefined,\n): number {\n const workspaceLimit = workspace.limits.maxReadBytes;\n if (!Number.isSafeInteger(workspaceLimit) || workspaceLimit <= 0) {\n throw new RangeError(\n 'workspace.limits.maxReadBytes must be a positive safe integer.',\n );\n }\n if (\n requested !== undefined &&\n (!Number.isSafeInteger(requested) || requested <= 0)\n ) {\n throw new RangeError('maxReadBytes must be a positive safe integer.');\n }\n return Math.min(requested ?? workspaceLimit, workspaceLimit);\n}\n\nfunction sanitizeToolError(\n error: unknown,\n signal: AbortSignal | undefined,\n): AiSdkWorkspaceToolError {\n if (error instanceof AiSdkWorkspaceToolError) {\n return error;\n }\n if (signal?.aborted === true) {\n return new AiSdkWorkspaceToolError(StorageErrorCode.ABORTED);\n }\n if (isStorageWorkspaceError(error)) {\n return new AiSdkWorkspaceToolError(error.code);\n }\n if (isStorageError(error)) {\n return new AiSdkWorkspaceToolError(error.code);\n }\n return new AiSdkWorkspaceToolError(StorageErrorCode.PROVIDER);\n}\n\nasync function executeSafely<Result>(\n signal: AbortSignal | undefined,\n operation: () => Promise<Result>,\n): Promise<Result> {\n try {\n return await operation();\n } catch (error) {\n throw sanitizeToolError(error, signal);\n }\n}\n\nfunction serializeFile(file: StorageWorkspaceFile): AiSdkWorkspaceFileResult {\n return {\n kind: 'file',\n path: file.path,\n name: file.name,\n size: file.size,\n contentType: file.contentType,\n ...(file.etag === undefined ? {} : { etag: file.etag }),\n ...(file.lastModified === undefined\n ? {}\n : { lastModified: file.lastModified.toISOString() }),\n };\n}\n\nfunction serializeEntry(\n entry: StorageWorkspaceEntry,\n): AiSdkWorkspaceEntryResult {\n return entry.kind === 'file'\n ? serializeFile(entry)\n : { kind: 'directory', path: entry.path, name: entry.name };\n}\n\nfunction serializeTextFile(\n file: StorageWorkspaceTextFile,\n): AiSdkWorkspaceTextFileResult {\n return { ...serializeFile(file), text: file.text };\n}\n\nfunction serializePage(page: {\n entries: StorageWorkspaceEntry[];\n cursor?: string;\n}): AiSdkWorkspacePageResult {\n return {\n entries: page.entries.map(serializeEntry),\n ...(page.cursor === undefined ? {} : { cursor: page.cursor }),\n };\n}\n\n/**\n * Creates Vercel AI SDK tools backed only by a mounted StorageWorkspace.\n *\n * A tool is omitted unless the workspace grants its required permission.\n * The workspace remains the enforcing boundary if a retained tool reference\n * is invoked after further narrowing.\n */\nexport function createAiSdkWorkspaceTools({\n workspace,\n maxReadBytes: requestedMaxReadBytes,\n requireApproval = true,\n}: CreateAiSdkWorkspaceToolsOptions): ToolSet {\n const maxReadBytes = resolveReadLimit(workspace, requestedMaxReadBytes);\n const tools: ToolSet = {};\n const pathSchema = logicalPath('File path', workspace.limits.maxPathBytes);\n const directorySchema = logicalPath(\n 'Directory path',\n workspace.limits.maxPathBytes,\n );\n const etagSchema = boundedEtag(workspace.limits.maxPathBytes);\n\n if (workspace.allows('list')) {\n tools.workspace_list = tool({\n description:\n 'List files and directories inside the mounted workspace. Omit directory to list the workspace root.',\n strict: true,\n inputSchema: z\n .object({\n directory: directorySchema.optional(),\n recursive: z\n .boolean()\n .optional()\n .describe('Whether to include descendants recursively.'),\n limit: positiveIntegerAtMost(\n workspace.limits.maxPageSize,\n `Maximum entries to return, up to ${workspace.limits.maxPageSize}.`,\n ),\n cursor: continuationCursor(\n 'Opaque one-use cursor returned by the preceding list call. Repeat the same directory, recursive, and limit options when continuing.',\n ),\n })\n .strict(),\n execute: (input, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializePage(\n await workspace.list({\n ...(input.directory === undefined\n ? {}\n : { directory: input.directory }),\n ...(input.recursive === undefined\n ? {}\n : { recursive: input.recursive }),\n ...(input.limit === undefined ? {} : { limit: input.limit }),\n ...(input.cursor === undefined ? {} : { cursor: input.cursor }),\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (workspace.allows('read')) {\n tools.workspace_stat = tool({\n description:\n 'Inspect a file inside the mounted workspace without reading its contents. Returns the ETag required for safe replace, move, and delete operations.',\n strict: true,\n inputSchema: z.object({ path: pathSchema }).strict(),\n execute: ({ path }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.stat(path, operationOptions(abortSignal)),\n ),\n ),\n });\n\n tools.workspace_read_file = tool({\n description: `Read a UTF-8 text file inside the mounted workspace. The result is bounded to ${maxReadBytes} bytes.`,\n strict: true,\n inputSchema: z.object({ path: pathSchema }).strict(),\n execute: ({ path }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeTextFile(\n await workspace.readText(path, {\n maxBytes: maxReadBytes,\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (workspace.allows('search')) {\n tools.workspace_search = tool({\n description:\n 'Search logical paths inside the mounted workspace using a bounded glob, substring, or exact match. Omit directory to search from the workspace root.',\n strict: true,\n inputSchema: z\n .object({\n query: searchQuery(workspace.limits.maxPathBytes),\n directory: directorySchema.optional(),\n match: z\n .enum(['glob', 'substring', 'exact'])\n .optional()\n .describe('Matching strategy; defaults to glob.'),\n caseInsensitive: z.boolean().optional(),\n limit: positiveIntegerAtMost(\n workspace.limits.maxSearchResults,\n `Maximum matches to return, up to ${workspace.limits.maxSearchResults}.`,\n ),\n cursor: continuationCursor(\n 'Opaque one-use cursor returned by the preceding search call. Repeat the same query, directory, match, caseInsensitive, and limit options when continuing.',\n ),\n })\n .strict(),\n execute: (\n { query, directory, match, caseInsensitive, limit, cursor },\n { abortSignal },\n ) =>\n executeSafely(abortSignal, async () =>\n serializePage(\n await workspace.search(query, {\n ...(directory === undefined ? {} : { directory }),\n ...(match === undefined ? {} : { match }),\n ...(caseInsensitive === undefined ? {} : { caseInsensitive }),\n ...(limit === undefined ? {} : { limit }),\n ...(cursor === undefined ? {} : { cursor }),\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n const canCreate = workspace.allows('create');\n const canReplace = workspace.allows('replace');\n if (canCreate || canReplace) {\n const commonWriteShape = {\n path: pathSchema,\n content: z\n .string()\n .refine(\n (value) =>\n utf8Encoder.encode(value).byteLength <=\n workspace.limits.maxWriteBytes,\n {\n message: `Content exceeds the ${workspace.limits.maxWriteBytes}-byte workspace write limit.`,\n },\n )\n .describe(\n `UTF-8 text to write. The workspace enforces its ${workspace.limits.maxWriteBytes}-byte write limit.`,\n ),\n };\n const createSchema = z\n .object({ ...commonWriteShape, mode: z.literal('create') })\n .strict();\n const replaceSchema = z\n .object({\n ...commonWriteShape,\n mode: z.literal('replace'),\n etag: etagSchema,\n })\n .strict();\n const inputSchema =\n canCreate && canReplace\n ? z.discriminatedUnion('mode', [createSchema, replaceSchema])\n : canCreate\n ? createSchema\n : replaceSchema;\n\n tools.workspace_write_file = tool({\n description:\n canCreate && canReplace\n ? 'Create a new UTF-8 text file or replace an existing file inside the mounted workspace. Create fails if the destination exists; replace requires its current ETag.'\n : canCreate\n ? 'Create a new UTF-8 text file inside the mounted workspace. The operation fails if the destination already exists.'\n : 'Replace an existing UTF-8 text file inside the mounted workspace using its current ETag.',\n strict: true,\n inputSchema,\n needsApproval: resolveApproval('workspace_write_file', requireApproval),\n execute: (input, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n input.mode === 'create'\n ? await workspace.writeFile(input.path, input.content, {\n mode: 'create',\n ...operationOptions(abortSignal),\n })\n : await workspace.writeFile(input.path, input.content, {\n mode: 'replace',\n etag: input.etag,\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n const canCopy =\n workspace.allows('copy') &&\n workspace.allows('read') &&\n workspace.allows('create');\n if (canCopy) {\n tools.workspace_copy_file = tool({\n description:\n 'Copy a file inside the mounted workspace. The source remains intact, and the operation fails if the destination already exists.',\n strict: true,\n inputSchema: z\n .object({\n source: logicalPath(\n 'Source file path',\n workspace.limits.maxPathBytes,\n ),\n destination: logicalPath(\n 'Destination file path',\n workspace.limits.maxPathBytes,\n ),\n })\n .strict(),\n needsApproval: resolveApproval('workspace_copy_file', requireApproval),\n execute: ({ source, destination }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.copyFile(\n source,\n destination,\n operationOptions(abortSignal),\n ),\n ),\n ),\n });\n }\n\n const canMove =\n workspace.allows('move') &&\n workspace.allows('read') &&\n workspace.allows('create') &&\n workspace.allows('delete');\n if (canMove) {\n tools.workspace_move_file = tool({\n description:\n \"Move a file inside the mounted workspace using the source's current ETag. The operation fails if the destination already exists. If source deletion cannot be confirmed, the destination is retained and the tool reports a conflict; inspect both paths before retrying.\",\n strict: true,\n inputSchema: z\n .object({\n source: logicalPath(\n 'Source file path',\n workspace.limits.maxPathBytes,\n ),\n destination: logicalPath(\n 'Destination file path',\n workspace.limits.maxPathBytes,\n ),\n etag: etagSchema.describe(\n 'Exact ETag of the source returned by the latest workspace stat or read.',\n ),\n })\n .strict(),\n needsApproval: resolveApproval('workspace_move_file', requireApproval),\n execute: ({ source, destination, etag }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.moveFile(source, destination, {\n etag,\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (workspace.allows('delete')) {\n tools.workspace_delete_file = tool({\n description:\n 'Delete a file inside the mounted workspace using its current ETag.',\n strict: true,\n inputSchema: z\n .object({\n path: pathSchema,\n etag: etagSchema,\n })\n .strict(),\n needsApproval: resolveApproval('workspace_delete_file', requireApproval),\n execute: ({ path, etag }, { abortSignal }) =>\n executeSafely(abortSignal, async () => {\n await workspace.deleteFile(path, {\n etag,\n ...operationOptions(abortSignal),\n });\n return { deleted: true as const, path };\n }),\n });\n }\n\n return tools;\n}\n\nexport function isAiSdkWorkspaceMutationToolName(\n value: string,\n): value is AiSdkWorkspaceMutationToolName {\n return mutationToolNames.has(value as AiSdkWorkspaceMutationToolName);\n}\n"]}
1
+ {"version":3,"file":"ai-sdk-workspace-tools.js","sourceRoot":"","sources":["../../src/ai-sdk/ai-sdk-workspace-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { tool, type JSONValue, type ToolSet } from 'ai';\nimport { z } from 'zod';\n\nimport {\n STORAGE_WORKSPACE_MAX_CURSOR_BYTES,\n isStorageWorkspaceError,\n type StorageWorkspace,\n type StorageWorkspaceEntry,\n type StorageWorkspaceFile,\n type StorageWorkspaceTextFile,\n} from '../workspace/index.js';\nimport {\n StorageErrorCode,\n isStorageError,\n type StorageErrorCode as StorageErrorCodeValue,\n} from '../storage.error.js';\nimport { isCanonicalStorageEtag } from '../storage-etag.js';\n\nexport const AI_SDK_WORKSPACE_TOOL_NAMES = [\n 'workspace_list',\n 'workspace_stat',\n 'workspace_read_file',\n 'workspace_search',\n 'workspace_write_file',\n 'workspace_copy_file',\n 'workspace_move_file',\n 'workspace_delete_file',\n] as const;\n\nexport type AiSdkWorkspaceToolName =\n (typeof AI_SDK_WORKSPACE_TOOL_NAMES)[number];\n\nexport type AiSdkWorkspaceMutationToolName = Extract<\n AiSdkWorkspaceToolName,\n | 'workspace_write_file'\n | 'workspace_copy_file'\n | 'workspace_move_file'\n | 'workspace_delete_file'\n>;\n\n/**\n * Approval policy for mutation tools. An omitted entry defaults to requiring\n * approval, matching an omitted policy.\n */\nexport type AiSdkWorkspaceApprovalConfig =\n boolean | Partial<Record<AiSdkWorkspaceMutationToolName, boolean>>;\n\nexport type AiSdkWorkspaceMutationMode = 'conditional' | 'last-write-wins';\n\nexport interface AiSdkWorkspaceCreateConflict {\n /** The logical destination inside the mounted workspace. */\n readonly path: string;\n}\n\nexport type AiSdkWorkspaceCreateConflictMapper<Result extends JSONValue> = (\n conflict: AiSdkWorkspaceCreateConflict,\n) => PromiseLike<Result> | Result;\n\nexport interface CreateAiSdkWorkspaceToolsOptions<\n CreateConflictResult extends JSONValue = never,\n> {\n /** The already-mounted, policy-enforcing workspace exposed to the tools. */\n workspace: StorageWorkspace;\n /**\n * Optional tighter read ceiling. Values above the workspace ceiling are\n * clamped; the model cannot choose or raise this value.\n */\n maxReadBytes?: number;\n /** Mutation tools require approval by default. */\n requireApproval?: AiSdkWorkspaceApprovalConfig;\n /**\n * Selects the mutation contract exposed to the model. Conditional mode is\n * the default; last-write-wins uses the workspace's ordinary Files path.\n */\n mutationMode?: AiSdkWorkspaceMutationMode;\n /**\n * Maps an atomic create collision to an application result. When omitted,\n * the collision remains an AiSdkWorkspaceToolError like every other storage\n * failure. Replace conflicts are never mapped by this hook. This option is\n * valid only when mutationMode is conditional.\n */\n mapCreateConflict?: AiSdkWorkspaceCreateConflictMapper<CreateConflictResult>;\n}\n\nexport type AiSdkWorkspaceToolErrorCode = StorageErrorCodeValue;\n\nconst SAFE_ERROR_MESSAGES: Readonly<\n Record<AiSdkWorkspaceToolErrorCode, string>\n> = {\n [StorageErrorCode.NOT_FOUND]: 'The requested workspace path was not found.',\n [StorageErrorCode.UNAUTHORIZED]:\n 'This operation is not permitted in the workspace.',\n [StorageErrorCode.CONFLICT]:\n 'The operation conflicts with current workspace state. Inspect the affected paths before retrying.',\n [StorageErrorCode.READ_ONLY]:\n 'This operation is not permitted in the workspace.',\n [StorageErrorCode.INVALID_ARGUMENT]: 'The workspace tool input was rejected.',\n [StorageErrorCode.NOT_SUPPORTED]:\n 'This workspace operation is not supported by the configured storage.',\n [StorageErrorCode.ABORTED]: 'The workspace operation was aborted.',\n [StorageErrorCode.TIMEOUT]: 'The workspace operation timed out.',\n [StorageErrorCode.LIMIT_EXCEEDED]:\n 'The workspace operation exceeded a configured limit.',\n [StorageErrorCode.PROVIDER]: 'The workspace operation failed.',\n};\n\n/**\n * Safe error exposed at the AI tool boundary. It deliberately carries no\n * provider error, storage key, mount prefix, store name, or cause.\n */\nexport class AiSdkWorkspaceToolError extends Error {\n readonly code: AiSdkWorkspaceToolErrorCode;\n\n constructor(code: AiSdkWorkspaceToolErrorCode) {\n super(SAFE_ERROR_MESSAGES[code]);\n this.name = 'AiSdkWorkspaceToolError';\n this.code = code;\n }\n}\n\nexport interface AiSdkWorkspaceFileResult {\n kind: 'file';\n path: string;\n name: string;\n size: number;\n contentType: string;\n etag?: string;\n lastModified?: string;\n}\n\nexport interface AiSdkWorkspaceDirectoryResult {\n kind: 'directory';\n path: string;\n name: string;\n}\n\nexport type AiSdkWorkspaceEntryResult =\n AiSdkWorkspaceFileResult | AiSdkWorkspaceDirectoryResult;\n\nexport interface AiSdkWorkspaceTextFileResult extends AiSdkWorkspaceFileResult {\n text: string;\n}\n\nexport interface AiSdkWorkspacePageResult {\n entries: AiSdkWorkspaceEntryResult[];\n cursor?: string;\n}\n\nconst mutationToolNames = new Set<AiSdkWorkspaceMutationToolName>([\n 'workspace_write_file',\n 'workspace_copy_file',\n 'workspace_move_file',\n 'workspace_delete_file',\n]);\nconst utf8Encoder = new TextEncoder();\nconst forbiddenUnicodeCharacter = /\\p{C}/u;\nconst workspaceCursor = /^[A-Za-z0-9._-]+$/u;\nconst windowsDeviceName = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\..*)?$/iu;\n\nfunction isLogicalPath(value: string): boolean {\n if (\n value.length === 0 ||\n value.startsWith('/') ||\n value.endsWith('/') ||\n value !== value.normalize('NFC') ||\n value.includes('\\\\') ||\n forbiddenUnicodeCharacter.test(value)\n ) {\n return false;\n }\n\n return value\n .split('/')\n .every(\n (segment) =>\n segment.length > 0 &&\n segment !== '.' &&\n segment !== '..' &&\n !segment.includes(':') &&\n !segment.endsWith('.') &&\n !segment.endsWith(' ') &&\n !windowsDeviceName.test(segment),\n );\n}\n\nfunction logicalPath(label: string, maxBytes: number) {\n return z\n .string()\n .min(1)\n .refine(isLogicalPath, {\n message: `${label} must be a portable, NFC-normalized, relative POSIX workspace path.`,\n })\n .refine((value) => utf8Encoder.encode(value).byteLength <= maxBytes, {\n message: `${label} exceeds the ${maxBytes}-byte workspace path limit.`,\n })\n .describe(\n `${label}. Use an NFC-normalized relative POSIX path inside the mounted workspace. Empty, dot, parent, colon, trailing dot or space, and Windows reserved device segments are forbidden.`,\n );\n}\n\nfunction searchQuery(maxBytes: number) {\n return z\n .string()\n .min(1)\n .refine(\n (value) =>\n !value.includes('\\\\') && !forbiddenUnicodeCharacter.test(value),\n { message: 'Search query contains forbidden characters.' },\n )\n .refine((value) => utf8Encoder.encode(value).byteLength <= maxBytes, {\n message: `Search query exceeds the ${maxBytes}-byte workspace limit.`,\n })\n .describe('Path pattern or text to find inside the mounted workspace.');\n}\n\nfunction boundedEtag() {\n return z\n .string()\n .refine(isCanonicalStorageEtag, {\n message: 'ETag must be a canonical bare value of at most 1,024 bytes.',\n })\n .describe(\n 'Exact canonical bare ETag returned by the latest workspace stat or read.',\n );\n}\n\nfunction continuationCursor(description: string, maxBytes: number) {\n return z\n .string()\n .min(1)\n .max(Math.min(STORAGE_WORKSPACE_MAX_CURSOR_BYTES, maxBytes))\n .regex(\n workspaceCursor,\n 'Cursor must be the bounded opaque token returned by the workspace.',\n )\n .optional()\n .describe(description);\n}\n\nfunction positiveIntegerAtMost(maximum: number, description: string) {\n return z\n .number()\n .int()\n .positive()\n .max(maximum)\n .optional()\n .describe(description);\n}\n\nfunction operationOptions(signal: AbortSignal | undefined): {\n signal?: AbortSignal;\n} {\n return signal === undefined ? {} : { signal };\n}\n\nfunction resolveApproval(\n toolName: AiSdkWorkspaceMutationToolName,\n config: AiSdkWorkspaceApprovalConfig,\n): boolean {\n return typeof config === 'boolean' ? config : (config[toolName] ?? true);\n}\n\nfunction resolveReadLimit(\n workspace: StorageWorkspace,\n requested: number | undefined,\n): number {\n const workspaceLimit = workspace.limits.maxReadBytes;\n if (!Number.isSafeInteger(workspaceLimit) || workspaceLimit <= 0) {\n throw new RangeError(\n 'workspace.limits.maxReadBytes must be a positive safe integer.',\n );\n }\n if (\n requested !== undefined &&\n (!Number.isSafeInteger(requested) || requested <= 0)\n ) {\n throw new RangeError('maxReadBytes must be a positive safe integer.');\n }\n return Math.min(requested ?? workspaceLimit, workspaceLimit);\n}\n\nfunction sanitizeToolError(\n error: unknown,\n signal: AbortSignal | undefined,\n): AiSdkWorkspaceToolError {\n if (error instanceof AiSdkWorkspaceToolError) {\n return error;\n }\n if (signal?.aborted === true) {\n return new AiSdkWorkspaceToolError(StorageErrorCode.ABORTED);\n }\n if (isStorageWorkspaceError(error)) {\n return new AiSdkWorkspaceToolError(error.code);\n }\n if (isStorageError(error)) {\n return new AiSdkWorkspaceToolError(error.code);\n }\n return new AiSdkWorkspaceToolError(StorageErrorCode.PROVIDER);\n}\n\nasync function executeSafely<Result>(\n signal: AbortSignal | undefined,\n operation: () => Promise<Result>,\n): Promise<Result> {\n try {\n return await operation();\n } catch (error) {\n throw sanitizeToolError(error, signal);\n }\n}\n\nasync function executeCreateAware<\n Result,\n CreateConflictResult extends JSONValue,\n>(\n signal: AbortSignal | undefined,\n input: { mode: 'create' | 'replace'; path: string },\n operation: () => Promise<Result>,\n mapCreateConflict:\n AiSdkWorkspaceCreateConflictMapper<CreateConflictResult> | undefined,\n): Promise<CreateConflictResult | Result> {\n try {\n return await operation();\n } catch (error) {\n const safeError = sanitizeToolError(error, signal);\n if (\n input.mode === 'create' &&\n safeError.code === StorageErrorCode.CONFLICT &&\n mapCreateConflict !== undefined\n ) {\n try {\n return await mapCreateConflict({ path: input.path });\n } catch {\n throw new AiSdkWorkspaceToolError(StorageErrorCode.PROVIDER);\n }\n }\n throw safeError;\n }\n}\n\nfunction serializeFile(file: StorageWorkspaceFile): AiSdkWorkspaceFileResult {\n if (file.etag !== undefined && !isCanonicalStorageEtag(file.etag)) {\n throw new Error('Workspace returned a malformed ETag.');\n }\n return {\n kind: 'file',\n path: file.path,\n name: file.name,\n size: file.size,\n contentType: file.contentType,\n ...(file.etag === undefined ? {} : { etag: file.etag }),\n ...(file.lastModified === undefined\n ? {}\n : { lastModified: file.lastModified.toISOString() }),\n };\n}\n\nfunction serializeEntry(\n entry: StorageWorkspaceEntry,\n): AiSdkWorkspaceEntryResult {\n return entry.kind === 'file'\n ? serializeFile(entry)\n : { kind: 'directory', path: entry.path, name: entry.name };\n}\n\nfunction serializeTextFile(\n file: StorageWorkspaceTextFile,\n): AiSdkWorkspaceTextFileResult {\n return { ...serializeFile(file), text: file.text };\n}\n\nfunction serializePage(page: {\n entries: StorageWorkspaceEntry[];\n cursor?: string;\n}): AiSdkWorkspacePageResult {\n return {\n entries: page.entries.map(serializeEntry),\n ...(page.cursor === undefined ? {} : { cursor: page.cursor }),\n };\n}\n\n/**\n * Creates Vercel AI SDK tools backed only by a mounted StorageWorkspace.\n *\n * A tool is omitted unless the workspace grants its required permission.\n * The workspace remains the enforcing boundary if a retained tool reference\n * is invoked after further narrowing.\n */\nexport function createAiSdkWorkspaceTools<\n CreateConflictResult extends JSONValue = never,\n>({\n workspace,\n maxReadBytes: requestedMaxReadBytes,\n mutationMode = 'conditional',\n requireApproval = true,\n mapCreateConflict,\n}: CreateAiSdkWorkspaceToolsOptions<CreateConflictResult>): ToolSet {\n if (mutationMode !== 'conditional' && mutationMode !== 'last-write-wins') {\n throw new RangeError(\n 'mutationMode must be \"conditional\" or \"last-write-wins\".',\n );\n }\n if (mutationMode === 'last-write-wins' && mapCreateConflict !== undefined) {\n throw new RangeError(\n 'mapCreateConflict is available only in conditional mutation mode.',\n );\n }\n const maxReadBytes = resolveReadLimit(workspace, requestedMaxReadBytes);\n const tools: ToolSet = {};\n const pathSchema = logicalPath('File path', workspace.limits.maxPathBytes);\n const directorySchema = logicalPath(\n 'Directory path',\n workspace.limits.maxPathBytes,\n );\n const etagSchema = boundedEtag();\n\n if (workspace.allows('list')) {\n tools.workspace_list = tool({\n description:\n 'List files and directories inside the mounted workspace. Omit directory to list the workspace root.',\n // Optional pagination and directory inputs are not compatible with\n // OpenAI strict function schemas, which require every property.\n strict: false,\n inputSchema: z\n .object({\n directory: directorySchema.optional(),\n recursive: z\n .boolean()\n .optional()\n .describe('Whether to include descendants recursively.'),\n limit: positiveIntegerAtMost(\n workspace.limits.maxPageSize,\n `Maximum entries to return, up to ${workspace.limits.maxPageSize}.`,\n ),\n cursor: continuationCursor(\n 'Opaque cursor returned by a preceding list call. It may be replayed before expiry while its provider continuation remains valid; repeat the same directory, recursive, and limit options when continuing.',\n workspace.limits.maxCursorBytes,\n ),\n })\n .strict(),\n execute: (input, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializePage(\n await workspace.list({\n ...(input.directory === undefined\n ? {}\n : { directory: input.directory }),\n ...(input.recursive === undefined\n ? {}\n : { recursive: input.recursive }),\n ...(input.limit === undefined ? {} : { limit: input.limit }),\n ...(input.cursor === undefined ? {} : { cursor: input.cursor }),\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (workspace.allows('read')) {\n tools.workspace_stat = tool({\n description:\n mutationMode === 'conditional'\n ? 'Inspect a file inside the mounted workspace without reading its contents. Returns the ETag required for safe replace, move, and delete operations.'\n : 'Inspect a file inside the mounted workspace without reading its contents. Any returned ETag is informational in last-write-wins mode.',\n strict: true,\n inputSchema: z.object({ path: pathSchema }).strict(),\n execute: ({ path }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.stat(path, operationOptions(abortSignal)),\n ),\n ),\n });\n\n tools.workspace_read_file = tool({\n description: `Read a UTF-8 text file inside the mounted workspace. The result is bounded to ${maxReadBytes} bytes.`,\n strict: true,\n inputSchema: z.object({ path: pathSchema }).strict(),\n execute: ({ path }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeTextFile(\n await workspace.readText(path, {\n maxBytes: maxReadBytes,\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (workspace.allows('search')) {\n tools.workspace_search = tool({\n description:\n 'Search logical paths inside the mounted workspace using a bounded glob, substring, or exact match. Omit directory to search from the workspace root.',\n // Search intentionally has optional filters and cursor inputs.\n strict: false,\n inputSchema: z\n .object({\n query: searchQuery(workspace.limits.maxPathBytes),\n directory: directorySchema.optional(),\n match: z\n .enum(['glob', 'substring', 'exact'])\n .optional()\n .describe('Matching strategy; defaults to glob.'),\n caseInsensitive: z.boolean().optional(),\n limit: positiveIntegerAtMost(\n workspace.limits.maxSearchResults,\n `Maximum matches to return, up to ${workspace.limits.maxSearchResults}.`,\n ),\n cursor: continuationCursor(\n 'Opaque cursor returned by a preceding search call. It may be replayed before expiry while its provider continuation remains valid; repeat the same query, directory, match, caseInsensitive, and limit options when continuing.',\n workspace.limits.maxCursorBytes,\n ),\n })\n .strict(),\n execute: (\n { query, directory, match, caseInsensitive, limit, cursor },\n { abortSignal },\n ) =>\n executeSafely(abortSignal, async () =>\n serializePage(\n await workspace.search(query, {\n ...(directory === undefined ? {} : { directory }),\n ...(match === undefined ? {} : { match }),\n ...(caseInsensitive === undefined ? {} : { caseInsensitive }),\n ...(limit === undefined ? {} : { limit }),\n ...(cursor === undefined ? {} : { cursor }),\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n const commonWriteShape = {\n path: pathSchema,\n content: z\n .string()\n .refine(\n (value) =>\n utf8Encoder.encode(value).byteLength <=\n workspace.limits.maxWriteBytes,\n {\n message: `Content exceeds the ${workspace.limits.maxWriteBytes}-byte workspace write limit.`,\n },\n )\n .describe(\n `UTF-8 text to write. The workspace enforces its ${workspace.limits.maxWriteBytes}-byte write limit.`,\n ),\n };\n if (mutationMode === 'last-write-wins' && workspace.allows('write')) {\n const inputSchema = z.object(commonWriteShape).strict();\n tools.workspace_write_file = tool({\n description:\n 'Write a UTF-8 text file inside the mounted workspace. An existing destination is overwritten; the last successful writer wins.',\n strict: true,\n inputSchema,\n needsApproval: resolveApproval('workspace_write_file', requireApproval),\n execute: ({ path, content }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.writeFile(path, content, {\n mode: 'overwrite',\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n } else if (mutationMode === 'conditional') {\n const canCreate = workspace.allows('create');\n const canReplace = workspace.allows('replace');\n if (canCreate || canReplace) {\n const createSchema = z\n .object({ ...commonWriteShape, mode: z.literal('create') })\n .strict();\n const replaceSchema = z\n .object({\n ...commonWriteShape,\n mode: z.literal('replace'),\n etag: etagSchema,\n })\n .strict();\n const inputSchema =\n canCreate && canReplace\n ? z.discriminatedUnion('mode', [createSchema, replaceSchema])\n : canCreate\n ? createSchema\n : replaceSchema;\n\n tools.workspace_write_file = tool<\n z.infer<typeof inputSchema>,\n unknown,\n Record<string, unknown>\n >({\n description:\n canCreate && canReplace\n ? 'Create a new UTF-8 text file or replace an existing file inside the mounted workspace. Create fails if the destination exists; replace requires its current ETag.'\n : canCreate\n ? 'Create a new UTF-8 text file inside the mounted workspace. The operation fails if the destination already exists.'\n : 'Replace an existing UTF-8 text file inside the mounted workspace using its current ETag.',\n // The combined create/replace schema is a discriminated union. OpenAI\n // strict function tools reject its root-level oneOf, while the runtime\n // Zod schema continues to validate every tool call in non-strict mode.\n strict: !(canCreate && canReplace),\n inputSchema,\n needsApproval: resolveApproval('workspace_write_file', requireApproval),\n execute: (input, { abortSignal }) =>\n executeCreateAware(\n abortSignal,\n input,\n async () =>\n serializeFile(\n input.mode === 'create'\n ? await workspace.writeFile(input.path, input.content, {\n mode: 'create',\n ...operationOptions(abortSignal),\n })\n : await workspace.writeFile(input.path, input.content, {\n mode: 'replace',\n etag: input.etag,\n ...operationOptions(abortSignal),\n }),\n ),\n mapCreateConflict,\n ),\n });\n }\n }\n\n const canCopy = workspace.allows('copy') && workspace.allows('read');\n if (\n mutationMode === 'last-write-wins' &&\n canCopy &&\n workspace.allows('write')\n ) {\n tools.workspace_copy_file = tool({\n description:\n 'Copy the latest readable contents of a file inside the mounted workspace. The source remains intact, and an existing destination is overwritten.',\n strict: true,\n inputSchema: z\n .object({\n source: logicalPath(\n 'Source file path',\n workspace.limits.maxPathBytes,\n ),\n destination: logicalPath(\n 'Destination file path',\n workspace.limits.maxPathBytes,\n ),\n })\n .strict(),\n needsApproval: resolveApproval('workspace_copy_file', requireApproval),\n execute: ({ source, destination }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.copyFile(source, destination, {\n mode: 'overwrite',\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n } else if (\n mutationMode === 'conditional' &&\n canCopy &&\n workspace.allows('create')\n ) {\n tools.workspace_copy_file = tool({\n description:\n 'Copy an exact observed version of a file inside the mounted workspace. The source remains intact, and the operation fails if the source changed or the destination already exists.',\n strict: true,\n inputSchema: z\n .object({\n source: logicalPath(\n 'Source file path',\n workspace.limits.maxPathBytes,\n ),\n destination: logicalPath(\n 'Destination file path',\n workspace.limits.maxPathBytes,\n ),\n etag: etagSchema.describe(\n 'Exact ETag of the source returned by the latest workspace stat or read.',\n ),\n })\n .strict(),\n needsApproval: resolveApproval('workspace_copy_file', requireApproval),\n execute: ({ source, destination, etag }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.copyFile(source, destination, {\n etag,\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (\n mutationMode === 'conditional' &&\n workspace.allows('move') &&\n workspace.allows('read') &&\n workspace.allows('delete') &&\n workspace.allows('create')\n ) {\n tools.workspace_move_file = tool({\n description:\n \"Move a file inside the mounted workspace using the source's current ETag. The operation fails if the destination already exists. If source deletion cannot be confirmed, the destination is retained and the tool reports a conflict; inspect both paths before retrying.\",\n strict: true,\n inputSchema: z\n .object({\n source: logicalPath(\n 'Source file path',\n workspace.limits.maxPathBytes,\n ),\n destination: logicalPath(\n 'Destination file path',\n workspace.limits.maxPathBytes,\n ),\n etag: etagSchema.describe(\n 'Exact ETag of the source returned by the latest workspace stat or read.',\n ),\n })\n .strict(),\n needsApproval: resolveApproval('workspace_move_file', requireApproval),\n execute: ({ source, destination, etag }, { abortSignal }) =>\n executeSafely(abortSignal, async () =>\n serializeFile(\n await workspace.moveFile(source, destination, {\n etag,\n ...operationOptions(abortSignal),\n }),\n ),\n ),\n });\n }\n\n if (\n mutationMode === 'last-write-wins' &&\n workspace.allows('delete') &&\n workspace.allows('write')\n ) {\n tools.workspace_delete_file = tool({\n description:\n 'Unconditionally delete the current file at a path inside the mounted workspace.',\n strict: true,\n inputSchema: z.object({ path: pathSchema }).strict(),\n needsApproval: resolveApproval('workspace_delete_file', requireApproval),\n execute: ({ path }, { abortSignal }) =>\n executeSafely(abortSignal, async () => {\n await workspace.deleteFile(path, {\n mode: 'unconditional',\n ...operationOptions(abortSignal),\n });\n return { deleted: true as const, path };\n }),\n });\n } else if (mutationMode === 'conditional' && workspace.allows('delete')) {\n tools.workspace_delete_file = tool({\n description:\n 'Delete a file inside the mounted workspace using its current ETag.',\n strict: true,\n inputSchema: z\n .object({\n path: pathSchema,\n etag: etagSchema,\n })\n .strict(),\n needsApproval: resolveApproval('workspace_delete_file', requireApproval),\n execute: ({ path, etag }, { abortSignal }) =>\n executeSafely(abortSignal, async () => {\n await workspace.deleteFile(path, {\n etag,\n ...operationOptions(abortSignal),\n });\n return { deleted: true as const, path };\n }),\n });\n }\n\n return tools;\n}\n\nexport function isAiSdkWorkspaceMutationToolName(\n value: string,\n): value is AiSdkWorkspaceMutationToolName {\n return mutationToolNames.has(value as AiSdkWorkspaceMutationToolName);\n}\n"]}
@@ -1,2 +1,2 @@
1
- export { AI_SDK_WORKSPACE_TOOL_NAMES, AiSdkWorkspaceToolError, createAiSdkWorkspaceTools, isAiSdkWorkspaceMutationToolName, type AiSdkWorkspaceApprovalConfig, type AiSdkWorkspaceDirectoryResult, type AiSdkWorkspaceEntryResult, type AiSdkWorkspaceFileResult, type AiSdkWorkspaceMutationToolName, type AiSdkWorkspacePageResult, type AiSdkWorkspaceTextFileResult, type AiSdkWorkspaceToolErrorCode, type AiSdkWorkspaceToolName, type CreateAiSdkWorkspaceToolsOptions, } from './ai-sdk-workspace-tools.js';
1
+ export { AI_SDK_WORKSPACE_TOOL_NAMES, AiSdkWorkspaceToolError, createAiSdkWorkspaceTools, isAiSdkWorkspaceMutationToolName, type AiSdkWorkspaceApprovalConfig, type AiSdkWorkspaceCreateConflict, type AiSdkWorkspaceCreateConflictMapper, type AiSdkWorkspaceDirectoryResult, type AiSdkWorkspaceEntryResult, type AiSdkWorkspaceFileResult, type AiSdkWorkspaceMutationMode, type AiSdkWorkspaceMutationToolName, type AiSdkWorkspacePageResult, type AiSdkWorkspaceTextFileResult, type AiSdkWorkspaceToolErrorCode, type AiSdkWorkspaceToolName, type CreateAiSdkWorkspaceToolsOptions, } from './ai-sdk-workspace-tools.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,EAChC,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,GACtC,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,EAChC,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EACjC,KAAK,kCAAkC,EACvC,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,GACtC,MAAM,6BAA6B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,GAWjC,MAAM,6BAA6B,CAAC","sourcesContent":["export {\n AI_SDK_WORKSPACE_TOOL_NAMES,\n AiSdkWorkspaceToolError,\n createAiSdkWorkspaceTools,\n isAiSdkWorkspaceMutationToolName,\n type AiSdkWorkspaceApprovalConfig,\n type AiSdkWorkspaceDirectoryResult,\n type AiSdkWorkspaceEntryResult,\n type AiSdkWorkspaceFileResult,\n type AiSdkWorkspaceMutationToolName,\n type AiSdkWorkspacePageResult,\n type AiSdkWorkspaceTextFileResult,\n type AiSdkWorkspaceToolErrorCode,\n type AiSdkWorkspaceToolName,\n type CreateAiSdkWorkspaceToolsOptions,\n} from './ai-sdk-workspace-tools.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,GAcjC,MAAM,6BAA6B,CAAC","sourcesContent":["export {\n AI_SDK_WORKSPACE_TOOL_NAMES,\n AiSdkWorkspaceToolError,\n createAiSdkWorkspaceTools,\n isAiSdkWorkspaceMutationToolName,\n type AiSdkWorkspaceApprovalConfig,\n type AiSdkWorkspaceCreateConflict,\n type AiSdkWorkspaceCreateConflictMapper,\n type AiSdkWorkspaceDirectoryResult,\n type AiSdkWorkspaceEntryResult,\n type AiSdkWorkspaceFileResult,\n type AiSdkWorkspaceMutationMode,\n type AiSdkWorkspaceMutationToolName,\n type AiSdkWorkspacePageResult,\n type AiSdkWorkspaceTextFileResult,\n type AiSdkWorkspaceToolErrorCode,\n type AiSdkWorkspaceToolName,\n type CreateAiSdkWorkspaceToolsOptions,\n} from './ai-sdk-workspace-tools.js';\n"]}