@rool-dev/sdk 0.10.1 → 0.10.2-dev.0bf8edb
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/README.md +79 -179
- package/dist/channel.d.ts +41 -129
- package/dist/channel.d.ts.map +1 -1
- package/dist/channel.js +220 -394
- package/dist/channel.js.map +1 -1
- package/dist/client.d.ts +3 -55
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -93
- package/dist/client.js.map +1 -1
- package/dist/graphql.d.ts +4 -46
- package/dist/graphql.d.ts.map +1 -1
- package/dist/graphql.js +28 -233
- package/dist/graphql.js.map +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/path.d.ts +6 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +47 -0
- package/dist/path.js.map +1 -0
- package/dist/reroute.d.ts +22 -0
- package/dist/reroute.d.ts.map +1 -0
- package/dist/reroute.js +61 -0
- package/dist/reroute.js.map +1 -0
- package/dist/rest.d.ts +9 -0
- package/dist/rest.d.ts.map +1 -1
- package/dist/rest.js +33 -1
- package/dist/rest.js.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +25 -10
- package/dist/router.js.map +1 -1
- package/dist/space.d.ts +10 -17
- package/dist/space.d.ts.map +1 -1
- package/dist/space.js +79 -55
- package/dist/space.js.map +1 -1
- package/dist/subscription.d.ts.map +1 -1
- package/dist/subscription.js +40 -32
- package/dist/subscription.js.map +1 -1
- package/dist/types.d.ts +52 -217
- package/dist/types.d.ts.map +1 -1
- package/dist/webdav.d.ts +44 -21
- package/dist/webdav.d.ts.map +1 -1
- package/dist/webdav.js +94 -57
- package/dist/webdav.js.map +1 -1
- package/package.json +2 -1
- package/dist/apps.d.ts +0 -30
- package/dist/apps.d.ts.map +0 -1
- package/dist/apps.js +0 -81
- package/dist/apps.js.map +0 -1
- package/dist/locations.d.ts +0 -34
- package/dist/locations.d.ts.map +0 -1
- package/dist/locations.js +0 -90
- package/dist/locations.js.map +0 -1
- package/dist/machine.d.ts +0 -16
- package/dist/machine.d.ts.map +0 -1
- package/dist/machine.js +0 -51
- package/dist/machine.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
The TypeScript SDK for Rool, a persistent and collaborative environment for organizing objects.
|
|
4
4
|
|
|
5
|
-
> **Building a new Rool extension?** Start with [`@rool-dev/extension`](/extension/) — it handles hosting, dev server, and gives you a reactive Svelte channel out of the box. This SDK is for advanced use cases: integrating Rool into an existing application, building Node.js scripts, or working outside the extension sandbox.
|
|
6
|
-
|
|
7
5
|
The SDK manages authentication, real-time synchronization, and per-space file storage. Core primitives:
|
|
8
6
|
|
|
9
7
|
- **Spaces** — Containers for objects, schema, metadata, channels, and files
|
|
@@ -65,10 +63,9 @@ const { message, objects } = await channel.prompt(
|
|
|
65
63
|
console.log(message); // AI explains what it did
|
|
66
64
|
console.log(`Modified ${objects.length} objects`);
|
|
67
65
|
|
|
68
|
-
//
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
});
|
|
66
|
+
// Read an object by location
|
|
67
|
+
const loadedEarth = await channel.getObject(earth.location);
|
|
68
|
+
console.log(loadedEarth?.body.name);
|
|
72
69
|
|
|
73
70
|
// Clean up
|
|
74
71
|
channel.close();
|
|
@@ -229,7 +226,7 @@ References are just data — no special API is needed to create or remove them.
|
|
|
229
226
|
#### Location helpers
|
|
230
227
|
|
|
231
228
|
```typescript
|
|
232
|
-
import { loc, parseLocation, normalizeLocation
|
|
229
|
+
import { loc, parseLocation, normalizeLocation } from '@rool-dev/sdk';
|
|
233
230
|
|
|
234
231
|
loc('article', 'welcome'); // '/space/article/welcome.json'
|
|
235
232
|
parseLocation('/space/article/welcome.json'); // { collection: 'article', basename: 'welcome' }
|
|
@@ -237,9 +234,6 @@ parseLocation('/space/article/welcome.json'); // { collection: 'article', basena
|
|
|
237
234
|
// normalizeLocation accepts canonical or short form and returns canonical
|
|
238
235
|
normalizeLocation('article/welcome'); // '/space/article/welcome.json'
|
|
239
236
|
normalizeLocation('/space/article/welcome.json'); // unchanged
|
|
240
|
-
|
|
241
|
-
// 6-char random basename — same generator the SDK uses by default
|
|
242
|
-
generateBasename(); // e.g., 'X7kQ9p'
|
|
243
237
|
```
|
|
244
238
|
|
|
245
239
|
SDK methods that accept a location (`getObject`, `updateObject`, `deleteObjects`, `moveObject`, etc.) accept either form and normalize internally. SDK return values always use the canonical full form.
|
|
@@ -320,24 +314,24 @@ await channel.createObject('article', {
|
|
|
320
314
|
|
|
321
315
|
### Real-time Sync
|
|
322
316
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
- `local_user` — This client made the change
|
|
326
|
-
- `remote_user` — Another user/client made the change
|
|
327
|
-
- `remote_agent` — AI agent made the change
|
|
328
|
-
- `system` — Resync after error
|
|
317
|
+
Object and file reactivity is WebDAV-based. Listen for space-level file change notifications, then reconcile with `webdav.syncCollection()` using your sync token. This covers both object files under `/space` and user files under `/rool-drive`.
|
|
329
318
|
|
|
330
319
|
```typescript
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
320
|
+
let token: string | null = null;
|
|
321
|
+
|
|
322
|
+
async function syncFiles() {
|
|
323
|
+
const result = await space.webdav.syncCollection('/', {
|
|
324
|
+
token,
|
|
325
|
+
level: 'infinite',
|
|
326
|
+
props: ['displayname', 'getetag', 'getlastmodified', 'resourcetype'],
|
|
327
|
+
});
|
|
328
|
+
token = result.token;
|
|
329
|
+
updateFileTree(result.responses);
|
|
330
|
+
}
|
|
338
331
|
|
|
339
|
-
|
|
340
|
-
|
|
332
|
+
space.on('filesChanged', syncFiles);
|
|
333
|
+
space.on('filesReset', () => { token = null; syncFiles(); });
|
|
334
|
+
await syncFiles();
|
|
341
335
|
```
|
|
342
336
|
|
|
343
337
|
### Locations & Basenames
|
|
@@ -358,7 +352,7 @@ await channel.createObject('article',
|
|
|
358
352
|
|
|
359
353
|
```typescript
|
|
360
354
|
// Fire-and-forget: create and reference without waiting
|
|
361
|
-
const basename =
|
|
355
|
+
const basename = 'idea-seed';
|
|
362
356
|
const location = loc('note', basename);
|
|
363
357
|
|
|
364
358
|
channel.createObject('note', { text: '{{expand this idea}}' }, { basename });
|
|
@@ -443,13 +437,12 @@ Returns a message (the AI's response) and the list of objects that were created
|
|
|
443
437
|
|
|
444
438
|
| Option | Description |
|
|
445
439
|
|--------|-------------|
|
|
446
|
-
| `locations` | Focus the AI on specific objects, identified by location (given primary attention in context). |
|
|
447
440
|
| `responseSchema` | Request structured JSON instead of text summary |
|
|
448
441
|
| `effort` | Effort level: `'QUICK'`, `'STANDARD'` (default), `'REASONING'`, or `'RESEARCH'` |
|
|
449
442
|
| `ephemeral` | If true, don't record in interaction history (useful for tab completion) |
|
|
450
443
|
| `readOnly` | If true, disable mutation tools (create, update, move, delete). Use for questions. |
|
|
451
444
|
| `parentInteractionId` | Parent interaction in the conversation tree. Omit to auto-continue from the active leaf. Pass `null` to start a new root-level branch. Pass a specific ID to branch from that point (edit/reroll). |
|
|
452
|
-
| `attachments` |
|
|
445
|
+
| `attachments` | Machine resources to focus the AI on, plus local files to upload (`File`, `Blob`, or `{ data, contentType, filename? }`). Pass object resources (`/space/...`) for object context and file resources (`/rool-drive/...`) for existing WebDAV files/folders. Local files are uploaded to authenticated space file storage first. The interaction stores canonical `rool-machine:/...` refs for UI rendering. The AI can interpret images (JPEG, PNG, GIF, WebP, SVG), PDFs, text-based files (plain text, Markdown, CSV, HTML, XML, JSON), and DOCX documents. Other file types are stored but the AI cannot natively consume their contents, only use shell tools on them. |
|
|
453
446
|
| `signal` | `AbortSignal` to stop the prompt mid-flight. When aborted, the agent loop halts and the streaming response closes. Note that any LLM turn already in flight on Vertex keeps generating server-side and is billed. |
|
|
454
447
|
|
|
455
448
|
### Effort Levels
|
|
@@ -470,9 +463,12 @@ const { objects } = await channel.prompt(
|
|
|
470
463
|
);
|
|
471
464
|
|
|
472
465
|
// Work with specific objects
|
|
466
|
+
const intro = resolveMachineResource('/space/article/intro.json');
|
|
467
|
+
const conclusion = resolveMachineResource('/space/article/conclusion.json');
|
|
468
|
+
if (!intro || !conclusion) throw new Error('invalid resource');
|
|
473
469
|
const result = await channel.prompt(
|
|
474
470
|
"Summarize these articles",
|
|
475
|
-
{
|
|
471
|
+
{ attachments: [intro, conclusion] }
|
|
476
472
|
);
|
|
477
473
|
|
|
478
474
|
// Quick question without mutations (fast model + read-only)
|
|
@@ -487,11 +483,13 @@ await channel.prompt(
|
|
|
487
483
|
{ effort: 'REASONING' }
|
|
488
484
|
);
|
|
489
485
|
|
|
490
|
-
// Attach
|
|
486
|
+
// Attach existing WebDAV files/folders or local uploads
|
|
487
|
+
const report = resolveMachineResource('/rool-drive/docs/report.pdf');
|
|
488
|
+
if (!report) throw new Error('invalid resource');
|
|
491
489
|
const file = fileInput.files[0]; // from <input type="file">
|
|
492
490
|
await channel.prompt(
|
|
493
|
-
"
|
|
494
|
-
{ attachments: [file] }
|
|
491
|
+
"Compare this report with the uploaded photo",
|
|
492
|
+
{ attachments: [report, file] }
|
|
495
493
|
);
|
|
496
494
|
|
|
497
495
|
// Cancel a long-running prompt
|
|
@@ -508,12 +506,18 @@ await channel.prompt("Do a deep analysis...", {
|
|
|
508
506
|
Use `responseSchema` to get structured JSON instead of a text message:
|
|
509
507
|
|
|
510
508
|
```typescript
|
|
509
|
+
const resources = [
|
|
510
|
+
'/space/item/widget.json',
|
|
511
|
+
'/space/item/gadget.json',
|
|
512
|
+
'/space/item/gizmo.json',
|
|
513
|
+
].map((path) => {
|
|
514
|
+
const resource = resolveMachineResource(path);
|
|
515
|
+
if (!resource) throw new Error(`invalid resource: ${path}`);
|
|
516
|
+
return resource;
|
|
517
|
+
});
|
|
518
|
+
|
|
511
519
|
const { message } = await channel.prompt("Categorize these items", {
|
|
512
|
-
|
|
513
|
-
'/space/item/widget.json',
|
|
514
|
-
'/space/item/gadget.json',
|
|
515
|
-
'/space/item/gizmo.json',
|
|
516
|
-
],
|
|
520
|
+
attachments: resources,
|
|
517
521
|
responseSchema: {
|
|
518
522
|
type: 'object',
|
|
519
523
|
properties: {
|
|
@@ -535,7 +539,7 @@ console.log(result.categories, result.summary);
|
|
|
535
539
|
AI operations automatically receive context:
|
|
536
540
|
- **Interaction history** — Previous interactions and their results from this channel
|
|
537
541
|
- **Recently modified objects** — Objects created or changed recently
|
|
538
|
-
- **
|
|
542
|
+
- **Attached resources** — Object resources passed via `attachments` are given primary focus; file resources are surfaced as `/rool-drive/...` paths
|
|
539
543
|
|
|
540
544
|
This context flows automatically — no configuration needed. The AI sees enough history to maintain coherent interactions while respecting the `_`-prefixed field hiding rules.
|
|
541
545
|
|
|
@@ -564,7 +568,7 @@ await space.addUser(user.id, 'editor');
|
|
|
564
568
|
| `owner` | Full control, can delete space and manage all users |
|
|
565
569
|
| `admin` | All editor capabilities, plus can manage users (except other admins/owners) |
|
|
566
570
|
| `editor` | Can create, modify, move, and delete objects |
|
|
567
|
-
| `viewer` | Read-only access (can query with `prompt` and
|
|
571
|
+
| `viewer` | Read-only access (can query with `prompt` and read objects/files) |
|
|
568
572
|
|
|
569
573
|
### Space Collaboration Methods
|
|
570
574
|
|
|
@@ -611,18 +615,9 @@ When a user accesses a space via URL, they're granted the corresponding role (`v
|
|
|
611
615
|
|
|
612
616
|
### Real-time Collaboration
|
|
613
617
|
|
|
614
|
-
When multiple users have a space open, changes
|
|
618
|
+
When multiple users have a space open, object and file changes are announced by `space.on('filesChanged')` and reconciled through WebDAV `syncCollection()`. Channel/conversation state still emits channel events; filesystem state does not use channel object events.
|
|
615
619
|
|
|
616
|
-
|
|
617
|
-
channel.on('objectUpdated', ({ location, object, source }) => {
|
|
618
|
-
if (source === 'remote_user') {
|
|
619
|
-
// Another user made this change
|
|
620
|
-
showCollaboratorActivity(object);
|
|
621
|
-
}
|
|
622
|
-
});
|
|
623
|
-
```
|
|
624
|
-
|
|
625
|
-
See [Real-time Sync](#real-time-sync) for more on event sources.
|
|
620
|
+
See [Real-time Sync](#real-time-sync) for a WebDAV sync-token example.
|
|
626
621
|
|
|
627
622
|
## RoolClient API
|
|
628
623
|
|
|
@@ -653,8 +648,6 @@ const client = new RoolClient({
|
|
|
653
648
|
| `duplicateSpace(sourceSpaceId, name): Promise<RoolSpace>` | Duplicate an existing space. Returns a handle to the new space. |
|
|
654
649
|
| `deleteSpace(id): Promise<void>` | Permanently delete a space (cannot be undone) |
|
|
655
650
|
| `importArchive(name, archive): Promise<RoolSpace>` | Import from a zip archive, creating a new space |
|
|
656
|
-
| `webdav(spaceId): RoolWebDAV` | Open a WebDAV client for a space's file storage |
|
|
657
|
-
| `getSpaceStorageUsage(spaceId): Promise<SpaceFileStorageUsage>` | Get WebDAV quota usage for a space |
|
|
658
651
|
|
|
659
652
|
### Channel Management
|
|
660
653
|
|
|
@@ -663,7 +656,6 @@ Manage channels on the `RoolSpace` handle:
|
|
|
663
656
|
| Method | Description |
|
|
664
657
|
|--------|-------------|
|
|
665
658
|
| `space.channels: ChannelInfo[]` | Live channel list (auto-updates via SSE) |
|
|
666
|
-
| `space.getChannels(): ChannelInfo[]` | List channels (deprecated — use `space.channels` instead) |
|
|
667
659
|
| `space.renameChannel(channelId, name): Promise<void>` | Rename a channel |
|
|
668
660
|
| `space.deleteChannel(channelId): Promise<void>` | Delete a channel and its interaction history |
|
|
669
661
|
| `channel.rename(name): Promise<void>` | Rename the current open channel |
|
|
@@ -707,39 +699,11 @@ client.on('userStorageChanged', ({ key, value, source }) => {
|
|
|
707
699
|
});
|
|
708
700
|
```
|
|
709
701
|
|
|
710
|
-
### Extensions
|
|
711
|
-
|
|
712
|
-
Manage and publish extensions. See [`@rool-dev/extension`](/extension/) for building extensions.
|
|
713
|
-
|
|
714
|
-
There are two distinct domains: your **personal library** (extensions you've created or installed) and the **published extensions** (extensions discoverable by all users). Each has its own return type.
|
|
715
|
-
|
|
716
|
-
#### Your Library (`ExtensionInfo`)
|
|
717
|
-
|
|
718
|
-
Manage extensions you own. Each `ExtensionInfo` includes `published` (whether it's listed in the marketplace) and `marketplaceExtensionId` (non-null if you installed it from someone else's listing, null if you authored it).
|
|
719
|
-
|
|
720
|
-
| Method | Description |
|
|
721
|
-
|--------|-------------|
|
|
722
|
-
| `uploadExtension(extensionId, options): Promise<ExtensionInfo>` | Upload or update an extension (`options.bundle`: zip with `index.html` and `manifest.json`) |
|
|
723
|
-
| `listExtensions(): Promise<ExtensionInfo[]>` | List your extensions |
|
|
724
|
-
| `getExtensionInfo(extensionId): Promise<ExtensionInfo \| null>` | Get info for a specific extension |
|
|
725
|
-
| `deleteExtension(extensionId): Promise<void>` | Delete an extension permanently (removes files and DB row) |
|
|
726
|
-
|
|
727
|
-
#### Marketplace (`PublishedExtensionInfo`)
|
|
728
|
-
|
|
729
|
-
Discover and install extensions published by other users.
|
|
730
|
-
|
|
731
|
-
| Method | Description |
|
|
732
|
-
|--------|-------------|
|
|
733
|
-
| `findExtensions(options?): Promise<PublishedExtensionInfo[]>` | Search the marketplace. Options: `query` (semantic search string), `limit` (default 20, max 100). Omit `query` to browse all. |
|
|
734
|
-
| `publishToPublic(extensionId): Promise<void>` | Publish one of your extensions to the marketplace |
|
|
735
|
-
| `unpublishFromPublic(extensionId): Promise<void>` | Remove from the marketplace (keeps the extension in your library) |
|
|
736
|
-
|
|
737
702
|
### Utilities
|
|
738
703
|
|
|
739
704
|
| Method | Description |
|
|
740
705
|
|--------|-------------|
|
|
741
|
-
| `RoolClient.
|
|
742
|
-
| `RoolClient.generateId(): string` | Same as `generateBasename()`; retained for callers minting non-object IDs (interactions, conversations, channels). |
|
|
706
|
+
| `RoolClient.generateId(): string` | Generate a unique 6-character alphanumeric ID. |
|
|
743
707
|
| `destroy(): void` | Clean up resources |
|
|
744
708
|
|
|
745
709
|
### Client Events
|
|
@@ -801,10 +765,8 @@ A space handle with a live SSE subscription. Extends `EventEmitter`. Manages use
|
|
|
801
765
|
| `addUser(userId, role): Promise<void>` | Add user to space |
|
|
802
766
|
| `removeUser(userId): Promise<void>` | Remove user from space |
|
|
803
767
|
| `setLinkAccess(linkAccess): Promise<void>` | Set URL sharing level |
|
|
804
|
-
| `getChannels(): ChannelInfo[]` | List channels (deprecated — use `channels` property instead) |
|
|
805
768
|
| `renameChannel(channelId, name): Promise<void>` | Rename a channel |
|
|
806
769
|
| `deleteChannel(channelId): Promise<void>` | Delete a channel |
|
|
807
|
-
| `installExtension(extensionId, channelId): Promise<string>` | Install an extension into a channel of this space. If you own it, wires it directly. If it's a marketplace extension, copies and builds a new extension in your library. Returns the channel ID. |
|
|
808
770
|
| `exportArchive(): Promise<Blob>` | Export space as zip archive |
|
|
809
771
|
| `getStorageUsage(): Promise<SpaceFileStorageUsage>` | Get WebDAV quota usage for this space |
|
|
810
772
|
| `fetchMachineResource(resource): Promise<Response>` | Fetch a resolved file `MachineResource` through this space |
|
|
@@ -814,8 +776,9 @@ A space handle with a live SSE subscription. Extends `EventEmitter`. Manages use
|
|
|
814
776
|
|
|
815
777
|
```typescript
|
|
816
778
|
space.on('channelCreated', (channel: ChannelInfo) => void) // New channel added
|
|
817
|
-
space.on('channelUpdated', (channel: ChannelInfo) => void) // Channel metadata changed
|
|
779
|
+
space.on('channelUpdated', (channel: ChannelInfo) => void) // Channel metadata changed
|
|
818
780
|
space.on('channelDeleted', (channelId: string) => void) // Channel removed
|
|
781
|
+
space.on('filesChanged', ({ source, timestamp }) => void) // WebDAV file storage changed; call webdav.syncCollection()
|
|
819
782
|
space.on('connectionStateChanged', (state: 'connected' | 'disconnected' | 'reconnecting') => void)
|
|
820
783
|
```
|
|
821
784
|
|
|
@@ -834,9 +797,6 @@ A channel is a named context within a space. All object operations, AI prompts,
|
|
|
834
797
|
| `userId: string` | Current user's ID |
|
|
835
798
|
| `channelId: string` | Channel ID (read-only, fixed at open time) |
|
|
836
799
|
| `isReadOnly: boolean` | True if viewer role |
|
|
837
|
-
| `extensionUrl: string \| null` | URL of the installed extension, or null if this is a plain channel |
|
|
838
|
-
| `extensionId: string \| null` | ID of the installed extension, or null if this is a plain channel |
|
|
839
|
-
| `manifest: ExtensionManifest \| null` | Extension manifest snapshot (name, icon, collections, etc.), or null |
|
|
840
800
|
|
|
841
801
|
### Lifecycle
|
|
842
802
|
|
|
@@ -856,8 +816,6 @@ All methods that accept a location accept either the canonical form or the short
|
|
|
856
816
|
|--------|-------------|
|
|
857
817
|
| `getObject(location): Promise<RoolObject \| undefined>` | Get an object, or undefined if not found. |
|
|
858
818
|
| `stat(location): RoolObjectStat \| undefined` | Get audit info for an object: when it was last modified, by whom, and where (channel/conversation/interaction). Sync read from local cache. |
|
|
859
|
-
| `findObjects(options): Promise<{ objects, message }>` | Find objects using structured filters and/or natural language. Results sorted by modifiedAt (desc by default). |
|
|
860
|
-
| `getObjectLocations(options?): string[]` | Get all object locations. Sorted by modifiedAt (desc by default). Options: `{ limit?, order? }`. |
|
|
861
819
|
| `createObject(collection, body, options?): Promise<{ object, message }>` | Create a new object in `collection`. The SDK mints a random basename unless you pass `options.basename`. |
|
|
862
820
|
| `updateObject(location, options): Promise<{ object, message }>` | Update an existing object's body. |
|
|
863
821
|
| `moveObject(from, to, options?): Promise<{ object, message }>` | Rename or relocate an object. See [Moving and Renaming](#moving-and-renaming). |
|
|
@@ -950,59 +908,6 @@ await channel.moveObject(from, to, {
|
|
|
950
908
|
| `ephemeral` | If true, the operation won't be recorded in interaction history. |
|
|
951
909
|
| `parentInteractionId` | Conversation tree parent. Omit to auto-continue; pass `null` for a new root. |
|
|
952
910
|
|
|
953
|
-
#### findObjects
|
|
954
|
-
|
|
955
|
-
Find objects using structured filters and/or natural language.
|
|
956
|
-
|
|
957
|
-
- **`where` only** — exact-match filtering, no AI, no credits.
|
|
958
|
-
- **`collection` only** — filter by collection name, no AI, no credits.
|
|
959
|
-
- **`prompt` only** — AI-powered semantic query over all objects.
|
|
960
|
-
- **`where` + `prompt`** — `where` (and `locations`) narrow the data set first, then the AI queries within the constrained set.
|
|
961
|
-
|
|
962
|
-
| Option | Description |
|
|
963
|
-
|--------|-------------|
|
|
964
|
-
| `where` | Exact-match body-field filter (e.g. `{ status: 'published' }`). Values must match literally — no operators or `{{placeholders}}`. When combined with `prompt`, constrains which objects the AI can see. |
|
|
965
|
-
| `collection` | Filter by collection name. |
|
|
966
|
-
| `prompt` | Natural language query. Triggers AI evaluation (uses credits). |
|
|
967
|
-
| `limit` | Maximum number of results. |
|
|
968
|
-
| `locations` | Scope to specific object locations. Constrains the candidate set in both structured and AI queries. |
|
|
969
|
-
| `order` | Sort order by modifiedAt: `'asc'` or `'desc'` (default: `'desc'`). |
|
|
970
|
-
| `ephemeral` | If true, the query won't be recorded in interaction history. Useful for responsive search. |
|
|
971
|
-
|
|
972
|
-
**Examples:**
|
|
973
|
-
|
|
974
|
-
```typescript
|
|
975
|
-
// Filter by collection (no AI, no credits)
|
|
976
|
-
const { objects } = await channel.findObjects({
|
|
977
|
-
collection: 'article'
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
// Exact field matching (no AI, no credits)
|
|
981
|
-
const { objects } = await channel.findObjects({
|
|
982
|
-
where: { status: 'published' }
|
|
983
|
-
});
|
|
984
|
-
|
|
985
|
-
// Combine collection and field filters
|
|
986
|
-
const { objects } = await channel.findObjects({
|
|
987
|
-
collection: 'article',
|
|
988
|
-
where: { status: 'published' }
|
|
989
|
-
});
|
|
990
|
-
|
|
991
|
-
// Pure natural language query (AI interprets)
|
|
992
|
-
const { objects, message } = await channel.findObjects({
|
|
993
|
-
prompt: 'articles about space exploration published this year'
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
// Combined: collection + where narrow the data, prompt queries within it
|
|
997
|
-
const { objects } = await channel.findObjects({
|
|
998
|
-
collection: 'article',
|
|
999
|
-
prompt: 'that discuss climate solutions positively',
|
|
1000
|
-
limit: 10
|
|
1001
|
-
});
|
|
1002
|
-
```
|
|
1003
|
-
|
|
1004
|
-
When `where` or `locations` are provided with a `prompt`, the AI only sees the filtered subset — not the full space. The returned `message` explains the query result.
|
|
1005
|
-
|
|
1006
911
|
### Undo/Redo
|
|
1007
912
|
|
|
1008
913
|
| Method | Description |
|
|
@@ -1030,12 +935,13 @@ Store arbitrary data alongside the space without it being part of an object's bo
|
|
|
1030
935
|
|
|
1031
936
|
Every space has authenticated file storage. WebDAV is the SDK surface for that storage: paths are relative to the space root and collection operations use WebDAV collection semantics. Human/AI file links use `rool-machine:/rool-drive/...`; resolve those links with `resolveMachineResource()` and fetch file resources with `space.fetchMachineResource(resource)`.
|
|
1032
937
|
|
|
1033
|
-
|
|
938
|
+
Open a space, then use `space.webdav`.
|
|
1034
939
|
|
|
1035
940
|
```typescript
|
|
1036
941
|
import { resolveMachineResource } from '@rool-dev/sdk';
|
|
1037
942
|
|
|
1038
|
-
const
|
|
943
|
+
const space = await client.openSpace('space-id');
|
|
944
|
+
const webdav = space.webdav;
|
|
1039
945
|
|
|
1040
946
|
await webdav.mkcol('docs');
|
|
1041
947
|
await webdav.put('docs/readme.md', '# Hello', {
|
|
@@ -1059,19 +965,33 @@ const usage = await space.getStorageUsage();
|
|
|
1059
965
|
console.log(usage.usedBytes);
|
|
1060
966
|
console.log(usage.availableBytes); // null means unlimited
|
|
1061
967
|
console.log(usage.limitBytes); // null means unlimited
|
|
968
|
+
|
|
969
|
+
const rootProps = await webdav.propfind('', {
|
|
970
|
+
depth: '0',
|
|
971
|
+
props: ['sync-token', 'supported-report-set'],
|
|
972
|
+
});
|
|
973
|
+
let syncToken = rootProps.responses[0]?.props.syncToken ?? null;
|
|
974
|
+
|
|
975
|
+
space.on('filesChanged', async () => {
|
|
976
|
+
const delta = await space.webdav.syncCollection('', {
|
|
977
|
+
token: syncToken,
|
|
978
|
+
level: 'infinite',
|
|
979
|
+
});
|
|
980
|
+
syncToken = delta.token;
|
|
981
|
+
console.log('Changed file responses:', delta.responses);
|
|
982
|
+
});
|
|
1062
983
|
```
|
|
1063
984
|
|
|
1064
985
|
Paths are space-relative (`docs/readme.md`, not `/docs/readme.md`). WebDAV methods accept WebDAV paths only. User-facing file links should use `rool-machine:/rool-drive/...`; resolve either that URI or a bare `/rool-drive/...` machine path with `resolveMachineResource()` and fetch the resulting file resource with `space.fetchMachineResource(resource)`. `PUT` writes an exact path and does not create parent collections; create parents with `mkcol()` first. Helpers preserve WebDAV status semantics: non-success responses throw `WebDAVError` with `status`, `statusText`, and `body`.
|
|
1065
986
|
|
|
1066
987
|
| Method | Description |
|
|
1067
988
|
|--------|-------------|
|
|
1068
|
-
| `client.webdav(spaceId)` | Create a WebDAV client for a space |
|
|
1069
|
-
| `client.getSpaceStorageUsage(spaceId)` | Get WebDAV quota usage for a space |
|
|
1070
989
|
| `space.webdav` | WebDAV client for an open space |
|
|
1071
990
|
| `space.getStorageUsage()` | Get WebDAV quota usage for an open space |
|
|
1072
991
|
| `webdav.getStorageUsage()` | Get WebDAV quota usage through the WebDAV client |
|
|
1073
992
|
| `webdav.path(path)` | Normalize a WebDAV path |
|
|
1074
|
-
| `webdav.propfind(path, options)` | Read properties/list collections; explicit `depth` required |
|
|
993
|
+
| `webdav.propfind(path, options)` | Read properties/list collections; explicit `depth` required. Supports `sync-token` and `supported-report-set` props. |
|
|
994
|
+
| `webdav.syncCollection(path, options)` | Reconcile WebDAV changes with `REPORT sync-collection`. Pass the previous `token` (or `null`), `level: '1' \| 'infinite'`, optional `props`/`limit`; returns changed responses plus the next `token`. |
|
|
1075
995
|
| `webdav.get(path, options?)` / `webdav.head(path)` | Read a file, including optional byte ranges for `get` |
|
|
1076
996
|
| `webdav.put(path, body, options?)` | Write an exact file path; parents must already exist |
|
|
1077
997
|
| `webdav.mkcol(path)` | Create one collection |
|
|
@@ -1198,37 +1118,23 @@ The archive bundles `data.json` (objects, metadata, and channels) together with
|
|
|
1198
1118
|
|
|
1199
1119
|
### Channel Events
|
|
1200
1120
|
|
|
1201
|
-
|
|
1121
|
+
Channel events are for channel/conversation state. Object and file reactivity goes through `space.on('filesChanged' | 'filesReset')` plus WebDAV `syncCollection()`.
|
|
1202
1122
|
|
|
1203
1123
|
```typescript
|
|
1204
|
-
//
|
|
1205
|
-
// - 'local_user': This client made the change
|
|
1206
|
-
// - 'remote_user': Another user/client made the change
|
|
1207
|
-
// - 'remote_agent': AI agent made the change
|
|
1208
|
-
// - 'system': Resync after error
|
|
1209
|
-
|
|
1210
|
-
// Object events — payload includes the full RoolObject
|
|
1211
|
-
channel.on('objectCreated', ({ location, object, source }) => void)
|
|
1212
|
-
channel.on('objectUpdated', ({ location, object, source }) => void)
|
|
1213
|
-
channel.on('objectDeleted', ({ location, source }) => void)
|
|
1214
|
-
channel.on('objectMoved', ({ from, to, object, source }) => void)
|
|
1215
|
-
|
|
1216
|
-
// Space metadata
|
|
1217
|
-
channel.on('metadataUpdated', ({ metadata, source }) => void)
|
|
1218
|
-
|
|
1219
|
-
// Collection schema changed
|
|
1220
|
-
channel.on('schemaUpdated', ({ schema, source }) => void)
|
|
1221
|
-
|
|
1222
|
-
// Channel metadata updated (name, extensionUrl)
|
|
1124
|
+
// Channel metadata updated
|
|
1223
1125
|
channel.on('channelUpdated', ({ channelId, source }) => void)
|
|
1224
1126
|
|
|
1225
1127
|
// Conversation interaction history updated
|
|
1226
1128
|
channel.on('conversationUpdated', ({ conversationId, channelId, source }) => void)
|
|
1227
1129
|
|
|
1130
|
+
// Space metadata / schema compatibility events
|
|
1131
|
+
channel.on('metadataUpdated', ({ metadata, source }) => void)
|
|
1132
|
+
channel.on('schemaUpdated', ({ schema, source }) => void)
|
|
1133
|
+
|
|
1228
1134
|
// Full state replacement (undo/redo, resync after error)
|
|
1229
1135
|
channel.on('reset', ({ source }) => void)
|
|
1230
1136
|
|
|
1231
|
-
// Sync error occurred
|
|
1137
|
+
// Sync error occurred
|
|
1232
1138
|
channel.on('syncError', (error: Error) => void)
|
|
1233
1139
|
```
|
|
1234
1140
|
|
|
@@ -1359,13 +1265,10 @@ interface Channel {
|
|
|
1359
1265
|
createdAt: number; // Timestamp when channel was created
|
|
1360
1266
|
createdBy: string; // User ID who created the channel
|
|
1361
1267
|
createdByName?: string; // Display name at time of creation
|
|
1362
|
-
extensionUrl?: string; // URL of installed extension (set by installExtension)
|
|
1363
|
-
extensionId?: string; // ID of installed extension (user_extensions.extension_id)
|
|
1364
|
-
manifest?: ExtensionManifest; // Extension manifest snapshot (set when extension is wired)
|
|
1365
1268
|
conversations: Record<string, Conversation>; // Keyed by conversation ID
|
|
1366
1269
|
}
|
|
1367
1270
|
|
|
1368
|
-
// Channel summary info (
|
|
1271
|
+
// Channel summary info (used by space.channels)
|
|
1369
1272
|
interface ChannelInfo {
|
|
1370
1273
|
id: string;
|
|
1371
1274
|
name: string | null;
|
|
@@ -1373,9 +1276,6 @@ interface ChannelInfo {
|
|
|
1373
1276
|
createdBy: string;
|
|
1374
1277
|
createdByName: string | null;
|
|
1375
1278
|
interactionCount: number;
|
|
1376
|
-
extensionUrl: string | null; // URL of installed extension, or null
|
|
1377
|
-
extensionId: string | null; // ID of installed extension, or null
|
|
1378
|
-
manifest: ExtensionManifest | null; // Extension manifest snapshot, or null
|
|
1379
1279
|
}
|
|
1380
1280
|
```
|
|
1381
1281
|
|
|
@@ -1414,7 +1314,7 @@ interface Interaction {
|
|
|
1414
1314
|
ai: boolean; // Whether AI was invoked (vs synthetic confirmation)
|
|
1415
1315
|
modifiedObjectLocations: string[]; // Locations of objects affected by this interaction
|
|
1416
1316
|
toolCalls: ToolCall[]; // Tools called during this interaction (for AI prompts)
|
|
1417
|
-
attachments?: string[]; // rool-machine
|
|
1317
|
+
attachments?: string[]; // canonical rool-machine:/... resource refs attached by the user
|
|
1418
1318
|
}
|
|
1419
1319
|
```
|
|
1420
1320
|
|
|
@@ -1435,15 +1335,15 @@ type ChangeSource = 'local_user' | 'remote_user' | 'remote_agent' | 'system';
|
|
|
1435
1335
|
|
|
1436
1336
|
```typescript
|
|
1437
1337
|
type PromptEffort = 'QUICK' | 'STANDARD' | 'REASONING' | 'RESEARCH';
|
|
1338
|
+
type PromptAttachment = File | Blob | { data: string; contentType: string; filename?: string } | MachineResource;
|
|
1438
1339
|
|
|
1439
1340
|
interface PromptOptions {
|
|
1440
|
-
locations?: string[]; // Scope to specific objects
|
|
1441
1341
|
responseSchema?: Record<string, unknown>;
|
|
1442
1342
|
effort?: PromptEffort; // Effort level (default: 'STANDARD')
|
|
1443
1343
|
ephemeral?: boolean; // Don't record in interaction history
|
|
1444
1344
|
readOnly?: boolean; // Disable mutation tools (default: false)
|
|
1445
1345
|
parentInteractionId?: string | null; // Branch from a specific interaction (omit to auto-continue)
|
|
1446
|
-
attachments?:
|
|
1346
|
+
attachments?: PromptAttachment[]; // Machine resources or local files to upload
|
|
1447
1347
|
signal?: AbortSignal; // Cancel an in-flight prompt
|
|
1448
1348
|
}
|
|
1449
1349
|
```
|