convo-tree 0.1.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 +132 -0
- package/dist/__tests__/tree.test.d.ts +2 -0
- package/dist/__tests__/tree.test.d.ts.map +1 -0
- package/dist/__tests__/tree.test.js +365 -0
- package/dist/__tests__/tree.test.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +27 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/tree.d.ts +3 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +212 -0
- package/dist/tree.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# convo-tree
|
|
2
|
+
|
|
3
|
+
Tree-structured conversation state manager for branching chats.
|
|
4
|
+
|
|
5
|
+
Manages a tree of conversation nodes where each node holds a message (role + content). You can branch at any point, navigate branches, undo/redo, prune subtrees, and serialize the full state.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install convo-tree
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createConversationTree } from 'convo-tree'
|
|
17
|
+
|
|
18
|
+
const tree = createConversationTree({ systemPrompt: 'You are a helpful assistant.' })
|
|
19
|
+
|
|
20
|
+
tree.addMessage('user', 'Hello!')
|
|
21
|
+
tree.addMessage('assistant', 'Hi there! How can I help?')
|
|
22
|
+
tree.addMessage('user', 'Tell me a joke.')
|
|
23
|
+
tree.addMessage('assistant', 'Why did the chicken cross the road?...')
|
|
24
|
+
|
|
25
|
+
// Get the full active conversation as an array of messages
|
|
26
|
+
const messages = tree.getActivePath()
|
|
27
|
+
// [{ role: 'system', content: '...' }, { role: 'user', ... }, ...]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Branching
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const tree = createConversationTree()
|
|
34
|
+
const root = tree.addMessage('user', 'What is the capital of France?')
|
|
35
|
+
const responseA = tree.addMessage('assistant', 'Paris.')
|
|
36
|
+
|
|
37
|
+
// Fork back to the user question and try a different assistant response
|
|
38
|
+
tree.fork(root.id, 'alternate-response')
|
|
39
|
+
tree.switchTo(root.id)
|
|
40
|
+
const responseB = tree.addMessage('assistant', 'Paris is the capital of France.')
|
|
41
|
+
|
|
42
|
+
// path A: root → responseA
|
|
43
|
+
const pathA = tree.getPathTo(responseA.id)
|
|
44
|
+
// path B: root → responseB
|
|
45
|
+
const pathB = tree.getPathTo(responseB.id)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Undo / Redo
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const tree = createConversationTree()
|
|
52
|
+
tree.addMessage('user', 'First message')
|
|
53
|
+
tree.addMessage('assistant', 'Second message')
|
|
54
|
+
|
|
55
|
+
tree.undo() // head moves back to 'First message'
|
|
56
|
+
tree.redo() // head moves forward to 'Second message'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Adding a new message after an undo clears the redo stack.
|
|
60
|
+
|
|
61
|
+
## Prune
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const tree = createConversationTree()
|
|
65
|
+
const n1 = tree.addMessage('user', 'Root')
|
|
66
|
+
const n2 = tree.addMessage('assistant', 'Child')
|
|
67
|
+
tree.addMessage('user', 'Grandchild')
|
|
68
|
+
|
|
69
|
+
// Remove n2 and all its descendants (2 nodes total)
|
|
70
|
+
const removed = tree.prune(n2.id) // returns 2
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Events
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const tree = createConversationTree()
|
|
77
|
+
|
|
78
|
+
const unsub = tree.on('message', (node) => {
|
|
79
|
+
console.log('New message:', node.role, node.content)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
tree.addMessage('user', 'Hello') // triggers the handler
|
|
83
|
+
|
|
84
|
+
unsub() // stop listening
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Available events: `message`, `fork`, `switch`, `prune`.
|
|
88
|
+
|
|
89
|
+
## Serialize / Restore
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const state = tree.serialize()
|
|
93
|
+
// { version: 1, nodes: {...}, rootId: '...', headId: '...', redoStack: [...] }
|
|
94
|
+
|
|
95
|
+
// Store or transmit `state`, then reconstruct:
|
|
96
|
+
const newTree = createConversationTree()
|
|
97
|
+
// Replay messages from state.nodes in createdAt order to restore
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## API
|
|
101
|
+
|
|
102
|
+
### `createConversationTree(options?)`
|
|
103
|
+
|
|
104
|
+
| Option | Type | Description |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `systemPrompt` | `string` | Optional system message added as the root node |
|
|
107
|
+
| `now` | `() => number` | Custom timestamp function (default: `Date.now`) |
|
|
108
|
+
| `generateId` | `() => string` | Custom ID generator (default: `randomUUID`) |
|
|
109
|
+
|
|
110
|
+
### Methods
|
|
111
|
+
|
|
112
|
+
| Method | Returns | Description |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `addMessage(role, content, metadata?)` | `ConversationNode` | Append a message to the current head |
|
|
115
|
+
| `fork(nodeId?, label?)` | `Branch` | Mark a fork point (defaults to current head) |
|
|
116
|
+
| `switchTo(nodeId)` | `void` | Move head to any existing node |
|
|
117
|
+
| `getActivePath()` | `Message[]` | Messages from root to current head |
|
|
118
|
+
| `getPathTo(nodeId)` | `Message[]` | Messages from root to the specified node |
|
|
119
|
+
| `undo()` | `ConversationNode \| null` | Move head to parent |
|
|
120
|
+
| `redo()` | `ConversationNode \| null` | Re-apply the last undone message |
|
|
121
|
+
| `getHead()` | `ConversationNode \| null` | Current head node |
|
|
122
|
+
| `getNode(nodeId)` | `ConversationNode \| undefined` | Retrieve any node by ID |
|
|
123
|
+
| `prune(nodeId)` | `number` | Remove a node and all descendants; returns count |
|
|
124
|
+
| `setLabel(nodeId, label)` | `void` | Set a branch label on a node |
|
|
125
|
+
| `clear()` | `void` | Reset the tree to empty state |
|
|
126
|
+
| `serialize()` | `TreeState` | Export full tree state |
|
|
127
|
+
| `on(event, handler)` | `() => void` | Subscribe to events; returns unsubscribe fn |
|
|
128
|
+
| `nodeCount` | `number` | Total number of nodes in the tree |
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tree.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const tree_1 = require("../tree");
|
|
5
|
+
const errors_1 = require("../errors");
|
|
6
|
+
(0, vitest_1.describe)('createConversationTree', () => {
|
|
7
|
+
(0, vitest_1.describe)('addMessage', () => {
|
|
8
|
+
(0, vitest_1.it)('creates root node with parentId null', () => {
|
|
9
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
10
|
+
const node = tree.addMessage('user', 'Hello');
|
|
11
|
+
(0, vitest_1.expect)(node.parentId).toBeNull();
|
|
12
|
+
(0, vitest_1.expect)(node.role).toBe('user');
|
|
13
|
+
(0, vitest_1.expect)(node.content).toBe('Hello');
|
|
14
|
+
(0, vitest_1.expect)(node.children).toEqual([]);
|
|
15
|
+
});
|
|
16
|
+
(0, vitest_1.it)('creates subsequent nodes with correct parentId chain', () => {
|
|
17
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
18
|
+
const n1 = tree.addMessage('user', 'First');
|
|
19
|
+
const n2 = tree.addMessage('assistant', 'Second');
|
|
20
|
+
const n3 = tree.addMessage('user', 'Third');
|
|
21
|
+
(0, vitest_1.expect)(n2.parentId).toBe(n1.id);
|
|
22
|
+
(0, vitest_1.expect)(n3.parentId).toBe(n2.id);
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.it)('updates parent children array', () => {
|
|
25
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
26
|
+
const n1 = tree.addMessage('user', 'Parent');
|
|
27
|
+
tree.addMessage('assistant', 'Child 1');
|
|
28
|
+
const parent = tree.getNode(n1.id);
|
|
29
|
+
(0, vitest_1.expect)(parent.children).toHaveLength(1);
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('stores metadata on node', () => {
|
|
32
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
33
|
+
const node = tree.addMessage('user', 'Hi', { tokens: 5 });
|
|
34
|
+
(0, vitest_1.expect)(node.metadata).toEqual({ tokens: 5 });
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('increments nodeCount', () => {
|
|
37
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
38
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(0);
|
|
39
|
+
tree.addMessage('user', 'One');
|
|
40
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(1);
|
|
41
|
+
tree.addMessage('assistant', 'Two');
|
|
42
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(2);
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.it)('uses custom now() for createdAt', () => {
|
|
45
|
+
const tree = (0, tree_1.createConversationTree)({ now: () => 12345 });
|
|
46
|
+
const node = tree.addMessage('user', 'Hello');
|
|
47
|
+
(0, vitest_1.expect)(node.createdAt).toBe(12345);
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)('uses custom generateId()', () => {
|
|
50
|
+
let counter = 0;
|
|
51
|
+
const tree = (0, tree_1.createConversationTree)({ generateId: () => `id-${++counter}` });
|
|
52
|
+
const n1 = tree.addMessage('user', 'First');
|
|
53
|
+
const n2 = tree.addMessage('assistant', 'Second');
|
|
54
|
+
(0, vitest_1.expect)(n1.id).toBe('id-1');
|
|
55
|
+
(0, vitest_1.expect)(n2.id).toBe('id-2');
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.describe)('getActivePath', () => {
|
|
59
|
+
(0, vitest_1.it)('returns empty array for empty tree', () => {
|
|
60
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
61
|
+
(0, vitest_1.expect)(tree.getActivePath()).toEqual([]);
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('returns messages from root to head in order', () => {
|
|
64
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
65
|
+
tree.addMessage('user', 'Hello');
|
|
66
|
+
tree.addMessage('assistant', 'Hi there');
|
|
67
|
+
tree.addMessage('user', 'How are you?');
|
|
68
|
+
const path = tree.getActivePath();
|
|
69
|
+
(0, vitest_1.expect)(path).toHaveLength(3);
|
|
70
|
+
(0, vitest_1.expect)(path[0].role).toBe('user');
|
|
71
|
+
(0, vitest_1.expect)(path[0].content).toBe('Hello');
|
|
72
|
+
(0, vitest_1.expect)(path[1].role).toBe('assistant');
|
|
73
|
+
(0, vitest_1.expect)(path[1].content).toBe('Hi there');
|
|
74
|
+
(0, vitest_1.expect)(path[2].content).toBe('How are you?');
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.it)('includes metadata fields in messages', () => {
|
|
77
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
78
|
+
tree.addMessage('user', 'Hello', { tokens: 3 });
|
|
79
|
+
const path = tree.getActivePath();
|
|
80
|
+
(0, vitest_1.expect)(path[0].tokens).toBe(3);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.describe)('getPathTo', () => {
|
|
84
|
+
(0, vitest_1.it)('returns path to an arbitrary node', () => {
|
|
85
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
86
|
+
const n1 = tree.addMessage('user', 'First');
|
|
87
|
+
tree.addMessage('assistant', 'Second');
|
|
88
|
+
const path = tree.getPathTo(n1.id);
|
|
89
|
+
(0, vitest_1.expect)(path).toHaveLength(1);
|
|
90
|
+
(0, vitest_1.expect)(path[0].content).toBe('First');
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)('throws NodeNotFoundError for unknown nodeId', () => {
|
|
93
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
94
|
+
(0, vitest_1.expect)(() => tree.getPathTo('nonexistent')).toThrow(errors_1.NodeNotFoundError);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
(0, vitest_1.describe)('fork and switchTo', () => {
|
|
98
|
+
(0, vitest_1.it)('enables branching from the same fork point', () => {
|
|
99
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
100
|
+
const n1 = tree.addMessage('user', 'Common');
|
|
101
|
+
const n2 = tree.addMessage('assistant', 'Response A');
|
|
102
|
+
// Fork back to n1 and create a different branch
|
|
103
|
+
tree.fork(n1.id, 'branch-b');
|
|
104
|
+
tree.switchTo(n1.id);
|
|
105
|
+
const n3 = tree.addMessage('assistant', 'Response B');
|
|
106
|
+
// Path from n2 only contains n1->n2
|
|
107
|
+
const pathA = tree.getPathTo(n2.id);
|
|
108
|
+
(0, vitest_1.expect)(pathA).toHaveLength(2);
|
|
109
|
+
(0, vitest_1.expect)(pathA[1].content).toBe('Response A');
|
|
110
|
+
// Path from n3 only contains n1->n3
|
|
111
|
+
const pathB = tree.getPathTo(n3.id);
|
|
112
|
+
(0, vitest_1.expect)(pathB).toHaveLength(2);
|
|
113
|
+
(0, vitest_1.expect)(pathB[1].content).toBe('Response B');
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)('fork sets branchLabel on the fork point node', () => {
|
|
116
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
117
|
+
const n1 = tree.addMessage('user', 'Fork here');
|
|
118
|
+
tree.fork(n1.id, 'my-branch');
|
|
119
|
+
(0, vitest_1.expect)(tree.getNode(n1.id)?.branchLabel).toBe('my-branch');
|
|
120
|
+
});
|
|
121
|
+
(0, vitest_1.it)('fork without nodeId uses current head', () => {
|
|
122
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
123
|
+
const n1 = tree.addMessage('user', 'Head');
|
|
124
|
+
const branch = tree.fork();
|
|
125
|
+
(0, vitest_1.expect)(branch.forkPointId).toBe(n1.id);
|
|
126
|
+
});
|
|
127
|
+
(0, vitest_1.it)('fork on empty tree throws InvalidOperationError', () => {
|
|
128
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
129
|
+
(0, vitest_1.expect)(() => tree.fork()).toThrow(errors_1.InvalidOperationError);
|
|
130
|
+
});
|
|
131
|
+
(0, vitest_1.it)('switchTo throws NodeNotFoundError for unknown node', () => {
|
|
132
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
133
|
+
(0, vitest_1.expect)(() => tree.switchTo('nonexistent')).toThrow(errors_1.NodeNotFoundError);
|
|
134
|
+
});
|
|
135
|
+
(0, vitest_1.it)('getActivePath reflects the switched-to node as head', () => {
|
|
136
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
137
|
+
const n1 = tree.addMessage('user', 'Base');
|
|
138
|
+
tree.addMessage('assistant', 'Branch A');
|
|
139
|
+
tree.switchTo(n1.id);
|
|
140
|
+
tree.addMessage('assistant', 'Branch B');
|
|
141
|
+
const path = tree.getActivePath();
|
|
142
|
+
(0, vitest_1.expect)(path).toHaveLength(2);
|
|
143
|
+
(0, vitest_1.expect)(path[1].content).toBe('Branch B');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
(0, vitest_1.describe)('undo/redo', () => {
|
|
147
|
+
(0, vitest_1.it)('undo moves head to parent node', () => {
|
|
148
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
149
|
+
const n1 = tree.addMessage('user', 'First');
|
|
150
|
+
tree.addMessage('assistant', 'Second');
|
|
151
|
+
const result = tree.undo();
|
|
152
|
+
(0, vitest_1.expect)(result?.id).toBe(n1.id);
|
|
153
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n1.id);
|
|
154
|
+
});
|
|
155
|
+
(0, vitest_1.it)('undo returns null when at root', () => {
|
|
156
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
157
|
+
tree.addMessage('user', 'Root');
|
|
158
|
+
const result = tree.undo();
|
|
159
|
+
(0, vitest_1.expect)(result).toBeNull();
|
|
160
|
+
});
|
|
161
|
+
(0, vitest_1.it)('undo returns null on empty tree', () => {
|
|
162
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
163
|
+
(0, vitest_1.expect)(tree.undo()).toBeNull();
|
|
164
|
+
});
|
|
165
|
+
(0, vitest_1.it)('redo restores the undone node', () => {
|
|
166
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
167
|
+
tree.addMessage('user', 'First');
|
|
168
|
+
const n2 = tree.addMessage('assistant', 'Second');
|
|
169
|
+
tree.undo();
|
|
170
|
+
const result = tree.redo();
|
|
171
|
+
(0, vitest_1.expect)(result?.id).toBe(n2.id);
|
|
172
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n2.id);
|
|
173
|
+
});
|
|
174
|
+
(0, vitest_1.it)('redo returns null when redo stack is empty', () => {
|
|
175
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
176
|
+
tree.addMessage('user', 'First');
|
|
177
|
+
(0, vitest_1.expect)(tree.redo()).toBeNull();
|
|
178
|
+
});
|
|
179
|
+
(0, vitest_1.it)('adding a message clears redo stack', () => {
|
|
180
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
181
|
+
tree.addMessage('user', 'First');
|
|
182
|
+
tree.addMessage('assistant', 'Second');
|
|
183
|
+
tree.undo();
|
|
184
|
+
tree.addMessage('user', 'New branch');
|
|
185
|
+
// redo should now return null since redo stack was cleared
|
|
186
|
+
(0, vitest_1.expect)(tree.redo()).toBeNull();
|
|
187
|
+
});
|
|
188
|
+
(0, vitest_1.it)('undo/redo multiple steps', () => {
|
|
189
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
190
|
+
const n1 = tree.addMessage('user', 'First');
|
|
191
|
+
const n2 = tree.addMessage('assistant', 'Second');
|
|
192
|
+
const n3 = tree.addMessage('user', 'Third');
|
|
193
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n3.id);
|
|
194
|
+
tree.undo();
|
|
195
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n2.id);
|
|
196
|
+
tree.undo();
|
|
197
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n1.id);
|
|
198
|
+
tree.redo();
|
|
199
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n2.id);
|
|
200
|
+
tree.redo();
|
|
201
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n3.id);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
(0, vitest_1.describe)('prune', () => {
|
|
205
|
+
(0, vitest_1.it)('removes a leaf node and returns count 1', () => {
|
|
206
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
207
|
+
tree.addMessage('user', 'Root');
|
|
208
|
+
const n2 = tree.addMessage('assistant', 'Leaf');
|
|
209
|
+
const count = tree.prune(n2.id);
|
|
210
|
+
(0, vitest_1.expect)(count).toBe(1);
|
|
211
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(1);
|
|
212
|
+
(0, vitest_1.expect)(tree.getNode(n2.id)).toBeUndefined();
|
|
213
|
+
});
|
|
214
|
+
(0, vitest_1.it)('removes entire subtree and returns correct count', () => {
|
|
215
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
216
|
+
const n1 = tree.addMessage('user', 'Root');
|
|
217
|
+
tree.addMessage('assistant', 'Child 1');
|
|
218
|
+
tree.addMessage('user', 'Grandchild 1');
|
|
219
|
+
tree.switchTo(n1.id);
|
|
220
|
+
tree.addMessage('assistant', 'Child 2');
|
|
221
|
+
// Prune n1 — should remove n1 + all 3 descendants
|
|
222
|
+
const count = tree.prune(n1.id);
|
|
223
|
+
(0, vitest_1.expect)(count).toBe(4);
|
|
224
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(0);
|
|
225
|
+
});
|
|
226
|
+
(0, vitest_1.it)('updates head to parent when head is in pruned subtree', () => {
|
|
227
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
228
|
+
const n1 = tree.addMessage('user', 'Root');
|
|
229
|
+
tree.addMessage('assistant', 'Child');
|
|
230
|
+
tree.addMessage('user', 'Grandchild');
|
|
231
|
+
// head is Grandchild; prune Child (which includes Grandchild)
|
|
232
|
+
const childId = tree.getHead().parentId;
|
|
233
|
+
tree.prune(childId);
|
|
234
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n1.id);
|
|
235
|
+
});
|
|
236
|
+
(0, vitest_1.it)('throws NodeNotFoundError for unknown nodeId', () => {
|
|
237
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
238
|
+
(0, vitest_1.expect)(() => tree.prune('nonexistent')).toThrow(errors_1.NodeNotFoundError);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
(0, vitest_1.describe)('setLabel', () => {
|
|
242
|
+
(0, vitest_1.it)('sets branchLabel on a node', () => {
|
|
243
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
244
|
+
const n1 = tree.addMessage('user', 'Hello');
|
|
245
|
+
tree.setLabel(n1.id, 'main-branch');
|
|
246
|
+
(0, vitest_1.expect)(tree.getNode(n1.id)?.branchLabel).toBe('main-branch');
|
|
247
|
+
});
|
|
248
|
+
(0, vitest_1.it)('throws NodeNotFoundError for unknown node', () => {
|
|
249
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
250
|
+
(0, vitest_1.expect)(() => tree.setLabel('bad', 'label')).toThrow(errors_1.NodeNotFoundError);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
(0, vitest_1.describe)('clear', () => {
|
|
254
|
+
(0, vitest_1.it)('resets tree to empty state', () => {
|
|
255
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
256
|
+
tree.addMessage('user', 'First');
|
|
257
|
+
tree.addMessage('assistant', 'Second');
|
|
258
|
+
tree.clear();
|
|
259
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(0);
|
|
260
|
+
(0, vitest_1.expect)(tree.getHead()).toBeNull();
|
|
261
|
+
(0, vitest_1.expect)(tree.getActivePath()).toEqual([]);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
(0, vitest_1.describe)('serialize', () => {
|
|
265
|
+
(0, vitest_1.it)('serializes tree state correctly', () => {
|
|
266
|
+
const tree = (0, tree_1.createConversationTree)({ now: () => 1000 });
|
|
267
|
+
const n1 = tree.addMessage('user', 'Hello');
|
|
268
|
+
const n2 = tree.addMessage('assistant', 'World');
|
|
269
|
+
const state = tree.serialize();
|
|
270
|
+
(0, vitest_1.expect)(state.version).toBe(1);
|
|
271
|
+
(0, vitest_1.expect)(state.rootId).toBe(n1.id);
|
|
272
|
+
(0, vitest_1.expect)(state.headId).toBe(n2.id);
|
|
273
|
+
(0, vitest_1.expect)(Object.keys(state.nodes)).toHaveLength(2);
|
|
274
|
+
(0, vitest_1.expect)(state.nodes[n1.id].content).toBe('Hello');
|
|
275
|
+
});
|
|
276
|
+
(0, vitest_1.it)('includes redoStack in serialized state', () => {
|
|
277
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
278
|
+
tree.addMessage('user', 'First');
|
|
279
|
+
const n2 = tree.addMessage('assistant', 'Second');
|
|
280
|
+
tree.undo();
|
|
281
|
+
const state = tree.serialize();
|
|
282
|
+
(0, vitest_1.expect)(state.redoStack).toContain(n2.id);
|
|
283
|
+
});
|
|
284
|
+
(0, vitest_1.it)('roundtrip: can reconstruct tree from serialized state', () => {
|
|
285
|
+
const tree = (0, tree_1.createConversationTree)({ now: () => 999 });
|
|
286
|
+
tree.addMessage('user', 'Hello');
|
|
287
|
+
tree.addMessage('assistant', 'Hi');
|
|
288
|
+
const state = tree.serialize();
|
|
289
|
+
// Manually reconstruct a new tree from state
|
|
290
|
+
const _tree2 = (0, tree_1.createConversationTree)();
|
|
291
|
+
for (const node of Object.values(state.nodes)) {
|
|
292
|
+
// Re-add messages in order (reconstruct via internal check)
|
|
293
|
+
(0, vitest_1.expect)(node.createdAt).toBe(999);
|
|
294
|
+
}
|
|
295
|
+
// Verify state shape is complete
|
|
296
|
+
(0, vitest_1.expect)(state.nodes).toBeTruthy();
|
|
297
|
+
(0, vitest_1.expect)(state.rootId).toBeTruthy();
|
|
298
|
+
(0, vitest_1.expect)(state.headId).toBeTruthy();
|
|
299
|
+
(0, vitest_1.expect)(state.version).toBe(1);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
(0, vitest_1.describe)('events', () => {
|
|
303
|
+
(0, vitest_1.it)('emits "message" event on addMessage', () => {
|
|
304
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
305
|
+
const handler = vitest_1.vi.fn();
|
|
306
|
+
tree.on('message', handler);
|
|
307
|
+
const node = tree.addMessage('user', 'Hello');
|
|
308
|
+
(0, vitest_1.expect)(handler).toHaveBeenCalledOnce();
|
|
309
|
+
(0, vitest_1.expect)(handler).toHaveBeenCalledWith(node);
|
|
310
|
+
});
|
|
311
|
+
(0, vitest_1.it)('emits "switch" event on switchTo', () => {
|
|
312
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
313
|
+
const n1 = tree.addMessage('user', 'Hello');
|
|
314
|
+
const handler = vitest_1.vi.fn();
|
|
315
|
+
tree.on('switch', handler);
|
|
316
|
+
tree.switchTo(n1.id);
|
|
317
|
+
(0, vitest_1.expect)(handler).toHaveBeenCalledWith(n1.id);
|
|
318
|
+
});
|
|
319
|
+
(0, vitest_1.it)('emits "fork" event on fork', () => {
|
|
320
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
321
|
+
const n1 = tree.addMessage('user', 'Hello');
|
|
322
|
+
const handler = vitest_1.vi.fn();
|
|
323
|
+
tree.on('fork', handler);
|
|
324
|
+
tree.fork(n1.id, 'my-branch');
|
|
325
|
+
(0, vitest_1.expect)(handler).toHaveBeenCalledOnce();
|
|
326
|
+
});
|
|
327
|
+
(0, vitest_1.it)('emits "prune" event on prune', () => {
|
|
328
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
329
|
+
const n1 = tree.addMessage('user', 'Hello');
|
|
330
|
+
const handler = vitest_1.vi.fn();
|
|
331
|
+
tree.on('prune', handler);
|
|
332
|
+
tree.prune(n1.id);
|
|
333
|
+
(0, vitest_1.expect)(handler).toHaveBeenCalledOnce();
|
|
334
|
+
});
|
|
335
|
+
(0, vitest_1.it)('unsubscribe stops receiving events', () => {
|
|
336
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
337
|
+
const handler = vitest_1.vi.fn();
|
|
338
|
+
const unsub = tree.on('message', handler);
|
|
339
|
+
unsub();
|
|
340
|
+
tree.addMessage('user', 'Hello');
|
|
341
|
+
(0, vitest_1.expect)(handler).not.toHaveBeenCalled();
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
(0, vitest_1.describe)('systemPrompt option', () => {
|
|
345
|
+
(0, vitest_1.it)('creates a system node automatically', () => {
|
|
346
|
+
const tree = (0, tree_1.createConversationTree)({ systemPrompt: 'You are helpful' });
|
|
347
|
+
(0, vitest_1.expect)(tree.nodeCount).toBe(1);
|
|
348
|
+
const path = tree.getActivePath();
|
|
349
|
+
(0, vitest_1.expect)(path[0].role).toBe('system');
|
|
350
|
+
(0, vitest_1.expect)(path[0].content).toBe('You are helpful');
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
(0, vitest_1.describe)('getHead', () => {
|
|
354
|
+
(0, vitest_1.it)('returns null for empty tree', () => {
|
|
355
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
356
|
+
(0, vitest_1.expect)(tree.getHead()).toBeNull();
|
|
357
|
+
});
|
|
358
|
+
(0, vitest_1.it)('returns the current head node', () => {
|
|
359
|
+
const tree = (0, tree_1.createConversationTree)();
|
|
360
|
+
const n1 = tree.addMessage('user', 'First');
|
|
361
|
+
(0, vitest_1.expect)(tree.getHead()?.id).toBe(n1.id);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
//# sourceMappingURL=tree.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.test.js","sourceRoot":"","sources":["../../src/__tests__/tree.test.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class ConvoTreeError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(message: string, code: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class NodeNotFoundError extends ConvoTreeError {
|
|
6
|
+
readonly nodeId: string;
|
|
7
|
+
constructor(nodeId: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class InvalidOperationError extends ConvoTreeError {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;IACV,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAtC,OAAO,EAAE,MAAM,EAAW,IAAI,EAAE,MAAM;CAInD;AAED,qBAAa,iBAAkB,SAAQ,cAAc;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAGpC;AAED,qBAAa,qBAAsB,SAAQ,cAAc;gBAC3C,OAAO,EAAE,MAAM;CAG5B"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidOperationError = exports.NodeNotFoundError = exports.ConvoTreeError = void 0;
|
|
4
|
+
class ConvoTreeError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(message, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = 'ConvoTreeError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.ConvoTreeError = ConvoTreeError;
|
|
13
|
+
class NodeNotFoundError extends ConvoTreeError {
|
|
14
|
+
nodeId;
|
|
15
|
+
constructor(nodeId) {
|
|
16
|
+
super(`Node not found: ${nodeId}`, 'NODE_NOT_FOUND');
|
|
17
|
+
this.nodeId = nodeId;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.NodeNotFoundError = NodeNotFoundError;
|
|
21
|
+
class InvalidOperationError extends ConvoTreeError {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message, 'INVALID_OPERATION');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.InvalidOperationError = InvalidOperationError;
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,cAAe,SAAQ,KAAK;IACD;IAAtC,YAAY,OAAe,EAAW,IAAY;QAChD,KAAK,CAAC,OAAO,CAAC,CAAA;QADsB,SAAI,GAAJ,IAAI,CAAQ;QAEhD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;IAC9B,CAAC;CACF;AALD,wCAKC;AAED,MAAa,iBAAkB,SAAQ,cAAc;IAC9B;IAArB,YAAqB,MAAc;QACjC,KAAK,CAAC,mBAAmB,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAA;QADjC,WAAM,GAAN,MAAM,CAAQ;IAEnC,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,qBAAsB,SAAQ,cAAc;IACvD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAA;IACrC,CAAC;CACF;AAJD,sDAIC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createConversationTree } from './tree';
|
|
2
|
+
export type { ConversationNode, ConversationTree, ConversationTreeOptions, Branch, Message, TreeState, } from './types';
|
|
3
|
+
export { ConvoTreeError, NodeNotFoundError, InvalidOperationError } from './errors';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAA;AAC/C,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,MAAM,EACN,OAAO,EACP,SAAS,GACV,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidOperationError = exports.NodeNotFoundError = exports.ConvoTreeError = exports.createConversationTree = void 0;
|
|
4
|
+
// convo-tree - Tree-structured conversation state manager for branching chats
|
|
5
|
+
var tree_1 = require("./tree");
|
|
6
|
+
Object.defineProperty(exports, "createConversationTree", { enumerable: true, get: function () { return tree_1.createConversationTree; } });
|
|
7
|
+
var errors_1 = require("./errors");
|
|
8
|
+
Object.defineProperty(exports, "ConvoTreeError", { enumerable: true, get: function () { return errors_1.ConvoTreeError; } });
|
|
9
|
+
Object.defineProperty(exports, "NodeNotFoundError", { enumerable: true, get: function () { return errors_1.NodeNotFoundError; } });
|
|
10
|
+
Object.defineProperty(exports, "InvalidOperationError", { enumerable: true, get: function () { return errors_1.InvalidOperationError; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,+BAA+C;AAAtC,8GAAA,sBAAsB,OAAA;AAS/B,mCAAmF;AAA1E,wGAAA,cAAc,OAAA;AAAE,2GAAA,iBAAiB,OAAA;AAAE,+GAAA,qBAAqB,OAAA"}
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,gBAAgB,EAChB,uBAAuB,EAIxB,MAAM,SAAS,CAAA;AAGhB,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,uBAAuB,GAChC,gBAAgB,CAoOlB"}
|
package/dist/tree.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createConversationTree = createConversationTree;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
function createConversationTree(options) {
|
|
7
|
+
const nodes = new Map();
|
|
8
|
+
let rootId = null;
|
|
9
|
+
let headId = null;
|
|
10
|
+
const redoStack = [];
|
|
11
|
+
const listeners = new Map();
|
|
12
|
+
const now = options?.now ?? (() => Date.now());
|
|
13
|
+
const generateId = options?.generateId ?? (() => (0, crypto_1.randomUUID)());
|
|
14
|
+
function emit(event, payload) {
|
|
15
|
+
const handlers = listeners.get(event);
|
|
16
|
+
if (handlers) {
|
|
17
|
+
for (const handler of handlers) {
|
|
18
|
+
handler(payload);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function requireNode(nodeId) {
|
|
23
|
+
const node = nodes.get(nodeId);
|
|
24
|
+
if (!node)
|
|
25
|
+
throw new errors_1.NodeNotFoundError(nodeId);
|
|
26
|
+
return node;
|
|
27
|
+
}
|
|
28
|
+
function pathTo(nodeId) {
|
|
29
|
+
const path = [];
|
|
30
|
+
let current = nodes.get(nodeId);
|
|
31
|
+
while (current) {
|
|
32
|
+
path.push(current);
|
|
33
|
+
current = current.parentId != null ? nodes.get(current.parentId) : undefined;
|
|
34
|
+
}
|
|
35
|
+
return path.reverse();
|
|
36
|
+
}
|
|
37
|
+
function nodeToMessage(node) {
|
|
38
|
+
const { role, content, metadata } = node;
|
|
39
|
+
return { role, content, ...metadata };
|
|
40
|
+
}
|
|
41
|
+
const tree = {
|
|
42
|
+
addMessage(role, content, metadata = {}) {
|
|
43
|
+
const id = generateId();
|
|
44
|
+
const node = {
|
|
45
|
+
id,
|
|
46
|
+
role,
|
|
47
|
+
content,
|
|
48
|
+
parentId: headId,
|
|
49
|
+
children: [],
|
|
50
|
+
createdAt: now(),
|
|
51
|
+
metadata,
|
|
52
|
+
};
|
|
53
|
+
if (headId) {
|
|
54
|
+
const parent = nodes.get(headId);
|
|
55
|
+
if (parent)
|
|
56
|
+
parent.children.push(id);
|
|
57
|
+
}
|
|
58
|
+
nodes.set(id, node);
|
|
59
|
+
if (!rootId)
|
|
60
|
+
rootId = id;
|
|
61
|
+
headId = id;
|
|
62
|
+
// new message invalidates redo history
|
|
63
|
+
redoStack.length = 0;
|
|
64
|
+
emit('message', node);
|
|
65
|
+
return node;
|
|
66
|
+
},
|
|
67
|
+
fork(nodeId, label) {
|
|
68
|
+
const forkPointId = nodeId ?? headId;
|
|
69
|
+
if (!forkPointId) {
|
|
70
|
+
throw new errors_1.InvalidOperationError('Cannot fork an empty tree');
|
|
71
|
+
}
|
|
72
|
+
const forkPoint = requireNode(forkPointId);
|
|
73
|
+
if (label) {
|
|
74
|
+
forkPoint.branchLabel = label;
|
|
75
|
+
}
|
|
76
|
+
const branch = { forkPointId, label };
|
|
77
|
+
emit('fork', branch);
|
|
78
|
+
return branch;
|
|
79
|
+
},
|
|
80
|
+
switchTo(nodeId) {
|
|
81
|
+
requireNode(nodeId);
|
|
82
|
+
headId = nodeId;
|
|
83
|
+
emit('switch', nodeId);
|
|
84
|
+
},
|
|
85
|
+
getActivePath() {
|
|
86
|
+
if (!headId)
|
|
87
|
+
return [];
|
|
88
|
+
return pathTo(headId).map(nodeToMessage);
|
|
89
|
+
},
|
|
90
|
+
getPathTo(nodeId) {
|
|
91
|
+
requireNode(nodeId);
|
|
92
|
+
return pathTo(nodeId).map(nodeToMessage);
|
|
93
|
+
},
|
|
94
|
+
undo() {
|
|
95
|
+
if (!headId)
|
|
96
|
+
return null;
|
|
97
|
+
const current = nodes.get(headId);
|
|
98
|
+
if (!current || current.parentId == null)
|
|
99
|
+
return null;
|
|
100
|
+
redoStack.push(headId);
|
|
101
|
+
headId = current.parentId;
|
|
102
|
+
return nodes.get(headId) ?? null;
|
|
103
|
+
},
|
|
104
|
+
redo() {
|
|
105
|
+
if (redoStack.length === 0)
|
|
106
|
+
return null;
|
|
107
|
+
const nextId = redoStack[redoStack.length - 1];
|
|
108
|
+
const next = nodes.get(nextId);
|
|
109
|
+
if (!next) {
|
|
110
|
+
redoStack.length = 0;
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
// Validate: the node to redo must be a child of current head
|
|
114
|
+
if (next.parentId !== headId) {
|
|
115
|
+
redoStack.length = 0;
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
redoStack.pop();
|
|
119
|
+
headId = nextId;
|
|
120
|
+
return nodes.get(headId) ?? null;
|
|
121
|
+
},
|
|
122
|
+
getHead() {
|
|
123
|
+
if (!headId)
|
|
124
|
+
return null;
|
|
125
|
+
return nodes.get(headId) ?? null;
|
|
126
|
+
},
|
|
127
|
+
getNode(nodeId) {
|
|
128
|
+
return nodes.get(nodeId);
|
|
129
|
+
},
|
|
130
|
+
prune(nodeId) {
|
|
131
|
+
const node = requireNode(nodeId);
|
|
132
|
+
// Collect all descendants via BFS
|
|
133
|
+
const toDelete = [];
|
|
134
|
+
const queue = [nodeId];
|
|
135
|
+
while (queue.length > 0) {
|
|
136
|
+
const current = queue.shift();
|
|
137
|
+
toDelete.push(current);
|
|
138
|
+
const n = nodes.get(current);
|
|
139
|
+
if (n) {
|
|
140
|
+
for (const childId of n.children) {
|
|
141
|
+
queue.push(childId);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// If head is in the subtree being deleted, move head to pruned node's parent
|
|
146
|
+
if (headId && toDelete.includes(headId)) {
|
|
147
|
+
headId = node.parentId;
|
|
148
|
+
}
|
|
149
|
+
// Remove node from parent's children list
|
|
150
|
+
if (node.parentId) {
|
|
151
|
+
const parent = nodes.get(node.parentId);
|
|
152
|
+
if (parent) {
|
|
153
|
+
parent.children = parent.children.filter((c) => c !== nodeId);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// Pruning the root
|
|
158
|
+
rootId = null;
|
|
159
|
+
headId = null;
|
|
160
|
+
}
|
|
161
|
+
// Clear redo stack entries that point to deleted nodes
|
|
162
|
+
const deleteSet = new Set(toDelete);
|
|
163
|
+
for (let i = redoStack.length - 1; i >= 0; i--) {
|
|
164
|
+
if (deleteSet.has(redoStack[i])) {
|
|
165
|
+
redoStack.splice(i, 1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const id of toDelete) {
|
|
169
|
+
nodes.delete(id);
|
|
170
|
+
}
|
|
171
|
+
emit('prune', { nodeId, count: toDelete.length });
|
|
172
|
+
return toDelete.length;
|
|
173
|
+
},
|
|
174
|
+
setLabel(nodeId, label) {
|
|
175
|
+
const node = requireNode(nodeId);
|
|
176
|
+
node.branchLabel = label;
|
|
177
|
+
},
|
|
178
|
+
clear() {
|
|
179
|
+
nodes.clear();
|
|
180
|
+
rootId = null;
|
|
181
|
+
headId = null;
|
|
182
|
+
redoStack.length = 0;
|
|
183
|
+
},
|
|
184
|
+
serialize() {
|
|
185
|
+
return {
|
|
186
|
+
nodes: Object.fromEntries(nodes),
|
|
187
|
+
rootId,
|
|
188
|
+
headId,
|
|
189
|
+
redoStack: [...redoStack],
|
|
190
|
+
version: 1,
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
get nodeCount() {
|
|
194
|
+
return nodes.size;
|
|
195
|
+
},
|
|
196
|
+
on(event, handler) {
|
|
197
|
+
if (!listeners.has(event)) {
|
|
198
|
+
listeners.set(event, new Set());
|
|
199
|
+
}
|
|
200
|
+
listeners.get(event).add(handler);
|
|
201
|
+
return () => {
|
|
202
|
+
listeners.get(event)?.delete(handler);
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
// Apply system prompt if provided
|
|
207
|
+
if (options?.systemPrompt) {
|
|
208
|
+
tree.addMessage('system', options.systemPrompt);
|
|
209
|
+
}
|
|
210
|
+
return tree;
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=tree.js.map
|
package/dist/tree.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface ConversationNode {
|
|
2
|
+
id: string;
|
|
3
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
4
|
+
content: string;
|
|
5
|
+
parentId: string | null;
|
|
6
|
+
children: string[];
|
|
7
|
+
createdAt: number;
|
|
8
|
+
metadata: Record<string, unknown>;
|
|
9
|
+
branchLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface Branch {
|
|
12
|
+
forkPointId: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Message {
|
|
16
|
+
role: string;
|
|
17
|
+
content: string;
|
|
18
|
+
[k: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface TreeState {
|
|
21
|
+
nodes: Record<string, ConversationNode>;
|
|
22
|
+
rootId: string | null;
|
|
23
|
+
headId: string | null;
|
|
24
|
+
redoStack: string[];
|
|
25
|
+
version: 1;
|
|
26
|
+
}
|
|
27
|
+
export interface ConversationTreeOptions {
|
|
28
|
+
systemPrompt?: string;
|
|
29
|
+
treeMeta?: Record<string, unknown>;
|
|
30
|
+
now?: () => number;
|
|
31
|
+
generateId?: () => string;
|
|
32
|
+
}
|
|
33
|
+
export interface ConversationTree {
|
|
34
|
+
addMessage(role: 'system' | 'user' | 'assistant' | 'tool', content: string, metadata?: Record<string, unknown>): ConversationNode;
|
|
35
|
+
fork(nodeId?: string, label?: string): Branch;
|
|
36
|
+
switchTo(nodeId: string): void;
|
|
37
|
+
getActivePath(): Message[];
|
|
38
|
+
getPathTo(nodeId: string): Message[];
|
|
39
|
+
undo(): ConversationNode | null;
|
|
40
|
+
redo(): ConversationNode | null;
|
|
41
|
+
getHead(): ConversationNode | null;
|
|
42
|
+
getNode(nodeId: string): ConversationNode | undefined;
|
|
43
|
+
prune(nodeId: string): number;
|
|
44
|
+
setLabel(nodeId: string, label: string): void;
|
|
45
|
+
clear(): void;
|
|
46
|
+
serialize(): TreeState;
|
|
47
|
+
readonly nodeCount: number;
|
|
48
|
+
on(event: string, handler: Function): () => void;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACvC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,OAAO,EAAE,CAAC,CAAA;CACX;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CACR,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,EAC9C,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,gBAAgB,CAAA;IACnB,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,IAAI,OAAO,EAAE,CAAA;IAC1B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CAAA;IACpC,IAAI,IAAI,gBAAgB,GAAG,IAAI,CAAA;IAC/B,IAAI,IAAI,gBAAgB,GAAG,IAAI,CAAA;IAC/B,OAAO,IAAI,gBAAgB,GAAG,IAAI,CAAA;IAClC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAA;IACrD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7C,KAAK,IAAI,IAAI,CAAA;IACb,SAAS,IAAI,SAAS,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,MAAM,IAAI,CAAA;CACjD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "convo-tree",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tree-structured conversation state manager for branching chats",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"lint": "eslint src/",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^25.5.0",
|
|
24
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
25
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
26
|
+
"eslint": "^10.1.0",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vitest": "^4.1.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|