@bytespell/amux-client 0.0.19
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/dist/accumulator.d.ts +77 -0
- package/dist/accumulator.d.ts.map +1 -0
- package/dist/accumulator.js +285 -0
- package/dist/accumulator.js.map +1 -0
- package/dist/client.d.ts +155 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +364 -0
- package/dist/client.js.map +1 -0
- package/dist/connection.d.ts +81 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +143 -0
- package/dist/connection.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/react/context.d.ts +60 -0
- package/dist/react/context.d.ts.map +1 -0
- package/dist/react/context.js +138 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/hooks.d.ts +153 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +156 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/index.d.ts +29 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +27 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types.d.ts +166 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
- package/src/accumulator.ts +307 -0
- package/src/client.ts +445 -0
- package/src/connection.ts +194 -0
- package/src/index.ts +59 -0
- package/src/react/context.tsx +200 -0
- package/src/react/hooks.ts +208 -0
- package/src/react/index.ts +37 -0
- package/src/types.ts +120 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { SessionUpdate } from '@bytespell/amux-types';
|
|
2
|
+
export type { SessionUpdate };
|
|
3
|
+
/**
|
|
4
|
+
* Content block types for accumulated messages
|
|
5
|
+
*/
|
|
6
|
+
export type ContentBlock = {
|
|
7
|
+
type: 'text';
|
|
8
|
+
text: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'thinking';
|
|
11
|
+
text: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: 'tool_use';
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
input: unknown;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'tool_result';
|
|
19
|
+
toolUseId: string;
|
|
20
|
+
content: unknown;
|
|
21
|
+
isError?: boolean;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'diff';
|
|
24
|
+
path: string;
|
|
25
|
+
oldText: string;
|
|
26
|
+
newText: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'image';
|
|
29
|
+
source: {
|
|
30
|
+
type: 'base64';
|
|
31
|
+
mediaType: string;
|
|
32
|
+
data: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Accumulated message
|
|
37
|
+
*/
|
|
38
|
+
export interface Message {
|
|
39
|
+
id: string;
|
|
40
|
+
role: 'user' | 'assistant';
|
|
41
|
+
content: ContentBlock[];
|
|
42
|
+
status: 'streaming' | 'complete';
|
|
43
|
+
timestamp: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Tool call state tracking
|
|
47
|
+
*/
|
|
48
|
+
export interface ToolCallState {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
input: unknown;
|
|
52
|
+
status: 'pending' | 'running' | 'complete' | 'error';
|
|
53
|
+
result?: unknown;
|
|
54
|
+
error?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Turn state - groups user message and assistant response
|
|
58
|
+
*/
|
|
59
|
+
export interface Turn {
|
|
60
|
+
id: string;
|
|
61
|
+
userMessage: Message | null;
|
|
62
|
+
assistantMessage: Message | null;
|
|
63
|
+
toolCalls: ToolCallState[];
|
|
64
|
+
status: 'idle' | 'streaming' | 'awaiting_permission' | 'complete';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Connection status
|
|
68
|
+
*/
|
|
69
|
+
export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'ready';
|
|
70
|
+
/**
|
|
71
|
+
* Permission option (from server)
|
|
72
|
+
*/
|
|
73
|
+
export interface PermissionOptionData {
|
|
74
|
+
id?: string;
|
|
75
|
+
optionId?: string;
|
|
76
|
+
label?: string;
|
|
77
|
+
title?: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Client event types
|
|
82
|
+
*/
|
|
83
|
+
export interface AmuxClientEvents {
|
|
84
|
+
ready: {
|
|
85
|
+
cwd: string;
|
|
86
|
+
sessionId: string | null;
|
|
87
|
+
capabilities: unknown;
|
|
88
|
+
agent: {
|
|
89
|
+
type: string;
|
|
90
|
+
name: string;
|
|
91
|
+
};
|
|
92
|
+
availableAgents: Array<{
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
}>;
|
|
96
|
+
availableModels?: Array<{
|
|
97
|
+
id: string;
|
|
98
|
+
name: string;
|
|
99
|
+
provider?: string;
|
|
100
|
+
supportsThinking?: boolean;
|
|
101
|
+
}>;
|
|
102
|
+
currentModelId?: string;
|
|
103
|
+
};
|
|
104
|
+
connecting: Record<string, never>;
|
|
105
|
+
update: SessionUpdate;
|
|
106
|
+
turn_start: Record<string, never>;
|
|
107
|
+
turn_end: Record<string, never>;
|
|
108
|
+
permission_request: {
|
|
109
|
+
requestId: string;
|
|
110
|
+
toolCall?: unknown;
|
|
111
|
+
options: PermissionOptionData[];
|
|
112
|
+
};
|
|
113
|
+
prompt_complete: {
|
|
114
|
+
stopReason?: string;
|
|
115
|
+
};
|
|
116
|
+
session_created: {
|
|
117
|
+
sessionId: string | null;
|
|
118
|
+
};
|
|
119
|
+
session_switched: {
|
|
120
|
+
sessionId: string;
|
|
121
|
+
};
|
|
122
|
+
history_replay: {
|
|
123
|
+
previousSessionId: string;
|
|
124
|
+
events: unknown[];
|
|
125
|
+
eventCount: number;
|
|
126
|
+
};
|
|
127
|
+
history: {
|
|
128
|
+
events: unknown[];
|
|
129
|
+
sessionId: string | null;
|
|
130
|
+
};
|
|
131
|
+
sessions: {
|
|
132
|
+
sessions: unknown[];
|
|
133
|
+
};
|
|
134
|
+
error: {
|
|
135
|
+
message: string;
|
|
136
|
+
};
|
|
137
|
+
agent_exit: {
|
|
138
|
+
code: number | null;
|
|
139
|
+
signal: string | null;
|
|
140
|
+
};
|
|
141
|
+
connection_status: {
|
|
142
|
+
status: ConnectionStatus;
|
|
143
|
+
};
|
|
144
|
+
messages_updated: {
|
|
145
|
+
messages: Message[];
|
|
146
|
+
};
|
|
147
|
+
turns_updated: {
|
|
148
|
+
turns: Turn[];
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Options for creating an AmuxClient
|
|
153
|
+
*/
|
|
154
|
+
export interface AmuxClientOptions {
|
|
155
|
+
/** WebSocket URL to connect to */
|
|
156
|
+
url: string;
|
|
157
|
+
/** Auto-connect on creation (default: true) */
|
|
158
|
+
autoConnect?: boolean;
|
|
159
|
+
/** Auto-reconnect on disconnect (default: true) */
|
|
160
|
+
reconnect?: boolean;
|
|
161
|
+
/** Reconnect interval in ms (default: 1000) */
|
|
162
|
+
reconnectInterval?: number;
|
|
163
|
+
/** Max reconnect attempts (default: Infinity) */
|
|
164
|
+
maxReconnectAttempts?: number;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
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,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bytespell/amux-client",
|
|
3
|
+
"version": "0.0.19",
|
|
4
|
+
"description": "Client library for consuming amux over WebSocket",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./react": {
|
|
14
|
+
"types": "./dist/react/index.d.ts",
|
|
15
|
+
"import": "./dist/react/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"dev": "tsc --watch",
|
|
21
|
+
"typecheck": "tsc --noEmit"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"amux",
|
|
25
|
+
"client",
|
|
26
|
+
"websocket",
|
|
27
|
+
"acp",
|
|
28
|
+
"react"
|
|
29
|
+
],
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@bytespell/amux-types": "*"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependenciesMeta": {
|
|
39
|
+
"react": {
|
|
40
|
+
"optional": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/react": "^18.0.0",
|
|
45
|
+
"react": "^18.0.0",
|
|
46
|
+
"typescript": "~5.7.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import type { SessionUpdate } from '@bytespell/amux-types';
|
|
2
|
+
import type { Message, Turn, ToolCallState } from './types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generate a unique ID
|
|
6
|
+
*/
|
|
7
|
+
function generateId(): string {
|
|
8
|
+
return Math.random().toString(36).substring(2, 15);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Message and Turn accumulator
|
|
13
|
+
*
|
|
14
|
+
* Processes streaming session updates and builds structured conversation data.
|
|
15
|
+
*/
|
|
16
|
+
export class Accumulator {
|
|
17
|
+
private _messages: Message[] = [];
|
|
18
|
+
private _turns: Turn[] = [];
|
|
19
|
+
private _currentTurn: Turn | null = null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* All accumulated messages
|
|
23
|
+
*/
|
|
24
|
+
get messages(): Message[] {
|
|
25
|
+
return this._messages;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* All turns (grouped user/assistant pairs)
|
|
30
|
+
*/
|
|
31
|
+
get turns(): Turn[] {
|
|
32
|
+
return this._turns;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Current active turn (if streaming)
|
|
37
|
+
*/
|
|
38
|
+
get currentTurn(): Turn | null {
|
|
39
|
+
return this._currentTurn;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Last user message
|
|
44
|
+
*/
|
|
45
|
+
get lastUserMessage(): Message | null {
|
|
46
|
+
for (let i = this._messages.length - 1; i >= 0; i--) {
|
|
47
|
+
if (this._messages[i]?.role === 'user') {
|
|
48
|
+
return this._messages[i] ?? null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Last assistant message
|
|
56
|
+
*/
|
|
57
|
+
get lastAssistantMessage(): Message | null {
|
|
58
|
+
for (let i = this._messages.length - 1; i >= 0; i--) {
|
|
59
|
+
if (this._messages[i]?.role === 'assistant') {
|
|
60
|
+
return this._messages[i] ?? null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Start a new turn
|
|
68
|
+
*/
|
|
69
|
+
startTurn(): void {
|
|
70
|
+
this._currentTurn = {
|
|
71
|
+
id: generateId(),
|
|
72
|
+
userMessage: null,
|
|
73
|
+
assistantMessage: null,
|
|
74
|
+
toolCalls: [],
|
|
75
|
+
status: 'streaming',
|
|
76
|
+
};
|
|
77
|
+
this._turns.push(this._currentTurn);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* End the current turn
|
|
82
|
+
*/
|
|
83
|
+
endTurn(): void {
|
|
84
|
+
if (this._currentTurn) {
|
|
85
|
+
this._currentTurn.status = 'complete';
|
|
86
|
+
if (this._currentTurn.userMessage) {
|
|
87
|
+
this._currentTurn.userMessage.status = 'complete';
|
|
88
|
+
}
|
|
89
|
+
if (this._currentTurn.assistantMessage) {
|
|
90
|
+
this._currentTurn.assistantMessage.status = 'complete';
|
|
91
|
+
}
|
|
92
|
+
this._currentTurn = null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Set turn status to awaiting permission
|
|
98
|
+
*/
|
|
99
|
+
setAwaitingPermission(): void {
|
|
100
|
+
if (this._currentTurn) {
|
|
101
|
+
this._currentTurn.status = 'awaiting_permission';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resume streaming after permission
|
|
107
|
+
*/
|
|
108
|
+
resumeStreaming(): void {
|
|
109
|
+
if (this._currentTurn && this._currentTurn.status === 'awaiting_permission') {
|
|
110
|
+
this._currentTurn.status = 'streaming';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Process a session update
|
|
116
|
+
*/
|
|
117
|
+
processUpdate(update: SessionUpdate): void {
|
|
118
|
+
const updateType = update.sessionUpdate;
|
|
119
|
+
|
|
120
|
+
switch (updateType) {
|
|
121
|
+
case 'user_message_chunk':
|
|
122
|
+
this.processUserChunk(update);
|
|
123
|
+
break;
|
|
124
|
+
case 'agent_message_chunk':
|
|
125
|
+
this.processAssistantChunk(update);
|
|
126
|
+
break;
|
|
127
|
+
case 'tool_call':
|
|
128
|
+
this.processToolCall(update);
|
|
129
|
+
break;
|
|
130
|
+
case 'tool_call_update':
|
|
131
|
+
this.processToolCallUpdate(update);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Process user message chunk
|
|
138
|
+
*/
|
|
139
|
+
private processUserChunk(update: SessionUpdate): void {
|
|
140
|
+
if (update.sessionUpdate !== 'user_message_chunk') return;
|
|
141
|
+
|
|
142
|
+
// Create or get current turn
|
|
143
|
+
if (!this._currentTurn) {
|
|
144
|
+
this.startTurn();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Create user message if needed
|
|
148
|
+
if (!this._currentTurn!.userMessage) {
|
|
149
|
+
const userMessage: Message = {
|
|
150
|
+
id: generateId(),
|
|
151
|
+
role: 'user',
|
|
152
|
+
content: [],
|
|
153
|
+
status: 'streaming',
|
|
154
|
+
timestamp: Date.now(),
|
|
155
|
+
};
|
|
156
|
+
this._currentTurn!.userMessage = userMessage;
|
|
157
|
+
this._messages.push(userMessage);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Add content
|
|
161
|
+
const content = update.content as { type: string; text?: string };
|
|
162
|
+
if (content?.type === 'text' && content.text) {
|
|
163
|
+
const lastBlock = this._currentTurn!.userMessage!.content[
|
|
164
|
+
this._currentTurn!.userMessage!.content.length - 1
|
|
165
|
+
];
|
|
166
|
+
if (lastBlock?.type === 'text') {
|
|
167
|
+
lastBlock.text += content.text;
|
|
168
|
+
} else {
|
|
169
|
+
this._currentTurn!.userMessage!.content.push({
|
|
170
|
+
type: 'text',
|
|
171
|
+
text: content.text,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Process assistant message chunk
|
|
179
|
+
*/
|
|
180
|
+
private processAssistantChunk(update: SessionUpdate): void {
|
|
181
|
+
if (update.sessionUpdate !== 'agent_message_chunk') return;
|
|
182
|
+
|
|
183
|
+
// Create turn if needed
|
|
184
|
+
if (!this._currentTurn) {
|
|
185
|
+
this.startTurn();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Create assistant message if needed
|
|
189
|
+
if (!this._currentTurn!.assistantMessage) {
|
|
190
|
+
const assistantMessage: Message = {
|
|
191
|
+
id: generateId(),
|
|
192
|
+
role: 'assistant',
|
|
193
|
+
content: [],
|
|
194
|
+
status: 'streaming',
|
|
195
|
+
timestamp: Date.now(),
|
|
196
|
+
};
|
|
197
|
+
this._currentTurn!.assistantMessage = assistantMessage;
|
|
198
|
+
this._messages.push(assistantMessage);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Add content based on type
|
|
202
|
+
const content = update.content as { type: string; text?: string; [key: string]: unknown };
|
|
203
|
+
if (!content) return;
|
|
204
|
+
|
|
205
|
+
const assistantContent = this._currentTurn!.assistantMessage!.content;
|
|
206
|
+
|
|
207
|
+
if (content.type === 'text' && content.text) {
|
|
208
|
+
const lastBlock = assistantContent[assistantContent.length - 1];
|
|
209
|
+
if (lastBlock?.type === 'text') {
|
|
210
|
+
lastBlock.text += content.text;
|
|
211
|
+
} else {
|
|
212
|
+
assistantContent.push({ type: 'text', text: content.text });
|
|
213
|
+
}
|
|
214
|
+
} else if (content.type === 'thinking' && content.text) {
|
|
215
|
+
const lastBlock = assistantContent[assistantContent.length - 1];
|
|
216
|
+
if (lastBlock?.type === 'thinking') {
|
|
217
|
+
lastBlock.text += content.text;
|
|
218
|
+
} else {
|
|
219
|
+
assistantContent.push({ type: 'thinking', text: content.text });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Process tool call
|
|
226
|
+
*/
|
|
227
|
+
private processToolCall(update: SessionUpdate): void {
|
|
228
|
+
if (update.sessionUpdate !== 'tool_call') return;
|
|
229
|
+
|
|
230
|
+
if (!this._currentTurn) return;
|
|
231
|
+
|
|
232
|
+
const toolCall: ToolCallState = {
|
|
233
|
+
id: (update as { toolCallId?: string }).toolCallId ?? generateId(),
|
|
234
|
+
name: (update as { title?: string }).title ?? 'unknown',
|
|
235
|
+
input: (update as { input?: unknown }).input,
|
|
236
|
+
status: 'pending',
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
this._currentTurn.toolCalls.push(toolCall);
|
|
240
|
+
|
|
241
|
+
// Also add to assistant message content
|
|
242
|
+
if (this._currentTurn.assistantMessage) {
|
|
243
|
+
this._currentTurn.assistantMessage.content.push({
|
|
244
|
+
type: 'tool_use',
|
|
245
|
+
id: toolCall.id,
|
|
246
|
+
name: toolCall.name,
|
|
247
|
+
input: toolCall.input,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Process tool call update
|
|
254
|
+
*/
|
|
255
|
+
private processToolCallUpdate(update: SessionUpdate): void {
|
|
256
|
+
if (update.sessionUpdate !== 'tool_call_update') return;
|
|
257
|
+
|
|
258
|
+
if (!this._currentTurn) return;
|
|
259
|
+
|
|
260
|
+
const toolCallId = (update as { toolCallId?: string }).toolCallId;
|
|
261
|
+
if (!toolCallId) return;
|
|
262
|
+
|
|
263
|
+
const toolCall = this._currentTurn.toolCalls.find((tc) => tc.id === toolCallId);
|
|
264
|
+
if (!toolCall) return;
|
|
265
|
+
|
|
266
|
+
const status = (update as { status?: string }).status;
|
|
267
|
+
if (status === 'running') {
|
|
268
|
+
toolCall.status = 'running';
|
|
269
|
+
} else if (status === 'completed') {
|
|
270
|
+
toolCall.status = 'complete';
|
|
271
|
+
toolCall.result = (update as { output?: unknown }).output;
|
|
272
|
+
} else if (status === 'error') {
|
|
273
|
+
toolCall.status = 'error';
|
|
274
|
+
toolCall.error = (update as { error?: string }).error;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Replay history events
|
|
280
|
+
*/
|
|
281
|
+
replayHistory(events: unknown[]): void {
|
|
282
|
+
// Clear current state
|
|
283
|
+
this._messages = [];
|
|
284
|
+
this._turns = [];
|
|
285
|
+
this._currentTurn = null;
|
|
286
|
+
|
|
287
|
+
for (const event of events) {
|
|
288
|
+
const e = event as { type: string; update?: SessionUpdate };
|
|
289
|
+
if (e.type === 'turn_start') {
|
|
290
|
+
this.startTurn();
|
|
291
|
+
} else if (e.type === 'turn_end') {
|
|
292
|
+
this.endTurn();
|
|
293
|
+
} else if (e.type === 'session_update' && e.update) {
|
|
294
|
+
this.processUpdate(e.update);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Clear all accumulated data
|
|
301
|
+
*/
|
|
302
|
+
clear(): void {
|
|
303
|
+
this._messages = [];
|
|
304
|
+
this._turns = [];
|
|
305
|
+
this._currentTurn = null;
|
|
306
|
+
}
|
|
307
|
+
}
|