@rool-dev/sdk 0.2.0 → 0.3.0-dev.c36df33
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 +290 -178
- package/dist/channel.d.ts +316 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +793 -0
- package/dist/channel.js.map +1 -0
- package/dist/client.d.ts +39 -32
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +108 -70
- package/dist/client.js.map +1 -1
- package/dist/graphql.d.ts +41 -23
- package/dist/graphql.d.ts.map +1 -1
- package/dist/graphql.js +166 -97
- package/dist/graphql.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/media.js +1 -1
- package/dist/space.d.ts +29 -268
- package/dist/space.d.ts.map +1 -1
- package/dist/space.js +49 -799
- package/dist/space.js.map +1 -1
- package/dist/subscription.d.ts +7 -7
- package/dist/subscription.d.ts.map +1 -1
- package/dist/subscription.js +40 -34
- package/dist/subscription.js.map +1 -1
- package/dist/types.d.ts +83 -89
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Rool SDK
|
|
2
2
|
|
|
3
|
-
The TypeScript SDK for Rool
|
|
3
|
+
The TypeScript SDK for Rool, a persistent and collaborative environment for organizing objects.
|
|
4
4
|
|
|
5
|
-
Rool
|
|
5
|
+
Rool enables you to build applications where AI operates on a structured world model rather than a text conversation. The context for all AI operations is the full object graph, allowing the system to reason about, update, and expand the state of your application directly.
|
|
6
6
|
|
|
7
7
|
Use Rool to programmatically instruct agents to generate content, research topics, or reorganize data. The client manages authentication, real-time synchronization, and media storage, supporting both single-user and multi-user workflows.
|
|
8
8
|
|
|
9
9
|
**Core primitives:**
|
|
10
|
+
- **Spaces** — Containers for objects, schema, metadata, and channels
|
|
11
|
+
- **Channels** — Named contexts within a space, each with independent interaction history. All object and AI operations go through a channel.
|
|
10
12
|
- **Objects** — Key-value records with any fields you define. References between objects are data fields whose values are object IDs.
|
|
11
13
|
- **AI operations** — Create, update, or query objects using natural language and `{{placeholders}}`
|
|
12
14
|
|
|
@@ -30,48 +32,79 @@ if (!authenticated) {
|
|
|
30
32
|
client.login('My App'); // Redirects to auth page, shows "Sign in to My App"
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
// Create a new space
|
|
35
|
+
// Create a new space, then open a channel on it
|
|
34
36
|
const space = await client.createSpace('Solar System');
|
|
37
|
+
const channel = await space.openChannel('main');
|
|
38
|
+
|
|
39
|
+
// Define the schema — what types of objects exist and their fields
|
|
40
|
+
await channel.createCollection('body', [
|
|
41
|
+
{ name: 'name', type: { kind: 'string' } },
|
|
42
|
+
{ name: 'mass', type: { kind: 'string' } },
|
|
43
|
+
{ name: 'radius', type: { kind: 'string' } },
|
|
44
|
+
{ name: 'orbits', type: { kind: 'maybe', inner: { kind: 'ref' } } },
|
|
45
|
+
]);
|
|
35
46
|
|
|
36
47
|
// Create objects with AI-generated content using {{placeholders}}
|
|
37
|
-
const { object: sun } = await
|
|
48
|
+
const { object: sun } = await channel.createObject({
|
|
38
49
|
data: {
|
|
39
|
-
type: 'star',
|
|
40
50
|
name: 'Sun',
|
|
41
51
|
mass: '{{mass in solar masses}}',
|
|
42
|
-
|
|
52
|
+
radius: '{{radius in km}}'
|
|
43
53
|
}
|
|
44
54
|
});
|
|
45
55
|
|
|
46
|
-
const { object: earth } = await
|
|
56
|
+
const { object: earth } = await channel.createObject({
|
|
47
57
|
data: {
|
|
48
|
-
type: 'planet',
|
|
49
58
|
name: 'Earth',
|
|
50
59
|
mass: '{{mass in Earth masses}}',
|
|
51
60
|
radius: '{{radius in km}}',
|
|
52
|
-
orbitalPeriod: '{{orbital period in days}}',
|
|
53
61
|
orbits: sun.id // Reference to the sun object
|
|
54
62
|
}
|
|
55
63
|
});
|
|
56
64
|
|
|
57
65
|
// Use the AI agent to work with your data
|
|
58
|
-
const { message, objects } = await
|
|
66
|
+
const { message, objects } = await channel.prompt(
|
|
59
67
|
'Add the other planets in our solar system, each referencing the Sun'
|
|
60
68
|
);
|
|
61
69
|
console.log(message); // AI explains what it did
|
|
62
70
|
console.log(`Created ${objects.length} objects`);
|
|
63
71
|
|
|
64
72
|
// Query with natural language
|
|
65
|
-
const { objects: innerPlanets } = await
|
|
73
|
+
const { objects: innerPlanets } = await channel.findObjects({
|
|
66
74
|
prompt: 'planets closer to the sun than Earth'
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
// Clean up
|
|
70
|
-
|
|
78
|
+
channel.close();
|
|
71
79
|
```
|
|
72
80
|
|
|
73
81
|
## Core Concepts
|
|
74
82
|
|
|
83
|
+
### Spaces and Channels
|
|
84
|
+
|
|
85
|
+
A **space** is a container that holds objects, schema, metadata, and channels. A **channel** is a named context within a space — it's the handle you use for all object and AI operations. Each channel has its own interaction history.
|
|
86
|
+
|
|
87
|
+
There are two main handles:
|
|
88
|
+
- **`RoolSpace`** — Lightweight admin handle for user management, link access, channel management, and export. No real-time subscription.
|
|
89
|
+
- **`RoolChannel`** — Full real-time handle for objects, AI prompts, media, schema, and undo/redo.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Open a space for admin operations
|
|
93
|
+
const space = await client.openSpace('space-id');
|
|
94
|
+
await space.addUser(userId, 'editor');
|
|
95
|
+
await space.setLinkAccess('viewer');
|
|
96
|
+
|
|
97
|
+
// Open a channel for object and AI operations
|
|
98
|
+
const channel = await client.openChannel('space-id', 'my-channel');
|
|
99
|
+
await channel.prompt('Create some planets');
|
|
100
|
+
|
|
101
|
+
// Or open a channel via the space handle
|
|
102
|
+
const channel2 = await space.openChannel('research');
|
|
103
|
+
await channel2.prompt('Analyze the data'); // Independent channel
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The `channelId` is fixed when you open a channel and cannot be changed. To use a different channel, open a new one. Both channels share the same objects and schema — only the interaction history differs.
|
|
107
|
+
|
|
75
108
|
### Objects & References
|
|
76
109
|
|
|
77
110
|
**Objects** are plain key-value records. The `id` field is reserved; everything else is application-defined.
|
|
@@ -98,7 +131,7 @@ Use `{{description}}` in field values to have AI generate content:
|
|
|
98
131
|
|
|
99
132
|
```typescript
|
|
100
133
|
// Create with AI-generated content
|
|
101
|
-
await
|
|
134
|
+
await channel.createObject({
|
|
102
135
|
data: {
|
|
103
136
|
type: 'article',
|
|
104
137
|
headline: '{{catchy headline about coffee}}',
|
|
@@ -107,12 +140,12 @@ await space.createObject({
|
|
|
107
140
|
});
|
|
108
141
|
|
|
109
142
|
// Update existing content with AI
|
|
110
|
-
await
|
|
143
|
+
await channel.updateObject('abc123', {
|
|
111
144
|
prompt: 'Make the body shorter and more casual'
|
|
112
145
|
});
|
|
113
146
|
|
|
114
147
|
// Add new AI-generated field to existing object
|
|
115
|
-
await
|
|
148
|
+
await channel.updateObject('abc123', {
|
|
116
149
|
data: { summary: '{{one-sentence summary}}' }
|
|
117
150
|
});
|
|
118
151
|
```
|
|
@@ -127,17 +160,17 @@ Undo/redo works on **checkpoints**, not individual operations. Call `checkpoint(
|
|
|
127
160
|
|
|
128
161
|
```typescript
|
|
129
162
|
// Create a checkpoint before user action
|
|
130
|
-
await
|
|
131
|
-
await
|
|
163
|
+
await channel.checkpoint('Delete object');
|
|
164
|
+
await channel.deleteObjects([objectId]);
|
|
132
165
|
|
|
133
166
|
// User can now undo back to the checkpoint
|
|
134
|
-
if (await
|
|
135
|
-
await
|
|
167
|
+
if (await channel.canUndo()) {
|
|
168
|
+
await channel.undo(); // Restores the deleted object
|
|
136
169
|
}
|
|
137
170
|
|
|
138
171
|
// Redo reapplies the undone action
|
|
139
|
-
if (await
|
|
140
|
-
await
|
|
172
|
+
if (await channel.canRedo()) {
|
|
173
|
+
await channel.redo(); // Deletes the object again
|
|
141
174
|
}
|
|
142
175
|
```
|
|
143
176
|
|
|
@@ -150,7 +183,7 @@ In collaborative scenarios, conflicting changes (modified by others since your c
|
|
|
150
183
|
Fields starting with `_` (e.g., `_ui`, `_cache`) are hidden from AI but otherwise behave like normal fields — they sync in real-time, persist to the server, support undo/redo, and are visible to all users of the Space. Use them for UI state, positions, or other data the AI shouldn't see or modify:
|
|
151
184
|
|
|
152
185
|
```typescript
|
|
153
|
-
await
|
|
186
|
+
await channel.createObject({
|
|
154
187
|
data: {
|
|
155
188
|
title: 'My Article',
|
|
156
189
|
author: "John Doe",
|
|
@@ -170,7 +203,7 @@ Events fire for both local and remote changes. The `source` field indicates orig
|
|
|
170
203
|
|
|
171
204
|
```typescript
|
|
172
205
|
// All UI updates happen in one place, regardless of change source
|
|
173
|
-
|
|
206
|
+
channel.on('objectUpdated', ({ objectId, object, source }) => {
|
|
174
207
|
renderObject(objectId, object);
|
|
175
208
|
if (source === 'remote_agent') {
|
|
176
209
|
doLayout(); // AI might have added content
|
|
@@ -178,7 +211,7 @@ space.on('objectUpdated', ({ objectId, object, source }) => {
|
|
|
178
211
|
});
|
|
179
212
|
|
|
180
213
|
// Caller just makes the change - event handler does the UI work
|
|
181
|
-
|
|
214
|
+
channel.updateObject(objectId, { prompt: 'expand this' });
|
|
182
215
|
```
|
|
183
216
|
|
|
184
217
|
### Custom Object IDs
|
|
@@ -186,7 +219,7 @@ space.updateObject(objectId, { prompt: 'expand this' });
|
|
|
186
219
|
By default, `createObject` generates a 6-character alphanumeric ID. Provide your own via `data.id`:
|
|
187
220
|
|
|
188
221
|
```typescript
|
|
189
|
-
await
|
|
222
|
+
await channel.createObject({ data: { id: 'article-42', title: 'The Meaning of Life' } });
|
|
190
223
|
```
|
|
191
224
|
|
|
192
225
|
**Why use custom IDs?**
|
|
@@ -196,8 +229,8 @@ await space.createObject({ data: { id: 'article-42', title: 'The Meaning of Life
|
|
|
196
229
|
```typescript
|
|
197
230
|
// Fire-and-forget: create and reference without waiting
|
|
198
231
|
const id = RoolClient.generateId();
|
|
199
|
-
|
|
200
|
-
|
|
232
|
+
channel.createObject({ data: { id, type: 'note', text: '{{expand this idea}}' } });
|
|
233
|
+
channel.updateObject(parentId, { data: { notes: [...existingNotes, id] } }); // Add reference immediately
|
|
201
234
|
```
|
|
202
235
|
|
|
203
236
|
**Constraints:**
|
|
@@ -252,7 +285,7 @@ if (!authenticated) {
|
|
|
252
285
|
The `prompt()` method is the primary way to invoke the AI agent. The agent has editor-level capabilities — it can create, modify, and delete objects — but cannot see or modify `_`-prefixed fields.
|
|
253
286
|
|
|
254
287
|
```typescript
|
|
255
|
-
const { message, objects } = await
|
|
288
|
+
const { message, objects } = await channel.prompt(
|
|
256
289
|
"Create a topic node for the solar system, then child nodes for each planet."
|
|
257
290
|
);
|
|
258
291
|
console.log(`AI: ${message}`);
|
|
@@ -276,7 +309,7 @@ Returns a message (the AI's response) and the list of objects that were created
|
|
|
276
309
|
| `objectIds` | Limit context to specific objects |
|
|
277
310
|
| `responseSchema` | Request structured JSON instead of text summary |
|
|
278
311
|
| `effort` | Effort level: `'QUICK'`, `'STANDARD'` (default), `'REASONING'`, or `'RESEARCH'` |
|
|
279
|
-
| `ephemeral` | If true, don't record in
|
|
312
|
+
| `ephemeral` | If true, don't record in interaction history (useful for tab completion) |
|
|
280
313
|
| `readOnly` | If true, disable mutation tools (create, update, delete). Use for questions. |
|
|
281
314
|
| `attachments` | Files to attach (`File`, `Blob`, or `{ data, contentType }`). Uploaded to the media store via `uploadMedia()`. Resulting URLs are stored on the interaction's `attachments` field for UI rendering. **Currently only images are interpreted by the AI**; other file types are uploaded and stored but the AI cannot read their contents. |
|
|
282
315
|
|
|
@@ -293,31 +326,31 @@ Returns a message (the AI's response) and the list of objects that were created
|
|
|
293
326
|
|
|
294
327
|
```typescript
|
|
295
328
|
// Reorganize existing objects
|
|
296
|
-
const { objects } = await
|
|
329
|
+
const { objects } = await channel.prompt(
|
|
297
330
|
"Group these notes by topic and create a parent node for each group."
|
|
298
331
|
);
|
|
299
332
|
|
|
300
333
|
// Work with specific objects
|
|
301
|
-
const result = await
|
|
334
|
+
const result = await channel.prompt(
|
|
302
335
|
"Summarize these articles",
|
|
303
336
|
{ objectIds: ['article-1', 'article-2'] }
|
|
304
337
|
);
|
|
305
338
|
|
|
306
339
|
// Quick question without mutations (fast model + read-only)
|
|
307
|
-
const { message } = await
|
|
340
|
+
const { message } = await channel.prompt(
|
|
308
341
|
"What topics are covered?",
|
|
309
342
|
{ effort: 'QUICK', readOnly: true }
|
|
310
343
|
);
|
|
311
344
|
|
|
312
345
|
// Complex analysis with extended reasoning
|
|
313
|
-
await
|
|
346
|
+
await channel.prompt(
|
|
314
347
|
"Analyze relationships and reorganize",
|
|
315
348
|
{ effort: 'REASONING' }
|
|
316
349
|
);
|
|
317
350
|
|
|
318
351
|
// Attach files for the AI to see (File from <input>, Blob, or base64)
|
|
319
352
|
const file = fileInput.files[0]; // from <input type="file">
|
|
320
|
-
await
|
|
353
|
+
await channel.prompt(
|
|
321
354
|
"Describe what's in this photo and create an object for it",
|
|
322
355
|
{ attachments: [file] }
|
|
323
356
|
);
|
|
@@ -328,7 +361,7 @@ await space.prompt(
|
|
|
328
361
|
Use `responseSchema` to get structured JSON instead of a text message:
|
|
329
362
|
|
|
330
363
|
```typescript
|
|
331
|
-
const { message } = await
|
|
364
|
+
const { message } = await channel.prompt("Categorize these items", {
|
|
332
365
|
objectIds: ['item-1', 'item-2', 'item-3'],
|
|
333
366
|
responseSchema: {
|
|
334
367
|
type: 'object',
|
|
@@ -349,7 +382,7 @@ console.log(result.categories, result.summary);
|
|
|
349
382
|
### Context Flow
|
|
350
383
|
|
|
351
384
|
AI operations automatically receive context:
|
|
352
|
-
- **Interaction history** — Previous interactions and their results from this
|
|
385
|
+
- **Interaction history** — Previous interactions and their results from this channel
|
|
353
386
|
- **Recently modified objects** — Objects created or changed recently
|
|
354
387
|
- **Selected objects** — Objects passed via `objectIds` are given primary focus
|
|
355
388
|
|
|
@@ -369,6 +402,7 @@ if (!user) {
|
|
|
369
402
|
}
|
|
370
403
|
|
|
371
404
|
// Add them to the space
|
|
405
|
+
const space = await client.openSpace('space-id');
|
|
372
406
|
await space.addUser(user.id, 'editor');
|
|
373
407
|
```
|
|
374
408
|
|
|
@@ -383,6 +417,8 @@ await space.addUser(user.id, 'editor');
|
|
|
383
417
|
|
|
384
418
|
### Space Collaboration Methods
|
|
385
419
|
|
|
420
|
+
These methods are available on `RoolSpace`:
|
|
421
|
+
|
|
386
422
|
| Method | Description |
|
|
387
423
|
|--------|-------------|
|
|
388
424
|
| `listUsers(): Promise<SpaceMember[]>` | List users with access |
|
|
@@ -395,6 +431,8 @@ await space.addUser(user.id, 'editor');
|
|
|
395
431
|
Enable public URL access to allow anyone with the space URL to access it:
|
|
396
432
|
|
|
397
433
|
```typescript
|
|
434
|
+
const space = await client.openSpace('space-id');
|
|
435
|
+
|
|
398
436
|
// Allow anyone with the URL to view
|
|
399
437
|
await space.setLinkAccess('viewer');
|
|
400
438
|
|
|
@@ -423,7 +461,7 @@ When a user accesses a space via URL, they're granted the corresponding role (`v
|
|
|
423
461
|
When multiple users have a space open, changes sync in real-time. The `source` field in events tells you who made the change:
|
|
424
462
|
|
|
425
463
|
```typescript
|
|
426
|
-
|
|
464
|
+
channel.on('objectUpdated', ({ objectId, object, source }) => {
|
|
427
465
|
if (source === 'remote_user') {
|
|
428
466
|
// Another user made this change
|
|
429
467
|
showCollaboratorActivity(object);
|
|
@@ -452,14 +490,28 @@ const client = new RoolClient({
|
|
|
452
490
|
});
|
|
453
491
|
```
|
|
454
492
|
|
|
455
|
-
### Space Lifecycle
|
|
493
|
+
### Space & Channel Lifecycle
|
|
456
494
|
|
|
457
495
|
| Method | Description |
|
|
458
496
|
|--------|-------------|
|
|
459
497
|
| `listSpaces(): Promise<RoolSpaceInfo[]>` | List available spaces |
|
|
460
|
-
| `openSpace(
|
|
461
|
-
| `
|
|
498
|
+
| `openSpace(spaceId): Promise<RoolSpace>` | Open a space for admin operations (no real-time subscription) |
|
|
499
|
+
| `openChannel(spaceId, channelId): Promise<RoolChannel>` | Open a channel on a space |
|
|
500
|
+
| `createSpace(name): Promise<RoolSpace>` | Create a new space, returns admin handle |
|
|
462
501
|
| `deleteSpace(id): Promise<void>` | Permanently delete a space (cannot be undone) |
|
|
502
|
+
| `importArchive(name, archive): Promise<RoolSpace>` | Import from a zip archive, creating a new space |
|
|
503
|
+
|
|
504
|
+
### Channel Management
|
|
505
|
+
|
|
506
|
+
Manage channels within a space. Available on both the client and space handles:
|
|
507
|
+
|
|
508
|
+
| Method | Description |
|
|
509
|
+
|--------|-------------|
|
|
510
|
+
| `client.renameChannel(spaceId, channelId, name): Promise<void>` | Rename a channel |
|
|
511
|
+
| `client.deleteChannel(spaceId, channelId): Promise<void>` | Delete a channel and its interaction history |
|
|
512
|
+
| `space.getChannels(): ChannelInfo[]` | List channels (from cached snapshot) |
|
|
513
|
+
| `space.deleteChannel(channelId): Promise<void>` | Delete a channel |
|
|
514
|
+
| `channel.rename(name): Promise<void>` | Rename the current channel |
|
|
463
515
|
|
|
464
516
|
### User Storage
|
|
465
517
|
|
|
@@ -516,6 +568,9 @@ client.on('authStateChanged', (authenticated: boolean) => void)
|
|
|
516
568
|
client.on('spaceAdded', (space: RoolSpaceInfo) => void) // Space created or access granted
|
|
517
569
|
client.on('spaceRemoved', (spaceId: string) => void) // Space deleted or access revoked
|
|
518
570
|
client.on('spaceRenamed', (spaceId: string, newName: string) => void)
|
|
571
|
+
client.on('channelCreated', (spaceId: string, channel: ChannelInfo) => void)
|
|
572
|
+
client.on('channelRenamed', (spaceId: string, channelId: string, newName: string) => void)
|
|
573
|
+
client.on('channelDeleted', (spaceId: string, channelId: string) => void)
|
|
519
574
|
client.on('userStorageChanged', ({ key, value, source }: UserStorageChangedEvent) => void)
|
|
520
575
|
client.on('connectionStateChanged', (state: 'connected' | 'disconnected' | 'reconnecting') => void)
|
|
521
576
|
client.on('error', (error: Error, context?: string) => void)
|
|
@@ -535,7 +590,36 @@ client.on('spaceRenamed', (id, name) => {
|
|
|
535
590
|
|
|
536
591
|
## RoolSpace API
|
|
537
592
|
|
|
538
|
-
|
|
593
|
+
A space is a lightweight admin handle for space-level operations. It does not have a real-time subscription — use channels for live data and object operations.
|
|
594
|
+
|
|
595
|
+
### Properties
|
|
596
|
+
|
|
597
|
+
| Property | Description |
|
|
598
|
+
|----------|-------------|
|
|
599
|
+
| `id: string` | Space ID |
|
|
600
|
+
| `name: string` | Space name |
|
|
601
|
+
| `role: RoolUserRole` | User's role |
|
|
602
|
+
| `linkAccess: LinkAccess` | URL sharing level |
|
|
603
|
+
|
|
604
|
+
### Methods
|
|
605
|
+
|
|
606
|
+
| Method | Description |
|
|
607
|
+
|--------|-------------|
|
|
608
|
+
| `openChannel(channelId): Promise<RoolChannel>` | Open a channel on this space |
|
|
609
|
+
| `rename(newName): Promise<void>` | Rename this space |
|
|
610
|
+
| `delete(): Promise<void>` | Permanently delete this space |
|
|
611
|
+
| `listUsers(): Promise<SpaceMember[]>` | List users with access |
|
|
612
|
+
| `addUser(userId, role): Promise<void>` | Add user to space |
|
|
613
|
+
| `removeUser(userId): Promise<void>` | Remove user from space |
|
|
614
|
+
| `setLinkAccess(linkAccess): Promise<void>` | Set URL sharing level |
|
|
615
|
+
| `getChannels(): ChannelInfo[]` | List channels (from cached snapshot) |
|
|
616
|
+
| `deleteChannel(channelId): Promise<void>` | Delete a channel |
|
|
617
|
+
| `exportArchive(): Promise<Blob>` | Export space as zip archive |
|
|
618
|
+
| `refresh(): Promise<void>` | Refresh space data from server |
|
|
619
|
+
|
|
620
|
+
## RoolChannel API
|
|
621
|
+
|
|
622
|
+
A channel is a named context within a space. All object operations, AI prompts, and real-time sync go through a channel. The `channelId` is fixed at open time — to use a different channel, open a new one.
|
|
539
623
|
|
|
540
624
|
### Properties
|
|
541
625
|
|
|
@@ -546,24 +630,24 @@ Spaces are first-class objects with built-in undo/redo, event emission, and real
|
|
|
546
630
|
| `role: RoolUserRole` | User's role (`'owner' \| 'admin' \| 'editor' \| 'viewer'`) |
|
|
547
631
|
| `linkAccess: LinkAccess` | URL sharing level (`'none' \| 'viewer' \| 'editor'`) |
|
|
548
632
|
| `userId: string` | Current user's ID |
|
|
549
|
-
| `
|
|
550
|
-
| `isReadOnly
|
|
633
|
+
| `channelId: string` | Channel ID (read-only, fixed at open time) |
|
|
634
|
+
| `isReadOnly: boolean` | True if viewer role |
|
|
551
635
|
|
|
552
636
|
### Lifecycle
|
|
553
637
|
|
|
554
638
|
| Method | Description |
|
|
555
639
|
|--------|-------------|
|
|
556
640
|
| `close(): void` | Clean up resources and stop receiving updates |
|
|
557
|
-
| `rename(
|
|
641
|
+
| `rename(name): Promise<void>` | Rename this channel |
|
|
558
642
|
|
|
559
643
|
### Object Operations
|
|
560
644
|
|
|
561
|
-
Objects are plain key/value records. `id` is the only reserved field; everything else is application-defined. References between objects are data fields whose values are object IDs.
|
|
645
|
+
Objects are plain key/value records. `id` is the only reserved field; everything else is application-defined. References between objects are data fields whose values are object IDs. All objects must belong to a collection (see below in the schema section). Before adding a new type of object, update the schema in the space.
|
|
562
646
|
|
|
563
647
|
| Method | Description |
|
|
564
648
|
|--------|-------------|
|
|
565
649
|
| `getObject(objectId): Promise<RoolObject \| undefined>` | Get object data, or undefined if not found. |
|
|
566
|
-
| `stat(objectId):
|
|
650
|
+
| `stat(objectId): RoolObjectStat \| undefined` | Get object stat (audit info: modifiedAt, modifiedBy, modifiedByName), or undefined if not found. Sync read from local cache. |
|
|
567
651
|
| `findObjects(options): Promise<{ objects, message }>` | Find objects using structured filters and natural language. Results sorted by modifiedAt (desc by default). |
|
|
568
652
|
| `getObjectIds(options?): string[]` | Get all object IDs. Sorted by modifiedAt (desc by default). Options: `{ limit?, order? }`. |
|
|
569
653
|
| `createObject(options): Promise<{ object, message }>` | Create a new object. Returns the object (with AI-filled content) and message. |
|
|
@@ -575,7 +659,7 @@ Objects are plain key/value records. `id` is the only reserved field; everything
|
|
|
575
659
|
| Option | Description |
|
|
576
660
|
|--------|-------------|
|
|
577
661
|
| `data` | Object data fields (required). Include `id` to use a custom ID. Use `{{placeholder}}` for AI-generated content. Fields prefixed with `_` are hidden from AI. |
|
|
578
|
-
| `ephemeral` | If true, the operation won't be recorded in
|
|
662
|
+
| `ephemeral` | If true, the operation won't be recorded in interaction history. Useful for transient operations. |
|
|
579
663
|
|
|
580
664
|
#### updateObject Options
|
|
581
665
|
|
|
@@ -583,7 +667,7 @@ Objects are plain key/value records. `id` is the only reserved field; everything
|
|
|
583
667
|
|--------|-------------|
|
|
584
668
|
| `data` | Fields to add or update. Pass `null`/`undefined` to delete a field. Use `{{placeholder}}` for AI-generated content. Fields prefixed with `_` are hidden from AI. |
|
|
585
669
|
| `prompt` | Natural language instruction for AI to modify content. |
|
|
586
|
-
| `ephemeral` | If true, the operation won't be recorded in
|
|
670
|
+
| `ephemeral` | If true, the operation won't be recorded in interaction history. Useful for transient operations. |
|
|
587
671
|
|
|
588
672
|
#### findObjects Options
|
|
589
673
|
|
|
@@ -600,23 +684,23 @@ Find objects using structured filters and/or natural language.
|
|
|
600
684
|
| `limit` | Maximum number of results. |
|
|
601
685
|
| `objectIds` | Scope to specific object IDs. Constrains the candidate set in both structured and AI queries. |
|
|
602
686
|
| `order` | Sort order by modifiedAt: `'asc'` or `'desc'` (default: `'desc'`). |
|
|
603
|
-
| `ephemeral` | If true, the query won't be recorded in
|
|
687
|
+
| `ephemeral` | If true, the query won't be recorded in interaction history. Useful for responsive search. |
|
|
604
688
|
|
|
605
689
|
**Examples:**
|
|
606
690
|
|
|
607
691
|
```typescript
|
|
608
692
|
// Exact field matching (no AI, no credits)
|
|
609
|
-
const { objects } = await
|
|
693
|
+
const { objects } = await channel.findObjects({
|
|
610
694
|
where: { type: 'article', status: 'published' }
|
|
611
695
|
});
|
|
612
696
|
|
|
613
697
|
// Pure natural language query (AI interprets)
|
|
614
|
-
const { objects, message } = await
|
|
698
|
+
const { objects, message } = await channel.findObjects({
|
|
615
699
|
prompt: 'articles about space exploration published this year'
|
|
616
700
|
});
|
|
617
701
|
|
|
618
702
|
// Combined: where narrows the data, prompt queries within it
|
|
619
|
-
const { objects } = await
|
|
703
|
+
const { objects } = await channel.findObjects({
|
|
620
704
|
where: { type: 'article' },
|
|
621
705
|
prompt: 'that discuss climate solutions positively',
|
|
622
706
|
limit: 10
|
|
@@ -661,33 +745,85 @@ Media URLs in object fields are visible to AI. Both uploaded and AI-generated me
|
|
|
661
745
|
|
|
662
746
|
```typescript
|
|
663
747
|
// Upload an image
|
|
664
|
-
const url = await
|
|
665
|
-
await
|
|
748
|
+
const url = await channel.uploadMedia(file);
|
|
749
|
+
await channel.createObject({ data: { title: 'Photo', image: url } });
|
|
666
750
|
|
|
667
751
|
// Or let AI generate one using a placeholder
|
|
668
|
-
await
|
|
752
|
+
await channel.createObject({
|
|
669
753
|
data: { title: 'Mascot', image: '{{generate an image of a flying tortoise}}' }
|
|
670
754
|
});
|
|
671
755
|
|
|
672
756
|
// Display media (handles auth automatically)
|
|
673
|
-
const response = await
|
|
757
|
+
const response = await channel.fetchMedia(object.image);
|
|
674
758
|
if (response.contentType.startsWith('image/')) {
|
|
675
759
|
const blob = await response.blob();
|
|
676
760
|
img.src = URL.createObjectURL(blob);
|
|
677
761
|
}
|
|
678
762
|
```
|
|
679
763
|
|
|
764
|
+
### Collection Schema
|
|
765
|
+
|
|
766
|
+
Collections are types you can use to group objects in a space. Every object must belong to a collection. Collections make up the schema and are stored in the space data, syncing in real time together with the rest of the space. The schema is also visible to the AI agent, which it can use to understand what collections exist and what fields they contain, producing more consistent objects.
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
// Define a collection with typed fields
|
|
771
|
+
await channel.createCollection('article', [
|
|
772
|
+
{ name: 'title', type: { kind: 'string' } },
|
|
773
|
+
{ name: 'status', type: { kind: 'enum', values: ['draft', 'published', 'archived'] } },
|
|
774
|
+
{ name: 'tags', type: { kind: 'array', inner: { kind: 'string' } } },
|
|
775
|
+
{ name: 'author', type: { kind: 'ref' } },
|
|
776
|
+
]);
|
|
777
|
+
|
|
778
|
+
// Read the current schema
|
|
779
|
+
const schema = channel.getSchema();
|
|
780
|
+
console.log(schema.article.fields); // FieldDef[]
|
|
781
|
+
|
|
782
|
+
// Modify an existing collection's fields
|
|
783
|
+
await channel.alterCollection('article', [
|
|
784
|
+
{ name: 'title', type: { kind: 'string' } },
|
|
785
|
+
{ name: 'status', type: { kind: 'enum', values: ['draft', 'review', 'published', 'archived'] } },
|
|
786
|
+
{ name: 'tags', type: { kind: 'array', inner: { kind: 'string' } } },
|
|
787
|
+
{ name: 'author', type: { kind: 'ref' } },
|
|
788
|
+
{ name: 'wordCount', type: { kind: 'number' } },
|
|
789
|
+
]);
|
|
790
|
+
|
|
791
|
+
// Remove a collection
|
|
792
|
+
await channel.dropCollection('article');
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
| Method | Description |
|
|
796
|
+
|--------|-------------|
|
|
797
|
+
| `getSchema(): SpaceSchema` | Get all collection definitions |
|
|
798
|
+
| `createCollection(name, fields): Promise<CollectionDef>` | Add a new collection to the schema |
|
|
799
|
+
| `alterCollection(name, fields): Promise<CollectionDef>` | Replace a collection's field definitions |
|
|
800
|
+
| `dropCollection(name): Promise<void>` | Remove a collection from the schema |
|
|
801
|
+
|
|
802
|
+
#### Field Types
|
|
803
|
+
|
|
804
|
+
| Kind | Description | Example |
|
|
805
|
+
|------|-------------|---------|
|
|
806
|
+
| `string` | Text value | `{ kind: 'string' }` |
|
|
807
|
+
| `number` | Numeric value | `{ kind: 'number' }` |
|
|
808
|
+
| `boolean` | True/false | `{ kind: 'boolean' }` |
|
|
809
|
+
| `ref` | Reference to another object | `{ kind: 'ref' }` |
|
|
810
|
+
| `enum` | One of a set of values | `{ kind: 'enum', values: ['a', 'b'] }` |
|
|
811
|
+
| `literal` | Exact value | `{ kind: 'literal', value: 'fixed' }` |
|
|
812
|
+
| `array` | List of values | `{ kind: 'array', inner: { kind: 'string' } }` |
|
|
813
|
+
| `maybe` | Optional (nullable) | `{ kind: 'maybe', inner: { kind: 'number' } }` |
|
|
814
|
+
|
|
680
815
|
### Import/Export
|
|
681
816
|
|
|
682
817
|
Export and import space data as zip archives for backup, portability, or migration:
|
|
683
818
|
|
|
684
819
|
| Method | Description |
|
|
685
820
|
|--------|-------------|
|
|
686
|
-
| `space.exportArchive(): Promise<Blob>` | Export objects, metadata,
|
|
821
|
+
| `space.exportArchive(): Promise<Blob>` | Export objects, metadata, channels, and media as a zip archive |
|
|
687
822
|
| `client.importArchive(name, archive): Promise<RoolSpace>` | Import from a zip archive, creating a new space |
|
|
688
823
|
|
|
689
824
|
**Export:**
|
|
690
825
|
```typescript
|
|
826
|
+
const space = await client.openSpace('space-id');
|
|
691
827
|
const archive = await space.exportArchive();
|
|
692
828
|
// Save as .zip file
|
|
693
829
|
const url = URL.createObjectURL(archive);
|
|
@@ -695,12 +831,13 @@ const url = URL.createObjectURL(archive);
|
|
|
695
831
|
|
|
696
832
|
**Import:**
|
|
697
833
|
```typescript
|
|
698
|
-
const
|
|
834
|
+
const space = await client.importArchive('Imported Data', archiveBlob);
|
|
835
|
+
const channel = await space.openChannel('main');
|
|
699
836
|
```
|
|
700
837
|
|
|
701
|
-
The archive format bundles `data.json` (with objects, metadata, and
|
|
838
|
+
The archive format bundles `data.json` (with objects, metadata, and channels) and a `media/` folder containing all media files. Media URLs are rewritten to relative paths within the archive and restored on import.
|
|
702
839
|
|
|
703
|
-
###
|
|
840
|
+
### Channel Events
|
|
704
841
|
|
|
705
842
|
Semantic events describe what changed. Events fire for both local changes and remote changes.
|
|
706
843
|
|
|
@@ -712,27 +849,21 @@ Semantic events describe what changed. Events fire for both local changes and re
|
|
|
712
849
|
// - 'system': Resync after error
|
|
713
850
|
|
|
714
851
|
// Object events
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
852
|
+
channel.on('objectCreated', ({ objectId, object, source }) => void)
|
|
853
|
+
channel.on('objectUpdated', ({ objectId, object, source }) => void)
|
|
854
|
+
channel.on('objectDeleted', ({ objectId, source }) => void)
|
|
718
855
|
|
|
719
856
|
// Space metadata
|
|
720
|
-
|
|
857
|
+
channel.on('metadataUpdated', ({ metadata, source }) => void)
|
|
721
858
|
|
|
722
|
-
//
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
// Conversation list changed (created, deleted, renamed)
|
|
726
|
-
space.on('conversationsChanged', ({ action, conversationId, name, source }) => void)
|
|
859
|
+
// Channel updated (fetch with getInteractions())
|
|
860
|
+
channel.on('channelUpdated', ({ channelId, source }) => void)
|
|
727
861
|
|
|
728
862
|
// Full state replacement (undo/redo, resync after error)
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
// ConversationId was changed on the space
|
|
732
|
-
space.on('conversationIdChanged', ({ previousConversationId, newConversationId }) => void)
|
|
863
|
+
channel.on('reset', ({ source }) => void)
|
|
733
864
|
|
|
734
|
-
// Sync error occurred,
|
|
735
|
-
|
|
865
|
+
// Sync error occurred, channel resynced from server
|
|
866
|
+
channel.on('syncError', (error: Error) => void)
|
|
736
867
|
```
|
|
737
868
|
|
|
738
869
|
### Error Handling
|
|
@@ -741,7 +872,7 @@ AI operations may fail due to rate limiting or other transient errors. Check `er
|
|
|
741
872
|
|
|
742
873
|
```typescript
|
|
743
874
|
try {
|
|
744
|
-
await
|
|
875
|
+
await channel.updateObject(objectId, { prompt: 'expand this' });
|
|
745
876
|
} catch (error) {
|
|
746
877
|
if (error.message.includes('temporarily unavailable')) {
|
|
747
878
|
showToast('Service busy, please try again in a moment');
|
|
@@ -751,21 +882,15 @@ try {
|
|
|
751
882
|
}
|
|
752
883
|
```
|
|
753
884
|
|
|
754
|
-
### Internal / Advanced
|
|
755
|
-
|
|
756
|
-
| Method | Description |
|
|
757
|
-
|--------|-------------|
|
|
758
|
-
| `getData(): RoolSpaceData` | Get full space data (internal format) |
|
|
759
|
-
|
|
760
885
|
## Interaction History
|
|
761
886
|
|
|
762
|
-
Each
|
|
887
|
+
Each channel has a `channelId` that identifies it. The history records all meaningful interactions (prompts, object mutations) as self-contained entries, each capturing the request and its result. History is stored in the space data itself and syncs in real-time to all clients.
|
|
763
888
|
|
|
764
889
|
### What the AI Receives
|
|
765
890
|
|
|
766
891
|
AI operations (`prompt`, `createObject`, `updateObject`, `findObjects`) automatically receive:
|
|
767
892
|
|
|
768
|
-
- **Interaction history** — Previous interactions and their results from this
|
|
893
|
+
- **Interaction history** — Previous interactions and their results from this channel
|
|
769
894
|
- **Recently modified objects** — Objects in the space recently created or changed
|
|
770
895
|
- **Selected objects** — Objects passed via `objectIds` are given primary focus
|
|
771
896
|
|
|
@@ -774,50 +899,39 @@ This context flows automatically — no configuration needed. The AI sees enough
|
|
|
774
899
|
### Accessing History
|
|
775
900
|
|
|
776
901
|
```typescript
|
|
777
|
-
// Get interactions for
|
|
778
|
-
const interactions =
|
|
902
|
+
// Get interactions for this channel
|
|
903
|
+
const interactions = channel.getInteractions();
|
|
779
904
|
// Returns: Interaction[]
|
|
780
|
-
|
|
781
|
-
// Get interactions for a specific conversation ID
|
|
782
|
-
const interactions = space.getInteractionsById('other-conversation-id');
|
|
783
|
-
// Returns: Interaction[]
|
|
784
|
-
|
|
785
|
-
// List all conversation IDs that have interactions
|
|
786
|
-
const conversationIds = space.getConversationIds();
|
|
787
|
-
// Returns: string[]
|
|
788
905
|
```
|
|
789
906
|
|
|
790
|
-
###
|
|
907
|
+
### Channel History Methods
|
|
791
908
|
|
|
792
909
|
| Method | Description |
|
|
793
910
|
|--------|-------------|
|
|
794
|
-
| `getInteractions(): Interaction[]` | Get interactions for
|
|
795
|
-
| `
|
|
796
|
-
| `
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
| `listConversations(): Promise<ConversationInfo[]>` | List all conversations with summary info. |
|
|
800
|
-
| `getSystemInstruction(): string \| undefined` | Get system instruction for current conversation. |
|
|
801
|
-
| `setSystemInstruction(instruction): Promise<void>` | Set system instruction for current conversation. Pass `null` to clear. |
|
|
911
|
+
| `getInteractions(): Interaction[]` | Get interactions for this channel |
|
|
912
|
+
| `getSystemInstruction(): string \| undefined` | Get system instruction for this channel |
|
|
913
|
+
| `setSystemInstruction(instruction): Promise<void>` | Set system instruction for this channel. Pass `null` to clear. |
|
|
914
|
+
|
|
915
|
+
Channel management (listing, renaming, deleting channels) is done via the client — see [Channel Management](#channel-management).
|
|
802
916
|
|
|
803
917
|
### System Instructions
|
|
804
918
|
|
|
805
|
-
System instructions customize how the AI behaves within a
|
|
919
|
+
System instructions customize how the AI behaves within a channel. The instruction persists across all prompts in that channel.
|
|
806
920
|
|
|
807
921
|
```typescript
|
|
808
922
|
// Make the AI behave like an SQL interpreter
|
|
809
|
-
await
|
|
923
|
+
await channel.setSystemInstruction(
|
|
810
924
|
'Behave like an intelligent SQL interpreter. Respond with simple markdown tables. ' +
|
|
811
925
|
'Translate the objects in the space to the implied structure in your responses.'
|
|
812
926
|
);
|
|
813
927
|
|
|
814
928
|
// Now prompts are interpreted as SQL-like queries
|
|
815
|
-
const { message } = await
|
|
929
|
+
const { message } = await channel.prompt('SELECT task, due_date FROM tasks ORDER BY due_date');
|
|
816
930
|
// Returns a markdown table of tasks, even if no "tasks" objects exist -
|
|
817
931
|
// the AI infers actual tasks from the space content
|
|
818
932
|
|
|
819
933
|
// Clear the instruction to return to default behavior
|
|
820
|
-
await
|
|
934
|
+
await channel.setSystemInstruction(null);
|
|
821
935
|
```
|
|
822
936
|
|
|
823
937
|
System instructions are useful for:
|
|
@@ -829,56 +943,37 @@ System instructions are useful for:
|
|
|
829
943
|
### Listening for Updates
|
|
830
944
|
|
|
831
945
|
```typescript
|
|
832
|
-
|
|
833
|
-
//
|
|
834
|
-
const interactions =
|
|
946
|
+
channel.on('channelUpdated', ({ channelId, source }) => {
|
|
947
|
+
// Channel updated - refresh if needed
|
|
948
|
+
const interactions = channel.getInteractions();
|
|
835
949
|
renderInteractions(interactions);
|
|
836
950
|
});
|
|
837
951
|
```
|
|
838
952
|
|
|
839
|
-
###
|
|
840
|
-
|
|
841
|
-
By default, each call to `openSpace()` or `createSpace()` generates a new `conversationId`. This means:
|
|
842
|
-
- Opening a space twice gives you two independent AI conversation histories
|
|
843
|
-
- Closing and reopening a space starts fresh
|
|
844
|
-
|
|
845
|
-
### Switching Conversations
|
|
953
|
+
### Multiple Channels
|
|
846
954
|
|
|
847
|
-
|
|
955
|
+
Each channel has its own interaction history. To work with multiple independent histories on the same space, open multiple channels:
|
|
848
956
|
|
|
849
957
|
```typescript
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
space.conversationId = 'research-thread';
|
|
854
|
-
await space.prompt("Analyze this data");
|
|
855
|
-
|
|
856
|
-
// User clicks "Main" thread
|
|
857
|
-
space.conversationId = 'main-thread';
|
|
858
|
-
await space.prompt("Summarize findings");
|
|
859
|
-
|
|
860
|
-
// Listen for conversation switches
|
|
861
|
-
space.on('conversationIdChanged', ({ previousConversationId, newConversationId }) => {
|
|
862
|
-
// Re-render chat UI with new conversation's history
|
|
863
|
-
renderChat(space.getInteractions());
|
|
864
|
-
});
|
|
865
|
-
```
|
|
866
|
-
|
|
867
|
-
### Resuming Conversations
|
|
958
|
+
// Open two channels on the same space
|
|
959
|
+
const research = await client.openChannel('space-id', 'research');
|
|
960
|
+
const main = await client.openChannel('space-id', 'main');
|
|
868
961
|
|
|
869
|
-
|
|
962
|
+
// Each has independent history
|
|
963
|
+
await research.prompt("Analyze this data");
|
|
964
|
+
await main.prompt("Summarize findings");
|
|
870
965
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
966
|
+
// Close when done
|
|
967
|
+
research.close();
|
|
968
|
+
main.close();
|
|
874
969
|
```
|
|
875
970
|
|
|
876
971
|
**Use cases:**
|
|
877
|
-
- **
|
|
878
|
-
- **
|
|
879
|
-
- **Collaborative
|
|
972
|
+
- **Chat app with sidebar** — Each sidebar entry is a channel with a different channelId
|
|
973
|
+
- **Page refresh** — Store the channelId in localStorage to resume the same channel
|
|
974
|
+
- **Collaborative channels** — Share a channelId between users to enable shared AI interaction history
|
|
880
975
|
|
|
881
|
-
**Tip:** Use the user's id as
|
|
976
|
+
**Tip:** Use the user's id as channelId to share context across tabs/devices, or a fixed string like `'shared'` to share context across all users.
|
|
882
977
|
|
|
883
978
|
Note: Interaction history is truncated to the most recent 50 entries to manage space size.
|
|
884
979
|
|
|
@@ -890,11 +985,38 @@ The `ai` field in interactions distinguishes AI-generated responses from synthet
|
|
|
890
985
|
|
|
891
986
|
### Tool Calls
|
|
892
987
|
|
|
893
|
-
The `toolCalls` array captures what the AI agent did during execution. Use it to build responsive UIs that show progress while the agent works — the `
|
|
988
|
+
The `toolCalls` array captures what the AI agent did during execution. Use it to build responsive UIs that show progress while the agent works — the `channelUpdated` event fires as each tool completes, letting you display status updates or hints in real-time.
|
|
894
989
|
|
|
895
990
|
## Data Types
|
|
896
991
|
|
|
897
|
-
###
|
|
992
|
+
### Schema Types
|
|
993
|
+
|
|
994
|
+
```typescript
|
|
995
|
+
// Allowed field types
|
|
996
|
+
type FieldType =
|
|
997
|
+
| { kind: 'string' }
|
|
998
|
+
| { kind: 'number' }
|
|
999
|
+
| { kind: 'boolean' }
|
|
1000
|
+
| { kind: 'array'; inner?: FieldType }
|
|
1001
|
+
| { kind: 'maybe'; inner: FieldType }
|
|
1002
|
+
| { kind: 'enum'; values: string[] }
|
|
1003
|
+
| { kind: 'literal'; value: string | number | boolean }
|
|
1004
|
+
| { kind: 'ref' };
|
|
1005
|
+
|
|
1006
|
+
interface FieldDef {
|
|
1007
|
+
name: string;
|
|
1008
|
+
type: FieldType;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
interface CollectionDef {
|
|
1012
|
+
fields: FieldDef[];
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Full schema — collection names to definitions
|
|
1016
|
+
type SpaceSchema = Record<string, CollectionDef>;
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
### Object Data
|
|
898
1020
|
|
|
899
1021
|
```typescript
|
|
900
1022
|
// RoolObject represents the object data you work with
|
|
@@ -906,25 +1028,29 @@ interface RoolObject {
|
|
|
906
1028
|
[key: string]: unknown;
|
|
907
1029
|
}
|
|
908
1030
|
|
|
909
|
-
// Object stat - audit information returned by
|
|
1031
|
+
// Object stat - audit information returned by channel.stat()
|
|
910
1032
|
interface RoolObjectStat {
|
|
911
1033
|
modifiedAt: number;
|
|
912
1034
|
modifiedBy: string;
|
|
913
1035
|
modifiedByName: string | null;
|
|
914
1036
|
}
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
### Channels
|
|
915
1040
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1041
|
+
```typescript
|
|
1042
|
+
// Channel container with metadata
|
|
1043
|
+
interface Channel {
|
|
1044
|
+
name?: string; // Channel name (optional)
|
|
1045
|
+
createdAt: number; // Timestamp when channel was created
|
|
1046
|
+
createdBy: string; // User ID who created the channel
|
|
921
1047
|
createdByName?: string; // Display name at time of creation
|
|
922
1048
|
systemInstruction?: string; // Custom system instruction for AI
|
|
923
1049
|
interactions: Interaction[]; // Interaction history
|
|
924
1050
|
}
|
|
925
1051
|
|
|
926
|
-
//
|
|
927
|
-
interface
|
|
1052
|
+
// Channel summary info (returned by client.getChannels)
|
|
1053
|
+
interface ChannelInfo {
|
|
928
1054
|
id: string;
|
|
929
1055
|
name: string | null;
|
|
930
1056
|
createdAt: number;
|
|
@@ -932,24 +1058,10 @@ interface ConversationInfo {
|
|
|
932
1058
|
createdByName: string | null;
|
|
933
1059
|
interactionCount: number;
|
|
934
1060
|
}
|
|
935
|
-
|
|
936
|
-
// Internal space data structure
|
|
937
|
-
interface RoolSpaceData {
|
|
938
|
-
version: number; // Monotonically increasing version for sync consistency
|
|
939
|
-
objects: Record<string, RoolObjectEntry>;
|
|
940
|
-
meta: Record<string, unknown>; // Space-level metadata
|
|
941
|
-
conversations?: Record<string, Conversation>; // Conversations keyed by conversationId
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// Full stored object structure (for advanced use with getData())
|
|
945
|
-
interface RoolObjectEntry {
|
|
946
|
-
data: RoolObject; // The actual object data
|
|
947
|
-
modifiedAt: number; // Timestamp of last modification
|
|
948
|
-
modifiedBy: string; // User ID who last modified
|
|
949
|
-
modifiedByName: string | null; // Display name at time of modification
|
|
950
|
-
}
|
|
951
1061
|
```
|
|
952
1062
|
|
|
1063
|
+
Note: `Channel` and `ChannelInfo` are data types describing the stored channel metadata. The `Channel` interface is the wire format; `RoolChannel` is the live SDK class you interact with.
|
|
1064
|
+
|
|
953
1065
|
### Interaction Types
|
|
954
1066
|
|
|
955
1067
|
```typescript
|
|
@@ -998,7 +1110,7 @@ interface PromptOptions {
|
|
|
998
1110
|
objectIds?: string[]; // Scope to specific objects
|
|
999
1111
|
responseSchema?: Record<string, unknown>;
|
|
1000
1112
|
effort?: PromptEffort; // Effort level (default: 'STANDARD')
|
|
1001
|
-
ephemeral?: boolean; // Don't record in
|
|
1113
|
+
ephemeral?: boolean; // Don't record in interaction history
|
|
1002
1114
|
readOnly?: boolean; // Disable mutation tools (default: false)
|
|
1003
1115
|
attachments?: Array<File | Blob | { data: string; contentType: string }>; // Files to attach (uploaded to media store)
|
|
1004
1116
|
}
|
|
@@ -1009,7 +1121,7 @@ interface PromptOptions {
|
|
|
1009
1121
|
A Rool Space is a persistent, shared world model. Applications project different interaction patterns onto the same core primitives:
|
|
1010
1122
|
|
|
1011
1123
|
- **Objects** store durable state, with references to other objects via data fields
|
|
1012
|
-
- **
|
|
1124
|
+
- **Channels** provide independent AI interaction contexts over shared objects
|
|
1013
1125
|
- **Events** describe what changed in real-time
|
|
1014
1126
|
|
|
1015
1127
|
Below are a few representative patterns.
|
|
@@ -1017,20 +1129,20 @@ Below are a few representative patterns.
|
|
|
1017
1129
|
### Chat With Generated Artifacts
|
|
1018
1130
|
|
|
1019
1131
|
- **Space**: documents, notes, images, tasks as objects
|
|
1020
|
-
- **
|
|
1132
|
+
- **Channels**: each chat thread is a separate channel on the same space
|
|
1021
1133
|
- **UI**: renders interactions from `getInteractions()` as chat; derives artifact lists from object events
|
|
1022
1134
|
|
|
1023
1135
|
**Pattern**
|
|
1024
1136
|
- Interaction history syncs in real-time; UI renders entries as chat bubbles
|
|
1025
|
-
- Artifacts are persistent objects
|
|
1026
|
-
- Listen to `
|
|
1137
|
+
- Artifacts are persistent objects shared across all channels
|
|
1138
|
+
- Listen to `channelUpdated` event to update chat UI
|
|
1027
1139
|
- Selecting objects defines the AI working set via `objectIds`
|
|
1028
1140
|
|
|
1029
1141
|
### Multi-User World / Text Adventure
|
|
1030
1142
|
|
|
1031
1143
|
- **Space**: rooms, items, NPCs, players as objects
|
|
1032
1144
|
- **References**: navigation, containment, location via data fields
|
|
1033
|
-
- **
|
|
1145
|
+
- **Channel**: player commands and narrative continuity
|
|
1034
1146
|
|
|
1035
1147
|
**Pattern**
|
|
1036
1148
|
- The space is the shared world state
|
|
@@ -1041,7 +1153,7 @@ Below are a few representative patterns.
|
|
|
1041
1153
|
|
|
1042
1154
|
- **Space**: concepts, sources, hypotheses as objects
|
|
1043
1155
|
- **References**: semantic connections between objects via data fields
|
|
1044
|
-
- **
|
|
1156
|
+
- **Channel**: exploratory analysis and questioning
|
|
1045
1157
|
|
|
1046
1158
|
**Pattern**
|
|
1047
1159
|
- Graph structure lives in object data fields containing other object IDs
|
|
@@ -1052,7 +1164,7 @@ Below are a few representative patterns.
|
|
|
1052
1164
|
|
|
1053
1165
|
- Durable content lives in space objects
|
|
1054
1166
|
- References between objects are data fields whose values are object IDs
|
|
1055
|
-
- Interaction history lives in
|
|
1167
|
+
- Interaction history lives in channels (persistent, synced, truncated to 50 entries)
|
|
1056
1168
|
- UI state lives in the client, space metadata, or `_`-prefixed fields
|
|
1057
1169
|
- AI focus is controlled by object selection, not by replaying history
|
|
1058
1170
|
|