@providerprotocol/agents 0.0.2 → 0.0.4

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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/dist/checkpoint/index.d.ts +43 -0
  3. package/dist/checkpoint/index.js +73 -0
  4. package/dist/checkpoint/index.js.map +1 -0
  5. package/{src/execution/loop.ts → dist/chunk-4ESYN66B.js} +54 -162
  6. package/dist/chunk-4ESYN66B.js.map +1 -0
  7. package/dist/chunk-EKRXMSDX.js +8 -0
  8. package/dist/chunk-EKRXMSDX.js.map +1 -0
  9. package/dist/chunk-T47B3VAF.js +427 -0
  10. package/dist/chunk-T47B3VAF.js.map +1 -0
  11. package/dist/execution/index.d.ts +105 -0
  12. package/dist/execution/index.js +679 -0
  13. package/dist/execution/index.js.map +1 -0
  14. package/dist/index-qsPwbY86.d.ts +65 -0
  15. package/dist/index.d.ts +101 -0
  16. package/dist/index.js +218 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/middleware/index.d.ts +23 -0
  19. package/dist/middleware/index.js +82 -0
  20. package/dist/middleware/index.js.map +1 -0
  21. package/dist/thread-tree/index.d.ts +115 -0
  22. package/dist/thread-tree/index.js +4 -0
  23. package/dist/thread-tree/index.js.map +1 -0
  24. package/dist/types-2Vsthzyu.d.ts +163 -0
  25. package/dist/types-BiyEVOnf.d.ts +65 -0
  26. package/dist/types-D1egxttz.d.ts +270 -0
  27. package/dist/types-DChRdQoX.d.ts +98 -0
  28. package/package.json +41 -9
  29. package/.claude/settings.local.json +0 -29
  30. package/AGENTS.md +0 -681
  31. package/CLAUDE.md +0 -681
  32. package/bun.lock +0 -472
  33. package/eslint.config.js +0 -75
  34. package/index.ts +0 -1
  35. package/llms.md +0 -796
  36. package/specs/UAP-1.0.md +0 -2355
  37. package/src/agent/index.ts +0 -384
  38. package/src/agent/types.ts +0 -91
  39. package/src/checkpoint/file.ts +0 -126
  40. package/src/checkpoint/index.ts +0 -40
  41. package/src/checkpoint/types.ts +0 -95
  42. package/src/execution/index.ts +0 -37
  43. package/src/execution/plan.ts +0 -497
  44. package/src/execution/react.ts +0 -340
  45. package/src/execution/tool-ordering.ts +0 -186
  46. package/src/execution/types.ts +0 -315
  47. package/src/index.ts +0 -80
  48. package/src/middleware/index.ts +0 -7
  49. package/src/middleware/logging.ts +0 -123
  50. package/src/middleware/types.ts +0 -69
  51. package/src/state/index.ts +0 -301
  52. package/src/state/types.ts +0 -173
  53. package/src/thread-tree/index.ts +0 -249
  54. package/src/thread-tree/types.ts +0 -29
  55. package/src/utils/uuid.ts +0 -7
  56. package/tests/live/agent-anthropic.test.ts +0 -288
  57. package/tests/live/agent-strategy-hooks.test.ts +0 -268
  58. package/tests/live/checkpoint.test.ts +0 -243
  59. package/tests/live/execution-strategies.test.ts +0 -255
  60. package/tests/live/plan-strategy.test.ts +0 -160
  61. package/tests/live/subagent-events.live.test.ts +0 -249
  62. package/tests/live/thread-tree.test.ts +0 -186
  63. package/tests/unit/agent.test.ts +0 -703
  64. package/tests/unit/checkpoint.test.ts +0 -232
  65. package/tests/unit/execution/equivalence.test.ts +0 -402
  66. package/tests/unit/execution/loop.test.ts +0 -437
  67. package/tests/unit/execution/plan.test.ts +0 -590
  68. package/tests/unit/execution/react.test.ts +0 -604
  69. package/tests/unit/execution/subagent-events.test.ts +0 -235
  70. package/tests/unit/execution/tool-ordering.test.ts +0 -310
  71. package/tests/unit/middleware/logging.test.ts +0 -276
  72. package/tests/unit/state.test.ts +0 -573
  73. package/tests/unit/thread-tree.test.ts +0 -249
  74. package/tsconfig.json +0 -29
@@ -1,301 +0,0 @@
1
- import type {
2
- Message,
3
- UserContent,
4
- AssistantContent,
5
- ToolCall,
6
- ToolResult,
7
- } from '@providerprotocol/ai';
8
- import { UserMessage, AssistantMessage, ToolResultMessage } from '@providerprotocol/ai';
9
- import { generateUUID } from '../utils/uuid.ts';
10
- import type {
11
- AgentStateInterface,
12
- AgentStateJSON,
13
- PlanStep,
14
- MessageJSON,
15
- SubagentExecutionTrace,
16
- } from './types.ts';
17
- import { UAP_VERSION } from './types.ts';
18
-
19
- /**
20
- * Immutable agent state snapshot.
21
- * All operations return new instances - the original state is never mutated.
22
- */
23
- export class AgentState implements AgentStateInterface {
24
- readonly id: string;
25
-
26
- readonly messages: readonly Message[];
27
-
28
- readonly step: number;
29
-
30
- readonly metadata: Readonly<Record<string, unknown>>;
31
-
32
- readonly reasoning: readonly string[];
33
-
34
- readonly plan: readonly PlanStep[] | undefined;
35
-
36
- readonly subagentTraces: readonly SubagentExecutionTrace[];
37
-
38
- private constructor(
39
- id: string,
40
- messages: readonly Message[],
41
- step: number,
42
- metadata: Readonly<Record<string, unknown>>,
43
- reasoning: readonly string[],
44
- plan: readonly PlanStep[] | undefined,
45
- subagentTraces: readonly SubagentExecutionTrace[],
46
- ) {
47
- this.id = id;
48
- this.messages = messages;
49
- this.step = step;
50
- this.metadata = metadata;
51
- this.reasoning = reasoning;
52
- this.plan = plan;
53
- this.subagentTraces = subagentTraces;
54
- }
55
-
56
- /**
57
- * Create an initial empty state.
58
- */
59
- static initial(): AgentState {
60
- return new AgentState(
61
- generateUUID(),
62
- [],
63
- 0,
64
- {},
65
- [],
66
- undefined,
67
- [],
68
- );
69
- }
70
-
71
- /**
72
- * Return new state with a message added.
73
- */
74
- withMessage(message: Message): AgentState {
75
- return new AgentState(
76
- generateUUID(),
77
- [...this.messages, message],
78
- this.step,
79
- this.metadata,
80
- this.reasoning,
81
- this.plan,
82
- this.subagentTraces,
83
- );
84
- }
85
-
86
- /**
87
- * Return new state with messages added.
88
- */
89
- withMessages(messages: Message[]): AgentState {
90
- return new AgentState(
91
- generateUUID(),
92
- [...this.messages, ...messages],
93
- this.step,
94
- this.metadata,
95
- this.reasoning,
96
- this.plan,
97
- this.subagentTraces,
98
- );
99
- }
100
-
101
- /**
102
- * Return new state with context replaced (all messages).
103
- * Use for context window management (pruning, summarization).
104
- */
105
- withContext(messages: Message[]): AgentState {
106
- return new AgentState(
107
- generateUUID(),
108
- [...messages],
109
- this.step,
110
- this.metadata,
111
- this.reasoning,
112
- this.plan,
113
- this.subagentTraces,
114
- );
115
- }
116
-
117
- /**
118
- * Return new state with updated step number.
119
- */
120
- withStep(step: number): AgentState {
121
- return new AgentState(
122
- generateUUID(),
123
- this.messages,
124
- step,
125
- this.metadata,
126
- this.reasoning,
127
- this.plan,
128
- this.subagentTraces,
129
- );
130
- }
131
-
132
- /**
133
- * Return new state with metadata entry added/updated.
134
- */
135
- withMetadata(key: string, value: unknown): AgentState {
136
- return new AgentState(
137
- generateUUID(),
138
- this.messages,
139
- this.step,
140
- { ...this.metadata, [key]: value },
141
- this.reasoning,
142
- this.plan,
143
- this.subagentTraces,
144
- );
145
- }
146
-
147
- /**
148
- * Return new state with reasoning trace added.
149
- */
150
- withReasoning(reasoning: string): AgentState {
151
- return new AgentState(
152
- generateUUID(),
153
- this.messages,
154
- this.step,
155
- this.metadata,
156
- [...this.reasoning, reasoning],
157
- this.plan,
158
- this.subagentTraces,
159
- );
160
- }
161
-
162
- /**
163
- * Return new state with plan set.
164
- */
165
- withPlan(plan: PlanStep[]): AgentState {
166
- return new AgentState(
167
- generateUUID(),
168
- this.messages,
169
- this.step,
170
- this.metadata,
171
- this.reasoning,
172
- [...plan],
173
- this.subagentTraces,
174
- );
175
- }
176
-
177
- /**
178
- * Return new state with sub-agent trace added.
179
- * Per UAP spec Section 8.8.
180
- */
181
- withSubagentTrace(trace: SubagentExecutionTrace): AgentState {
182
- return new AgentState(
183
- generateUUID(),
184
- this.messages,
185
- this.step,
186
- this.metadata,
187
- this.reasoning,
188
- this.plan,
189
- [...this.subagentTraces, trace],
190
- );
191
- }
192
-
193
- /**
194
- * Serialize state to JSON for persistence.
195
- */
196
- toJSON(): AgentStateJSON {
197
- return {
198
- version: UAP_VERSION,
199
- id: this.id,
200
- messages: this.messages.map((msg) => serializeMessage(msg)),
201
- step: this.step,
202
- metadata: { ...this.metadata },
203
- reasoning: [...this.reasoning],
204
- plan: this.plan ? this.plan.map((s) => ({ ...s })) : undefined,
205
- subagentTraces: this.subagentTraces.length > 0
206
- ? this.subagentTraces.map((t) => ({ ...t }))
207
- : undefined,
208
- };
209
- }
210
-
211
- /**
212
- * Deserialize state from JSON.
213
- */
214
- static fromJSON(json: AgentStateJSON): AgentState {
215
- if (json.version !== UAP_VERSION) {
216
- throw new Error(`Unsupported UAP version: ${json.version}. Expected: ${UAP_VERSION}`);
217
- }
218
-
219
- return new AgentState(
220
- json.id,
221
- json.messages.map((msg) => deserializeMessage(msg)),
222
- json.step,
223
- json.metadata,
224
- json.reasoning,
225
- json.plan ? json.plan.map((s) => ({ ...s })) : undefined,
226
- json.subagentTraces ? json.subagentTraces.map((t) => ({ ...t })) : [],
227
- );
228
- }
229
- }
230
-
231
- /**
232
- * Serialize a UPP Message to JSON.
233
- */
234
- function serializeMessage(message: Message): MessageJSON {
235
- if (message instanceof UserMessage) {
236
- return {
237
- role: 'user',
238
- content: message.content,
239
- metadata: message.metadata,
240
- };
241
- }
242
- if (message instanceof AssistantMessage) {
243
- return {
244
- role: 'assistant',
245
- content: {
246
- content: message.content,
247
- toolCalls: message.toolCalls,
248
- },
249
- metadata: message.metadata,
250
- };
251
- }
252
- if (message instanceof ToolResultMessage) {
253
- return {
254
- role: 'tool_result',
255
- content: message.results,
256
- metadata: message.metadata,
257
- };
258
- }
259
- throw new Error(`Unknown message type: ${typeof message}`);
260
- }
261
-
262
- /**
263
- * Deserialize a JSON message to UPP Message.
264
- */
265
- function deserializeMessage(json: MessageJSON): Message {
266
- switch (json.role) {
267
- case 'user':
268
- return new UserMessage(
269
- json.content as string | UserContent[],
270
- { metadata: json.metadata },
271
- );
272
- case 'assistant': {
273
- const assistantContent = json.content as {
274
- content: string | AssistantContent[];
275
- toolCalls?: ToolCall[];
276
- };
277
- return new AssistantMessage(
278
- assistantContent.content,
279
- assistantContent.toolCalls,
280
- { metadata: json.metadata },
281
- );
282
- }
283
- case 'tool_result':
284
- return new ToolResultMessage(
285
- json.content as ToolResult[],
286
- { metadata: json.metadata },
287
- );
288
- default:
289
- throw new Error(`Unknown message role: ${json.role}`);
290
- }
291
- }
292
-
293
- export type {
294
- AgentStateInterface,
295
- AgentStateJSON,
296
- PlanStep,
297
- PlanStepStatus,
298
- SubagentExecutionTrace,
299
- SubagentExecutionTraceJSON,
300
- ToolExecutionTrace,
301
- } from './types.ts';
@@ -1,173 +0,0 @@
1
- import type { Message, MessageMetadata, TokenUsage } from '@providerprotocol/ai';
2
-
3
- /**
4
- * Status of a plan step during execution.
5
- */
6
- export type PlanStepStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
7
-
8
- /**
9
- * A single tool execution trace from a sub-agent.
10
- * Per UAP spec Section 8.8.
11
- */
12
- export interface ToolExecutionTrace {
13
- /** Name of the tool */
14
- toolName: string;
15
- /** Tool call ID */
16
- toolCallId?: string;
17
- /** Arguments passed to the tool */
18
- arguments: Record<string, unknown>;
19
- /** Tool result */
20
- result: string;
21
- /** Whether the tool errored */
22
- isError?: boolean;
23
- /** Execution time in milliseconds */
24
- duration?: number;
25
- }
26
-
27
- /**
28
- * Sub-agent execution trace for checkpoint persistence.
29
- * Per UAP spec Section 8.8.
30
- */
31
- export interface SubagentExecutionTrace {
32
- /** Unique ID of the sub-agent instance */
33
- subagentId: string;
34
- /** Type/name of the sub-agent */
35
- subagentType: string;
36
- /** Tool call ID that spawned this sub-agent */
37
- parentToolCallId: string;
38
- /** The task given to the sub-agent */
39
- prompt: string;
40
- /** Start timestamp (ms since epoch) */
41
- startTime: number;
42
- /** End timestamp (ms since epoch) */
43
- endTime: number;
44
- /** Whether execution succeeded */
45
- success: boolean;
46
- /** Sub-agent's response (if successful) */
47
- result?: string;
48
- /** Error message (if failed) */
49
- error?: string;
50
- /** Tools used by sub-agent */
51
- toolExecutions?: ToolExecutionTrace[];
52
- /** Token usage for sub-agent */
53
- usage?: TokenUsage;
54
- }
55
-
56
- /**
57
- * Serialized form of SubagentExecutionTrace.
58
- */
59
- export interface SubagentExecutionTraceJSON {
60
- subagentId: string;
61
- subagentType: string;
62
- parentToolCallId: string;
63
- prompt: string;
64
- startTime: number;
65
- endTime: number;
66
- success: boolean;
67
- result?: string;
68
- error?: string;
69
- toolExecutions?: ToolExecutionTrace[];
70
- usage?: TokenUsage;
71
- }
72
-
73
- /**
74
- * A single step in an execution plan.
75
- */
76
- export interface PlanStep {
77
- /** Unique step identifier */
78
- id: string;
79
- /** Description of what this step does */
80
- description: string;
81
- /** Tool to use (if applicable) */
82
- tool?: string;
83
- /** IDs of steps this depends on */
84
- dependsOn: string[];
85
- /** Current status */
86
- status: PlanStepStatus;
87
- }
88
-
89
- /**
90
- * Serialized form of a PlanStep.
91
- */
92
- export interface PlanStepJSON {
93
- id: string;
94
- description: string;
95
- tool?: string;
96
- dependsOn: string[];
97
- status: PlanStepStatus;
98
- }
99
-
100
- /**
101
- * Serialized form of AgentState for persistence.
102
- */
103
- export interface AgentStateJSON {
104
- /** UAP version */
105
- version: string;
106
- /** State snapshot ID */
107
- id: string;
108
- /** Serialized messages */
109
- messages: MessageJSON[];
110
- /** Current step number */
111
- step: number;
112
- /** User-defined metadata */
113
- metadata: Record<string, unknown>;
114
- /** Reasoning traces (for ReAct) */
115
- reasoning: string[];
116
- /** Execution plan (for Plan strategy) */
117
- plan?: PlanStepJSON[];
118
- /** Sub-agent execution traces (per UAP spec Section 8.8) */
119
- subagentTraces?: SubagentExecutionTraceJSON[];
120
- }
121
-
122
- /**
123
- * Serialized form of a Message.
124
- * This preserves the UPP Message structure for serialization.
125
- */
126
- export interface MessageJSON {
127
- role: 'user' | 'assistant' | 'tool_result';
128
- content: unknown;
129
- metadata?: MessageMetadata;
130
- }
131
-
132
- /**
133
- * Interface for AgentState operations.
134
- * All operations return new instances (immutable).
135
- */
136
- export interface AgentStateInterface {
137
- /** State snapshot ID (UUIDv4) */
138
- readonly id: string;
139
- /** Conversation history (UPP Messages) */
140
- readonly messages: readonly Message[];
141
- /** Current step number */
142
- readonly step: number;
143
- /** User-defined metadata */
144
- readonly metadata: Readonly<Record<string, unknown>>;
145
- /** Reasoning traces (for ReAct) */
146
- readonly reasoning: readonly string[];
147
- /** Execution plan (for Plan strategy) */
148
- readonly plan: readonly PlanStep[] | undefined;
149
- /** Sub-agent execution traces (per UAP spec Section 8.8) */
150
- readonly subagentTraces: readonly SubagentExecutionTrace[];
151
-
152
- /** Return new state with message added */
153
- withMessage(message: Message): AgentStateInterface;
154
- /** Return new state with messages added */
155
- withMessages(messages: Message[]): AgentStateInterface;
156
- /** Return new state with context replaced (all messages) */
157
- withContext(messages: Message[]): AgentStateInterface;
158
- /** Return new state with updated step */
159
- withStep(step: number): AgentStateInterface;
160
- /** Return new state with metadata entry */
161
- withMetadata(key: string, value: unknown): AgentStateInterface;
162
- /** Return new state with reasoning added */
163
- withReasoning(reasoning: string): AgentStateInterface;
164
- /** Return new state with plan set */
165
- withPlan(plan: PlanStep[]): AgentStateInterface;
166
- /** Return new state with sub-agent trace added */
167
- withSubagentTrace(trace: SubagentExecutionTrace): AgentStateInterface;
168
- /** Serialize to JSON */
169
- toJSON(): AgentStateJSON;
170
- }
171
-
172
- /** UAP version for serialization */
173
- export const UAP_VERSION = '1.0.0';
@@ -1,249 +0,0 @@
1
- import { generateUUID } from '../utils/uuid.ts';
2
- import { AgentState } from '../state/index.ts';
3
- import type { ThreadNodeJSON, ThreadTreeJSON } from './types.ts';
4
-
5
- /**
6
- * A node in the thread tree representing a conversation state snapshot.
7
- */
8
- export class ThreadNode {
9
- /** Node ID (UUIDv4) */
10
- readonly id: string;
11
-
12
- /** Parent node ID (null for root) */
13
- readonly parentId: string | null;
14
-
15
- /** State snapshot at this node */
16
- state: AgentState;
17
-
18
- /** Optional branch name */
19
- name?: string;
20
-
21
- /** Child node IDs */
22
- readonly children: string[];
23
-
24
- constructor(
25
- id: string,
26
- parentId: string | null,
27
- state: AgentState,
28
- name?: string,
29
- children: string[] = [],
30
- ) {
31
- this.id = id;
32
- this.parentId = parentId;
33
- this.state = state;
34
- this.name = name;
35
- this.children = children;
36
- }
37
-
38
- /**
39
- * Serialize to JSON.
40
- */
41
- toJSON(): ThreadNodeJSON {
42
- return {
43
- id: this.id,
44
- parentId: this.parentId,
45
- state: this.state.toJSON(),
46
- name: this.name,
47
- children: [...this.children],
48
- };
49
- }
50
-
51
- /**
52
- * Deserialize from JSON.
53
- */
54
- static fromJSON(json: ThreadNodeJSON): ThreadNode {
55
- return new ThreadNode(
56
- json.id,
57
- json.parentId,
58
- AgentState.fromJSON(json.state),
59
- json.name,
60
- [...json.children],
61
- );
62
- }
63
- }
64
-
65
- /**
66
- * A tree-structured collection of conversation threads with parent-child relationships.
67
- * Enables branching conversations and easy switching between alternative paths.
68
- */
69
- export class ThreadTree {
70
- /** Root node */
71
- readonly root: ThreadNode;
72
-
73
- /** Currently active node */
74
- private currentNode: ThreadNode;
75
-
76
- /** All nodes by ID */
77
- readonly nodes: Map<string, ThreadNode>;
78
-
79
- constructor(root?: ThreadNode) {
80
- if (root) {
81
- this.root = root;
82
- this.currentNode = root;
83
- this.nodes = new Map([[root.id, root]]);
84
- } else {
85
- const rootNode = new ThreadNode(
86
- generateUUID(),
87
- null,
88
- AgentState.initial(),
89
- 'root',
90
- );
91
- this.root = rootNode;
92
- this.currentNode = rootNode;
93
- this.nodes = new Map([[rootNode.id, rootNode]]);
94
- }
95
- }
96
-
97
- /**
98
- * Get the currently active node.
99
- */
100
- get current(): ThreadNode {
101
- return this.currentNode;
102
- }
103
-
104
- /**
105
- * Create a branch from a node.
106
- *
107
- * @param fromId - ID of the node to branch from
108
- * @param name - Optional name for the branch
109
- * @returns ID of the new node
110
- */
111
- branch(fromId: string, name?: string): string {
112
- const parent = this.nodes.get(fromId);
113
- if (!parent) {
114
- throw new Error(`Node not found: ${fromId}`);
115
- }
116
-
117
- const newNode = new ThreadNode(
118
- generateUUID(),
119
- fromId,
120
- parent.state, // Copy parent's state
121
- name,
122
- );
123
-
124
- // Add to parent's children
125
- parent.children.push(newNode.id);
126
-
127
- // Add to nodes map
128
- this.nodes.set(newNode.id, newNode);
129
-
130
- return newNode.id;
131
- }
132
-
133
- /**
134
- * Switch to a different node.
135
- *
136
- * @param nodeId - ID of the node to switch to
137
- */
138
- checkout(nodeId: string): void {
139
- const node = this.nodes.get(nodeId);
140
- if (!node) {
141
- throw new Error(`Node not found: ${nodeId}`);
142
- }
143
-
144
- this.currentNode = node;
145
- }
146
-
147
- /**
148
- * Get the AgentState representing the full history from root to current node.
149
- * Since nodes store full state snapshots, this returns the current node's state.
150
- *
151
- * @returns AgentState with combined history
152
- */
153
- history(): AgentState {
154
- return this.currentNode.state
155
- .withMetadata('_threadTreeNodeId', this.currentNode.id);
156
- }
157
-
158
- /**
159
- * Get all leaf nodes (nodes with no children).
160
- *
161
- * @returns Array of leaf node IDs
162
- */
163
- getLeaves(): string[] {
164
- const leaves: string[] = [];
165
-
166
- for (const [id, node] of this.nodes) {
167
- if (node.children.length === 0) {
168
- leaves.push(id);
169
- }
170
- }
171
-
172
- return leaves;
173
- }
174
-
175
- /**
176
- * Get all branch names.
177
- *
178
- * @returns Map of node IDs to branch names
179
- */
180
- getBranches(): Map<string, string | undefined> {
181
- const branches = new Map<string, string | undefined>();
182
-
183
- for (const [id, node] of this.nodes) {
184
- if (node.name) {
185
- branches.set(id, node.name);
186
- }
187
- }
188
-
189
- return branches;
190
- }
191
-
192
- /**
193
- * Serialize to JSON.
194
- */
195
- toJSON(): ThreadTreeJSON {
196
- const nodes: ThreadNodeJSON[] = [];
197
-
198
- for (const node of this.nodes.values()) {
199
- nodes.push(node.toJSON());
200
- }
201
-
202
- return {
203
- rootId: this.root.id,
204
- currentId: this.currentNode.id,
205
- nodes,
206
- };
207
- }
208
-
209
- /**
210
- * Deserialize from JSON.
211
- */
212
- static fromJSON(json: ThreadTreeJSON): ThreadTree {
213
- // First, create all nodes
214
- const nodesMap = new Map<string, ThreadNode>();
215
-
216
- for (const nodeJson of json.nodes) {
217
- const node = ThreadNode.fromJSON(nodeJson);
218
- nodesMap.set(node.id, node);
219
- }
220
-
221
- // Find root and current nodes
222
- const root = nodesMap.get(json.rootId);
223
- const current = nodesMap.get(json.currentId);
224
-
225
- if (!root) {
226
- throw new Error(`Root node not found: ${json.rootId}`);
227
- }
228
-
229
- if (!current) {
230
- throw new Error(`Current node not found: ${json.currentId}`);
231
- }
232
-
233
- // Create tree with root
234
- const tree = new ThreadTree(root);
235
-
236
- // Replace the nodes map
237
- tree.nodes.clear();
238
- for (const [id, node] of nodesMap) {
239
- tree.nodes.set(id, node);
240
- }
241
-
242
- // Set current node
243
- tree.checkout(current.id);
244
-
245
- return tree;
246
- }
247
- }
248
-
249
- export type { ThreadNodeJSON, ThreadTreeJSON } from './types.ts';