@nestm/storage 0.1.0-alpha.10 → 0.1.0-alpha.12
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.
- package/CHANGELOG.md +20 -0
- package/README.md +161 -0
- package/SECURITY.md +27 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts +37 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.d.ts.map +1 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.js +258 -0
- package/dist/ai-sdk/ai-sdk-file-workflow-tools.js.map +1 -0
- package/dist/ai-sdk/index.d.ts +1 -0
- package/dist/ai-sdk/index.d.ts.map +1 -1
- package/dist/ai-sdk/index.js +1 -0
- package/dist/ai-sdk/index.js.map +1 -1
- package/dist/bytes/index.d.ts +30 -0
- package/dist/bytes/index.d.ts.map +1 -0
- package/dist/bytes/index.js +96 -0
- package/dist/bytes/index.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/storage-staged-content.d.ts +39 -0
- package/dist/core/storage-staged-content.d.ts.map +1 -0
- package/dist/core/storage-staged-content.js +104 -0
- package/dist/core/storage-staged-content.js.map +1 -0
- package/dist/core/storage-streams.d.ts +19 -0
- package/dist/core/storage-streams.d.ts.map +1 -0
- package/dist/core/storage-streams.js +95 -0
- package/dist/core/storage-streams.js.map +1 -0
- package/dist/core/storage-text.d.ts +33 -0
- package/dist/core/storage-text.d.ts.map +1 -0
- package/dist/core/storage-text.js +98 -0
- package/dist/core/storage-text.js.map +1 -0
- package/dist/crypto/index.d.ts +2 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +2 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/storage-encrypted-content.d.ts +49 -0
- package/dist/crypto/storage-encrypted-content.d.ts.map +1 -0
- package/dist/crypto/storage-encrypted-content.js +212 -0
- package/dist/crypto/storage-encrypted-content.js.map +1 -0
- package/dist/files-sdk/memory.d.ts +7 -0
- package/dist/files-sdk/memory.d.ts.map +1 -0
- package/dist/files-sdk/memory.js +72 -0
- package/dist/files-sdk/memory.js.map +1 -0
- package/dist/files-sdk/provider/index.d.ts.map +1 -1
- package/dist/files-sdk/provider/index.js +4 -0
- package/dist/files-sdk/provider/index.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/workspace/index.d.ts +5 -0
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +3 -0
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/storage-file-catalog.types.d.ts +65 -0
- package/dist/workspace/storage-file-catalog.types.d.ts.map +1 -0
- package/dist/workspace/storage-file-catalog.types.js +2 -0
- package/dist/workspace/storage-file-catalog.types.js.map +1 -0
- package/dist/workspace/storage-file-workflow.d.ts +7 -0
- package/dist/workspace/storage-file-workflow.d.ts.map +1 -0
- package/dist/workspace/storage-file-workflow.js +440 -0
- package/dist/workspace/storage-file-workflow.js.map +1 -0
- package/dist/workspace/storage-file-workflow.protection.d.ts +31 -0
- package/dist/workspace/storage-file-workflow.protection.d.ts.map +1 -0
- package/dist/workspace/storage-file-workflow.protection.js +258 -0
- package/dist/workspace/storage-file-workflow.protection.js.map +1 -0
- package/dist/workspace/storage-file-workflow.types.d.ts +128 -0
- package/dist/workspace/storage-file-workflow.types.d.ts.map +1 -0
- package/dist/workspace/storage-file-workflow.types.js +8 -0
- package/dist/workspace/storage-file-workflow.types.js.map +1 -0
- package/package.json +17 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @nestm/storage
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 009a0ed: Add optional `/crypto` encrypted staged content coordination over FileCipherEngine, with host-owned addressing, AAD, persistence and reference-protected cleanup. Preserve detached metadata preparation, exact physical acknowledgements, immutable ETag reads, authenticated ranges and cancellation. Trusted staged writers can reserve an identity before metadata preparation with `writeReserved`.
|
|
8
|
+
|
|
9
|
+
## 0.1.0-alpha.11
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 9c5f230: Add framework-neutral durable file workflows with immutable integrity-checked
|
|
14
|
+
staged bodies, bounded UTF-8 reads/search, idempotent chunk appends, and explicit
|
|
15
|
+
host transaction ports for atomic multi-file head commits. Add protected catalog
|
|
16
|
+
and draft capabilities and generic tools in the existing optional AI SDK entrypoint.
|
|
17
|
+
|
|
18
|
+
Add a browser-safe bytes entrypoint for verified upload resumption and UTF-8
|
|
19
|
+
chunk boundaries. Preserve the default memory driver with native conditional
|
|
20
|
+
create/replace/read/delete, evaluated atomically after body consumption, and
|
|
21
|
+
canonical SHA-256 ETags. Memory remains volatile and process-local.
|
|
22
|
+
|
|
3
23
|
## 0.1.0-alpha.10
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -375,6 +375,159 @@ materialize the workspace into a per-session container or VM, mount only that
|
|
|
375
375
|
directory, run the harness there, and synchronize reviewed changes back through
|
|
376
376
|
`StorageWorkspace`. A working directory alone is not a sandbox.
|
|
377
377
|
|
|
378
|
+
## Durable file workflows and catalog tools
|
|
379
|
+
|
|
380
|
+
`@nestm/storage` owns byte mechanics and the draft state machine. The host owns
|
|
381
|
+
logical file heads, authorization, persistence and transaction atomicity. No
|
|
382
|
+
database, NestJS, tenant model or runtime lease is required by these contracts.
|
|
383
|
+
|
|
384
|
+
| Entry point | Exports |
|
|
385
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
386
|
+
| `@nestm/storage/core` | `StorageStagedContentStore`, `collectStorageBytes`, `storageBytesStream`, `readStorageTextWindow`, `searchStorageText`, `applyStorageTextEdit` and their types |
|
|
387
|
+
| `@nestm/storage/workspace` | `StorageFileWorkflow`, draft/persistence/catalog contracts, `protectStorageFileWorkflowWorkspace`, `protectStorageFileWorkflowOperation`, `getStorageFileWorkflow`, `getStorageFileCatalog` |
|
|
388
|
+
| `@nestm/storage/ai-sdk` | `createAiSdkFileWorkflowTools`, `createAiSdkCatalogFileTools`, their options and tool-name constants; existing `createAiSdkWorkspaceTools` is unchanged |
|
|
389
|
+
| `@nestm/storage/bytes` | Browser-safe `sha256StorageBytes`, `verifyStorageChunkReceipt`, `trimStorageUtf8Chunk`, `encodeStorageBase64`, `isStorageUtf8Blob` |
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
import { StorageStagedContentStore } from '@nestm/storage/core';
|
|
393
|
+
import {
|
|
394
|
+
StorageFileWorkflow,
|
|
395
|
+
protectStorageFileWorkflowWorkspace,
|
|
396
|
+
} from '@nestm/storage/workspace';
|
|
397
|
+
import {
|
|
398
|
+
createAiSdkCatalogFileTools,
|
|
399
|
+
createAiSdkFileWorkflowTools,
|
|
400
|
+
} from '@nestm/storage/ai-sdk';
|
|
401
|
+
|
|
402
|
+
// These values are supplied by the host, never by the model.
|
|
403
|
+
const content = new StorageStagedContentStore({
|
|
404
|
+
client,
|
|
405
|
+
key: (scope: HostScope, payloadId) => hostBodyKey(scope, payloadId),
|
|
406
|
+
});
|
|
407
|
+
const workflows = new StorageFileWorkflow({ content, persistence });
|
|
408
|
+
const workspace = protectStorageFileWorkflowWorkspace({
|
|
409
|
+
workspace: hostCatalogWorkspace,
|
|
410
|
+
catalog: hostCatalog,
|
|
411
|
+
workflows: workflows.mount(trustedScope, {
|
|
412
|
+
permissions: ['read', 'write', 'commit'],
|
|
413
|
+
signal: executionSignal,
|
|
414
|
+
}),
|
|
415
|
+
signal: executionSignal,
|
|
416
|
+
authorize: ({ permission, signal }) =>
|
|
417
|
+
authorizeCurrentHostScope(trustedScope, permission, signal),
|
|
418
|
+
});
|
|
419
|
+
const tools = {
|
|
420
|
+
...createAiSdkCatalogFileTools({
|
|
421
|
+
catalog: workspace.catalog!,
|
|
422
|
+
commandId: (toolCallId) => hostCommandId(toolCallId),
|
|
423
|
+
}),
|
|
424
|
+
...createAiSdkFileWorkflowTools({
|
|
425
|
+
workflow: workspace.workflows,
|
|
426
|
+
idempotencyKey: (toolCallId) => hostCommandId(toolCallId),
|
|
427
|
+
}),
|
|
428
|
+
};
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
The catalog delegate implements the existing `StorageWorkspace` against the
|
|
432
|
+
host's logical catalog; do not pass a raw provider-prefix workspace alongside
|
|
433
|
+
an unrelated file service. `StorageFileCatalogCapability` adds opaque file IDs,
|
|
434
|
+
byte windows, literal content search and idempotent small write/edit commands.
|
|
435
|
+
Its `commandId` is host-scoped, stable across retries, and compared against a
|
|
436
|
+
canonical request fingerprint in host persistence. The host preserves its
|
|
437
|
+
additional policy when a generic edit targets a specialized file.
|
|
438
|
+
|
|
439
|
+
`createAiSdkCatalogFileEditSchemas(maxWriteBytes)` exposes typed append/edit
|
|
440
|
+
Zod objects used by the generic factory itself. A host can `.extend()` these
|
|
441
|
+
with an optional product-only metadata field while retaining the same UTF-8
|
|
442
|
+
byte rules. Delegate ordinary input to the generic tool; dispatch specialized
|
|
443
|
+
input through the same leased product capability and command identity. Do not
|
|
444
|
+
cast an opaque tool schema or rebuild the generic schema locally.
|
|
445
|
+
|
|
446
|
+
The protector retains the lease/caller signal and reauthorizes every call.
|
|
447
|
+
Create-only base grants cannot replace or edit a catalog file. Workflow
|
|
448
|
+
`restrict({ permissions, mutations, limits, signal })` intersects existing
|
|
449
|
+
grants/ceilings and retains parent cancellation; it never changes scope. The
|
|
450
|
+
protector restricts persisted draft mutations to the base create/replace grants,
|
|
451
|
+
including resumed sealed drafts and replay, without requiring a public read
|
|
452
|
+
grant to perform an otherwise authorized commit. Child mounts do
|
|
453
|
+
not inherit broader catalog/workflow handles. Configure both delegates with the
|
|
454
|
+
same scope and compatible limits; the host catalog must enforce scan budgets
|
|
455
|
+
inside its implementation. Structured extensions on the returned workspace
|
|
456
|
+
are supported: owning features can attach protected product closures while
|
|
457
|
+
retaining the same `.catalog` and `.workflows` members. The structural getters
|
|
458
|
+
are contract checks for trusted handles, not authentication of arbitrary objects.
|
|
459
|
+
These static file operations acquire no lease themselves.
|
|
460
|
+
|
|
461
|
+
### Host persistence transaction
|
|
462
|
+
|
|
463
|
+
Implement `StorageFileWorkflowPersistence<Scope, Receipt>.transaction(scope,
|
|
464
|
+
{ permission, signal }, work)`. On **every** call (including replay and body
|
|
465
|
+
preparation reads), reauthorize that intent and serialize the scope's draft and
|
|
466
|
+
idempotency records across replicas. `read` admits readers; `write` and `commit`
|
|
467
|
+
must enforce the host's mutation authority. The callback receives detached
|
|
468
|
+
records through `findDraftByKey`, `getDraft`, `saveDraft`, `listDrafts`,
|
|
469
|
+
`listParts`, `putPart` and `commitHeads`.
|
|
470
|
+
|
|
471
|
+
`commitHeads` receives sorted `{ draft, body }` changes. It must compare every
|
|
472
|
+
create/expected-ETag predicate and change all logical heads **in the same host
|
|
473
|
+
transaction** as the subsequent committed draft records and receipts. Return
|
|
474
|
+
one non-null receipt per change in the supplied order. A rejection rolls back
|
|
475
|
+
all callback effects. Serial object writes or independently committed database
|
|
476
|
+
calls do not satisfy this port. The package does not claim to implement database
|
|
477
|
+
atomicity. See the packed consumer fixture and filesystem e2e test for executable
|
|
478
|
+
minimal hosts; production hosts need their own cross-replica transaction/locking
|
|
479
|
+
implementation and rollback tests.
|
|
480
|
+
|
|
481
|
+
Drafts transition `open → sealed → committed` or `open/sealed → cancelled`.
|
|
482
|
+
Appends accept a bounded snapshot of bytes at the exact current byte offset.
|
|
483
|
+
Identical offset/size/SHA-256 replay succeeds; changed bytes or gaps conflict.
|
|
484
|
+
Text chunks must contain complete valid UTF-8. Public summaries and part receipts
|
|
485
|
+
omit staged body IDs and provider keys. A commit seals all requested drafts,
|
|
486
|
+
streams verified chunks into immutable bodies, then commits all heads and draft
|
|
487
|
+
receipts in one host transaction. Failed preparation or stale heads leave sealed
|
|
488
|
+
drafts retryable/cancellable. Mixed committed/uncommitted batches conflict;
|
|
489
|
+
replaying an entirely committed batch returns its stored receipts after checking
|
|
490
|
+
the requested size and optional digest. Cancellation cannot undo committed heads.
|
|
491
|
+
|
|
492
|
+
Check the signal before durable transaction commit. After commit, return the
|
|
493
|
+
receipt even if cancellation races the response. Do not automatically retry the
|
|
494
|
+
transaction callback. A lost response requires replay/reconciliation, not an
|
|
495
|
+
assumption of rollback. Provider writes happen before the metadata transaction;
|
|
496
|
+
failures, losing concurrent preparations, cancellations and superseded files can
|
|
497
|
+
leave unreferenced bodies. Retention eligibility, reference tracking and cleanup
|
|
498
|
+
scheduling remain host-owned. `StorageStagedContentStore.remove` performs an
|
|
499
|
+
ETag-conditional deletion only after the host proves eligibility; it is not a
|
|
500
|
+
collector and is never called automatically by the workflow.
|
|
501
|
+
|
|
502
|
+
### Byte and provider guarantees
|
|
503
|
+
|
|
504
|
+
Staging requires native create-only writes that return an ETag and native exact
|
|
505
|
+
ETag reads; byte ranges additionally require `rangeRead`. Missing primitives
|
|
506
|
+
fail with `NOT_SUPPORTED`, without an existence-check/unconditional-write or
|
|
507
|
+
full-download fallback. Files SDK remains the provider, streaming, range and
|
|
508
|
+
conditional-policy engine. Its multipart upload controls remain distinct from
|
|
509
|
+
the host-persisted draft protocol; it does not provide atomic catalog commits.
|
|
510
|
+
The bundled filesystem and memory drivers and verified native S3 profiles
|
|
511
|
+
support staging. Memory stores are process-local and volatile; their conditional
|
|
512
|
+
comparison/publication is synchronous after asynchronous body consumption.
|
|
513
|
+
Memory publications use canonical SHA-256 ETags. Direct raw-map mutation remains
|
|
514
|
+
a trusted testing escape hatch, outside protected workspace authority.
|
|
515
|
+
|
|
516
|
+
Windows count UTF-8 bytes, use inclusive provider range ends and preserve BOMs.
|
|
517
|
+
Offsets splitting a character and malformed/truncated UTF-8 at EOF fail. Search
|
|
518
|
+
budgets include the actual requested bytes; follow `nextOffset` even on an empty
|
|
519
|
+
match page. `applyStorageTextEdit` works on an already buffered string, requires a
|
|
520
|
+
result byte ceiling and rejects non-unique replacement targets; it is not a
|
|
521
|
+
streaming document editor. Model text appends default to 8192 bytes per call,
|
|
522
|
+
clamped to the capability. Mutation tools require approval by default; hosts may
|
|
523
|
+
apply an existing approval policy explicitly.
|
|
524
|
+
|
|
525
|
+
The browser bytes entrypoint imports no Node, provider, NestJS or AI modules.
|
|
526
|
+
`verifyStorageChunkReceipt(blob, receipt, { offset, maxBytes, signal })` verifies
|
|
527
|
+
ordering, bounds and the actual local SHA-256 before returning the next offset.
|
|
528
|
+
Filename/size/mtime are insufficient proof of resumed content identity. Filename
|
|
529
|
+
classification, browser session storage and HTTP transport remain host policy.
|
|
530
|
+
|
|
378
531
|
## Configure named stores
|
|
379
532
|
|
|
380
533
|
Use the package-owned S3 factory when applicable. For other providers, create a
|
|
@@ -1083,3 +1236,11 @@ or direct filesystem calls.
|
|
|
1083
1236
|
## License
|
|
1084
1237
|
|
|
1085
1238
|
MIT
|
|
1239
|
+
|
|
1240
|
+
## Encrypted staged content
|
|
1241
|
+
|
|
1242
|
+
`@nestm/storage/crypto` exports `StorageEncryptedContentStore<Scope>`. Install the optional `@nestm/crypto` peer only for this entry point. The store uses a host-owned `FileCipherEngine`, object-address function, fresh AAD buffers, allowed key providers, and metadata callbacks. It prepares detached encryption metadata before uploading and completes metadata only after plaintext and ciphertext accounting agree. Reads pin physical ETags and authenticate full content or bounded frame ranges.
|
|
1243
|
+
|
|
1244
|
+
The host authorizes reads, serializes metadata, enforces key policy and atomically proves reference eligibility before `metadata.discard` removes anything. A missing upload receipt means completion is uncertain: keep prepared cleanup inventory for a later sweep. A rejected prepare does not authorize cleanup of another writer's reservation. Engine shutdown stays with its owner. See [the standalone archive consumer](scripts/fixtures/encrypted-content-consumer.ts).
|
|
1245
|
+
|
|
1246
|
+
`StorageStagedContentStore.writeReserved(scope, payloadId, stream, options)` accepts a fresh UUID from a trusted caller. It retains create-only semantics and returns that exact identity in the receipt; it never overwrites an existing payload. Ordinary writers continue to use `write`.
|
package/SECURITY.md
CHANGED
|
@@ -49,6 +49,33 @@ application's metadata transaction commits.
|
|
|
49
49
|
|
|
50
50
|
## Workspace security boundary
|
|
51
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
|
+
|
|
52
79
|
`StorageWorkspace` is a narrowing capability for storage operations. Construct
|
|
53
80
|
it from trusted application context, keep the underlying `StorageClient` and
|
|
54
81
|
mount prefix private, and pass only the workspace or its AI tool set to
|
|
@@ -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"]}
|
package/dist/ai-sdk/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
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 AiSdkWorkspaceToolErrorOptions, type AiSdkWorkspaceToolName, type CreateAiSdkWorkspaceToolsOptions, } from './ai-sdk-workspace-tools.js';
|
|
2
|
+
export { createAiSdkFileWorkflowTools, createAiSdkCatalogFileTools, createAiSdkCatalogFileEditSchemas, AI_SDK_FILE_WORKFLOW_TOOL_NAMES, AI_SDK_CATALOG_FILE_TOOL_NAMES, type CreateAiSdkFileWorkflowToolsOptions, type CreateAiSdkCatalogFileToolsOptions, } from './ai-sdk-file-workflow-tools.js';
|
|
2
3
|
//# 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,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,8BAA8B,EACnC,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,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,GACtC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,iCAAiC,EACjC,+BAA+B,EAC/B,8BAA8B,EAC9B,KAAK,mCAAmC,EACxC,KAAK,kCAAkC,GACxC,MAAM,iCAAiC,CAAC"}
|
package/dist/ai-sdk/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { AI_SDK_WORKSPACE_TOOL_NAMES, AiSdkWorkspaceToolError, createAiSdkWorkspaceTools, isAiSdkWorkspaceMutationToolName, } from './ai-sdk-workspace-tools.js';
|
|
2
|
+
export { createAiSdkFileWorkflowTools, createAiSdkCatalogFileTools, createAiSdkCatalogFileEditSchemas, AI_SDK_FILE_WORKFLOW_TOOL_NAMES, AI_SDK_CATALOG_FILE_TOOL_NAMES, } from './ai-sdk-file-workflow-tools.js';
|
|
2
3
|
//# sourceMappingURL=index.js.map
|
package/dist/ai-sdk/index.js.map
CHANGED
|
@@ -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,GAejC,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 AiSdkWorkspaceToolErrorOptions,\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,GAejC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,iCAAiC,EACjC,+BAA+B,EAC/B,8BAA8B,GAG/B,MAAM,iCAAiC,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 AiSdkWorkspaceToolErrorOptions,\n type AiSdkWorkspaceToolName,\n type CreateAiSdkWorkspaceToolsOptions,\n} from './ai-sdk-workspace-tools.js';\nexport {\n createAiSdkFileWorkflowTools,\n createAiSdkCatalogFileTools,\n createAiSdkCatalogFileEditSchemas,\n AI_SDK_FILE_WORKFLOW_TOOL_NAMES,\n AI_SDK_CATALOG_FILE_TOOL_NAMES,\n type CreateAiSdkFileWorkflowToolsOptions,\n type CreateAiSdkCatalogFileToolsOptions,\n} from './ai-sdk-file-workflow-tools.js';\n"]}
|