@rool-dev/svelte 0.11.15 → 0.12.0
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 +29 -29
- package/dist/rool.svelte.d.ts.map +1 -1
- package/dist/rool.svelte.js +42 -27
- package/dist/space-session.svelte.d.ts +8 -8
- package/dist/space-session.svelte.d.ts.map +1 -1
- package/dist/space-session.svelte.js +83 -34
- package/dist/space.svelte.d.ts +4 -8
- package/dist/space.svelte.d.ts.map +1 -1
- package/dist/space.svelte.js +95 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -59,8 +59,9 @@ The Svelte wrapper adds reactive state on top of the SDK:
|
|
|
59
59
|
| `space.fileTree` | Canonical reactive WebDAV tree for `/`, including `/space` objects and `/rool-drive` user files |
|
|
60
60
|
| `space.objectPaths` | Object paths derived from `space.fileTree` |
|
|
61
61
|
| `space.collections` | Collection directories derived from `space.fileTree` |
|
|
62
|
-
| `space.conversations` |
|
|
63
|
-
| `thread.interactions` |
|
|
62
|
+
| `space.conversations` | Lightweight conversation roster, kept current from `openSpace` and SSE |
|
|
63
|
+
| `thread.interactions` | Active branch for one lazily opened conversation |
|
|
64
|
+
| `thread.loading` / `thread.error` | Load state for that conversation only |
|
|
64
65
|
| `watch.objects` | Objects matching a filter (auto-updates) |
|
|
65
66
|
| `watch.loading` | Whether watch is loading |
|
|
66
67
|
|
|
@@ -148,7 +149,7 @@ Reactive cross-device storage for user preferences. Synced from server on `init(
|
|
|
148
149
|
|
|
149
150
|
### Spaces & Conversations
|
|
150
151
|
|
|
151
|
-
Every space has its own SSE subscription.
|
|
152
|
+
Every space has its own SSE subscription. Conversation metadata is reactive at the space level; full contents are loaded only for conversation handles requested through `space.conversation(id)`. Repeated calls for the same ID return the same handle. Call `space.close()` when done to stop the subscription and close its conversation handles.
|
|
152
153
|
|
|
153
154
|
```typescript
|
|
154
155
|
// Open a space — reactive, with SSE
|
|
@@ -330,7 +331,7 @@ articles.close() // Stop listening for updates
|
|
|
330
331
|
|
|
331
332
|
### Reactive Conversation Handle
|
|
332
333
|
|
|
333
|
-
For apps with multiple independent interaction threads
|
|
334
|
+
For apps with multiple independent interaction threads, use `space.conversation()` to lazily load and retain reactive state for the threads currently in use:
|
|
334
335
|
|
|
335
336
|
```svelte
|
|
336
337
|
<script lang="ts">
|
|
@@ -358,21 +359,21 @@ For apps with multiple independent interaction threads (e.g., chat with threads)
|
|
|
358
359
|
```
|
|
359
360
|
|
|
360
361
|
```typescript
|
|
361
|
-
//
|
|
362
|
-
thread.
|
|
362
|
+
// State retained for this conversation only
|
|
363
|
+
thread.data // Conversation | null | undefined
|
|
364
|
+
thread.interactions // active branch; updates from space events
|
|
365
|
+
thread.activeLeafId
|
|
366
|
+
thread.loading
|
|
367
|
+
thread.error
|
|
363
368
|
|
|
364
|
-
// Conversation-scoped methods
|
|
365
369
|
await thread.prompt('Hello')
|
|
366
|
-
await thread.stop()
|
|
367
|
-
await thread.putObject('/space/note/welcome.json', { text: 'Note' })
|
|
368
|
-
await thread.patchObject('/space/note/welcome.json', { data: { text: 'Updated' } })
|
|
370
|
+
await thread.stop()
|
|
369
371
|
await thread.setSystemInstruction('Respond in haiku')
|
|
370
372
|
await thread.rename('Research Thread')
|
|
371
|
-
thread.
|
|
372
|
-
thread.getSystemInstruction()
|
|
373
|
+
thread.setActiveLeaf(interactionId)
|
|
373
374
|
|
|
374
|
-
//
|
|
375
|
-
thread.close()
|
|
375
|
+
// Evicts this handle from the space; requesting the ID again loads a new one.
|
|
376
|
+
thread.close()
|
|
376
377
|
```
|
|
377
378
|
|
|
378
379
|
Conversations are auto-created when you first write history or settings. Real-time events are owned by the space subscription; conversation handles subscribe to space events locally.
|
|
@@ -403,25 +404,24 @@ space.role
|
|
|
403
404
|
const path = '/space/note/welcome.json';
|
|
404
405
|
await space.getObject(path)
|
|
405
406
|
|
|
406
|
-
//
|
|
407
|
-
|
|
408
|
-
await
|
|
409
|
-
await
|
|
410
|
-
await
|
|
411
|
-
await
|
|
412
|
-
await conversation.prompt('Summarize everything')
|
|
413
|
-
await conversation.stop()
|
|
414
|
-
|
|
415
|
-
// Schema/metadata writes are also attributed to a conversation
|
|
416
|
-
space.getSchema()
|
|
417
|
-
await conversation.createCollection('article', [
|
|
407
|
+
// Object and schema APIs live on the space
|
|
408
|
+
await space.putObject(path, { text: 'Hello' })
|
|
409
|
+
await space.patchObject(path, { data: { text: 'Updated' } })
|
|
410
|
+
await space.moveObject(path, '/space/note/renamed.json')
|
|
411
|
+
await space.deleteObjects(['/space/note/renamed.json'])
|
|
412
|
+
await space.createCollection('article', [
|
|
418
413
|
{ name: 'title', type: { kind: 'string' } },
|
|
419
414
|
{ name: 'status', type: { kind: 'enum', values: ['draft', 'published'] } },
|
|
420
415
|
])
|
|
421
|
-
await
|
|
422
|
-
await
|
|
416
|
+
await space.alterCollection('article', updatedFields)
|
|
417
|
+
await space.dropCollection('article')
|
|
418
|
+
|
|
419
|
+
// Conversation state and operations are scoped to a lazy reactive handle
|
|
420
|
+
const conversation = space.conversation('thread-42');
|
|
421
|
+
await conversation.prompt('Summarize everything')
|
|
422
|
+
await conversation.stop()
|
|
423
423
|
await conversation.setSystemInstruction('You are helpful')
|
|
424
|
-
conversation.
|
|
424
|
+
conversation.interactions
|
|
425
425
|
|
|
426
426
|
// Space history/admin
|
|
427
427
|
await space.undo()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rool.svelte.d.ts","sourceRoot":"","sources":["../src/rool.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"rool.svelte.d.ts","sourceRoot":"","sources":["../src/rool.svelte.ts"],"names":[],"mappings":"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"}
|
package/dist/rool.svelte.js
CHANGED
|
@@ -12,7 +12,8 @@ import { wrapSpace } from './space.svelte.js';
|
|
|
12
12
|
class RoolImpl {
|
|
13
13
|
#client;
|
|
14
14
|
#unsubscribers = [];
|
|
15
|
-
#openSpaces = new
|
|
15
|
+
#openSpaces = new Map();
|
|
16
|
+
#openingSpaces = new Map();
|
|
16
17
|
// Reactive state
|
|
17
18
|
authenticated = $state(null); // null = checking, false = not auth, true = auth
|
|
18
19
|
spaces = $state(undefined);
|
|
@@ -150,10 +151,10 @@ class RoolImpl {
|
|
|
150
151
|
* Log out and close all open spaces.
|
|
151
152
|
*/
|
|
152
153
|
logout() {
|
|
153
|
-
for (const space of this.#openSpaces)
|
|
154
|
+
for (const space of this.#openSpaces.values())
|
|
154
155
|
space.close();
|
|
155
|
-
}
|
|
156
156
|
this.#openSpaces.clear();
|
|
157
|
+
this.#openingSpaces.clear();
|
|
157
158
|
this.#client.logout();
|
|
158
159
|
}
|
|
159
160
|
/**
|
|
@@ -161,31 +162,29 @@ class RoolImpl {
|
|
|
161
162
|
* Call `space.close()` when done to stop the subscription.
|
|
162
163
|
*/
|
|
163
164
|
async openSpace(spaceId) {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.#
|
|
168
|
-
|
|
165
|
+
const existing = this.#openSpaces.get(spaceId);
|
|
166
|
+
if (existing && !existing.isClosed)
|
|
167
|
+
return existing;
|
|
168
|
+
const opening = this.#openingSpaces.get(spaceId);
|
|
169
|
+
if (opening)
|
|
170
|
+
return opening;
|
|
171
|
+
const pending = this.#client.openSpace(spaceId)
|
|
172
|
+
.then((space) => this.#wrapSpace(space))
|
|
173
|
+
.finally(() => this.#openingSpaces.delete(spaceId));
|
|
174
|
+
this.#openingSpaces.set(spaceId, pending);
|
|
175
|
+
return pending;
|
|
169
176
|
}
|
|
170
177
|
/**
|
|
171
178
|
* Create a new space. Returns a ReactiveSpace.
|
|
172
179
|
*/
|
|
173
180
|
async createSpace(name) {
|
|
174
|
-
|
|
175
|
-
const reactive = wrapSpace(raw);
|
|
176
|
-
await reactive.ready();
|
|
177
|
-
this.#openSpaces.add(reactive);
|
|
178
|
-
return reactive;
|
|
181
|
+
return this.#wrapSpace(await this.#client.createSpace(name));
|
|
179
182
|
}
|
|
180
183
|
/**
|
|
181
184
|
* Duplicate an existing space. Returns a ReactiveSpace.
|
|
182
185
|
*/
|
|
183
186
|
async duplicateSpace(sourceSpaceId, name) {
|
|
184
|
-
|
|
185
|
-
const reactive = wrapSpace(raw);
|
|
186
|
-
await reactive.ready();
|
|
187
|
-
this.#openSpaces.add(reactive);
|
|
188
|
-
return reactive;
|
|
187
|
+
return this.#wrapSpace(await this.#client.duplicateSpace(sourceSpaceId, name));
|
|
189
188
|
}
|
|
190
189
|
/**
|
|
191
190
|
* Manually refresh the spaces list.
|
|
@@ -196,8 +195,10 @@ class RoolImpl {
|
|
|
196
195
|
/**
|
|
197
196
|
* Delete a space.
|
|
198
197
|
*/
|
|
199
|
-
deleteSpace(spaceId) {
|
|
200
|
-
|
|
198
|
+
async deleteSpace(spaceId) {
|
|
199
|
+
await this.#client.deleteSpace(spaceId);
|
|
200
|
+
this.#openSpaces.get(spaceId)?.close();
|
|
201
|
+
this.#openSpaces.delete(spaceId);
|
|
201
202
|
}
|
|
202
203
|
/**
|
|
203
204
|
* Mark the current user for deletion, then log out locally.
|
|
@@ -258,11 +259,7 @@ class RoolImpl {
|
|
|
258
259
|
* Import a space from a zip archive. Returns a ReactiveSpace.
|
|
259
260
|
*/
|
|
260
261
|
async importArchive(name, archive) {
|
|
261
|
-
|
|
262
|
-
const reactive = wrapSpace(raw);
|
|
263
|
-
await reactive.ready();
|
|
264
|
-
this.#openSpaces.add(reactive);
|
|
265
|
-
return reactive;
|
|
262
|
+
return this.#wrapSpace(await this.#client.importArchive(name, archive));
|
|
266
263
|
}
|
|
267
264
|
/**
|
|
268
265
|
* Get auth user info from JWT token.
|
|
@@ -286,14 +283,32 @@ class RoolImpl {
|
|
|
286
283
|
this.currentUser = user;
|
|
287
284
|
return user;
|
|
288
285
|
}
|
|
286
|
+
async #wrapSpace(space) {
|
|
287
|
+
const existing = this.#openSpaces.get(space.id);
|
|
288
|
+
if (existing && !existing.isClosed)
|
|
289
|
+
return existing;
|
|
290
|
+
const reactive = wrapSpace(space, () => {
|
|
291
|
+
if (this.#openSpaces.get(space.id) === reactive)
|
|
292
|
+
this.#openSpaces.delete(space.id);
|
|
293
|
+
});
|
|
294
|
+
try {
|
|
295
|
+
await reactive.ready();
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
reactive.close();
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
this.#openSpaces.set(space.id, reactive);
|
|
302
|
+
return reactive;
|
|
303
|
+
}
|
|
289
304
|
/**
|
|
290
305
|
* Clean up resources.
|
|
291
306
|
*/
|
|
292
307
|
destroy() {
|
|
293
|
-
for (const space of this.#openSpaces)
|
|
308
|
+
for (const space of this.#openSpaces.values())
|
|
294
309
|
space.close();
|
|
295
|
-
}
|
|
296
310
|
this.#openSpaces.clear();
|
|
311
|
+
this.#openingSpaces.clear();
|
|
297
312
|
for (const unsub of this.#unsubscribers) {
|
|
298
313
|
unsub();
|
|
299
314
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RoolSpace, Interaction, RoolObject, ConversationHandle } from '@rool-dev/sdk';
|
|
1
|
+
import type { RoolSpace, Interaction, Conversation, RoolObject, ConversationHandle } from '@rool-dev/sdk';
|
|
2
2
|
import { ReactiveFileTree } from './file-tree.svelte.js';
|
|
3
3
|
/**
|
|
4
4
|
* Options for creating a reactive watch.
|
|
@@ -41,22 +41,22 @@ export declare class ReactiveObjectImpl {
|
|
|
41
41
|
export type ReactiveObject = ReactiveObjectImpl;
|
|
42
42
|
export declare class ReactiveConversationHandleImpl {
|
|
43
43
|
#private;
|
|
44
|
+
data: Conversation | null | undefined;
|
|
44
45
|
interactions: Interaction[];
|
|
45
|
-
|
|
46
|
+
loading: boolean;
|
|
47
|
+
error: Error | null;
|
|
48
|
+
constructor(space: RoolSpace, conversationId: string, onClose: () => void);
|
|
46
49
|
get conversationId(): string;
|
|
50
|
+
get activeLeafId(): string | undefined;
|
|
51
|
+
refresh(): Promise<void>;
|
|
47
52
|
getInteractions(): Interaction[];
|
|
48
53
|
getTree(): Record<string, Interaction>;
|
|
49
|
-
get activeLeafId(): string | undefined;
|
|
50
54
|
setActiveLeaf(interactionId: string): void;
|
|
51
55
|
getSystemInstruction(): string | undefined;
|
|
52
56
|
setSystemInstruction(...args: Parameters<ConversationHandle['setSystemInstruction']>): Promise<void>;
|
|
53
57
|
rename(...args: Parameters<ConversationHandle['rename']>): Promise<void>;
|
|
54
58
|
delete(): Promise<void>;
|
|
55
|
-
prompt(
|
|
56
|
-
message: string;
|
|
57
|
-
objects: RoolObject[];
|
|
58
|
-
creditsUsed: number;
|
|
59
|
-
}>;
|
|
59
|
+
prompt(text: string, options?: Parameters<ConversationHandle['prompt']>[1]): ReturnType<ConversationHandle['prompt']>;
|
|
60
60
|
stop(): Promise<boolean>;
|
|
61
61
|
close(): void;
|
|
62
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"space-session.svelte.d.ts","sourceRoot":"","sources":["../src/space-session.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"space-session.svelte.d.ts","sourceRoot":"","sources":["../src/space-session.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,UAAU,EACV,kBAAkB,EAEnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAqD,MAAM,uBAAuB,CAAC;AAE5G;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACxB;AA8CD;;GAEG;AACH,qBAAa,iBAAiB;;IAO5B,OAAO,eAA4B;IACnC,OAAO,UAAgB;gBAEX,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY;IAgB/E,yEAAyE;IACnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,KAAK,IAAI,IAAI;CAId;AAED,MAAM,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAE9C;;GAEG;AACH,qBAAa,kBAAkB;;IAO7B,IAAI,yBAA6C;IACjD,OAAO,UAAgB;gBAEX,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM;IAoBhE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,KAAK,IAAI,IAAI;CAId;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAMhD,qBAAa,8BAA8B;;IASzC,IAAI,kCAAsD;IAC1D,YAAY,gBAA6B;IACzC,OAAO,UAAgB;IACvB,KAAK,eAA8B;gBAEvB,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI;IAezE,IAAI,cAAc,IAAI,MAAM,CAAiC;IAC7D,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAA+B;IAE/D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAc9B,eAAe,IAAI,WAAW,EAAE;IAChC,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAEtC,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAS1C,oBAAoB,IAAI,MAAM,GAAG,SAAS;IAC1C,oBAAoB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;IACpF,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM;IAEA,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GACpD,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAmB3C,IAAI;IAEJ,KAAK,IAAI,IAAI;CA0Bd;AAED,MAAM,MAAM,0BAA0B,GAAG,8BAA8B,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isObjectPath, machinePath } from '@rool-dev/sdk';
|
|
1
|
+
import { conversationBranch, defaultConversationLeaf, generateEntityId, isObjectPath, machinePath, } from '@rool-dev/sdk';
|
|
2
2
|
function objectCollection(path) {
|
|
3
3
|
if (!isObjectPath(path))
|
|
4
4
|
return undefined;
|
|
@@ -137,60 +137,109 @@ export class ReactiveObjectImpl {
|
|
|
137
137
|
export class ReactiveConversationHandleImpl {
|
|
138
138
|
#handle;
|
|
139
139
|
#conversationId;
|
|
140
|
+
#activeLeafId = $state(undefined);
|
|
141
|
+
#revision = 0;
|
|
142
|
+
#closed = false;
|
|
140
143
|
#unsubscribers = [];
|
|
141
|
-
|
|
144
|
+
#onClose;
|
|
145
|
+
data = $state(undefined);
|
|
142
146
|
interactions = $state([]);
|
|
143
|
-
|
|
147
|
+
loading = $state(true);
|
|
148
|
+
error = $state(null);
|
|
149
|
+
constructor(space, conversationId, onClose) {
|
|
144
150
|
this.#conversationId = conversationId;
|
|
145
151
|
this.#handle = space.conversation(conversationId);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (this.#handle.loaded) {
|
|
149
|
-
this.interactions = this.#handle.getInteractions();
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
void this.#handle.load().then(() => {
|
|
153
|
-
this.interactions = this.#handle.getInteractions();
|
|
154
|
-
});
|
|
155
|
-
}
|
|
152
|
+
this.#onClose = onClose;
|
|
153
|
+
void this.refresh();
|
|
156
154
|
const onConversationUpdated = (event) => {
|
|
157
155
|
if (event.conversationId !== this.#conversationId)
|
|
158
156
|
return;
|
|
159
|
-
this.#
|
|
160
|
-
this
|
|
157
|
+
this.#revision += 1;
|
|
158
|
+
this.#apply(event.conversation);
|
|
161
159
|
};
|
|
162
160
|
space.on('conversationUpdated', onConversationUpdated);
|
|
163
161
|
this.#unsubscribers.push(() => space.off('conversationUpdated', onConversationUpdated));
|
|
164
|
-
// Reconnect reset: force-reload the conversation (we may have missed SSE).
|
|
165
|
-
const onReset = () => {
|
|
166
|
-
if (!this.#handle.loaded)
|
|
167
|
-
return;
|
|
168
|
-
void this.#handle.load(true).then(() => {
|
|
169
|
-
this.interactions = this.#handle.getInteractions();
|
|
170
|
-
});
|
|
171
|
-
};
|
|
172
|
-
space.on('reset', onReset);
|
|
173
|
-
this.#unsubscribers.push(() => space.off('reset', onReset));
|
|
174
162
|
}
|
|
175
163
|
get conversationId() { return this.#conversationId; }
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
164
|
+
get activeLeafId() { return this.#activeLeafId; }
|
|
165
|
+
async refresh() {
|
|
166
|
+
const revision = this.#revision;
|
|
167
|
+
this.loading = true;
|
|
168
|
+
this.error = null;
|
|
169
|
+
try {
|
|
170
|
+
const conversation = await this.#handle.get();
|
|
171
|
+
if (!this.#closed && revision === this.#revision)
|
|
172
|
+
this.#apply(conversation);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (!this.#closed)
|
|
176
|
+
this.error = error instanceof Error ? error : new Error(String(error));
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
if (!this.#closed)
|
|
180
|
+
this.loading = false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
getInteractions() { return this.interactions; }
|
|
184
|
+
getTree() { return this.data?.interactions ?? {}; }
|
|
180
185
|
setActiveLeaf(interactionId) {
|
|
181
|
-
this
|
|
182
|
-
|
|
186
|
+
if (!this.data?.interactions[interactionId]) {
|
|
187
|
+
throw new Error(`Interaction "${interactionId}" not found in conversation "${this.#conversationId}"`);
|
|
188
|
+
}
|
|
189
|
+
this.#revision += 1;
|
|
190
|
+
this.#activeLeafId = interactionId;
|
|
191
|
+
this.interactions = conversationBranch(this.data, interactionId);
|
|
183
192
|
}
|
|
184
|
-
getSystemInstruction() { return this
|
|
193
|
+
getSystemInstruction() { return this.data?.systemInstruction; }
|
|
185
194
|
setSystemInstruction(...args) { return this.#handle.setSystemInstruction(...args); }
|
|
186
195
|
rename(...args) { return this.#handle.rename(...args); }
|
|
187
196
|
delete() { return this.#handle.delete(); }
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
async prompt(text, options) {
|
|
198
|
+
const previousLeaf = this.#activeLeafId;
|
|
199
|
+
const interactionId = options?.interactionId ?? generateEntityId();
|
|
200
|
+
this.#revision += 1;
|
|
201
|
+
this.#activeLeafId = interactionId;
|
|
202
|
+
try {
|
|
203
|
+
return await this.#handle.prompt(text, {
|
|
204
|
+
...options,
|
|
205
|
+
interactionId,
|
|
206
|
+
parentInteractionId: options?.parentInteractionId === undefined
|
|
207
|
+
? previousLeaf ?? null
|
|
208
|
+
: options.parentInteractionId,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
if (this.#activeLeafId === interactionId)
|
|
213
|
+
this.#activeLeafId = previousLeaf;
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
190
217
|
stop() { return this.#handle.stop(); }
|
|
191
218
|
close() {
|
|
219
|
+
if (this.#closed)
|
|
220
|
+
return;
|
|
221
|
+
this.#closed = true;
|
|
192
222
|
for (const unsub of this.#unsubscribers)
|
|
193
223
|
unsub();
|
|
194
224
|
this.#unsubscribers.length = 0;
|
|
225
|
+
this.#onClose();
|
|
226
|
+
}
|
|
227
|
+
#apply(conversation) {
|
|
228
|
+
this.data = conversation;
|
|
229
|
+
if (!conversation) {
|
|
230
|
+
this.#activeLeafId = undefined;
|
|
231
|
+
this.interactions = [];
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const currentLeaf = this.#activeLeafId;
|
|
235
|
+
if (currentLeaf) {
|
|
236
|
+
const child = Object.values(conversation.interactions).find((interaction) => interaction.parentId === currentLeaf);
|
|
237
|
+
if (child)
|
|
238
|
+
this.#activeLeafId = child.id;
|
|
239
|
+
}
|
|
240
|
+
if (!this.#activeLeafId || !conversation.interactions[this.#activeLeafId]) {
|
|
241
|
+
this.#activeLeafId = defaultConversationLeaf(conversation);
|
|
242
|
+
}
|
|
243
|
+
this.interactions = conversationBranch(conversation, this.#activeLeafId);
|
|
195
244
|
}
|
|
196
245
|
}
|
package/dist/space.svelte.d.ts
CHANGED
|
@@ -17,9 +17,10 @@ import { ReactiveFileTree } from './file-tree.svelte.js';
|
|
|
17
17
|
declare class ReactiveSpaceImpl {
|
|
18
18
|
#private;
|
|
19
19
|
connectionState: ConnectionState;
|
|
20
|
+
openSpaceError: Error | null;
|
|
20
21
|
meta: Record<string, unknown>;
|
|
21
22
|
schema: SpaceSchema;
|
|
22
|
-
constructor(space: RoolSpace);
|
|
23
|
+
constructor(space: RoolSpace, onClose: () => void);
|
|
23
24
|
/** Resolve when the initial meta/schema fetch has settled. */
|
|
24
25
|
ready(): Promise<void>;
|
|
25
26
|
/**
|
|
@@ -29,7 +30,7 @@ declare class ReactiveSpaceImpl {
|
|
|
29
30
|
*/
|
|
30
31
|
setMeta(key: string, value: unknown): Promise<void>;
|
|
31
32
|
get isClosed(): boolean;
|
|
32
|
-
/** Get
|
|
33
|
+
/** Get the shared reactive handle for one lazily loaded conversation. */
|
|
33
34
|
conversation(conversationId: string): ReactiveConversationHandleImpl;
|
|
34
35
|
/**
|
|
35
36
|
* Close this space and stop the SSE subscription. Idempotent.
|
|
@@ -62,16 +63,11 @@ declare class ReactiveSpaceImpl {
|
|
|
62
63
|
dropCollection(...args: Parameters<RoolSpace['dropCollection']>): Promise<void>;
|
|
63
64
|
object(path: string): ReactiveObjectImpl;
|
|
64
65
|
watch(options: WatchOptions): ReactiveWatchImpl;
|
|
65
|
-
/** @deprecated Use {@link stopConversation}. */
|
|
66
|
-
stopInteraction(...args: Parameters<RoolSpace['stopInteraction']>): Promise<boolean>;
|
|
67
66
|
stopConversation(...args: Parameters<RoolSpace['stopConversation']>): Promise<boolean>;
|
|
68
|
-
checkpoint(...args: Parameters<RoolSpace['checkpoint']>): Promise<string>;
|
|
69
67
|
canUndo(...args: Parameters<RoolSpace['canUndo']>): Promise<boolean>;
|
|
70
68
|
canRedo(...args: Parameters<RoolSpace['canRedo']>): Promise<boolean>;
|
|
71
69
|
undo(...args: Parameters<RoolSpace['undo']>): Promise<boolean>;
|
|
72
70
|
redo(...args: Parameters<RoolSpace['redo']>): Promise<boolean>;
|
|
73
|
-
clearHistory(...args: Parameters<RoolSpace['clearHistory']>): Promise<void>;
|
|
74
|
-
getConversations(...args: Parameters<RoolSpace['getConversations']>): ConversationMeta[];
|
|
75
71
|
createConversation(...args: Parameters<RoolSpace['createConversation']>): Promise<string>;
|
|
76
72
|
deleteConversation(...args: Parameters<RoolSpace['deleteConversation']>): Promise<void>;
|
|
77
73
|
listAgents(...args: Parameters<RoolSpace['listAgents']>): Promise<string[]>;
|
|
@@ -94,7 +90,7 @@ declare class ReactiveSpaceImpl {
|
|
|
94
90
|
on(...args: Parameters<RoolSpace['on']>): () => void;
|
|
95
91
|
off(...args: Parameters<RoolSpace['off']>): void;
|
|
96
92
|
}
|
|
97
|
-
export declare function wrapSpace(space: RoolSpace): ReactiveSpace;
|
|
93
|
+
export declare function wrapSpace(space: RoolSpace, onClose?: () => void): ReactiveSpace;
|
|
98
94
|
export type ReactiveSpace = ReactiveSpaceImpl;
|
|
99
95
|
export {};
|
|
100
96
|
//# sourceMappingURL=space.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"space.svelte.d.ts","sourceRoot":"","sources":["../src/space.svelte.ts"],"names":[],"mappings":"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"}
|
package/dist/space.svelte.js
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { ReactiveConversationHandleImpl, ReactiveObjectImpl, ReactiveWatchImpl } from './space-session.svelte.js';
|
|
2
2
|
import { ReactiveFileTree } from './file-tree.svelte.js';
|
|
3
|
+
function conversationMeta(id, conversation, updatedAt) {
|
|
4
|
+
return {
|
|
5
|
+
id,
|
|
6
|
+
agent: conversation.agent ?? 'rool',
|
|
7
|
+
visibility: conversation.visibility ?? 'shared',
|
|
8
|
+
name: conversation.name ?? null,
|
|
9
|
+
systemInstruction: conversation.systemInstruction ?? null,
|
|
10
|
+
createdAt: conversation.createdAt,
|
|
11
|
+
createdBy: conversation.createdBy,
|
|
12
|
+
interactionCount: Object.keys(conversation.interactions).length,
|
|
13
|
+
updatedAt,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
3
16
|
/**
|
|
4
17
|
* A reactive wrapper around a RoolSpace. Exposes reactive `conversations`,
|
|
5
18
|
* `connectionState`, `meta`, and `schema`, plus space-level
|
|
@@ -17,10 +30,16 @@ class ReactiveSpaceImpl {
|
|
|
17
30
|
#space;
|
|
18
31
|
#unsubscribers = [];
|
|
19
32
|
#fileTree;
|
|
33
|
+
#conversationHandles = new Map();
|
|
34
|
+
#onClose;
|
|
20
35
|
#closed = false;
|
|
21
|
-
|
|
36
|
+
#name = $state('');
|
|
37
|
+
#role = $state('viewer');
|
|
38
|
+
#memberCount = $state(0);
|
|
22
39
|
#conversationList = $state([]);
|
|
40
|
+
#conversationRevision = 0;
|
|
23
41
|
connectionState = $state('reconnecting');
|
|
42
|
+
openSpaceError = $state(null);
|
|
24
43
|
// Reactive space content read from the WebDAV filesystem.
|
|
25
44
|
meta = $state({});
|
|
26
45
|
schema = $state({});
|
|
@@ -28,20 +47,39 @@ class ReactiveSpaceImpl {
|
|
|
28
47
|
// meta/schema already populated (avoids a default-theme flash on switch).
|
|
29
48
|
#metaReady = Promise.resolve();
|
|
30
49
|
#schemaReady = Promise.resolve();
|
|
31
|
-
constructor(space) {
|
|
50
|
+
constructor(space, onClose) {
|
|
32
51
|
this.#space = space;
|
|
52
|
+
this.#onClose = onClose;
|
|
33
53
|
this.#fileTree = new ReactiveFileTree(space);
|
|
34
|
-
this
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
54
|
+
this.connectionState = space.connectionState;
|
|
55
|
+
this.#applyOpenSpace(space.openSpaceResult, true);
|
|
56
|
+
const updateConversation = (event) => {
|
|
57
|
+
this.#conversationRevision += 1;
|
|
58
|
+
if (event.conversation === null) {
|
|
59
|
+
this.#conversationList = this.#conversationList.filter((conversation) => conversation.id !== event.conversationId);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const next = conversationMeta(event.conversationId, event.conversation, event.timestamp);
|
|
63
|
+
const index = this.#conversationList.findIndex((conversation) => conversation.id === event.conversationId);
|
|
64
|
+
this.#conversationList = index === -1
|
|
65
|
+
? [next, ...this.#conversationList]
|
|
66
|
+
: [
|
|
67
|
+
...this.#conversationList.slice(0, index),
|
|
68
|
+
next,
|
|
69
|
+
...this.#conversationList.slice(index + 1),
|
|
70
|
+
];
|
|
71
|
+
};
|
|
72
|
+
space.on('conversationUpdated', updateConversation);
|
|
73
|
+
this.#unsubscribers.push(() => space.off('conversationUpdated', updateConversation));
|
|
40
74
|
const onConnectionStateChanged = (state) => {
|
|
41
75
|
this.connectionState = state;
|
|
76
|
+
if (state === 'connected')
|
|
77
|
+
this.#reloadAfterConnection();
|
|
42
78
|
};
|
|
43
79
|
space.on('connectionStateChanged', onConnectionStateChanged);
|
|
44
80
|
this.#unsubscribers.push(() => space.off('connectionStateChanged', onConnectionStateChanged));
|
|
81
|
+
if (this.connectionState === 'connected')
|
|
82
|
+
this.#reloadAfterConnection();
|
|
45
83
|
// Seed meta/schema from the filesystem, and re-fetch the relevant one when
|
|
46
84
|
// the file tree reports its node changed. Remote writes (another tab, the
|
|
47
85
|
// agent) land here the same as local ones.
|
|
@@ -66,6 +104,26 @@ class ReactiveSpaceImpl {
|
|
|
66
104
|
return;
|
|
67
105
|
this.schema = await this.#space.readSchema();
|
|
68
106
|
}
|
|
107
|
+
#applyOpenSpace(result, replaceConversations) {
|
|
108
|
+
this.#name = result.name;
|
|
109
|
+
this.#role = result.role;
|
|
110
|
+
this.#memberCount = result.memberCount;
|
|
111
|
+
if (replaceConversations)
|
|
112
|
+
this.#conversationList = [...result.conversationMeta];
|
|
113
|
+
this.openSpaceError = null;
|
|
114
|
+
}
|
|
115
|
+
async #refreshOpenSpace() {
|
|
116
|
+
const conversationRevision = this.#conversationRevision;
|
|
117
|
+
const result = await this.#space.refresh();
|
|
118
|
+
this.#applyOpenSpace(result, conversationRevision === this.#conversationRevision);
|
|
119
|
+
}
|
|
120
|
+
#reloadAfterConnection() {
|
|
121
|
+
void this.#refreshOpenSpace().catch((error) => {
|
|
122
|
+
this.openSpaceError = error instanceof Error ? error : new Error(String(error));
|
|
123
|
+
});
|
|
124
|
+
for (const conversation of this.#conversationHandles.values())
|
|
125
|
+
void conversation.refresh();
|
|
126
|
+
}
|
|
69
127
|
/** Resolve when the initial meta/schema fetch has settled. */
|
|
70
128
|
async ready() {
|
|
71
129
|
await Promise.all([this.#metaReady, this.#schemaReady]);
|
|
@@ -85,9 +143,18 @@ class ReactiveSpaceImpl {
|
|
|
85
143
|
await this.#space.writeMeta(next);
|
|
86
144
|
}
|
|
87
145
|
get isClosed() { return this.#closed; }
|
|
88
|
-
/** Get
|
|
146
|
+
/** Get the shared reactive handle for one lazily loaded conversation. */
|
|
89
147
|
conversation(conversationId) {
|
|
90
|
-
|
|
148
|
+
const existing = this.#conversationHandles.get(conversationId);
|
|
149
|
+
if (existing)
|
|
150
|
+
return existing;
|
|
151
|
+
const conversation = new ReactiveConversationHandleImpl(this.#space, conversationId, () => {
|
|
152
|
+
if (this.#conversationHandles.get(conversationId) === conversation) {
|
|
153
|
+
this.#conversationHandles.delete(conversationId);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
this.#conversationHandles.set(conversationId, conversation);
|
|
157
|
+
return conversation;
|
|
91
158
|
}
|
|
92
159
|
/**
|
|
93
160
|
* Close this space and stop the SSE subscription. Idempotent.
|
|
@@ -99,16 +166,20 @@ class ReactiveSpaceImpl {
|
|
|
99
166
|
for (const unsub of this.#unsubscribers)
|
|
100
167
|
unsub();
|
|
101
168
|
this.#unsubscribers.length = 0;
|
|
169
|
+
for (const conversation of this.#conversationHandles.values())
|
|
170
|
+
conversation.close();
|
|
171
|
+
this.#conversationHandles.clear();
|
|
102
172
|
this.#fileTree.close();
|
|
103
173
|
this.#space.close();
|
|
174
|
+
this.#onClose();
|
|
104
175
|
}
|
|
105
176
|
// Reactive getters
|
|
106
177
|
get conversations() { return this.#conversationList; }
|
|
107
178
|
// Proxy read-only properties
|
|
108
179
|
get id() { return this.#space.id; }
|
|
109
|
-
get name() { return this.#
|
|
110
|
-
get role() { return this.#
|
|
111
|
-
get memberCount() { return this.#
|
|
180
|
+
get name() { return this.#name; }
|
|
181
|
+
get role() { return this.#role; }
|
|
182
|
+
get memberCount() { return this.#memberCount; }
|
|
112
183
|
get webdav() { return this.#space.webdav; }
|
|
113
184
|
get fileTree() { return this.#fileTree; }
|
|
114
185
|
// Space-level methods
|
|
@@ -123,16 +194,11 @@ class ReactiveSpaceImpl {
|
|
|
123
194
|
dropCollection(...args) { return this.#space.dropCollection(...args); }
|
|
124
195
|
object(path) { return new ReactiveObjectImpl(this.#space, this.#fileTree, path); }
|
|
125
196
|
watch(options) { return new ReactiveWatchImpl(this.#space, this.#fileTree, options); }
|
|
126
|
-
/** @deprecated Use {@link stopConversation}. */
|
|
127
|
-
stopInteraction(...args) { return this.#space.stopInteraction(...args); }
|
|
128
197
|
stopConversation(...args) { return this.#space.stopConversation(...args); }
|
|
129
|
-
checkpoint(...args) { return this.#space.checkpoint(...args); }
|
|
130
198
|
canUndo(...args) { return this.#space.canUndo(...args); }
|
|
131
199
|
canRedo(...args) { return this.#space.canRedo(...args); }
|
|
132
200
|
undo(...args) { return this.#space.undo(...args); }
|
|
133
201
|
redo(...args) { return this.#space.redo(...args); }
|
|
134
|
-
clearHistory(...args) { return this.#space.clearHistory(...args); }
|
|
135
|
-
getConversations(...args) { return this.#space.getConversations(...args); }
|
|
136
202
|
createConversation(...args) { return this.#space.createConversation(...args); }
|
|
137
203
|
deleteConversation(...args) { return this.#space.deleteConversation(...args); }
|
|
138
204
|
listAgents(...args) { return this.#space.listAgents(...args); }
|
|
@@ -146,8 +212,14 @@ class ReactiveSpaceImpl {
|
|
|
146
212
|
getStorageUsage(...args) { return this.#space.getStorageUsage(...args); }
|
|
147
213
|
fetchPath(...args) { return this.#space.fetchPath(...args); }
|
|
148
214
|
// Proxy admin methods
|
|
149
|
-
rename(newName) {
|
|
150
|
-
|
|
215
|
+
async rename(newName) {
|
|
216
|
+
await this.#space.rename(newName);
|
|
217
|
+
this.#name = newName;
|
|
218
|
+
}
|
|
219
|
+
async delete() {
|
|
220
|
+
await this.#space.delete();
|
|
221
|
+
this.close();
|
|
222
|
+
}
|
|
151
223
|
listUsers() { return this.#space.listUsers(); }
|
|
152
224
|
setUserRole(...args) { return this.#space.setUserRole(...args); }
|
|
153
225
|
removeUser(userId) { return this.#space.removeUser(userId); }
|
|
@@ -155,11 +227,11 @@ class ReactiveSpaceImpl {
|
|
|
155
227
|
listInvites(...args) { return this.#space.listInvites(...args); }
|
|
156
228
|
revokeInvite(...args) { return this.#space.revokeInvite(...args); }
|
|
157
229
|
exportArchive() { return this.#space.exportArchive(); }
|
|
158
|
-
refresh() { return this.#
|
|
230
|
+
refresh() { return this.#refreshOpenSpace(); }
|
|
159
231
|
// Events on the underlying space (conversationUpdated, filesChanged, connectionStateChanged)
|
|
160
232
|
on(...args) { return this.#space.on(...args); }
|
|
161
233
|
off(...args) { return this.#space.off(...args); }
|
|
162
234
|
}
|
|
163
|
-
export function wrapSpace(space) {
|
|
164
|
-
return new ReactiveSpaceImpl(space);
|
|
235
|
+
export function wrapSpace(space, onClose = () => { }) {
|
|
236
|
+
return new ReactiveSpaceImpl(space, onClose);
|
|
165
237
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rool-dev/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Svelte 5 runes for Rool Spaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"svelte": "./dist/index.js",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@rool-dev/sdk": "0.
|
|
44
|
+
"@rool-dev/sdk": "0.12.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"svelte": "^5.0.0"
|