@nestm/storage 0.1.0-alpha.1 → 0.1.0-alpha.11

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 (162) hide show
  1. package/CHANGELOG.md +271 -0
  2. package/README.md +877 -25
  3. package/SECURITY.md +128 -0
  4. package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts +37 -0
  5. package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts.map +1 -0
  6. package/dist/ai-sdk/ai-sdk-file-workflow-tools.js +258 -0
  7. package/dist/ai-sdk/ai-sdk-file-workflow-tools.js.map +1 -0
  8. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts +91 -0
  9. package/dist/ai-sdk/ai-sdk-workspace-tools.d.ts.map +1 -0
  10. package/dist/ai-sdk/ai-sdk-workspace-tools.js +491 -0
  11. package/dist/ai-sdk/ai-sdk-workspace-tools.js.map +1 -0
  12. package/dist/ai-sdk/index.d.ts +3 -0
  13. package/dist/ai-sdk/index.d.ts.map +1 -0
  14. package/dist/ai-sdk/index.js +3 -0
  15. package/dist/ai-sdk/index.js.map +1 -0
  16. package/dist/bytes/index.d.ts +30 -0
  17. package/dist/bytes/index.d.ts.map +1 -0
  18. package/dist/bytes/index.js +96 -0
  19. package/dist/bytes/index.js.map +1 -0
  20. package/dist/core/index.d.ts +9 -0
  21. package/dist/core/index.d.ts.map +1 -0
  22. package/dist/core/index.js +7 -0
  23. package/dist/core/index.js.map +1 -0
  24. package/dist/core/storage-staged-content.d.ts +37 -0
  25. package/dist/core/storage-staged-content.d.ts.map +1 -0
  26. package/dist/core/storage-staged-content.js +94 -0
  27. package/dist/core/storage-staged-content.js.map +1 -0
  28. package/dist/core/storage-streams.d.ts +19 -0
  29. package/dist/core/storage-streams.d.ts.map +1 -0
  30. package/dist/core/storage-streams.js +95 -0
  31. package/dist/core/storage-streams.js.map +1 -0
  32. package/dist/core/storage-text.d.ts +33 -0
  33. package/dist/core/storage-text.d.ts.map +1 -0
  34. package/dist/core/storage-text.js +98 -0
  35. package/dist/core/storage-text.js.map +1 -0
  36. package/dist/files-sdk/files-sdk.driver.d.ts +85 -3
  37. package/dist/files-sdk/files-sdk.driver.d.ts.map +1 -1
  38. package/dist/files-sdk/files-sdk.driver.js +1437 -37
  39. package/dist/files-sdk/files-sdk.driver.js.map +1 -1
  40. package/dist/files-sdk/fs/index.d.ts +42 -0
  41. package/dist/files-sdk/fs/index.d.ts.map +1 -0
  42. package/dist/files-sdk/fs/index.js +1117 -0
  43. package/dist/files-sdk/fs/index.js.map +1 -0
  44. package/dist/files-sdk/index.d.ts +1 -1
  45. package/dist/files-sdk/index.d.ts.map +1 -1
  46. package/dist/files-sdk/index.js.map +1 -1
  47. package/dist/files-sdk/memory.d.ts +7 -0
  48. package/dist/files-sdk/memory.d.ts.map +1 -0
  49. package/dist/files-sdk/memory.js +72 -0
  50. package/dist/files-sdk/memory.js.map +1 -0
  51. package/dist/files-sdk/provider/index.d.ts +58 -0
  52. package/dist/files-sdk/provider/index.d.ts.map +1 -0
  53. package/dist/files-sdk/provider/index.js +151 -0
  54. package/dist/files-sdk/provider/index.js.map +1 -0
  55. package/dist/files-sdk/s3/construction-metadata.d.ts +9 -0
  56. package/dist/files-sdk/s3/construction-metadata.d.ts.map +1 -0
  57. package/dist/files-sdk/s3/construction-metadata.js +24 -0
  58. package/dist/files-sdk/s3/construction-metadata.js.map +1 -0
  59. package/dist/files-sdk/s3/index.d.ts +54 -0
  60. package/dist/files-sdk/s3/index.d.ts.map +1 -0
  61. package/dist/files-sdk/s3/index.js +1505 -0
  62. package/dist/files-sdk/s3/index.js.map +1 -0
  63. package/dist/gateway/index.d.ts +1 -1
  64. package/dist/gateway/index.d.ts.map +1 -1
  65. package/dist/gateway/index.js.map +1 -1
  66. package/dist/gateway/storage-gateway-fastify-parser.d.ts.map +1 -1
  67. package/dist/gateway/storage-gateway-fastify-parser.js.map +1 -1
  68. package/dist/gateway/storage-gateway.controller.d.ts +12 -11
  69. package/dist/gateway/storage-gateway.controller.d.ts.map +1 -1
  70. package/dist/gateway/storage-gateway.controller.js +240 -70
  71. package/dist/gateway/storage-gateway.controller.js.map +1 -1
  72. package/dist/gateway/storage-gateway.guard.d.ts.map +1 -1
  73. package/dist/gateway/storage-gateway.guard.js.map +1 -1
  74. package/dist/gateway/storage-gateway.module.d.ts.map +1 -1
  75. package/dist/gateway/storage-gateway.module.js +60 -1
  76. package/dist/gateway/storage-gateway.module.js.map +1 -1
  77. package/dist/gateway/storage-gateway.tokens.d.ts +1 -0
  78. package/dist/gateway/storage-gateway.tokens.d.ts.map +1 -1
  79. package/dist/gateway/storage-gateway.tokens.js +1 -0
  80. package/dist/gateway/storage-gateway.tokens.js.map +1 -1
  81. package/dist/gateway/storage-gateway.types.d.ts +53 -10
  82. package/dist/gateway/storage-gateway.types.d.ts.map +1 -1
  83. package/dist/gateway/storage-gateway.types.js.map +1 -1
  84. package/dist/index.d.ts +1 -5
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +1 -3
  87. package/dist/index.js.map +1 -1
  88. package/dist/inject-storage.decorator.js.map +1 -1
  89. package/dist/storage-etag.d.ts +13 -0
  90. package/dist/storage-etag.d.ts.map +1 -0
  91. package/dist/storage-etag.js +31 -0
  92. package/dist/storage-etag.js.map +1 -0
  93. package/dist/storage-upload-control.d.ts.map +1 -1
  94. package/dist/storage.client.d.ts +15 -3
  95. package/dist/storage.client.d.ts.map +1 -1
  96. package/dist/storage.client.js +204 -2
  97. package/dist/storage.client.js.map +1 -1
  98. package/dist/storage.driver.d.ts +28 -1
  99. package/dist/storage.driver.d.ts.map +1 -1
  100. package/dist/storage.driver.js.map +1 -1
  101. package/dist/storage.error.d.ts +17 -10
  102. package/dist/storage.error.d.ts.map +1 -1
  103. package/dist/storage.error.js +47 -1
  104. package/dist/storage.error.js.map +1 -1
  105. package/dist/storage.module.d.ts.map +1 -1
  106. package/dist/storage.module.js.map +1 -1
  107. package/dist/storage.service.d.ts.map +1 -1
  108. package/dist/storage.service.js +28 -3
  109. package/dist/storage.service.js.map +1 -1
  110. package/dist/storage.tokens.js.map +1 -1
  111. package/dist/storage.types.d.ts +150 -1
  112. package/dist/storage.types.d.ts.map +1 -1
  113. package/dist/storage.types.js.map +1 -1
  114. package/dist/testing/index.d.ts +1 -0
  115. package/dist/testing/index.d.ts.map +1 -1
  116. package/dist/testing/index.js +3 -1
  117. package/dist/testing/index.js.map +1 -1
  118. package/dist/testing/provider-conformance.d.ts +65 -0
  119. package/dist/testing/provider-conformance.d.ts.map +1 -0
  120. package/dist/testing/provider-conformance.js +869 -0
  121. package/dist/testing/provider-conformance.js.map +1 -0
  122. package/dist/workspace/index.d.ts +10 -0
  123. package/dist/workspace/index.d.ts.map +1 -0
  124. package/dist/workspace/index.js +8 -0
  125. package/dist/workspace/index.js.map +1 -0
  126. package/dist/workspace/storage-file-catalog.types.d.ts +65 -0
  127. package/dist/workspace/storage-file-catalog.types.d.ts.map +1 -0
  128. package/dist/workspace/storage-file-catalog.types.js +2 -0
  129. package/dist/workspace/storage-file-catalog.types.js.map +1 -0
  130. package/dist/workspace/storage-file-workflow.d.ts +7 -0
  131. package/dist/workspace/storage-file-workflow.d.ts.map +1 -0
  132. package/dist/workspace/storage-file-workflow.js +440 -0
  133. package/dist/workspace/storage-file-workflow.js.map +1 -0
  134. package/dist/workspace/storage-file-workflow.protection.d.ts +31 -0
  135. package/dist/workspace/storage-file-workflow.protection.d.ts.map +1 -0
  136. package/dist/workspace/storage-file-workflow.protection.js +258 -0
  137. package/dist/workspace/storage-file-workflow.protection.js.map +1 -0
  138. package/dist/workspace/storage-file-workflow.types.d.ts +128 -0
  139. package/dist/workspace/storage-file-workflow.types.d.ts.map +1 -0
  140. package/dist/workspace/storage-file-workflow.types.js +8 -0
  141. package/dist/workspace/storage-file-workflow.types.js.map +1 -0
  142. package/dist/workspace/storage-workspace.cursor.d.ts +71 -0
  143. package/dist/workspace/storage-workspace.cursor.d.ts.map +1 -0
  144. package/dist/workspace/storage-workspace.cursor.js +408 -0
  145. package/dist/workspace/storage-workspace.cursor.js.map +1 -0
  146. package/dist/workspace/storage-workspace.d.ts +6 -0
  147. package/dist/workspace/storage-workspace.d.ts.map +1 -0
  148. package/dist/workspace/storage-workspace.error.d.ts +32 -0
  149. package/dist/workspace/storage-workspace.error.d.ts.map +1 -0
  150. package/dist/workspace/storage-workspace.error.js +75 -0
  151. package/dist/workspace/storage-workspace.error.js.map +1 -0
  152. package/dist/workspace/storage-workspace.js +849 -0
  153. package/dist/workspace/storage-workspace.js.map +1 -0
  154. package/dist/workspace/storage-workspace.path.d.ts +9 -0
  155. package/dist/workspace/storage-workspace.path.d.ts.map +1 -0
  156. package/dist/workspace/storage-workspace.path.js +68 -0
  157. package/dist/workspace/storage-workspace.path.js.map +1 -0
  158. package/dist/workspace/storage-workspace.types.d.ts +123 -0
  159. package/dist/workspace/storage-workspace.types.d.ts.map +1 -0
  160. package/dist/workspace/storage-workspace.types.js +22 -0
  161. package/dist/workspace/storage-workspace.types.js.map +1 -0
  162. package/package.json +94 -20
package/SECURITY.md CHANGED
@@ -23,3 +23,131 @@ cross-store pruning, or dependency compromise are especially useful.
23
23
  For a vulnerability originating in NestJS, `files-sdk`, or a provider SDK,
24
24
  follow that project's security policy as well. You may still report it here
25
25
  privately when this integration needs a mitigation.
26
+
27
+ ## Gateway security boundary
28
+
29
+ Mounting the optional HTTP gateway requires both authentication guards and a
30
+ `StorageGatewayKeyPolicy`. The policy receives parsed paths and must derive the
31
+ provider key space from trusted request context. Do not treat a client prefix
32
+ or object key as a tenant identifier. `unsafeAllowUnscopedKeys` exists only to
33
+ migrate trusted single-tenant deployments and is unsafe on an exposed gateway.
34
+
35
+ Signed URL expiry, signed-upload byte size, and signed-upload MIME are bounded
36
+ by module configuration and cannot be increased by a request. Only `inline`
37
+ and `attachment` content dispositions are accepted. File type still must be
38
+ verified from magic bytes after upload; a signed MIME condition proves only
39
+ what header the uploader supplied. The gateway rejects signed-upload drivers
40
+ that do not advertise provider-enforced content-type and size-range policies.
41
+ It also rejects download adapters that cannot guarantee the requested expiry;
42
+ in particular, the S3 bridge does not treat `publicBaseUrl` links as expiring.
43
+
44
+ For staged uploads on S3, use `promote`/`promoteTo` with the ETag returned by
45
+ the validated `head` or with an immutable provider version. Ordinary `copy`
46
+ does not protect against a staging-key replay between validation and copy.
47
+ Conditional promotion keeps the staging source; delete it only after the
48
+ application's metadata transaction commits.
49
+
50
+ ## Workspace security boundary
51
+
52
+ Durable file workflows use opaque host scopes and explicit persistence ports.
53
+ The host must reauthorize `transaction`'s `permission` on every call, including
54
+ idempotent replay, and serialize the scope's draft state across replicas. Head
55
+ predicates, all head changes, and committed draft receipts must share one
56
+ rollback-capable host transaction. Streamed object preparation is outside that
57
+ transaction; the package does not make object-store writes multi-file atomic.
58
+ Provider/network response loss can remain ambiguous. Reconcile by replaying the
59
+ durable request; do not infer rollback from an abort or lost response.
60
+
61
+ Construct protected catalog/workflow handles from the same trusted host scope,
62
+ bind their execution signal, and keep storage clients and persistence ports
63
+ private. The protector rechecks fresh authorization and composes caller aborts;
64
+ the host transaction independently rechecks authority at commit.
65
+ Workflow restrictions check each persisted draft's create/replace intent on
66
+ mutation and replay; they cannot widen grants, limits or detach parent abort.
67
+ The checks do not depend on a public draft-read permission. Product-only
68
+ feature closures must capture these same checks when the handle is acquired.
69
+ The structural catalog/workflow getters do not authenticate untrusted objects.
70
+
71
+ Staged bodies use native create-only writes and exact ETag reads. Integrity
72
+ receipts verify full draft chunks during assembly. Conditional body removal is
73
+ available only as a host-invoked primitive: references, eligibility and cleanup
74
+ races are host-owned. Never delete a body merely because a commit request failed
75
+ or timed out; another in-flight or committed request may reference it. The
76
+ memory adapter is volatile and its raw Map is a trusted escape hatch, not an
77
+ authorization boundary.
78
+
79
+ `StorageWorkspace` is a narrowing capability for storage operations. Construct
80
+ it from trusted application context, keep the underlying `StorageClient` and
81
+ mount prefix private, and pass only the workspace or its AI tool set to
82
+ untrusted agent code. A tenant id, run id, prefix, provider cursor, snapshot id,
83
+ or fork id supplied by a model is not a safe mount coordinate.
84
+
85
+ The workspace accepts only canonical mount-relative POSIX paths and rechecks
86
+ every key returned by a driver before unscoping it. Pagination cursors are bound
87
+ to the store, normalized physical prefix, stable mount identity, trusted
88
+ tenant/workspace scope, operation, complete effective limits, normalized query,
89
+ and expiry. Provider continuations and prefixes stay inside the encrypted or
90
+ server-side payload. Both layers are non-consuming: a durable opaque token
91
+ store must read rather than consume a record, and an embedded provider cursor
92
+ must remain replayable through a fresh compatible driver against the same
93
+ backend namespace while that provider cursor remains valid and available.
94
+ Provider cursors cannot depend on process-local state; an adapter for a
95
+ consuming or instance-bound backend token must materialize a stable continuation
96
+ before exposing paginated `StorageDriver.list` results.
97
+
98
+ Under unchanged provider-visible state, cursors are reusable while their
99
+ provider continuation remains valid and available. The authenticated expiry is
100
+ an authorization ceiling, not a guarantee of provider-token lifetime, snapshot
101
+ isolation, provider/network availability, or valid credentials. Provider
102
+ invalidation remains an operational failure, and concurrent mutations remain
103
+ subject to provider ordering, duplicate, and omission semantics.
104
+
105
+ Production pagination must configure either the built-in AES-256-GCM codec with
106
+ a dedicated shared 32-byte key ring or an authenticated shared durable token
107
+ store. Do not reuse an authentication, session, storage-provider, or encryption
108
+ key from another purpose. All replicas must use the same stable identities and
109
+ key ring, compatible driver configuration, and logical backend namespace. New
110
+ cursors use the active key id; retain prior keys for at least the maximum cursor
111
+ TTL during rotation. Dropping a key, changing a binding field, or restarting
112
+ with a different ephemeral key intentionally invalidates outstanding cursors.
113
+ Tokens and decoded payloads are bounded, and malformed, altered, expired,
114
+ cross-query, cross-operation, cross-workspace, and cross-store cursors fail
115
+ closed.
116
+
117
+ Permissions, byte limits, result limits, and conditional mutation preconditions
118
+ are enforced inside the capability; tool omission and user approval are
119
+ additional workflow controls, not the authorization boundary.
120
+
121
+ Conditional mutations can still have an ambiguous outcome when a remote
122
+ provider commits and then loses or violates its response, or when a configured
123
+ post-operation plugin fails after the driver has committed. Known post-commit
124
+ failures report `StorageError.applied === true`; a conditional upload also
125
+ carries `appliedEtag` when its committed generation is known. This is positive
126
+ evidence, not a complete remote-commit oracle: a timeout, connection loss, or
127
+ exhausted retry can lose a provider success response and still leave
128
+ `applied === false`. Do not reissue an ambiguous predicate blindly. Reconcile
129
+ the logical destination first, using an exact ETag read when `appliedEtag` is
130
+ available and inspecting the relevant source/destination state for copy or
131
+ delete. Create-only and ETag preconditions prevent a blind retry from silently
132
+ overwriting a different object, but they cannot make a multi-object move
133
+ transactionally atomic.
134
+
135
+ This guarantee covers calls made through `StorageWorkspace`. It does not
136
+ confine arbitrary `node:fs`, shell, subprocess, or native-code access in the
137
+ same process. A coding harness with built-in shell or filesystem tools must run
138
+ inside an OS sandbox (container, VM, or equivalent) that exposes only a
139
+ materialized workspace. Setting `cwd` to a workspace directory is not
140
+ isolation.
141
+
142
+ For local filesystem storage, use a dedicated service-owned root and route all
143
+ in-process mutations through the package-decorated adapter; its ordinary and
144
+ conditional mutation paths share one lock domain. A separate process,
145
+ unwrapped adapter, or direct filesystem writer can bypass that coordination and
146
+ must not mutate the tree concurrently. High-level Node filesystem checks reject
147
+ symlinks and hard-linked object files in existing workspace read and mutation
148
+ paths, including metadata sidecars, but cannot provide a race-proof boundary
149
+ against an actor that can replace path components between validation and use.
150
+ For that threat model, mount only the workspace into a separate
151
+ UID/container/VM and synchronize approved results back through storage. The
152
+ local adapter also commits the body and metadata sidecar as two files; a process
153
+ crash between their atomic renames can require reconciliation.
@@ -0,0 +1,37 @@
1
+ import { type ToolSet } from 'ai';
2
+ import { z } from 'zod';
3
+ import type { StorageFileCatalogCapability, StorageFileWorkflowCapability } from '../workspace/index.js';
4
+ export interface CreateAiSdkFileWorkflowToolsOptions<Receipt> {
5
+ readonly workflow: StorageFileWorkflowCapability<Receipt>;
6
+ readonly requireApproval?: boolean;
7
+ /** Host-generated token, scoped and stable across replay of this tool call. */
8
+ readonly idempotencyKey?: (toolCallId: string) => string;
9
+ readonly maxChunkBytes?: number;
10
+ }
11
+ export interface CreateAiSdkCatalogFileToolsOptions<Receipt> {
12
+ readonly catalog: StorageFileCatalogCapability<Receipt>;
13
+ readonly requireApproval?: boolean;
14
+ readonly commandId?: (toolCallId: string) => string;
15
+ readonly maxWriteBytes?: number;
16
+ }
17
+ export declare const AI_SDK_FILE_WORKFLOW_TOOL_NAMES: readonly ['workspace_begin_file_draft', 'workspace_append_file_draft', 'workspace_list_file_drafts', 'workspace_read_file_draft', 'workspace_list_file_draft_parts', 'workspace_cancel_file_draft', 'workspace_commit_files'];
18
+ export declare const AI_SDK_CATALOG_FILE_TOOL_NAMES: readonly ['workspace_list', 'workspace_stat', 'workspace_search', 'workspace_read_file', 'workspace_search_content', 'workspace_write_file', 'workspace_append_file', 'workspace_edit_file'];
19
+ /** Typed extension seam for host-only metadata; preserves generic byte validation. */
20
+ export declare function createAiSdkCatalogFileEditSchemas(maxWriteBytes?: number): {
21
+ append: z.ZodObject<{
22
+ path: z.ZodString;
23
+ expectedEtag: z.ZodString;
24
+ content: z.ZodString;
25
+ }, z.core.$strict>;
26
+ edit: z.ZodObject<{
27
+ path: z.ZodString;
28
+ expectedEtag: z.ZodString;
29
+ oldText: z.ZodString;
30
+ newText: z.ZodString;
31
+ }, z.core.$strict>;
32
+ };
33
+ /** Generic durable-file tools. Provider upload controls are a separate capability. */
34
+ export declare function createAiSdkFileWorkflowTools<Receipt>(options: CreateAiSdkFileWorkflowToolsOptions<Receipt>): ToolSet;
35
+ /** Catalog-backed alternative to the existing raw-workspace tool factory. */
36
+ export declare function createAiSdkCatalogFileTools<Receipt>(options: CreateAiSdkCatalogFileToolsOptions<Receipt>): ToolSet;
37
+ //# sourceMappingURL=ai-sdk-file-workflow-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-sdk-file-workflow-tools.d.ts","sourceRoot":"","sources":["../../src/ai-sdk/ai-sdk-file-workflow-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,uBAAuB,CAAC;AAG/B,MAAM,WAAW,mCAAmC,CAAC,OAAO;IAC1D,QAAQ,CAAC,QAAQ,EAAE,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAC1D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AACD,MAAM,WAAW,kCAAkC,CAAC,OAAO;IACzD,QAAQ,CAAC,OAAO,EAAE,4BAA4B,CAAC,OAAO,CAAC,CAAC;IACxD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACpD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AACD,eAAO,MAAM,+BAA+B,YAC1C,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,2BAA2B,EAC3B,iCAAiC,EACjC,6BAA6B,EAC7B,wBAAwB,CAChB,CAAC;AACX,eAAO,MAAM,8BAA8B,YACzC,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,CACb,CAAC;AAuCX,sFAAsF;AACtF,wBAAgB,iCAAiC,CAAC,aAAa,SAAO;IAGlE,MAAM;;;;;IACN,IAAI;;;;;;EAOP;AAED,sFAAsF;AACtF,wBAAgB,4BAA4B,CAAC,OAAO,EAClD,OAAO,EAAE,mCAAmC,CAAC,OAAO,CAAC,GACpD,OAAO,CA6GT;AAED,6EAA6E;AAC7E,wBAAgB,2BAA2B,CAAC,OAAO,EACjD,OAAO,EAAE,kCAAkC,CAAC,OAAO,CAAC,GACnD,OAAO,CAgIT"}
@@ -0,0 +1,258 @@
1
+ import { tool } from 'ai';
2
+ import { z } from 'zod';
3
+ import { isStorageError } from '../storage.error.js';
4
+ import { AiSdkWorkspaceToolError } from './ai-sdk-workspace-tools.js';
5
+ export const AI_SDK_FILE_WORKFLOW_TOOL_NAMES = [
6
+ 'workspace_begin_file_draft',
7
+ 'workspace_append_file_draft',
8
+ 'workspace_list_file_drafts',
9
+ 'workspace_read_file_draft',
10
+ 'workspace_list_file_draft_parts',
11
+ 'workspace_cancel_file_draft',
12
+ 'workspace_commit_files',
13
+ ];
14
+ export const AI_SDK_CATALOG_FILE_TOOL_NAMES = [
15
+ 'workspace_list',
16
+ 'workspace_stat',
17
+ 'workspace_search',
18
+ 'workspace_read_file',
19
+ 'workspace_search_content',
20
+ 'workspace_write_file',
21
+ 'workspace_append_file',
22
+ 'workspace_edit_file',
23
+ ];
24
+ const offset = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
25
+ const identity = z.string().min(1).max(256);
26
+ const etag = z.string().min(1).max(1024);
27
+ const path = z.string().min(1).max(1024);
28
+ const page = { offset: offset.default(0) };
29
+ function textSchema(maxBytes) {
30
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1)
31
+ throw new TypeError('Text tool limit must be a positive safe integer.');
32
+ return z
33
+ .string()
34
+ .max(maxBytes)
35
+ .refine((text) => !/[\uD800-\uDFFF]/u.test(text), 'Text must be well-formed UTF-8.')
36
+ .refine((text) => new TextEncoder().encode(text).byteLength <= maxBytes, `Use at most ${maxBytes} UTF-8 bytes per call.`);
37
+ }
38
+ async function safe(work) {
39
+ try {
40
+ return await work();
41
+ }
42
+ catch (error) {
43
+ if (isStorageError(error))
44
+ throw new AiSdkWorkspaceToolError(error.code, {
45
+ applied: error.applied,
46
+ ...(error.appliedEtag === undefined
47
+ ? {}
48
+ : { appliedEtag: error.appliedEtag }),
49
+ });
50
+ if (error instanceof DOMException && error.name === 'AbortError')
51
+ throw new AiSdkWorkspaceToolError('ABORTED');
52
+ throw new AiSdkWorkspaceToolError('PROVIDER');
53
+ }
54
+ }
55
+ /** Typed extension seam for host-only metadata; preserves generic byte validation. */
56
+ export function createAiSdkCatalogFileEditSchemas(maxWriteBytes = 8192) {
57
+ const content = textSchema(maxWriteBytes);
58
+ return {
59
+ append: z.strictObject({ path, expectedEtag: etag, content }),
60
+ edit: z.strictObject({
61
+ path,
62
+ expectedEtag: etag,
63
+ oldText: content.refine((text) => text.length > 0),
64
+ newText: content,
65
+ }),
66
+ };
67
+ }
68
+ /** Generic durable-file tools. Provider upload controls are a separate capability. */
69
+ export function createAiSdkFileWorkflowTools(options) {
70
+ const { workflow } = options;
71
+ const tools = {};
72
+ const content = textSchema(Math.min(options.maxChunkBytes ?? 8192, workflow.limits.maxChunkBytes));
73
+ const approval = options.requireApproval ?? true;
74
+ if (workflow.allows('read'))
75
+ Object.assign(tools, {
76
+ workspace_list_file_drafts: tool({
77
+ description: 'List durable drafts. Resume open drafts at their current UTF-8 byte size; use nextOffset for pagination.',
78
+ inputSchema: z.strictObject(page),
79
+ execute: (input, context) => safe(() => workflow.list({ ...input, signal: context.abortSignal })),
80
+ }),
81
+ workspace_read_file_draft: tool({
82
+ description: `Read a draft window of at most ${workflow.limits.maxReadBytes} UTF-8 bytes. Continue with nextOffset, which is a byte position at a Unicode boundary.`,
83
+ inputSchema: z.strictObject({ draftId: identity, ...page }),
84
+ execute: (input, context) => safe(() => workflow.read({ ...input, signal: context.abortSignal })),
85
+ }),
86
+ workspace_list_file_draft_parts: tool({
87
+ description: 'List bounded chunk integrity receipts for resumption. Each receipt contains its byte offset, size, and SHA-256.',
88
+ inputSchema: z.strictObject({ draftId: identity, ...page }),
89
+ execute: (input, context) => safe(() => workflow.parts({ ...input, signal: context.abortSignal })),
90
+ }),
91
+ });
92
+ if (workflow.allows('write'))
93
+ Object.assign(tools, {
94
+ workspace_begin_file_draft: tool({
95
+ strict: false,
96
+ needsApproval: approval,
97
+ description: 'Begin a durable text draft without changing a visible file. Omit expectedEtag to create a new path; supply the exact current ETag to replace. Use drafts for substantial content and resume interrupted drafts.',
98
+ inputSchema: z.strictObject({ path, expectedEtag: etag.optional() }),
99
+ execute: (input, context) => safe(() => workflow.begin({
100
+ ...input,
101
+ text: true,
102
+ idempotencyKey: options.idempotencyKey?.(context.toolCallId) ??
103
+ context.toolCallId,
104
+ signal: context.abortSignal,
105
+ })),
106
+ }),
107
+ workspace_append_file_draft: tool({
108
+ needsApproval: approval,
109
+ description: 'Append a bounded UTF-8 chunk at the draft’s returned byte size. Replaying identical bytes at the same offset is safe; different bytes or a stale offset fail.',
110
+ inputSchema: z.strictObject({
111
+ draftId: identity,
112
+ offset,
113
+ content: content.refine((text) => text.length > 0),
114
+ }),
115
+ execute: (input, context) => safe(() => workflow.append({
116
+ draftId: input.draftId,
117
+ offset: input.offset,
118
+ bytes: new TextEncoder().encode(input.content),
119
+ signal: context.abortSignal,
120
+ })),
121
+ }),
122
+ workspace_cancel_file_draft: tool({
123
+ needsApproval: approval,
124
+ description: 'Cancel an unfinished draft without changing a visible file. A committed draft cannot be cancelled.',
125
+ inputSchema: z.strictObject({ draftId: identity }),
126
+ execute: (input, context) => safe(() => workflow.cancel({ ...input, signal: context.abortSignal })),
127
+ }),
128
+ });
129
+ if (workflow.allows('commit'))
130
+ tools.workspace_commit_files = tool({
131
+ strict: false,
132
+ needsApproval: approval,
133
+ description: `Atomically commit 1–${workflow.limits.maxCommitFiles} distinct completed drafts. Supply exact byte sizes. Optional SHA-256 must be known, never invented. A stale head rolls the whole batch back; replay returns stored receipts.`,
134
+ inputSchema: z.strictObject({
135
+ drafts: z
136
+ .array(z.strictObject({
137
+ draftId: identity,
138
+ size: offset,
139
+ sha256: z
140
+ .string()
141
+ .regex(/^[0-9a-f]{64}$/u)
142
+ .optional(),
143
+ }))
144
+ .min(1)
145
+ .max(workflow.limits.maxCommitFiles),
146
+ }),
147
+ execute: (input, context) => safe(async () => ({
148
+ items: await workflow.commit({
149
+ ...input,
150
+ signal: context.abortSignal,
151
+ }),
152
+ })),
153
+ });
154
+ return Object.freeze(tools);
155
+ }
156
+ /** Catalog-backed alternative to the existing raw-workspace tool factory. */
157
+ export function createAiSdkCatalogFileTools(options) {
158
+ const { catalog } = options;
159
+ const tools = {};
160
+ const content = textSchema(Math.min(options.maxWriteBytes ?? 8192, catalog.limits.maxWriteBytes));
161
+ const editSchemas = createAiSdkCatalogFileEditSchemas(Math.min(options.maxWriteBytes ?? 8192, catalog.limits.maxWriteBytes));
162
+ const approval = options.requireApproval ?? true;
163
+ const commandId = options.commandId ?? ((toolCallId) => toolCallId);
164
+ if (catalog.allows('read'))
165
+ Object.assign(tools, {
166
+ workspace_list: tool({
167
+ strict: false,
168
+ description: 'List authorized file catalog entries. Paths are mount-relative. Continue with nextOffset.',
169
+ inputSchema: z.strictObject({
170
+ directory: z.string().optional(),
171
+ ...page,
172
+ }),
173
+ execute: (input, context) => safe(() => catalog.list({ ...input, signal: context.abortSignal })),
174
+ }),
175
+ workspace_stat: tool({
176
+ description: 'Read a file identity, ETag, size and content type without loading its body.',
177
+ inputSchema: z.strictObject({ path }),
178
+ execute: (input, context) => safe(() => catalog.stat({ ...input, signal: context.abortSignal })),
179
+ }),
180
+ workspace_search: tool({
181
+ description: 'Search file paths by literal substring. Continue with nextOffset even when a page has no matches.',
182
+ inputSchema: z.strictObject({
183
+ query: z.string().min(1).max(256),
184
+ ...page,
185
+ }),
186
+ execute: (input, context) => safe(() => catalog.search({ ...input, signal: context.abortSignal })),
187
+ }),
188
+ workspace_read_file: tool({
189
+ strict: false,
190
+ description: `Read at most ${catalog.limits.maxReadBytes} UTF-8 bytes. offset/nextOffset are byte positions at Unicode boundaries. Continue with nextOffset and the same expectedEtag.`,
191
+ inputSchema: z.strictObject({
192
+ path,
193
+ expectedEtag: etag.optional(),
194
+ ...page,
195
+ }),
196
+ execute: (input, context) => safe(() => catalog.readWindow({ ...input, signal: context.abortSignal })),
197
+ }),
198
+ workspace_search_content: tool({
199
+ strict: false,
200
+ description: `Search literal text in one exact file revision. Scan at most ${catalog.limits.maxSearchScanBytes} bytes per call. Continue with nextOffset and the same expectedEtag.`,
201
+ inputSchema: z.strictObject({
202
+ path,
203
+ expectedEtag: etag,
204
+ query: z.string().min(1).max(256),
205
+ ...page,
206
+ }),
207
+ execute: (input, context) => safe(() => catalog.searchContent({ ...input, signal: context.abortSignal })),
208
+ }),
209
+ });
210
+ if (catalog.allows('write'))
211
+ Object.assign(tools, {
212
+ workspace_write_file: tool({
213
+ strict: false,
214
+ needsApproval: approval,
215
+ description: 'Create or conditionally replace a small UTF-8 file. Omit expectedEtag to create; supply the exact current ETag to replace. Use durable drafts for substantial content.',
216
+ inputSchema: z.strictObject({
217
+ path,
218
+ expectedEtag: etag.optional(),
219
+ content,
220
+ }),
221
+ execute: (input, context) => safe(() => catalog.write({
222
+ ...input,
223
+ commandId: commandId(context.toolCallId),
224
+ signal: context.abortSignal,
225
+ })),
226
+ }),
227
+ workspace_append_file: tool({
228
+ needsApproval: approval,
229
+ description: 'Append a bounded UTF-8 chunk to one exact file revision. Pass the latest ETag; retry identity prevents duplicate appends. Durable drafts support large generation.',
230
+ inputSchema: editSchemas.append,
231
+ execute: (input, context) => safe(() => catalog.edit({
232
+ path: input.path,
233
+ expectedEtag: input.expectedEtag,
234
+ change: { kind: 'append', text: input.content },
235
+ commandId: commandId(context.toolCallId),
236
+ signal: context.abortSignal,
237
+ })),
238
+ }),
239
+ workspace_edit_file: tool({
240
+ needsApproval: approval,
241
+ description: 'Replace one exact unique text span at the latest expectedEtag. oldText must match exactly once. The result carries the next revision receipt.',
242
+ inputSchema: editSchemas.edit,
243
+ execute: (input, context) => safe(() => catalog.edit({
244
+ path: input.path,
245
+ expectedEtag: input.expectedEtag,
246
+ change: {
247
+ kind: 'replace',
248
+ oldText: input.oldText,
249
+ newText: input.newText,
250
+ },
251
+ commandId: commandId(context.toolCallId),
252
+ signal: context.abortSignal,
253
+ })),
254
+ }),
255
+ });
256
+ return Object.freeze(tools);
257
+ }
258
+ //# sourceMappingURL=ai-sdk-file-workflow-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-sdk-file-workflow-tools.js","sourceRoot":"","sources":["../../src/ai-sdk/ai-sdk-file-workflow-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { tool, type ToolSet } from 'ai';\nimport { z } from 'zod';\nimport { isStorageError } from '../storage.error.js';\nimport type {\n StorageFileCatalogCapability,\n StorageFileWorkflowCapability,\n} from '../workspace/index.js';\nimport { AiSdkWorkspaceToolError } from './ai-sdk-workspace-tools.js';\n\nexport interface CreateAiSdkFileWorkflowToolsOptions<Receipt> {\n readonly workflow: StorageFileWorkflowCapability<Receipt>;\n readonly requireApproval?: boolean;\n /** Host-generated token, scoped and stable across replay of this tool call. */\n readonly idempotencyKey?: (toolCallId: string) => string;\n readonly maxChunkBytes?: number;\n}\nexport interface CreateAiSdkCatalogFileToolsOptions<Receipt> {\n readonly catalog: StorageFileCatalogCapability<Receipt>;\n readonly requireApproval?: boolean;\n readonly commandId?: (toolCallId: string) => string;\n readonly maxWriteBytes?: number;\n}\nexport const AI_SDK_FILE_WORKFLOW_TOOL_NAMES = [\n 'workspace_begin_file_draft',\n 'workspace_append_file_draft',\n 'workspace_list_file_drafts',\n 'workspace_read_file_draft',\n 'workspace_list_file_draft_parts',\n 'workspace_cancel_file_draft',\n 'workspace_commit_files',\n] as const;\nexport const AI_SDK_CATALOG_FILE_TOOL_NAMES = [\n 'workspace_list',\n 'workspace_stat',\n 'workspace_search',\n 'workspace_read_file',\n 'workspace_search_content',\n 'workspace_write_file',\n 'workspace_append_file',\n 'workspace_edit_file',\n] as const;\n\nconst offset = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);\nconst identity = z.string().min(1).max(256);\nconst etag = z.string().min(1).max(1024);\nconst path = z.string().min(1).max(1024);\nconst page = { offset: offset.default(0) };\nfunction textSchema(maxBytes: number) {\n if (!Number.isSafeInteger(maxBytes) || maxBytes < 1)\n throw new TypeError('Text tool limit must be a positive safe integer.');\n return z\n .string()\n .max(maxBytes)\n .refine(\n (text) => !/[\\uD800-\\uDFFF]/u.test(text),\n 'Text must be well-formed UTF-8.',\n )\n .refine(\n (text) => new TextEncoder().encode(text).byteLength <= maxBytes,\n `Use at most ${maxBytes} UTF-8 bytes per call.`,\n );\n}\nasync function safe<Result>(work: () => Promise<Result>): Promise<Result> {\n try {\n return await work();\n } catch (error) {\n if (isStorageError(error))\n throw new AiSdkWorkspaceToolError(error.code, {\n applied: error.applied,\n ...(error.appliedEtag === undefined\n ? {}\n : { appliedEtag: error.appliedEtag }),\n });\n if (error instanceof DOMException && error.name === 'AbortError')\n throw new AiSdkWorkspaceToolError('ABORTED');\n throw new AiSdkWorkspaceToolError('PROVIDER');\n }\n}\n\n/** Typed extension seam for host-only metadata; preserves generic byte validation. */\nexport function createAiSdkCatalogFileEditSchemas(maxWriteBytes = 8192) {\n const content = textSchema(maxWriteBytes);\n return {\n append: z.strictObject({ path, expectedEtag: etag, content }),\n edit: z.strictObject({\n path,\n expectedEtag: etag,\n oldText: content.refine((text) => text.length > 0),\n newText: content,\n }),\n };\n}\n\n/** Generic durable-file tools. Provider upload controls are a separate capability. */\nexport function createAiSdkFileWorkflowTools<Receipt>(\n options: CreateAiSdkFileWorkflowToolsOptions<Receipt>,\n): ToolSet {\n const { workflow } = options;\n const tools: ToolSet = {};\n const content = textSchema(\n Math.min(options.maxChunkBytes ?? 8192, workflow.limits.maxChunkBytes),\n );\n const approval = options.requireApproval ?? true;\n if (workflow.allows('read'))\n Object.assign(tools, {\n workspace_list_file_drafts: tool({\n description:\n 'List durable drafts. Resume open drafts at their current UTF-8 byte size; use nextOffset for pagination.',\n inputSchema: z.strictObject(page),\n execute: (input, context) =>\n safe(() => workflow.list({ ...input, signal: context.abortSignal })),\n }),\n workspace_read_file_draft: tool({\n description: `Read a draft window of at most ${workflow.limits.maxReadBytes} UTF-8 bytes. Continue with nextOffset, which is a byte position at a Unicode boundary.`,\n inputSchema: z.strictObject({ draftId: identity, ...page }),\n execute: (input, context) =>\n safe(() => workflow.read({ ...input, signal: context.abortSignal })),\n }),\n workspace_list_file_draft_parts: tool({\n description:\n 'List bounded chunk integrity receipts for resumption. Each receipt contains its byte offset, size, and SHA-256.',\n inputSchema: z.strictObject({ draftId: identity, ...page }),\n execute: (input, context) =>\n safe(() => workflow.parts({ ...input, signal: context.abortSignal })),\n }),\n } satisfies ToolSet);\n if (workflow.allows('write'))\n Object.assign(tools, {\n workspace_begin_file_draft: tool({\n strict: false,\n needsApproval: approval,\n description:\n 'Begin a durable text draft without changing a visible file. Omit expectedEtag to create a new path; supply the exact current ETag to replace. Use drafts for substantial content and resume interrupted drafts.',\n inputSchema: z.strictObject({ path, expectedEtag: etag.optional() }),\n execute: (input, context) =>\n safe(() =>\n workflow.begin({\n ...input,\n text: true,\n idempotencyKey:\n options.idempotencyKey?.(context.toolCallId) ??\n context.toolCallId,\n signal: context.abortSignal,\n }),\n ),\n }),\n workspace_append_file_draft: tool({\n needsApproval: approval,\n description:\n 'Append a bounded UTF-8 chunk at the draft’s returned byte size. Replaying identical bytes at the same offset is safe; different bytes or a stale offset fail.',\n inputSchema: z.strictObject({\n draftId: identity,\n offset,\n content: content.refine((text) => text.length > 0),\n }),\n execute: (input, context) =>\n safe(() =>\n workflow.append({\n draftId: input.draftId,\n offset: input.offset,\n bytes: new TextEncoder().encode(input.content),\n signal: context.abortSignal,\n }),\n ),\n }),\n workspace_cancel_file_draft: tool({\n needsApproval: approval,\n description:\n 'Cancel an unfinished draft without changing a visible file. A committed draft cannot be cancelled.',\n inputSchema: z.strictObject({ draftId: identity }),\n execute: (input, context) =>\n safe(() =>\n workflow.cancel({ ...input, signal: context.abortSignal }),\n ),\n }),\n } satisfies ToolSet);\n if (workflow.allows('commit'))\n tools.workspace_commit_files = tool({\n strict: false,\n needsApproval: approval,\n description: `Atomically commit 1–${workflow.limits.maxCommitFiles} distinct completed drafts. Supply exact byte sizes. Optional SHA-256 must be known, never invented. A stale head rolls the whole batch back; replay returns stored receipts.`,\n inputSchema: z.strictObject({\n drafts: z\n .array(\n z.strictObject({\n draftId: identity,\n size: offset,\n sha256: z\n .string()\n .regex(/^[0-9a-f]{64}$/u)\n .optional(),\n }),\n )\n .min(1)\n .max(workflow.limits.maxCommitFiles),\n }),\n execute: (input, context) =>\n safe(async () => ({\n items: await workflow.commit({\n ...input,\n signal: context.abortSignal,\n }),\n })),\n });\n return Object.freeze(tools);\n}\n\n/** Catalog-backed alternative to the existing raw-workspace tool factory. */\nexport function createAiSdkCatalogFileTools<Receipt>(\n options: CreateAiSdkCatalogFileToolsOptions<Receipt>,\n): ToolSet {\n const { catalog } = options;\n const tools: ToolSet = {};\n const content = textSchema(\n Math.min(options.maxWriteBytes ?? 8192, catalog.limits.maxWriteBytes),\n );\n const editSchemas = createAiSdkCatalogFileEditSchemas(\n Math.min(options.maxWriteBytes ?? 8192, catalog.limits.maxWriteBytes),\n );\n const approval = options.requireApproval ?? true;\n const commandId = options.commandId ?? ((toolCallId: string) => toolCallId);\n if (catalog.allows('read'))\n Object.assign(tools, {\n workspace_list: tool({\n strict: false,\n description:\n 'List authorized file catalog entries. Paths are mount-relative. Continue with nextOffset.',\n inputSchema: z.strictObject({\n directory: z.string().optional(),\n ...page,\n }),\n execute: (input, context) =>\n safe(() => catalog.list({ ...input, signal: context.abortSignal })),\n }),\n workspace_stat: tool({\n description:\n 'Read a file identity, ETag, size and content type without loading its body.',\n inputSchema: z.strictObject({ path }),\n execute: (input, context) =>\n safe(() => catalog.stat({ ...input, signal: context.abortSignal })),\n }),\n workspace_search: tool({\n description:\n 'Search file paths by literal substring. Continue with nextOffset even when a page has no matches.',\n inputSchema: z.strictObject({\n query: z.string().min(1).max(256),\n ...page,\n }),\n execute: (input, context) =>\n safe(() => catalog.search({ ...input, signal: context.abortSignal })),\n }),\n workspace_read_file: tool({\n strict: false,\n description: `Read at most ${catalog.limits.maxReadBytes} UTF-8 bytes. offset/nextOffset are byte positions at Unicode boundaries. Continue with nextOffset and the same expectedEtag.`,\n inputSchema: z.strictObject({\n path,\n expectedEtag: etag.optional(),\n ...page,\n }),\n execute: (input, context) =>\n safe(() =>\n catalog.readWindow({ ...input, signal: context.abortSignal }),\n ),\n }),\n workspace_search_content: tool({\n strict: false,\n description: `Search literal text in one exact file revision. Scan at most ${catalog.limits.maxSearchScanBytes} bytes per call. Continue with nextOffset and the same expectedEtag.`,\n inputSchema: z.strictObject({\n path,\n expectedEtag: etag,\n query: z.string().min(1).max(256),\n ...page,\n }),\n execute: (input, context) =>\n safe(() =>\n catalog.searchContent({ ...input, signal: context.abortSignal }),\n ),\n }),\n } satisfies ToolSet);\n if (catalog.allows('write'))\n Object.assign(tools, {\n workspace_write_file: tool({\n strict: false,\n needsApproval: approval,\n description:\n 'Create or conditionally replace a small UTF-8 file. Omit expectedEtag to create; supply the exact current ETag to replace. Use durable drafts for substantial content.',\n inputSchema: z.strictObject({\n path,\n expectedEtag: etag.optional(),\n content,\n }),\n execute: (input, context) =>\n safe<unknown>(() =>\n catalog.write({\n ...input,\n commandId: commandId(context.toolCallId),\n signal: context.abortSignal,\n }),\n ),\n }),\n workspace_append_file: tool({\n needsApproval: approval,\n description:\n 'Append a bounded UTF-8 chunk to one exact file revision. Pass the latest ETag; retry identity prevents duplicate appends. Durable drafts support large generation.',\n inputSchema: editSchemas.append,\n execute: (input, context) =>\n safe<unknown>(() =>\n catalog.edit({\n path: input.path,\n expectedEtag: input.expectedEtag,\n change: { kind: 'append', text: input.content },\n commandId: commandId(context.toolCallId),\n signal: context.abortSignal,\n }),\n ),\n }),\n workspace_edit_file: tool({\n needsApproval: approval,\n description:\n 'Replace one exact unique text span at the latest expectedEtag. oldText must match exactly once. The result carries the next revision receipt.',\n inputSchema: editSchemas.edit,\n execute: (input, context) =>\n safe<unknown>(() =>\n catalog.edit({\n path: input.path,\n expectedEtag: input.expectedEtag,\n change: {\n kind: 'replace',\n oldText: input.oldText,\n newText: input.newText,\n },\n commandId: commandId(context.toolCallId),\n signal: context.abortSignal,\n }),\n ),\n }),\n } satisfies ToolSet);\n return Object.freeze(tools);\n}\n"]}
@@ -0,0 +1,91 @@
1
+ import { type JSONValue, type ToolSet } from 'ai';
2
+ import { type StorageWorkspace } from '../workspace/index.js';
3
+ import { type StorageErrorCode as StorageErrorCodeValue } from '../storage.error.js';
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'];
5
+ export type AiSdkWorkspaceToolName = (typeof AI_SDK_WORKSPACE_TOOL_NAMES)[number];
6
+ export type AiSdkWorkspaceMutationToolName = Extract<AiSdkWorkspaceToolName, 'workspace_write_file' | 'workspace_copy_file' | 'workspace_move_file' | 'workspace_delete_file'>;
7
+ /**
8
+ * Approval policy for mutation tools. An omitted entry defaults to requiring
9
+ * approval, matching an omitted policy.
10
+ */
11
+ export type AiSdkWorkspaceApprovalConfig = boolean | Partial<Record<AiSdkWorkspaceMutationToolName, boolean>>;
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> {
19
+ /** The already-mounted, policy-enforcing workspace exposed to the tools. */
20
+ workspace: StorageWorkspace;
21
+ /**
22
+ * Optional tighter read ceiling. Values above the workspace ceiling are
23
+ * clamped; the model cannot choose or raise this value.
24
+ */
25
+ maxReadBytes?: number;
26
+ /** Mutation tools require approval by default. */
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>;
40
+ }
41
+ export type AiSdkWorkspaceToolErrorCode = StorageErrorCodeValue;
42
+ export interface AiSdkWorkspaceToolErrorOptions {
43
+ /** True when the failed operation may already have committed. */
44
+ readonly applied?: boolean;
45
+ /** Canonical ETag of the committed object, when the provider returned one. */
46
+ readonly appliedEtag?: string;
47
+ }
48
+ /**
49
+ * Safe error exposed at the AI tool boundary. It deliberately carries no
50
+ * provider error, storage key, mount prefix, store name, or cause. Applied
51
+ * reconciliation metadata is retained so callers do not blindly retry a
52
+ * mutation that may already have committed.
53
+ */
54
+ export declare class AiSdkWorkspaceToolError extends Error {
55
+ readonly code: AiSdkWorkspaceToolErrorCode;
56
+ readonly applied?: true;
57
+ readonly appliedEtag?: string;
58
+ constructor(code: AiSdkWorkspaceToolErrorCode, options?: AiSdkWorkspaceToolErrorOptions);
59
+ }
60
+ export interface AiSdkWorkspaceFileResult {
61
+ kind: 'file';
62
+ path: string;
63
+ name: string;
64
+ size: number;
65
+ contentType: string;
66
+ etag?: string;
67
+ lastModified?: string;
68
+ }
69
+ export interface AiSdkWorkspaceDirectoryResult {
70
+ kind: 'directory';
71
+ path: string;
72
+ name: string;
73
+ }
74
+ export type AiSdkWorkspaceEntryResult = AiSdkWorkspaceFileResult | AiSdkWorkspaceDirectoryResult;
75
+ export interface AiSdkWorkspaceTextFileResult extends AiSdkWorkspaceFileResult {
76
+ text: string;
77
+ }
78
+ export interface AiSdkWorkspacePageResult {
79
+ entries: AiSdkWorkspaceEntryResult[];
80
+ cursor?: string;
81
+ }
82
+ /**
83
+ * Creates Vercel AI SDK tools backed only by a mounted StorageWorkspace.
84
+ *
85
+ * A tool is omitted unless the workspace grants its required permission.
86
+ * The workspace remains the enforcing boundary if a retained tool reference
87
+ * is invoked after further narrowing.
88
+ */
89
+ export declare function createAiSdkWorkspaceTools<CreateConflictResult extends JSONValue = never>({ workspace, maxReadBytes: requestedMaxReadBytes, mutationMode, requireApproval, mapCreateConflict, }: CreateAiSdkWorkspaceToolsOptions<CreateConflictResult>): ToolSet;
90
+ export declare function isAiSdkWorkspaceMutationToolName(value: string): value is AiSdkWorkspaceMutationToolName;
91
+ //# sourceMappingURL=ai-sdk-workspace-tools.d.ts.map
@@ -0,0 +1 @@
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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"}