@aomi-labs/react 0.0.0 → 0.2.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/dist/index.cjs +1445 -1400
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +313 -136
- package/dist/index.d.ts +313 -136
- package/dist/index.js +1461 -1395
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -38,388 +38,642 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
38
38
|
var index_exports = {};
|
|
39
39
|
__export(index_exports, {
|
|
40
40
|
AomiRuntimeProvider: () => AomiRuntimeProvider,
|
|
41
|
-
AomiRuntimeProviderWithNotifications: () => AomiRuntimeProviderWithNotifications,
|
|
42
41
|
BackendApi: () => BackendApi,
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
EventContextProvider: () => EventContextProvider,
|
|
43
|
+
NotificationContextProvider: () => NotificationContextProvider,
|
|
45
44
|
ThreadContextProvider: () => ThreadContextProvider,
|
|
46
|
-
|
|
45
|
+
UserContextProvider: () => UserContextProvider,
|
|
47
46
|
cn: () => cn,
|
|
48
|
-
constructSystemMessage: () => toInboundSystem,
|
|
49
|
-
constructThreadMessage: () => toInboundMessage,
|
|
50
47
|
formatAddress: () => formatAddress,
|
|
51
48
|
getNetworkName: () => getNetworkName,
|
|
52
|
-
|
|
53
|
-
pickInjectedProvider: () => pickInjectedProvider,
|
|
54
|
-
toHexQuantity: () => toHexQuantity,
|
|
49
|
+
useAomiRuntime: () => useAomiRuntime,
|
|
55
50
|
useCurrentThreadMessages: () => useCurrentThreadMessages,
|
|
56
51
|
useCurrentThreadMetadata: () => useCurrentThreadMetadata,
|
|
52
|
+
useEventContext: () => useEventContext,
|
|
57
53
|
useNotification: () => useNotification,
|
|
58
|
-
|
|
59
|
-
useThreadContext: () => useThreadContext
|
|
54
|
+
useNotificationHandler: () => useNotificationHandler,
|
|
55
|
+
useThreadContext: () => useThreadContext,
|
|
56
|
+
useUser: () => useUser,
|
|
57
|
+
useWalletHandler: () => useWalletHandler
|
|
60
58
|
});
|
|
61
59
|
module.exports = __toCommonJS(index_exports);
|
|
62
60
|
|
|
63
|
-
// src/
|
|
64
|
-
function
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
params.set(key, String(value));
|
|
69
|
-
}
|
|
70
|
-
const qs = params.toString();
|
|
71
|
-
return qs ? `?${qs}` : "";
|
|
72
|
-
}
|
|
73
|
-
async function postState(backendUrl, path, payload) {
|
|
74
|
-
const query = toQueryString(payload);
|
|
75
|
-
const url = `${backendUrl}${path}${query}`;
|
|
76
|
-
console.log("\u{1F535} [postState] URL:", url);
|
|
77
|
-
console.log("\u{1F535} [postState] Payload:", payload);
|
|
78
|
-
const response = await fetch(url, {
|
|
79
|
-
method: "POST"
|
|
80
|
-
});
|
|
81
|
-
console.log("\u{1F535} [postState] Response status:", response.status);
|
|
82
|
-
if (!response.ok) {
|
|
83
|
-
console.error("\u{1F534} [postState] Error:", response.status, response.statusText);
|
|
84
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
85
|
-
}
|
|
86
|
-
const data = await response.json();
|
|
87
|
-
console.log("\u{1F7E2} [postState] Success:", data);
|
|
88
|
-
return data;
|
|
61
|
+
// src/backend/sse.ts
|
|
62
|
+
function extractSseData(rawEvent) {
|
|
63
|
+
const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
|
|
64
|
+
if (!dataLines.length) return null;
|
|
65
|
+
return dataLines.join("\n");
|
|
89
66
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
async postChatMessage(sessionId, message, publicKey) {
|
|
112
|
-
console.log("\u{1F535} [postChatMessage] Called with sessionId:", sessionId, "message:", message);
|
|
113
|
-
const result = await postState(this.backendUrl, "/api/chat", {
|
|
114
|
-
message,
|
|
115
|
-
session_id: sessionId,
|
|
116
|
-
public_key: publicKey
|
|
117
|
-
});
|
|
118
|
-
console.log("\u{1F7E2} [postChatMessage] Success:", result);
|
|
119
|
-
return result;
|
|
120
|
-
}
|
|
121
|
-
async postSystemMessage(sessionId, message) {
|
|
122
|
-
console.log("\u{1F535} [postSystemMessage] Called with sessionId:", sessionId, "message:", message);
|
|
123
|
-
const result = await postState(this.backendUrl, "/api/system", {
|
|
124
|
-
message,
|
|
125
|
-
session_id: sessionId
|
|
126
|
-
});
|
|
127
|
-
console.log("\u{1F7E2} [postSystemMessage] Success:", result);
|
|
128
|
-
return result;
|
|
129
|
-
}
|
|
130
|
-
async postInterrupt(sessionId) {
|
|
131
|
-
console.log("\u{1F535} [postInterrupt] Called with sessionId:", sessionId);
|
|
132
|
-
const result = await postState(this.backendUrl, "/api/interrupt", {
|
|
133
|
-
session_id: sessionId
|
|
134
|
-
});
|
|
135
|
-
console.log("\u{1F7E2} [postInterrupt] Success:", result);
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
138
|
-
disconnectSSE() {
|
|
139
|
-
if (this.eventSource) {
|
|
140
|
-
this.eventSource.close();
|
|
141
|
-
this.eventSource = null;
|
|
67
|
+
async function readSseStream(stream, signal, onMessage) {
|
|
68
|
+
const reader = stream.getReader();
|
|
69
|
+
const decoder = new TextDecoder();
|
|
70
|
+
let buffer = "";
|
|
71
|
+
try {
|
|
72
|
+
while (!signal.aborted) {
|
|
73
|
+
const { value, done } = await reader.read();
|
|
74
|
+
if (done) break;
|
|
75
|
+
buffer += decoder.decode(value, { stream: true });
|
|
76
|
+
buffer = buffer.replace(/\r/g, "");
|
|
77
|
+
let separatorIndex = buffer.indexOf("\n\n");
|
|
78
|
+
while (separatorIndex >= 0) {
|
|
79
|
+
const rawEvent = buffer.slice(0, separatorIndex);
|
|
80
|
+
buffer = buffer.slice(separatorIndex + 2);
|
|
81
|
+
const data = extractSseData(rawEvent);
|
|
82
|
+
if (data) {
|
|
83
|
+
onMessage(data);
|
|
84
|
+
}
|
|
85
|
+
separatorIndex = buffer.indexOf("\n\n");
|
|
86
|
+
}
|
|
142
87
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
setConnectionStatus(on) {
|
|
146
|
-
this.connectionStatus = on;
|
|
88
|
+
} finally {
|
|
89
|
+
reader.releaseLock();
|
|
147
90
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
91
|
+
}
|
|
92
|
+
function createSseSubscriber({
|
|
93
|
+
backendUrl,
|
|
94
|
+
getHeaders,
|
|
95
|
+
shouldLog = process.env.NODE_ENV !== "production"
|
|
96
|
+
}) {
|
|
97
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
98
|
+
const subscribe2 = (sessionId, onUpdate, onError) => {
|
|
99
|
+
const existing = subscriptions.get(sessionId);
|
|
100
|
+
const listener = { onUpdate, onError };
|
|
101
|
+
if (existing) {
|
|
102
|
+
existing.listeners.add(listener);
|
|
103
|
+
if (shouldLog) {
|
|
104
|
+
console.debug("[aomi][sse] listener added", {
|
|
105
|
+
sessionId,
|
|
106
|
+
listeners: existing.listeners.size
|
|
107
|
+
});
|
|
155
108
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
109
|
+
return () => {
|
|
110
|
+
existing.listeners.delete(listener);
|
|
111
|
+
if (shouldLog) {
|
|
112
|
+
console.debug("[aomi][sse] listener removed", {
|
|
113
|
+
sessionId,
|
|
114
|
+
listeners: existing.listeners.size
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (existing.listeners.size === 0) {
|
|
118
|
+
existing.stop("unsubscribe");
|
|
119
|
+
if (subscriptions.get(sessionId) === existing) {
|
|
120
|
+
subscriptions.delete(sessionId);
|
|
121
|
+
}
|
|
166
122
|
}
|
|
167
123
|
};
|
|
168
|
-
this.eventSource.onerror = (error) => {
|
|
169
|
-
console.error("SSE connection error:", error);
|
|
170
|
-
};
|
|
171
|
-
} catch (error) {
|
|
172
|
-
console.error("Failed to establish SSE connection:", error);
|
|
173
|
-
this.handleConnectionError(sessionId, publicKey);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
handleConnectionError(sessionId, publicKey) {
|
|
177
|
-
this.setConnectionStatus(false);
|
|
178
|
-
let attempt = 0;
|
|
179
|
-
const total = 3;
|
|
180
|
-
if (attempt < total) {
|
|
181
|
-
attempt++;
|
|
182
|
-
console.log(`Attempting to reconnect (${attempt}/${total})...`);
|
|
183
|
-
setTimeout(() => {
|
|
184
|
-
this.connectSSE(sessionId, publicKey);
|
|
185
|
-
}, 100);
|
|
186
|
-
} else {
|
|
187
|
-
console.error("Max reconnection attempts reached");
|
|
188
|
-
this.setConnectionStatus(false);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
subscribeToUpdatesInternal(sessionId, onUpdate, onError, logLabel) {
|
|
192
|
-
const updatesUrl = new URL("/api/updates", this.backendUrl);
|
|
193
|
-
updatesUrl.searchParams.set("session_id", sessionId);
|
|
194
|
-
const updatesUrlString = updatesUrl.toString();
|
|
195
|
-
const existing = this.updatesEventSources.get(sessionId);
|
|
196
|
-
if (existing) {
|
|
197
|
-
existing.cleanup();
|
|
198
|
-
this.updatesEventSources.delete(sessionId);
|
|
199
124
|
}
|
|
200
125
|
const subscription = {
|
|
201
|
-
|
|
126
|
+
abortController: null,
|
|
202
127
|
retries: 0,
|
|
203
128
|
retryTimer: null,
|
|
204
129
|
stopped: false,
|
|
205
|
-
|
|
130
|
+
listeners: /* @__PURE__ */ new Set([listener]),
|
|
131
|
+
stop: (reason) => {
|
|
132
|
+
var _a;
|
|
206
133
|
subscription.stopped = true;
|
|
207
134
|
if (subscription.retryTimer) {
|
|
208
135
|
clearTimeout(subscription.retryTimer);
|
|
209
136
|
subscription.retryTimer = null;
|
|
210
137
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
138
|
+
(_a = subscription.abortController) == null ? void 0 : _a.abort();
|
|
139
|
+
subscription.abortController = null;
|
|
140
|
+
if (shouldLog) {
|
|
141
|
+
console.debug("[aomi][sse] stop", {
|
|
142
|
+
sessionId,
|
|
143
|
+
reason,
|
|
144
|
+
retries: subscription.retries
|
|
145
|
+
});
|
|
214
146
|
}
|
|
215
147
|
}
|
|
216
148
|
};
|
|
217
149
|
const scheduleRetry = () => {
|
|
150
|
+
if (subscription.stopped) return;
|
|
218
151
|
subscription.retries += 1;
|
|
219
152
|
const delayMs = Math.min(500 * 2 ** (subscription.retries - 1), 1e4);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
153
|
+
if (shouldLog) {
|
|
154
|
+
console.debug("[aomi][sse] retry scheduled", {
|
|
155
|
+
sessionId,
|
|
156
|
+
delayMs,
|
|
157
|
+
retries: subscription.retries
|
|
158
|
+
});
|
|
159
|
+
}
|
|
224
160
|
subscription.retryTimer = setTimeout(() => {
|
|
225
|
-
open();
|
|
161
|
+
void open();
|
|
226
162
|
}, delayMs);
|
|
227
163
|
};
|
|
228
|
-
const open = () => {
|
|
164
|
+
const open = async () => {
|
|
165
|
+
var _a;
|
|
229
166
|
if (subscription.stopped) return;
|
|
230
167
|
if (subscription.retryTimer) {
|
|
231
168
|
clearTimeout(subscription.retryTimer);
|
|
232
169
|
subscription.retryTimer = null;
|
|
233
170
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
console.log("\u{1F514} [updates] message", { url: updatesUrlString, data: event.data });
|
|
247
|
-
const parsed = JSON.parse(event.data);
|
|
248
|
-
onUpdate(parsed);
|
|
249
|
-
} catch (error) {
|
|
250
|
-
console.error("Failed to parse system update SSE:", error);
|
|
251
|
-
onError == null ? void 0 : onError(error);
|
|
171
|
+
const controller = new AbortController();
|
|
172
|
+
subscription.abortController = controller;
|
|
173
|
+
const openedAt = Date.now();
|
|
174
|
+
try {
|
|
175
|
+
const response = await fetch(`${backendUrl}/api/updates`, {
|
|
176
|
+
headers: getHeaders(sessionId),
|
|
177
|
+
signal: controller.signal
|
|
178
|
+
});
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`SSE HTTP ${response.status}: ${response.statusText}`
|
|
182
|
+
);
|
|
252
183
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
184
|
+
if (!response.body) {
|
|
185
|
+
throw new Error("SSE response missing body");
|
|
186
|
+
}
|
|
187
|
+
subscription.retries = 0;
|
|
188
|
+
await readSseStream(response.body, controller.signal, (data) => {
|
|
189
|
+
var _a2, _b;
|
|
190
|
+
let parsed;
|
|
191
|
+
try {
|
|
192
|
+
parsed = JSON.parse(data);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
for (const item of subscription.listeners) {
|
|
195
|
+
(_a2 = item.onError) == null ? void 0 : _a2.call(item, error);
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
for (const item of subscription.listeners) {
|
|
200
|
+
try {
|
|
201
|
+
item.onUpdate(parsed);
|
|
202
|
+
} catch (error) {
|
|
203
|
+
(_b = item.onError) == null ? void 0 : _b.call(item, error);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
259
206
|
});
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
207
|
+
if (shouldLog) {
|
|
208
|
+
console.debug("[aomi][sse] stream ended", {
|
|
209
|
+
sessionId,
|
|
210
|
+
aborted: controller.signal.aborted,
|
|
211
|
+
stopped: subscription.stopped,
|
|
212
|
+
durationMs: Date.now() - openedAt
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if (!controller.signal.aborted && !subscription.stopped) {
|
|
217
|
+
for (const item of subscription.listeners) {
|
|
218
|
+
(_a = item.onError) == null ? void 0 : _a.call(item, error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!subscription.stopped) {
|
|
263
223
|
scheduleRetry();
|
|
264
|
-
}
|
|
224
|
+
}
|
|
265
225
|
};
|
|
266
|
-
|
|
267
|
-
open();
|
|
226
|
+
subscriptions.set(sessionId, subscription);
|
|
227
|
+
void open();
|
|
268
228
|
return () => {
|
|
269
|
-
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
229
|
+
subscription.listeners.delete(listener);
|
|
230
|
+
if (shouldLog) {
|
|
231
|
+
console.debug("[aomi][sse] listener removed", {
|
|
232
|
+
sessionId,
|
|
233
|
+
listeners: subscription.listeners.size
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (subscription.listeners.size === 0) {
|
|
237
|
+
subscription.stop("unsubscribe");
|
|
238
|
+
if (subscriptions.get(sessionId) === subscription) {
|
|
239
|
+
subscriptions.delete(sessionId);
|
|
240
|
+
}
|
|
275
241
|
}
|
|
276
242
|
};
|
|
243
|
+
};
|
|
244
|
+
return { subscribe: subscribe2 };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/backend/client.ts
|
|
248
|
+
var SESSION_ID_HEADER = "X-Session-Id";
|
|
249
|
+
function toQueryString(payload) {
|
|
250
|
+
const params = new URLSearchParams();
|
|
251
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
252
|
+
if (value === void 0 || value === null) continue;
|
|
253
|
+
params.set(key, String(value));
|
|
277
254
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
255
|
+
const qs = params.toString();
|
|
256
|
+
return qs ? `?${qs}` : "";
|
|
257
|
+
}
|
|
258
|
+
function withSessionHeader(sessionId, init) {
|
|
259
|
+
const headers = new Headers(init);
|
|
260
|
+
headers.set(SESSION_ID_HEADER, sessionId);
|
|
261
|
+
return headers;
|
|
262
|
+
}
|
|
263
|
+
async function postState(backendUrl, path, payload, sessionId) {
|
|
264
|
+
const query = toQueryString(payload);
|
|
265
|
+
const url = `${backendUrl}${path}${query}`;
|
|
266
|
+
const response = await fetch(url, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: withSessionHeader(sessionId)
|
|
269
|
+
});
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
272
|
+
}
|
|
273
|
+
return await response.json();
|
|
274
|
+
}
|
|
275
|
+
var BackendApi = class {
|
|
276
|
+
constructor(backendUrl) {
|
|
277
|
+
this.backendUrl = backendUrl;
|
|
278
|
+
this.sseSubscriber = createSseSubscriber({
|
|
279
|
+
backendUrl,
|
|
280
|
+
getHeaders: (sessionId) => withSessionHeader(sessionId, { Accept: "text/event-stream" })
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
async fetchState(sessionId, userState) {
|
|
284
|
+
const url = new URL("/api/state", this.backendUrl);
|
|
285
|
+
if (userState) {
|
|
286
|
+
url.searchParams.set("user_state", JSON.stringify(userState));
|
|
287
|
+
}
|
|
288
|
+
const response = await fetch(url.toString(), {
|
|
289
|
+
headers: withSessionHeader(sessionId)
|
|
290
|
+
});
|
|
291
|
+
if (!response.ok) {
|
|
292
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
293
|
+
}
|
|
294
|
+
return await response.json();
|
|
295
|
+
}
|
|
296
|
+
async postChatMessage(sessionId, message, publicKey) {
|
|
297
|
+
return postState(
|
|
298
|
+
this.backendUrl,
|
|
299
|
+
"/api/chat",
|
|
300
|
+
{
|
|
301
|
+
message,
|
|
302
|
+
public_key: publicKey
|
|
303
|
+
},
|
|
304
|
+
sessionId
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
async postSystemMessage(sessionId, message) {
|
|
308
|
+
return postState(
|
|
309
|
+
this.backendUrl,
|
|
310
|
+
"/api/system",
|
|
311
|
+
{
|
|
312
|
+
message
|
|
313
|
+
},
|
|
314
|
+
sessionId
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
async postInterrupt(sessionId) {
|
|
318
|
+
return postState(
|
|
319
|
+
this.backendUrl,
|
|
320
|
+
"/api/interrupt",
|
|
321
|
+
{},
|
|
322
|
+
sessionId
|
|
284
323
|
);
|
|
285
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Subscribe to SSE updates for a session.
|
|
327
|
+
* Uses fetch streaming and reconnects on disconnects.
|
|
328
|
+
* Returns an unsubscribe function.
|
|
329
|
+
*/
|
|
330
|
+
subscribeSSE(sessionId, onUpdate, onError) {
|
|
331
|
+
return this.sseSubscriber.subscribe(sessionId, onUpdate, onError);
|
|
332
|
+
}
|
|
286
333
|
async fetchThreads(publicKey) {
|
|
287
|
-
console.log("\u{1F535} [fetchThreads] Called with publicKey:", publicKey);
|
|
288
334
|
const url = `${this.backendUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;
|
|
289
|
-
console.log("\u{1F535} [fetchThreads] URL:", url);
|
|
290
335
|
const response = await fetch(url);
|
|
291
|
-
console.log("\u{1F535} [fetchThreads] Response status:", response.status);
|
|
292
336
|
if (!response.ok) {
|
|
293
|
-
console.error("\u{1F534} [fetchThreads] Error:", response.status);
|
|
294
337
|
throw new Error(`Failed to fetch threads: HTTP ${response.status}`);
|
|
295
338
|
}
|
|
296
|
-
|
|
297
|
-
console.log("\u{1F7E2} [fetchThreads] Success:", data);
|
|
298
|
-
return data;
|
|
339
|
+
return await response.json();
|
|
299
340
|
}
|
|
300
|
-
async
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
body.title = title;
|
|
341
|
+
async fetchThread(sessionId) {
|
|
342
|
+
const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
|
|
343
|
+
const response = await fetch(url, {
|
|
344
|
+
headers: withSessionHeader(sessionId)
|
|
345
|
+
});
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
308
348
|
}
|
|
309
|
-
|
|
349
|
+
return await response.json();
|
|
350
|
+
}
|
|
351
|
+
async createThread(threadId, publicKey) {
|
|
352
|
+
const body = {};
|
|
353
|
+
if (publicKey) body.public_key = publicKey;
|
|
310
354
|
const url = `${this.backendUrl}/api/sessions`;
|
|
311
|
-
console.log("\u{1F535} [createThread] URL:", url);
|
|
312
355
|
const response = await fetch(url, {
|
|
313
356
|
method: "POST",
|
|
314
|
-
headers: {
|
|
357
|
+
headers: withSessionHeader(threadId, {
|
|
358
|
+
"Content-Type": "application/json"
|
|
359
|
+
}),
|
|
315
360
|
body: JSON.stringify(body)
|
|
316
361
|
});
|
|
317
|
-
console.log("\u{1F535} [createThread] Response status:", response.status);
|
|
318
362
|
if (!response.ok) {
|
|
319
|
-
console.error("\u{1F534} [createThread] Error:", response.status);
|
|
320
363
|
throw new Error(`Failed to create thread: HTTP ${response.status}`);
|
|
321
364
|
}
|
|
322
|
-
|
|
323
|
-
console.log("\u{1F7E2} [createThread] Success:", data);
|
|
324
|
-
return data;
|
|
365
|
+
return await response.json();
|
|
325
366
|
}
|
|
326
367
|
async archiveThread(sessionId) {
|
|
327
|
-
console.log("\u{1F535} [archiveThread] Called with sessionId:", sessionId);
|
|
328
368
|
const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
369
|
+
const response = await fetch(url, {
|
|
370
|
+
method: "POST",
|
|
371
|
+
headers: withSessionHeader(sessionId)
|
|
372
|
+
});
|
|
332
373
|
if (!response.ok) {
|
|
333
|
-
console.error("\u{1F534} [archiveThread] Error:", response.status);
|
|
334
374
|
throw new Error(`Failed to archive thread: HTTP ${response.status}`);
|
|
335
375
|
}
|
|
336
|
-
console.log("\u{1F7E2} [archiveThread] Success");
|
|
337
376
|
}
|
|
338
377
|
async unarchiveThread(sessionId) {
|
|
339
|
-
console.log("\u{1F535} [unarchiveThread] Called with sessionId:", sessionId);
|
|
340
378
|
const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
379
|
+
const response = await fetch(url, {
|
|
380
|
+
method: "POST",
|
|
381
|
+
headers: withSessionHeader(sessionId)
|
|
382
|
+
});
|
|
344
383
|
if (!response.ok) {
|
|
345
|
-
console.error("\u{1F534} [unarchiveThread] Error:", response.status);
|
|
346
384
|
throw new Error(`Failed to unarchive thread: HTTP ${response.status}`);
|
|
347
385
|
}
|
|
348
|
-
console.log("\u{1F7E2} [unarchiveThread] Success");
|
|
349
386
|
}
|
|
350
387
|
async deleteThread(sessionId) {
|
|
351
|
-
console.log("\u{1F535} [deleteThread] Called with sessionId:", sessionId);
|
|
352
388
|
const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
389
|
+
const response = await fetch(url, {
|
|
390
|
+
method: "DELETE",
|
|
391
|
+
headers: withSessionHeader(sessionId)
|
|
392
|
+
});
|
|
356
393
|
if (!response.ok) {
|
|
357
|
-
console.error("\u{1F534} [deleteThread] Error:", response.status);
|
|
358
394
|
throw new Error(`Failed to delete thread: HTTP ${response.status}`);
|
|
359
395
|
}
|
|
360
|
-
console.log("\u{1F7E2} [deleteThread] Success");
|
|
361
396
|
}
|
|
362
397
|
async renameThread(sessionId, newTitle) {
|
|
363
|
-
console.log("\u{1F535} [renameThread] Called with sessionId:", sessionId, "newTitle:", newTitle);
|
|
364
398
|
const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
|
|
365
|
-
console.log("\u{1F535} [renameThread] URL:", url);
|
|
366
399
|
const response = await fetch(url, {
|
|
367
400
|
method: "PATCH",
|
|
368
|
-
headers: {
|
|
401
|
+
headers: withSessionHeader(sessionId, {
|
|
402
|
+
"Content-Type": "application/json"
|
|
403
|
+
}),
|
|
369
404
|
body: JSON.stringify({ title: newTitle })
|
|
370
405
|
});
|
|
371
|
-
console.log("\u{1F535} [renameThread] Response status:", response.status);
|
|
372
406
|
if (!response.ok) {
|
|
373
|
-
console.error("\u{1F534} [renameThread] Error:", response.status);
|
|
374
407
|
throw new Error(`Failed to rename thread: HTTP ${response.status}`);
|
|
375
408
|
}
|
|
376
|
-
console.log("\u{1F7E2} [renameThread] Success");
|
|
377
409
|
}
|
|
378
|
-
async
|
|
410
|
+
async getSystemEvents(sessionId, count) {
|
|
379
411
|
const url = new URL("/api/events", this.backendUrl);
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
412
|
+
if (count !== void 0) {
|
|
413
|
+
url.searchParams.set("count", String(count));
|
|
414
|
+
}
|
|
415
|
+
const response = await fetch(url.toString(), {
|
|
416
|
+
headers: withSessionHeader(sessionId)
|
|
417
|
+
});
|
|
385
418
|
if (!response.ok) {
|
|
386
|
-
|
|
419
|
+
if (response.status === 404) return [];
|
|
420
|
+
throw new Error(`Failed to get system events: HTTP ${response.status}`);
|
|
387
421
|
}
|
|
388
422
|
return await response.json();
|
|
389
423
|
}
|
|
390
|
-
|
|
391
|
-
return this.subscribeToUpdatesInternal(
|
|
392
|
-
sessionId,
|
|
393
|
-
onUpdate,
|
|
394
|
-
onError,
|
|
395
|
-
"subscribeToUpdatesWithNotification"
|
|
396
|
-
);
|
|
397
|
-
}
|
|
424
|
+
// fetchEventsAfter removed: /api/events only supports count now
|
|
398
425
|
};
|
|
399
426
|
|
|
400
427
|
// src/runtime/aomi-runtime.tsx
|
|
401
|
-
var
|
|
402
|
-
var import_react7 = require("@assistant-ui/react");
|
|
428
|
+
var import_react9 = require("react");
|
|
403
429
|
|
|
404
|
-
// src/
|
|
430
|
+
// src/contexts/event-context.tsx
|
|
405
431
|
var import_react = require("react");
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
function
|
|
409
|
-
|
|
432
|
+
|
|
433
|
+
// src/backend/types.ts
|
|
434
|
+
function isInlineCall(event) {
|
|
435
|
+
return "InlineCall" in event;
|
|
436
|
+
}
|
|
437
|
+
function isSystemNotice(event) {
|
|
438
|
+
return "SystemNotice" in event;
|
|
439
|
+
}
|
|
440
|
+
function isSystemError(event) {
|
|
441
|
+
return "SystemError" in event;
|
|
442
|
+
}
|
|
443
|
+
function isAsyncCallback(event) {
|
|
444
|
+
return "AsyncCallback" in event;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/state/event-buffer.ts
|
|
448
|
+
function createEventBuffer() {
|
|
449
|
+
return {
|
|
450
|
+
inboundQueue: [],
|
|
451
|
+
outboundQueue: [],
|
|
452
|
+
sseStatus: "disconnected",
|
|
453
|
+
lastEventId: null,
|
|
454
|
+
subscribers: /* @__PURE__ */ new Map()
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function enqueueInbound(state, event) {
|
|
458
|
+
state.inboundQueue.push(__spreadProps(__spreadValues({}, event), {
|
|
459
|
+
status: "pending",
|
|
460
|
+
timestamp: Date.now()
|
|
461
|
+
}));
|
|
462
|
+
}
|
|
463
|
+
function subscribe(state, type, callback) {
|
|
464
|
+
if (!state.subscribers.has(type)) {
|
|
465
|
+
state.subscribers.set(type, /* @__PURE__ */ new Set());
|
|
466
|
+
}
|
|
467
|
+
state.subscribers.get(type).add(callback);
|
|
468
|
+
return () => {
|
|
469
|
+
var _a;
|
|
470
|
+
(_a = state.subscribers.get(type)) == null ? void 0 : _a.delete(callback);
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function dispatch(state, event) {
|
|
474
|
+
const typeSubscribers = state.subscribers.get(event.type);
|
|
475
|
+
if (typeSubscribers) {
|
|
476
|
+
for (const callback of typeSubscribers) {
|
|
477
|
+
callback(event);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const allSubscribers = state.subscribers.get("*");
|
|
481
|
+
if (allSubscribers) {
|
|
482
|
+
for (const callback of allSubscribers) {
|
|
483
|
+
callback(event);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function setSSEStatus(state, status) {
|
|
488
|
+
state.sseStatus = status;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// src/contexts/event-context.tsx
|
|
492
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
493
|
+
var EventContextState = (0, import_react.createContext)(null);
|
|
494
|
+
function useEventContext() {
|
|
495
|
+
const context = (0, import_react.useContext)(EventContextState);
|
|
410
496
|
if (!context) {
|
|
411
|
-
throw new Error(
|
|
497
|
+
throw new Error(
|
|
498
|
+
"useEventContext must be used within EventContextProvider. Wrap your app with <EventContextProvider>...</EventContextProvider>"
|
|
499
|
+
);
|
|
412
500
|
}
|
|
413
501
|
return context;
|
|
414
502
|
}
|
|
503
|
+
function EventContextProvider({
|
|
504
|
+
children,
|
|
505
|
+
backendApi,
|
|
506
|
+
sessionId
|
|
507
|
+
}) {
|
|
508
|
+
const bufferRef = (0, import_react.useRef)(null);
|
|
509
|
+
if (!bufferRef.current) {
|
|
510
|
+
bufferRef.current = createEventBuffer();
|
|
511
|
+
}
|
|
512
|
+
const buffer = bufferRef.current;
|
|
513
|
+
const [sseStatus, setSseStatus] = (0, import_react.useState)("disconnected");
|
|
514
|
+
(0, import_react.useEffect)(() => {
|
|
515
|
+
setSSEStatus(buffer, "connecting");
|
|
516
|
+
setSseStatus("connecting");
|
|
517
|
+
const unsubscribe = backendApi.subscribeSSE(
|
|
518
|
+
sessionId,
|
|
519
|
+
(event) => {
|
|
520
|
+
enqueueInbound(buffer, {
|
|
521
|
+
type: event.type,
|
|
522
|
+
sessionId: event.session_id,
|
|
523
|
+
payload: event
|
|
524
|
+
});
|
|
525
|
+
const inboundEvent = {
|
|
526
|
+
type: event.type,
|
|
527
|
+
sessionId: event.session_id,
|
|
528
|
+
payload: event,
|
|
529
|
+
status: "fetched",
|
|
530
|
+
timestamp: Date.now()
|
|
531
|
+
};
|
|
532
|
+
dispatch(buffer, inboundEvent);
|
|
533
|
+
},
|
|
534
|
+
(error) => {
|
|
535
|
+
console.error("SSE error:", error);
|
|
536
|
+
setSSEStatus(buffer, "disconnected");
|
|
537
|
+
setSseStatus("disconnected");
|
|
538
|
+
}
|
|
539
|
+
);
|
|
540
|
+
setSSEStatus(buffer, "connected");
|
|
541
|
+
setSseStatus("connected");
|
|
542
|
+
return () => {
|
|
543
|
+
unsubscribe();
|
|
544
|
+
setSSEStatus(buffer, "disconnected");
|
|
545
|
+
setSseStatus("disconnected");
|
|
546
|
+
};
|
|
547
|
+
}, [backendApi, sessionId, buffer]);
|
|
548
|
+
const subscribeCallback = (0, import_react.useCallback)(
|
|
549
|
+
(type, callback) => {
|
|
550
|
+
return subscribe(buffer, type, callback);
|
|
551
|
+
},
|
|
552
|
+
[buffer]
|
|
553
|
+
);
|
|
554
|
+
const sendOutbound = (0, import_react.useCallback)(
|
|
555
|
+
async (event) => {
|
|
556
|
+
try {
|
|
557
|
+
const message = JSON.stringify({
|
|
558
|
+
type: event.type,
|
|
559
|
+
payload: event.payload
|
|
560
|
+
});
|
|
561
|
+
await backendApi.postSystemMessage(event.sessionId, message);
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error("Failed to send outbound event:", error);
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
[backendApi]
|
|
567
|
+
);
|
|
568
|
+
const dispatchSystemEvents = (0, import_react.useCallback)(
|
|
569
|
+
(sessionId2, events) => {
|
|
570
|
+
var _a;
|
|
571
|
+
for (const event of events) {
|
|
572
|
+
let eventType;
|
|
573
|
+
let payload;
|
|
574
|
+
if (isInlineCall(event)) {
|
|
575
|
+
eventType = event.InlineCall.type;
|
|
576
|
+
payload = (_a = event.InlineCall.payload) != null ? _a : event.InlineCall;
|
|
577
|
+
} else if (isSystemNotice(event)) {
|
|
578
|
+
eventType = "system_notice";
|
|
579
|
+
payload = { message: event.SystemNotice };
|
|
580
|
+
} else if (isSystemError(event)) {
|
|
581
|
+
eventType = "system_error";
|
|
582
|
+
payload = { message: event.SystemError };
|
|
583
|
+
} else if (isAsyncCallback(event)) {
|
|
584
|
+
eventType = "async_callback";
|
|
585
|
+
payload = event.AsyncCallback;
|
|
586
|
+
} else {
|
|
587
|
+
console.warn("Unknown system event type:", event);
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
const inboundEvent = {
|
|
591
|
+
type: eventType,
|
|
592
|
+
sessionId: sessionId2,
|
|
593
|
+
payload,
|
|
594
|
+
status: "fetched",
|
|
595
|
+
timestamp: Date.now()
|
|
596
|
+
};
|
|
597
|
+
enqueueInbound(buffer, {
|
|
598
|
+
type: eventType,
|
|
599
|
+
sessionId: sessionId2,
|
|
600
|
+
payload
|
|
601
|
+
});
|
|
602
|
+
dispatch(buffer, inboundEvent);
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
[buffer]
|
|
606
|
+
);
|
|
607
|
+
const contextValue = {
|
|
608
|
+
subscribe: subscribeCallback,
|
|
609
|
+
sendOutboundSystem: sendOutbound,
|
|
610
|
+
dispatchInboundSystem: dispatchSystemEvents,
|
|
611
|
+
sseStatus
|
|
612
|
+
};
|
|
613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EventContextState.Provider, { value: contextValue, children });
|
|
614
|
+
}
|
|
415
615
|
|
|
416
|
-
// src/
|
|
417
|
-
var import_react3 = require("react");
|
|
418
|
-
|
|
419
|
-
// src/state/thread-context.tsx
|
|
616
|
+
// src/contexts/notification-context.tsx
|
|
420
617
|
var import_react2 = require("react");
|
|
618
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
619
|
+
var NotificationContext = (0, import_react2.createContext)(null);
|
|
620
|
+
function useNotification() {
|
|
621
|
+
const context = (0, import_react2.useContext)(NotificationContext);
|
|
622
|
+
if (!context) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
"useNotification must be used within NotificationContextProvider"
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
return context;
|
|
628
|
+
}
|
|
629
|
+
var notificationIdCounter = 0;
|
|
630
|
+
function generateId() {
|
|
631
|
+
return `notif-${Date.now()}-${++notificationIdCounter}`;
|
|
632
|
+
}
|
|
633
|
+
function NotificationContextProvider({
|
|
634
|
+
children
|
|
635
|
+
}) {
|
|
636
|
+
const [notifications, setNotifications] = (0, import_react2.useState)([]);
|
|
637
|
+
const showNotification = (0, import_react2.useCallback)((params) => {
|
|
638
|
+
const id = generateId();
|
|
639
|
+
const notification = __spreadProps(__spreadValues({}, params), {
|
|
640
|
+
id,
|
|
641
|
+
timestamp: Date.now()
|
|
642
|
+
});
|
|
643
|
+
setNotifications((prev) => [notification, ...prev]);
|
|
644
|
+
return id;
|
|
645
|
+
}, []);
|
|
646
|
+
const dismissNotification = (0, import_react2.useCallback)((id) => {
|
|
647
|
+
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
|
648
|
+
}, []);
|
|
649
|
+
const clearAll = (0, import_react2.useCallback)(() => {
|
|
650
|
+
setNotifications([]);
|
|
651
|
+
}, []);
|
|
652
|
+
const value = {
|
|
653
|
+
notifications,
|
|
654
|
+
showNotification,
|
|
655
|
+
dismissNotification,
|
|
656
|
+
clearAll
|
|
657
|
+
};
|
|
658
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NotificationContext.Provider, { value, children });
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// src/contexts/thread-context.tsx
|
|
662
|
+
var import_react3 = require("react");
|
|
421
663
|
|
|
422
664
|
// src/state/thread-store.ts
|
|
665
|
+
var shouldLogThreadUpdates = process.env.NODE_ENV !== "production";
|
|
666
|
+
var logThreadMetadataChange = (source, threadId, prev, next) => {
|
|
667
|
+
if (!shouldLogThreadUpdates) return;
|
|
668
|
+
if (!prev && !next) return;
|
|
669
|
+
if (!prev || !next) {
|
|
670
|
+
console.debug(`[aomi][thread:${source}]`, { threadId, prev, next });
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (prev.title !== next.title || prev.status !== next.status || prev.lastActiveAt !== next.lastActiveAt) {
|
|
674
|
+
console.debug(`[aomi][thread:${source}]`, { threadId, prev, next });
|
|
675
|
+
}
|
|
676
|
+
};
|
|
423
677
|
var ThreadStore = class {
|
|
424
678
|
constructor(options) {
|
|
425
679
|
this.listeners = /* @__PURE__ */ new Set();
|
|
@@ -446,7 +700,21 @@ var ThreadStore = class {
|
|
|
446
700
|
this.updateState({ threads: new Map(nextThreads) });
|
|
447
701
|
};
|
|
448
702
|
this.setThreadMetadata = (updater) => {
|
|
449
|
-
const
|
|
703
|
+
const prevMetadata = this.state.threadMetadata;
|
|
704
|
+
const nextMetadata = this.resolveStateAction(updater, prevMetadata);
|
|
705
|
+
for (const [threadId, next] of nextMetadata.entries()) {
|
|
706
|
+
logThreadMetadataChange(
|
|
707
|
+
"setThreadMetadata",
|
|
708
|
+
threadId,
|
|
709
|
+
prevMetadata.get(threadId),
|
|
710
|
+
next
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
for (const [threadId, prev] of prevMetadata.entries()) {
|
|
714
|
+
if (!nextMetadata.has(threadId)) {
|
|
715
|
+
logThreadMetadataChange("setThreadMetadata", threadId, prev, void 0);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
450
718
|
this.updateState({ threadMetadata: new Map(nextMetadata) });
|
|
451
719
|
};
|
|
452
720
|
this.setThreadMessages = (threadId, messages) => {
|
|
@@ -467,8 +735,10 @@ var ThreadStore = class {
|
|
|
467
735
|
if (!existing) {
|
|
468
736
|
return;
|
|
469
737
|
}
|
|
738
|
+
const next = __spreadValues(__spreadValues({}, existing), updates);
|
|
470
739
|
const nextMetadata = new Map(this.state.threadMetadata);
|
|
471
|
-
nextMetadata.set(threadId,
|
|
740
|
+
nextMetadata.set(threadId, next);
|
|
741
|
+
logThreadMetadataChange("updateThreadMetadata", threadId, existing, next);
|
|
472
742
|
this.updateState({ threadMetadata: nextMetadata });
|
|
473
743
|
};
|
|
474
744
|
var _a;
|
|
@@ -526,9 +796,9 @@ var ThreadStore = class {
|
|
|
526
796
|
setCurrentThreadId: this.setCurrentThreadId,
|
|
527
797
|
threadViewKey: this.state.threadViewKey,
|
|
528
798
|
bumpThreadViewKey: this.bumpThreadViewKey,
|
|
529
|
-
|
|
799
|
+
allThreads: this.state.threads,
|
|
530
800
|
setThreads: this.setThreads,
|
|
531
|
-
|
|
801
|
+
allThreadsMetadata: this.state.threadMetadata,
|
|
532
802
|
setThreadMetadata: this.setThreadMetadata,
|
|
533
803
|
threadCnt: this.state.threadCnt,
|
|
534
804
|
setThreadCnt: this.setThreadCnt,
|
|
@@ -540,11 +810,11 @@ var ThreadStore = class {
|
|
|
540
810
|
}
|
|
541
811
|
};
|
|
542
812
|
|
|
543
|
-
// src/
|
|
544
|
-
var
|
|
545
|
-
var ThreadContextState = (0,
|
|
813
|
+
// src/contexts/thread-context.tsx
|
|
814
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
815
|
+
var ThreadContextState = (0, import_react3.createContext)(null);
|
|
546
816
|
function useThreadContext() {
|
|
547
|
-
const context = (0,
|
|
817
|
+
const context = (0, import_react3.useContext)(ThreadContextState);
|
|
548
818
|
if (!context) {
|
|
549
819
|
throw new Error(
|
|
550
820
|
"useThreadContext must be used within ThreadContextProvider. Wrap your app with <ThreadContextProvider>...</ThreadContextProvider>"
|
|
@@ -556,33 +826,133 @@ function ThreadContextProvider({
|
|
|
556
826
|
children,
|
|
557
827
|
initialThreadId
|
|
558
828
|
}) {
|
|
559
|
-
const storeRef = (0,
|
|
829
|
+
const storeRef = (0, import_react3.useRef)(null);
|
|
560
830
|
if (!storeRef.current) {
|
|
561
831
|
storeRef.current = new ThreadStore({ initialThreadId });
|
|
562
832
|
}
|
|
563
833
|
const store = storeRef.current;
|
|
564
|
-
const value = (0,
|
|
565
|
-
|
|
834
|
+
const value = (0, import_react3.useSyncExternalStore)(
|
|
835
|
+
store.subscribe,
|
|
836
|
+
store.getSnapshot,
|
|
837
|
+
store.getSnapshot
|
|
838
|
+
);
|
|
839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ThreadContextState.Provider, { value, children });
|
|
566
840
|
}
|
|
567
841
|
function useCurrentThreadMessages() {
|
|
568
842
|
const { currentThreadId, getThreadMessages } = useThreadContext();
|
|
569
|
-
return (0,
|
|
843
|
+
return (0, import_react3.useMemo)(
|
|
844
|
+
() => getThreadMessages(currentThreadId),
|
|
845
|
+
[currentThreadId, getThreadMessages]
|
|
846
|
+
);
|
|
570
847
|
}
|
|
571
848
|
function useCurrentThreadMetadata() {
|
|
572
849
|
const { currentThreadId, getThreadMetadata } = useThreadContext();
|
|
573
|
-
return (0,
|
|
850
|
+
return (0, import_react3.useMemo)(
|
|
851
|
+
() => getThreadMetadata(currentThreadId),
|
|
852
|
+
[currentThreadId, getThreadMetadata]
|
|
853
|
+
);
|
|
574
854
|
}
|
|
575
855
|
|
|
576
|
-
// src/
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
856
|
+
// src/contexts/user-context.tsx
|
|
857
|
+
var import_react4 = require("react");
|
|
858
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
859
|
+
var UserContext = (0, import_react4.createContext)(void 0);
|
|
860
|
+
function useUser() {
|
|
861
|
+
const context = (0, import_react4.useContext)(UserContext);
|
|
862
|
+
if (!context) {
|
|
863
|
+
throw new Error("useUser must be used within UserContextProvider");
|
|
864
|
+
}
|
|
865
|
+
return {
|
|
866
|
+
user: context.user,
|
|
867
|
+
setUser: context.setUser,
|
|
868
|
+
getUserState: context.getUserState,
|
|
869
|
+
onUserStateChange: context.onUserStateChange
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
function UserContextProvider({ children }) {
|
|
873
|
+
const [user, setUserState] = (0, import_react4.useState)({
|
|
874
|
+
isConnected: false,
|
|
875
|
+
address: void 0,
|
|
876
|
+
chainId: void 0,
|
|
877
|
+
ensName: void 0
|
|
878
|
+
});
|
|
879
|
+
const userRef = (0, import_react4.useRef)(user);
|
|
880
|
+
userRef.current = user;
|
|
881
|
+
const StateChangeCallbacks = (0, import_react4.useRef)(
|
|
882
|
+
/* @__PURE__ */ new Set()
|
|
883
|
+
);
|
|
884
|
+
const setUser = (0, import_react4.useCallback)((data) => {
|
|
885
|
+
setUserState((prev) => {
|
|
886
|
+
const next = __spreadValues(__spreadValues({}, prev), data);
|
|
887
|
+
StateChangeCallbacks.current.forEach((callback) => {
|
|
888
|
+
callback(next);
|
|
889
|
+
});
|
|
890
|
+
return next;
|
|
891
|
+
});
|
|
892
|
+
}, []);
|
|
893
|
+
const getUserState = (0, import_react4.useCallback)(() => userRef.current, []);
|
|
894
|
+
const onUserStateChange = (0, import_react4.useCallback)(
|
|
895
|
+
(callback) => {
|
|
896
|
+
StateChangeCallbacks.current.add(callback);
|
|
897
|
+
return () => {
|
|
898
|
+
StateChangeCallbacks.current.delete(callback);
|
|
899
|
+
};
|
|
900
|
+
},
|
|
901
|
+
[]
|
|
902
|
+
);
|
|
903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
904
|
+
UserContext.Provider,
|
|
905
|
+
{
|
|
906
|
+
value: {
|
|
907
|
+
user,
|
|
908
|
+
setUser,
|
|
909
|
+
getUserState,
|
|
910
|
+
onUserStateChange
|
|
911
|
+
},
|
|
912
|
+
children
|
|
913
|
+
}
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// src/runtime/core.tsx
|
|
918
|
+
var import_react7 = require("react");
|
|
919
|
+
var import_react8 = require("@assistant-ui/react");
|
|
920
|
+
|
|
921
|
+
// src/runtime/orchestrator.ts
|
|
922
|
+
var import_react5 = require("react");
|
|
923
|
+
|
|
924
|
+
// src/runtime/utils.ts
|
|
925
|
+
var import_clsx = require("clsx");
|
|
926
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
927
|
+
function cn(...inputs) {
|
|
928
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
929
|
+
}
|
|
930
|
+
var parseTimestamp = (value) => {
|
|
931
|
+
if (value === void 0 || value === null) return 0;
|
|
932
|
+
if (typeof value === "number") {
|
|
933
|
+
return Number.isFinite(value) ? value < 1e12 ? value * 1e3 : value : 0;
|
|
934
|
+
}
|
|
935
|
+
const numeric = Number(value);
|
|
936
|
+
if (!Number.isNaN(numeric)) {
|
|
937
|
+
return numeric < 1e12 ? numeric * 1e3 : numeric;
|
|
938
|
+
}
|
|
939
|
+
const ts = Date.parse(value);
|
|
940
|
+
return Number.isNaN(ts) ? 0 : ts;
|
|
941
|
+
};
|
|
942
|
+
var isPlaceholderTitle = (title) => {
|
|
943
|
+
var _a;
|
|
944
|
+
const normalized = (_a = title == null ? void 0 : title.trim()) != null ? _a : "";
|
|
945
|
+
return !normalized || normalized.startsWith("#[");
|
|
946
|
+
};
|
|
947
|
+
function toInboundMessage(msg) {
|
|
948
|
+
var _a;
|
|
949
|
+
if (msg.sender === "system") return null;
|
|
950
|
+
const content = [];
|
|
581
951
|
const role = msg.sender === "user" ? "user" : "assistant";
|
|
582
952
|
if (msg.content) {
|
|
583
953
|
content.push({ type: "text", text: msg.content });
|
|
584
954
|
}
|
|
585
|
-
const [topic, toolContent] = (_a =
|
|
955
|
+
const [topic, toolContent] = (_a = parseToolPayload(msg)) != null ? _a : [];
|
|
586
956
|
if (topic && toolContent) {
|
|
587
957
|
content.push({
|
|
588
958
|
type: "tool-call",
|
|
@@ -604,84 +974,61 @@ function toInboundMessage(msg) {
|
|
|
604
974
|
}, msg.timestamp && { createdAt: new Date(msg.timestamp) });
|
|
605
975
|
return threadMessage;
|
|
606
976
|
}
|
|
607
|
-
function
|
|
608
|
-
|
|
609
|
-
const [topic] = (_a = parseToolStream(msg.tool_stream)) != null ? _a : [];
|
|
610
|
-
const messageText = topic || msg.content || "";
|
|
611
|
-
const timestamp = parseTimestamp(msg.timestamp);
|
|
612
|
-
if (!messageText.trim()) return null;
|
|
613
|
-
return __spreadValues({
|
|
614
|
-
role: "system",
|
|
615
|
-
content: [{ type: "text", text: messageText }]
|
|
616
|
-
}, timestamp && { createdAt: timestamp });
|
|
617
|
-
}
|
|
618
|
-
function parseTimestamp(timestamp) {
|
|
619
|
-
if (!timestamp) return void 0;
|
|
620
|
-
const parsed = new Date(timestamp);
|
|
621
|
-
return Number.isNaN(parsed.valueOf()) ? void 0 : parsed;
|
|
977
|
+
function parseToolPayload(msg) {
|
|
978
|
+
return parseToolResult(msg.tool_result);
|
|
622
979
|
}
|
|
623
|
-
function
|
|
624
|
-
if (!
|
|
625
|
-
if (Array.isArray(
|
|
626
|
-
const [topic, content] =
|
|
627
|
-
return [String(topic), content];
|
|
628
|
-
}
|
|
629
|
-
if (typeof toolStream === "object") {
|
|
630
|
-
const topic = toolStream.topic;
|
|
631
|
-
const content = toolStream.content;
|
|
632
|
-
return topic ? [String(topic), String(content)] : null;
|
|
980
|
+
function parseToolResult(toolResult) {
|
|
981
|
+
if (!toolResult) return null;
|
|
982
|
+
if (Array.isArray(toolResult) && toolResult.length === 2) {
|
|
983
|
+
const [topic, content] = toolResult;
|
|
984
|
+
return [String(topic), String(content != null ? content : "")];
|
|
633
985
|
}
|
|
634
986
|
return null;
|
|
635
987
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
988
|
+
var getNetworkName = (chainId) => {
|
|
989
|
+
if (chainId === void 0) return "";
|
|
990
|
+
const id = typeof chainId === "string" ? Number(chainId) : chainId;
|
|
991
|
+
switch (id) {
|
|
992
|
+
case 1:
|
|
993
|
+
return "ethereum";
|
|
994
|
+
case 137:
|
|
995
|
+
return "polygon";
|
|
996
|
+
case 42161:
|
|
997
|
+
return "arbitrum";
|
|
998
|
+
case 8453:
|
|
999
|
+
return "base";
|
|
1000
|
+
case 10:
|
|
1001
|
+
return "optimism";
|
|
1002
|
+
case 11155111:
|
|
1003
|
+
return "sepolia";
|
|
1004
|
+
case 1337:
|
|
1005
|
+
case 31337:
|
|
1006
|
+
return "testnet";
|
|
1007
|
+
case 59140:
|
|
1008
|
+
return "linea-sepolia";
|
|
1009
|
+
case 59144:
|
|
1010
|
+
return "linea";
|
|
1011
|
+
default:
|
|
1012
|
+
return "testnet";
|
|
647
1013
|
}
|
|
648
|
-
const ts = Date.parse(value);
|
|
649
|
-
return Number.isNaN(ts) ? 0 : ts;
|
|
650
|
-
};
|
|
651
|
-
var isPlaceholderTitle = (title) => {
|
|
652
|
-
var _a;
|
|
653
|
-
const normalized = (_a = title == null ? void 0 : title.trim()) != null ? _a : "";
|
|
654
|
-
return !normalized || normalized.startsWith("#[");
|
|
655
1014
|
};
|
|
1015
|
+
var formatAddress = (addr) => addr ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : "Connect Wallet";
|
|
656
1016
|
|
|
657
|
-
// src/
|
|
658
|
-
function
|
|
1017
|
+
// src/state/backend-state.ts
|
|
1018
|
+
function createBackendState() {
|
|
659
1019
|
return {
|
|
660
|
-
tempToBackendId: /* @__PURE__ */ new Map(),
|
|
661
1020
|
skipInitialFetch: /* @__PURE__ */ new Set(),
|
|
662
1021
|
pendingChat: /* @__PURE__ */ new Map(),
|
|
663
|
-
pendingSystem: /* @__PURE__ */ new Map(),
|
|
664
1022
|
runningThreads: /* @__PURE__ */ new Set(),
|
|
665
1023
|
creatingThreadId: null,
|
|
666
1024
|
createThreadPromise: null
|
|
667
1025
|
};
|
|
668
1026
|
}
|
|
669
1027
|
function resolveThreadId(state, threadId) {
|
|
670
|
-
|
|
671
|
-
return (_a = state.tempToBackendId.get(threadId)) != null ? _a : threadId;
|
|
1028
|
+
return threadId;
|
|
672
1029
|
}
|
|
673
1030
|
function isThreadReady(state, threadId) {
|
|
674
|
-
|
|
675
|
-
return state.tempToBackendId.has(threadId);
|
|
676
|
-
}
|
|
677
|
-
function setBackendMapping(state, tempId, backendId) {
|
|
678
|
-
state.tempToBackendId.set(tempId, backendId);
|
|
679
|
-
}
|
|
680
|
-
function findTempIdForBackendId(state, backendId) {
|
|
681
|
-
for (const [tempId, id] of state.tempToBackendId.entries()) {
|
|
682
|
-
if (id === backendId) return tempId;
|
|
683
|
-
}
|
|
684
|
-
return void 0;
|
|
1031
|
+
return state.creatingThreadId !== threadId;
|
|
685
1032
|
}
|
|
686
1033
|
function markSkipInitialFetch(state, threadId) {
|
|
687
1034
|
state.skipInitialFetch.add(threadId);
|
|
@@ -717,17 +1064,6 @@ function hasPendingChat(state, threadId) {
|
|
|
717
1064
|
var _a, _b;
|
|
718
1065
|
return ((_b = (_a = state.pendingChat.get(threadId)) == null ? void 0 : _a.length) != null ? _b : 0) > 0;
|
|
719
1066
|
}
|
|
720
|
-
function enqueuePendingSystem(state, threadId, text) {
|
|
721
|
-
var _a;
|
|
722
|
-
const existing = (_a = state.pendingSystem.get(threadId)) != null ? _a : [];
|
|
723
|
-
state.pendingSystem.set(threadId, [...existing, text]);
|
|
724
|
-
}
|
|
725
|
-
function dequeuePendingSystem(state, threadId) {
|
|
726
|
-
var _a;
|
|
727
|
-
const pending = (_a = state.pendingSystem.get(threadId)) != null ? _a : [];
|
|
728
|
-
state.pendingSystem.delete(threadId);
|
|
729
|
-
return pending;
|
|
730
|
-
}
|
|
731
1067
|
|
|
732
1068
|
// src/runtime/message-controller.ts
|
|
733
1069
|
var MessageController = class {
|
|
@@ -742,13 +1078,6 @@ var MessageController = class {
|
|
|
742
1078
|
}
|
|
743
1079
|
const threadMessages = [];
|
|
744
1080
|
for (const msg of msgs) {
|
|
745
|
-
if (msg.sender === "system") {
|
|
746
|
-
const systemMessage = toInboundSystem(msg);
|
|
747
|
-
if (systemMessage) {
|
|
748
|
-
threadMessages.push(systemMessage);
|
|
749
|
-
}
|
|
750
|
-
continue;
|
|
751
|
-
}
|
|
752
1081
|
const threadMessage = toInboundMessage(msg);
|
|
753
1082
|
if (threadMessage) {
|
|
754
1083
|
threadMessages.push(threadMessage);
|
|
@@ -757,9 +1086,13 @@ var MessageController = class {
|
|
|
757
1086
|
this.getThreadContextApi().setThreadMessages(threadId, threadMessages);
|
|
758
1087
|
}
|
|
759
1088
|
async outbound(message, threadId) {
|
|
760
|
-
var _a, _b;
|
|
1089
|
+
var _a, _b, _c;
|
|
761
1090
|
const backendState = this.config.backendStateRef.current;
|
|
762
|
-
const text = message.content.filter(
|
|
1091
|
+
const text = message.content.filter(
|
|
1092
|
+
(part) => part.type === "text"
|
|
1093
|
+
).map(
|
|
1094
|
+
(part) => part.text
|
|
1095
|
+
).join("\n");
|
|
763
1096
|
if (!text) return;
|
|
764
1097
|
const threadState = this.getThreadContextApi();
|
|
765
1098
|
const existingMessages = threadState.getThreadMessages(threadId);
|
|
@@ -769,7 +1102,9 @@ var MessageController = class {
|
|
|
769
1102
|
createdAt: /* @__PURE__ */ new Date()
|
|
770
1103
|
};
|
|
771
1104
|
threadState.setThreadMessages(threadId, [...existingMessages, userMessage]);
|
|
772
|
-
threadState.updateThreadMetadata(threadId, {
|
|
1105
|
+
threadState.updateThreadMetadata(threadId, {
|
|
1106
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1107
|
+
});
|
|
773
1108
|
if (!isThreadReady(backendState, threadId)) {
|
|
774
1109
|
this.markRunning(threadId, true);
|
|
775
1110
|
enqueuePendingChat(backendState, threadId, text);
|
|
@@ -779,62 +1114,30 @@ var MessageController = class {
|
|
|
779
1114
|
const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
|
|
780
1115
|
try {
|
|
781
1116
|
this.markRunning(threadId, true);
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1117
|
+
const response = publicKey ? await this.config.backendApiRef.current.postChatMessage(
|
|
1118
|
+
backendThreadId,
|
|
1119
|
+
text,
|
|
1120
|
+
publicKey
|
|
1121
|
+
) : await this.config.backendApiRef.current.postChatMessage(
|
|
1122
|
+
backendThreadId,
|
|
1123
|
+
text
|
|
1124
|
+
);
|
|
1125
|
+
if (response == null ? void 0 : response.messages) {
|
|
1126
|
+
this.inbound(threadId, response.messages);
|
|
790
1127
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
async outboundSystem(threadId, text) {
|
|
799
|
-
const backendState = this.config.backendStateRef.current;
|
|
800
|
-
if (!isThreadReady(backendState, threadId)) return;
|
|
801
|
-
const threadMessages = this.getThreadContextApi().getThreadMessages(threadId);
|
|
802
|
-
const hasUserMessages = threadMessages.some((msg) => msg.role === "user");
|
|
803
|
-
if (!hasUserMessages) {
|
|
804
|
-
enqueuePendingSystem(backendState, threadId, text);
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
await this.outboundSystemInner(threadId, text);
|
|
808
|
-
}
|
|
809
|
-
async outboundSystemInner(threadId, text) {
|
|
810
|
-
const backendState = this.config.backendStateRef.current;
|
|
811
|
-
const threadState = this.getThreadContextApi();
|
|
812
|
-
const backendThreadId = resolveThreadId(backendState, threadId);
|
|
813
|
-
this.markRunning(threadId, true);
|
|
814
|
-
try {
|
|
815
|
-
const response = await this.config.backendApiRef.current.postSystemMessage(backendThreadId, text);
|
|
816
|
-
if (response.res) {
|
|
817
|
-
const systemMessage = toInboundSystem(response.res);
|
|
818
|
-
if (systemMessage) {
|
|
819
|
-
const updatedMessages = [...threadState.getThreadMessages(threadId), systemMessage];
|
|
820
|
-
threadState.setThreadMessages(threadId, updatedMessages);
|
|
821
|
-
}
|
|
1128
|
+
if (((_c = response == null ? void 0 : response.system_events) == null ? void 0 : _c.length) && this.config.onSyncEvents) {
|
|
1129
|
+
this.config.onSyncEvents(backendThreadId, response.system_events);
|
|
1130
|
+
}
|
|
1131
|
+
if (response == null ? void 0 : response.is_processing) {
|
|
1132
|
+
this.config.polling.start(threadId);
|
|
1133
|
+
} else if (!this.config.polling.isPolling(threadId)) {
|
|
1134
|
+
this.markRunning(threadId, false);
|
|
822
1135
|
}
|
|
823
|
-
await this.flushPendingSystem(threadId);
|
|
824
|
-
this.config.polling.start(threadId);
|
|
825
1136
|
} catch (error) {
|
|
826
|
-
console.error("Failed to send
|
|
1137
|
+
console.error("Failed to send message:", error);
|
|
827
1138
|
this.markRunning(threadId, false);
|
|
828
1139
|
}
|
|
829
1140
|
}
|
|
830
|
-
async flushPendingSystem(threadId) {
|
|
831
|
-
const backendState = this.config.backendStateRef.current;
|
|
832
|
-
const pending = dequeuePendingSystem(backendState, threadId);
|
|
833
|
-
if (!pending.length) return;
|
|
834
|
-
for (const pendingMessage of pending) {
|
|
835
|
-
await this.outboundSystemInner(threadId, pendingMessage);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
1141
|
async flushPendingChat(threadId) {
|
|
839
1142
|
var _a, _b;
|
|
840
1143
|
const backendState = this.config.backendStateRef.current;
|
|
@@ -851,7 +1154,10 @@ var MessageController = class {
|
|
|
851
1154
|
publicKey
|
|
852
1155
|
);
|
|
853
1156
|
} else {
|
|
854
|
-
await this.config.backendApiRef.current.postChatMessage(
|
|
1157
|
+
await this.config.backendApiRef.current.postChatMessage(
|
|
1158
|
+
backendThreadId,
|
|
1159
|
+
text
|
|
1160
|
+
);
|
|
855
1161
|
}
|
|
856
1162
|
} catch (error) {
|
|
857
1163
|
console.error("Failed to send queued message:", error);
|
|
@@ -860,12 +1166,19 @@ var MessageController = class {
|
|
|
860
1166
|
this.config.polling.start(threadId);
|
|
861
1167
|
}
|
|
862
1168
|
async cancel(threadId) {
|
|
1169
|
+
var _a;
|
|
863
1170
|
const backendState = this.config.backendStateRef.current;
|
|
864
1171
|
if (!isThreadReady(backendState, threadId)) return;
|
|
865
1172
|
this.config.polling.stop(threadId);
|
|
866
1173
|
const backendThreadId = resolveThreadId(backendState, threadId);
|
|
867
1174
|
try {
|
|
868
|
-
await this.config.backendApiRef.current.postInterrupt(backendThreadId);
|
|
1175
|
+
const response = await this.config.backendApiRef.current.postInterrupt(backendThreadId);
|
|
1176
|
+
if (response == null ? void 0 : response.messages) {
|
|
1177
|
+
this.inbound(threadId, response.messages);
|
|
1178
|
+
}
|
|
1179
|
+
if (((_a = response == null ? void 0 : response.system_events) == null ? void 0 : _a.length) && this.config.onSyncEvents) {
|
|
1180
|
+
this.config.onSyncEvents(backendThreadId, response.system_events);
|
|
1181
|
+
}
|
|
869
1182
|
this.markRunning(threadId, false);
|
|
870
1183
|
} catch (error) {
|
|
871
1184
|
console.error("Failed to cancel:", error);
|
|
@@ -891,29 +1204,28 @@ var PollingController = class {
|
|
|
891
1204
|
this.intervals = /* @__PURE__ */ new Map();
|
|
892
1205
|
var _a;
|
|
893
1206
|
this.intervalMs = (_a = config.intervalMs) != null ? _a : 500;
|
|
894
|
-
this.handleSystemEvents = config.handleSystemEvents;
|
|
895
|
-
}
|
|
896
|
-
setSystemEventsHandler(handler) {
|
|
897
|
-
this.handleSystemEvents = handler;
|
|
898
1207
|
}
|
|
899
1208
|
start(threadId) {
|
|
1209
|
+
var _a, _b;
|
|
900
1210
|
const backendState = this.config.backendStateRef.current;
|
|
901
1211
|
if (!isThreadReady(backendState, threadId)) return;
|
|
902
|
-
if (this.intervals.has(threadId))
|
|
903
|
-
return;
|
|
904
|
-
}
|
|
1212
|
+
if (this.intervals.has(threadId)) return;
|
|
905
1213
|
const backendThreadId = resolveThreadId(backendState, threadId);
|
|
906
1214
|
setThreadRunning(backendState, threadId, true);
|
|
907
1215
|
const tick = async () => {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
}
|
|
1216
|
+
var _a2, _b2;
|
|
1217
|
+
if (!this.intervals.has(threadId)) return;
|
|
911
1218
|
try {
|
|
912
|
-
console.log(
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1219
|
+
console.log(
|
|
1220
|
+
"[PollingController] Fetching state for threadId:",
|
|
1221
|
+
threadId
|
|
1222
|
+
);
|
|
1223
|
+
const userState = (_b2 = (_a2 = this.config).getUserState) == null ? void 0 : _b2.call(_a2);
|
|
1224
|
+
const state = await this.config.backendApiRef.current.fetchState(
|
|
1225
|
+
backendThreadId,
|
|
1226
|
+
userState
|
|
1227
|
+
);
|
|
1228
|
+
if (!this.intervals.has(threadId)) return;
|
|
917
1229
|
this.handleState(threadId, state);
|
|
918
1230
|
} catch (error) {
|
|
919
1231
|
console.error("Polling error:", error);
|
|
@@ -922,9 +1234,7 @@ var PollingController = class {
|
|
|
922
1234
|
};
|
|
923
1235
|
const intervalId = setInterval(tick, this.intervalMs);
|
|
924
1236
|
this.intervals.set(threadId, intervalId);
|
|
925
|
-
|
|
926
|
-
this.config.onStart(threadId);
|
|
927
|
-
}
|
|
1237
|
+
(_b = (_a = this.config).onStart) == null ? void 0 : _b.call(_a, threadId);
|
|
928
1238
|
}
|
|
929
1239
|
stop(threadId) {
|
|
930
1240
|
var _a, _b;
|
|
@@ -945,14 +1255,11 @@ var PollingController = class {
|
|
|
945
1255
|
}
|
|
946
1256
|
}
|
|
947
1257
|
handleState(threadId, state) {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
const backendThreadId = resolveThreadId(backendState, threadId);
|
|
954
|
-
if (this.handleSystemEvents && state.system_events) {
|
|
955
|
-
this.handleSystemEvents(backendThreadId, threadId, state.system_events);
|
|
1258
|
+
var _a;
|
|
1259
|
+
if (((_a = state.system_events) == null ? void 0 : _a.length) && this.config.onSyncEvents) {
|
|
1260
|
+
const backendState = this.config.backendStateRef.current;
|
|
1261
|
+
const sessionId = resolveThreadId(backendState, threadId);
|
|
1262
|
+
this.config.onSyncEvents(sessionId, state.system_events);
|
|
956
1263
|
}
|
|
957
1264
|
this.config.applyMessages(threadId, state.messages);
|
|
958
1265
|
if (!state.is_processing) {
|
|
@@ -962,17 +1269,17 @@ var PollingController = class {
|
|
|
962
1269
|
};
|
|
963
1270
|
|
|
964
1271
|
// src/runtime/orchestrator.ts
|
|
965
|
-
function useRuntimeOrchestrator(
|
|
1272
|
+
function useRuntimeOrchestrator(backendApi, options) {
|
|
966
1273
|
const threadContext = useThreadContext();
|
|
967
|
-
const threadContextRef = (0,
|
|
1274
|
+
const threadContextRef = (0, import_react5.useRef)(threadContext);
|
|
968
1275
|
threadContextRef.current = threadContext;
|
|
969
|
-
const backendApiRef = (0,
|
|
970
|
-
|
|
971
|
-
const
|
|
972
|
-
const
|
|
973
|
-
const
|
|
974
|
-
const
|
|
975
|
-
const
|
|
1276
|
+
const backendApiRef = (0, import_react5.useRef)(backendApi);
|
|
1277
|
+
backendApiRef.current = backendApi;
|
|
1278
|
+
const backendStateRef = (0, import_react5.useRef)(createBackendState());
|
|
1279
|
+
const [isRunning, setIsRunning] = (0, import_react5.useState)(false);
|
|
1280
|
+
const messageControllerRef = (0, import_react5.useRef)(null);
|
|
1281
|
+
const pollingRef = (0, import_react5.useRef)(null);
|
|
1282
|
+
const pendingFetches = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
|
|
976
1283
|
if (!pollingRef.current) {
|
|
977
1284
|
pollingRef.current = new PollingController({
|
|
978
1285
|
backendApiRef,
|
|
@@ -981,6 +1288,8 @@ function useRuntimeOrchestrator(backendUrl, options) {
|
|
|
981
1288
|
var _a;
|
|
982
1289
|
(_a = messageControllerRef.current) == null ? void 0 : _a.inbound(threadId, msgs);
|
|
983
1290
|
},
|
|
1291
|
+
onSyncEvents: options == null ? void 0 : options.onSyncEvents,
|
|
1292
|
+
getUserState: options == null ? void 0 : options.getUserState,
|
|
984
1293
|
onStart: (threadId) => {
|
|
985
1294
|
if (threadContextRef.current.currentThreadId === threadId) {
|
|
986
1295
|
setIsRunning(true);
|
|
@@ -1000,80 +1309,56 @@ function useRuntimeOrchestrator(backendUrl, options) {
|
|
|
1000
1309
|
threadContextRef,
|
|
1001
1310
|
polling: pollingRef.current,
|
|
1002
1311
|
setGlobalIsRunning: setIsRunning,
|
|
1003
|
-
getPublicKey: options == null ? void 0 : options.getPublicKey
|
|
1312
|
+
getPublicKey: options == null ? void 0 : options.getPublicKey,
|
|
1313
|
+
onSyncEvents: options == null ? void 0 : options.onSyncEvents
|
|
1004
1314
|
});
|
|
1005
1315
|
}
|
|
1006
|
-
const
|
|
1007
|
-
var _a;
|
|
1008
|
-
|
|
1009
|
-
(
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
for (const controller of inFlightRef.current.values()) {
|
|
1014
|
-
controller.abort();
|
|
1015
|
-
}
|
|
1016
|
-
inFlightRef.current.clear();
|
|
1017
|
-
};
|
|
1018
|
-
}, []);
|
|
1019
|
-
const ensureInitialState = (0, import_react3.useCallback)(
|
|
1020
|
-
async (threadId) => {
|
|
1021
|
-
var _a, _b;
|
|
1022
|
-
const backendState = backendStateRef.current;
|
|
1023
|
-
if (shouldSkipInitialFetch(backendState, threadId)) {
|
|
1024
|
-
clearSkipInitialFetch(backendState, threadId);
|
|
1025
|
-
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1026
|
-
setIsRunning(false);
|
|
1027
|
-
}
|
|
1028
|
-
return;
|
|
1316
|
+
const ensureInitialState = (0, import_react5.useCallback)(async (threadId) => {
|
|
1317
|
+
var _a, _b, _c, _d;
|
|
1318
|
+
const backendState = backendStateRef.current;
|
|
1319
|
+
if (shouldSkipInitialFetch(backendState, threadId)) {
|
|
1320
|
+
clearSkipInitialFetch(backendState, threadId);
|
|
1321
|
+
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1322
|
+
setIsRunning(false);
|
|
1029
1323
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
if (!isThreadReady(backendState, threadId)) {
|
|
1327
|
+
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1328
|
+
setIsRunning(false);
|
|
1035
1329
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
if (pendingFetches.current.has(threadId)) return;
|
|
1333
|
+
const backendThreadId = resolveThreadId(backendState, threadId);
|
|
1334
|
+
pendingFetches.current.add(threadId);
|
|
1335
|
+
try {
|
|
1336
|
+
const userState = (_a = options == null ? void 0 : options.getUserState) == null ? void 0 : _a.call(options);
|
|
1337
|
+
const state = await backendApiRef.current.fetchState(
|
|
1338
|
+
backendThreadId,
|
|
1339
|
+
userState
|
|
1340
|
+
);
|
|
1341
|
+
(_b = messageControllerRef.current) == null ? void 0 : _b.inbound(threadId, state.messages);
|
|
1342
|
+
if (((_c = state.system_events) == null ? void 0 : _c.length) && (options == null ? void 0 : options.onSyncEvents)) {
|
|
1343
|
+
options.onSyncEvents(backendThreadId, state.system_events);
|
|
1038
1344
|
}
|
|
1039
|
-
|
|
1040
|
-
const controller = new AbortController();
|
|
1041
|
-
inFlightRef.current.set(threadId, controller);
|
|
1042
|
-
try {
|
|
1043
|
-
console.log("\u{1F535} [Orchestrator] Fetching initial state for threadId:", threadId);
|
|
1044
|
-
const state = await backendApiRef.current.fetchState(backendThreadId, {
|
|
1045
|
-
signal: controller.signal
|
|
1046
|
-
});
|
|
1047
|
-
(_a = messageControllerRef.current) == null ? void 0 : _a.inbound(threadId, state.messages);
|
|
1048
|
-
if (systemEventsHandlerRef.current && state.system_events) {
|
|
1049
|
-
systemEventsHandlerRef.current(backendThreadId, threadId, state.system_events);
|
|
1050
|
-
}
|
|
1345
|
+
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1051
1346
|
if (state.is_processing) {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
}
|
|
1055
|
-
(_b = pollingRef.current) == null ? void 0 : _b.start(threadId);
|
|
1347
|
+
setIsRunning(true);
|
|
1348
|
+
(_d = pollingRef.current) == null ? void 0 : _d.start(threadId);
|
|
1056
1349
|
} else {
|
|
1057
|
-
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1058
|
-
setIsRunning(false);
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
} catch (error) {
|
|
1062
|
-
if (controller.signal.aborted) {
|
|
1063
|
-
return;
|
|
1064
|
-
}
|
|
1065
|
-
console.error("Failed to fetch initial state:", error);
|
|
1066
|
-
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1067
1350
|
setIsRunning(false);
|
|
1068
1351
|
}
|
|
1069
|
-
} finally {
|
|
1070
|
-
if (inFlightRef.current.get(threadId) === controller) {
|
|
1071
|
-
inFlightRef.current.delete(threadId);
|
|
1072
|
-
}
|
|
1073
1352
|
}
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
console.error("Failed to fetch initial state:", error);
|
|
1355
|
+
if (threadContextRef.current.currentThreadId === threadId) {
|
|
1356
|
+
setIsRunning(false);
|
|
1357
|
+
}
|
|
1358
|
+
} finally {
|
|
1359
|
+
pendingFetches.current.delete(threadId);
|
|
1360
|
+
}
|
|
1361
|
+
}, []);
|
|
1077
1362
|
return {
|
|
1078
1363
|
backendStateRef,
|
|
1079
1364
|
polling: pollingRef.current,
|
|
@@ -1081,590 +1366,275 @@ function useRuntimeOrchestrator(backendUrl, options) {
|
|
|
1081
1366
|
isRunning,
|
|
1082
1367
|
setIsRunning,
|
|
1083
1368
|
ensureInitialState,
|
|
1084
|
-
setSystemEventsHandler,
|
|
1085
1369
|
backendApiRef
|
|
1086
1370
|
};
|
|
1087
1371
|
}
|
|
1088
1372
|
|
|
1089
|
-
// src/
|
|
1090
|
-
var
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
function
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
throw new Error("useNotification must be used within NotificationProvider");
|
|
1099
|
-
}
|
|
1100
|
-
return context;
|
|
1101
|
-
}
|
|
1102
|
-
function NotificationProvider({ children }) {
|
|
1103
|
-
const [notifications, setNotifications] = (0, import_react4.useState)([]);
|
|
1104
|
-
const showNotification = (0, import_react4.useCallback)(
|
|
1105
|
-
(notification) => {
|
|
1106
|
-
var _a, _b;
|
|
1107
|
-
const id = `notification-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1108
|
-
const newNotification = __spreadProps(__spreadValues({}, notification), {
|
|
1109
|
-
id,
|
|
1110
|
-
duration: (_a = notification.duration) != null ? _a : 5e3
|
|
1111
|
-
});
|
|
1112
|
-
setNotifications((prev) => [newNotification, ...prev]);
|
|
1113
|
-
const duration = (_b = newNotification.duration) != null ? _b : 5e3;
|
|
1114
|
-
if (duration > 0) {
|
|
1115
|
-
setTimeout(() => {
|
|
1116
|
-
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
|
1117
|
-
}, duration);
|
|
1118
|
-
}
|
|
1119
|
-
},
|
|
1120
|
-
[]
|
|
1373
|
+
// src/runtime/threadlist-adapter.ts
|
|
1374
|
+
var sortByLastActiveDesc = ([, metaA], [, metaB]) => {
|
|
1375
|
+
const tsA = parseTimestamp(metaA.lastActiveAt);
|
|
1376
|
+
const tsB = parseTimestamp(metaB.lastActiveAt);
|
|
1377
|
+
return tsB - tsA;
|
|
1378
|
+
};
|
|
1379
|
+
function buildThreadLists(threadMetadata) {
|
|
1380
|
+
const entries = Array.from(threadMetadata.entries()).filter(
|
|
1381
|
+
([, meta]) => !isPlaceholderTitle(meta.title)
|
|
1121
1382
|
);
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
value: { showNotification, notifications, dismissNotification },
|
|
1129
|
-
children
|
|
1130
|
-
}
|
|
1383
|
+
const regularThreads = entries.filter(([, meta]) => meta.status !== "archived").sort(sortByLastActiveDesc).map(
|
|
1384
|
+
([id, meta]) => ({
|
|
1385
|
+
id,
|
|
1386
|
+
title: meta.title || "New Chat",
|
|
1387
|
+
status: "regular"
|
|
1388
|
+
})
|
|
1131
1389
|
);
|
|
1390
|
+
const archivedThreads = entries.filter(([, meta]) => meta.status === "archived").sort(sortByLastActiveDesc).map(
|
|
1391
|
+
([id, meta]) => ({
|
|
1392
|
+
id,
|
|
1393
|
+
title: meta.title || "New Chat",
|
|
1394
|
+
status: "archived"
|
|
1395
|
+
})
|
|
1396
|
+
);
|
|
1397
|
+
return { regularThreads, archivedThreads };
|
|
1132
1398
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
return "ethereum";
|
|
1142
|
-
case 137:
|
|
1143
|
-
return "polygon";
|
|
1144
|
-
case 42161:
|
|
1145
|
-
return "arbitrum";
|
|
1146
|
-
case 8453:
|
|
1147
|
-
return "base";
|
|
1148
|
-
case 10:
|
|
1149
|
-
return "optimism";
|
|
1150
|
-
case 11155111:
|
|
1151
|
-
return "sepolia";
|
|
1152
|
-
case 1337:
|
|
1153
|
-
case 31337:
|
|
1154
|
-
return "testnet";
|
|
1155
|
-
case 59140:
|
|
1156
|
-
return "linea-sepolia";
|
|
1157
|
-
case 59144:
|
|
1158
|
-
return "linea";
|
|
1159
|
-
default:
|
|
1160
|
-
return "testnet";
|
|
1161
|
-
}
|
|
1162
|
-
};
|
|
1163
|
-
var formatAddress = (addr) => addr ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : "Connect Wallet";
|
|
1164
|
-
function normalizeWalletError(error) {
|
|
1165
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1166
|
-
const e = error;
|
|
1167
|
-
const cause = (_a = e == null ? void 0 : e.cause) != null ? _a : null;
|
|
1168
|
-
const code = (_b = typeof (e == null ? void 0 : e.code) === "number" ? e.code : void 0) != null ? _b : typeof (cause == null ? void 0 : cause.code) === "number" ? cause.code : void 0;
|
|
1169
|
-
const name = (_c = typeof (e == null ? void 0 : e.name) === "string" ? e.name : void 0) != null ? _c : typeof (cause == null ? void 0 : cause.name) === "string" ? cause.name : void 0;
|
|
1170
|
-
const msg = (_g = (_f = (_e = (_d = typeof (e == null ? void 0 : e.shortMessage) === "string" ? e.shortMessage : void 0) != null ? _d : typeof (cause == null ? void 0 : cause.shortMessage) === "string" ? cause.shortMessage : void 0) != null ? _e : typeof (e == null ? void 0 : e.message) === "string" ? e.message : void 0) != null ? _f : typeof (cause == null ? void 0 : cause.message) === "string" ? cause.message : void 0) != null ? _g : "Unknown wallet error";
|
|
1171
|
-
const rejected = code === 4001 || name === "UserRejectedRequestError" || name === "RejectedRequestError" || /user rejected|rejected the request|denied|request rejected|canceled|cancelled/i.test(
|
|
1172
|
-
msg
|
|
1173
|
-
);
|
|
1174
|
-
return { rejected, message: msg };
|
|
1175
|
-
}
|
|
1176
|
-
function toHexQuantity(value) {
|
|
1177
|
-
const trimmed = value.trim();
|
|
1178
|
-
const asBigInt = BigInt(trimmed);
|
|
1179
|
-
return `0x${asBigInt.toString(16)}`;
|
|
1180
|
-
}
|
|
1181
|
-
async function pickInjectedProvider(publicKey) {
|
|
1182
|
-
const ethereum = globalThis.ethereum;
|
|
1183
|
-
if (!(ethereum == null ? void 0 : ethereum.request)) return void 0;
|
|
1184
|
-
const candidates = Array.isArray(ethereum.providers) ? ethereum.providers.filter(
|
|
1185
|
-
(p) => !!(p == null ? void 0 : p.request)
|
|
1186
|
-
) : [ethereum];
|
|
1187
|
-
const target = publicKey == null ? void 0 : publicKey.toLowerCase();
|
|
1188
|
-
if (target) {
|
|
1189
|
-
for (const candidate of candidates) {
|
|
1190
|
-
try {
|
|
1191
|
-
const accounts = await candidate.request({
|
|
1192
|
-
method: "eth_accounts"
|
|
1193
|
-
});
|
|
1194
|
-
const list = Array.isArray(accounts) ? accounts.map((a) => String(a).toLowerCase()) : [];
|
|
1195
|
-
if (list.includes(target)) return candidate;
|
|
1196
|
-
} catch (e) {
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
return candidates[0];
|
|
1201
|
-
}
|
|
1202
|
-
function WalletSystemMessageEmitter({
|
|
1203
|
-
wallet
|
|
1399
|
+
function buildThreadListAdapter({
|
|
1400
|
+
backendStateRef,
|
|
1401
|
+
backendApiRef,
|
|
1402
|
+
threadContext,
|
|
1403
|
+
currentThreadIdRef,
|
|
1404
|
+
polling,
|
|
1405
|
+
userAddress,
|
|
1406
|
+
setIsRunning
|
|
1204
1407
|
}) {
|
|
1205
|
-
const
|
|
1206
|
-
const
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
const
|
|
1211
|
-
if (
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
void sendSystemMessage("Wallet disconnected by user.");
|
|
1225
|
-
console.log("Wallet disconnected by user.");
|
|
1226
|
-
lastWalletRef.current = { isConnected: false };
|
|
1227
|
-
return;
|
|
1408
|
+
const backendState = backendStateRef.current;
|
|
1409
|
+
const { regularThreads, archivedThreads } = buildThreadLists(
|
|
1410
|
+
threadContext.allThreadsMetadata
|
|
1411
|
+
);
|
|
1412
|
+
const preparePendingThread = (threadId) => {
|
|
1413
|
+
const previousPendingId = backendState.creatingThreadId;
|
|
1414
|
+
if (previousPendingId && previousPendingId !== threadId) {
|
|
1415
|
+
threadContext.setThreadMetadata((prev) => {
|
|
1416
|
+
const next = new Map(prev);
|
|
1417
|
+
next.delete(previousPendingId);
|
|
1418
|
+
return next;
|
|
1419
|
+
});
|
|
1420
|
+
threadContext.setThreads((prev) => {
|
|
1421
|
+
const next = new Map(prev);
|
|
1422
|
+
next.delete(previousPendingId);
|
|
1423
|
+
return next;
|
|
1424
|
+
});
|
|
1425
|
+
backendState.pendingChat.delete(previousPendingId);
|
|
1426
|
+
backendState.skipInitialFetch.delete(previousPendingId);
|
|
1228
1427
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1428
|
+
backendState.creatingThreadId = threadId;
|
|
1429
|
+
backendState.pendingChat.delete(threadId);
|
|
1430
|
+
threadContext.setThreadMetadata(
|
|
1431
|
+
(prev) => new Map(prev).set(threadId, {
|
|
1432
|
+
title: "New Chat",
|
|
1433
|
+
status: "pending",
|
|
1434
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1435
|
+
})
|
|
1436
|
+
);
|
|
1437
|
+
threadContext.setThreadMessages(threadId, []);
|
|
1438
|
+
threadContext.setCurrentThreadId(threadId);
|
|
1439
|
+
setIsRunning(false);
|
|
1440
|
+
threadContext.bumpThreadViewKey();
|
|
1441
|
+
};
|
|
1442
|
+
const findPendingThreadId = () => {
|
|
1443
|
+
if (backendState.creatingThreadId) return backendState.creatingThreadId;
|
|
1444
|
+
for (const [id, meta] of threadContext.allThreadsMetadata.entries()) {
|
|
1445
|
+
if (meta.status === "pending") return id;
|
|
1239
1446
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
handleRequest(sessionId, threadId, request) {
|
|
1253
|
-
if (this.config.getCurrentThreadId() !== threadId) return;
|
|
1254
|
-
const description = request.description || request.topic || "Wallet transaction requested";
|
|
1255
|
-
this.config.showNotification({
|
|
1256
|
-
type: "notice",
|
|
1257
|
-
iconType: "wallet",
|
|
1258
|
-
title: "Transaction Request",
|
|
1259
|
-
message: description
|
|
1260
|
-
});
|
|
1261
|
-
this.enqueue(sessionId, threadId, request);
|
|
1262
|
-
void this.drain();
|
|
1263
|
-
}
|
|
1264
|
-
enqueue(sessionId, threadId, request) {
|
|
1265
|
-
var _a;
|
|
1266
|
-
const key = `${sessionId}:${(_a = request.timestamp) != null ? _a : JSON.stringify(request)}`;
|
|
1267
|
-
if (this.handledRequests.has(key)) return;
|
|
1268
|
-
this.handledRequests.add(key);
|
|
1269
|
-
this.queue.push({ sessionId, threadId, request });
|
|
1270
|
-
}
|
|
1271
|
-
async drain() {
|
|
1272
|
-
var _a, _b, _c;
|
|
1273
|
-
if (this.inFlight) return;
|
|
1274
|
-
const next = this.queue.shift();
|
|
1275
|
-
if (!next) return;
|
|
1276
|
-
this.inFlight = true;
|
|
1277
|
-
try {
|
|
1278
|
-
if (this.config.onWalletTxRequest) {
|
|
1279
|
-
const txHash2 = await this.config.onWalletTxRequest(next.request, {
|
|
1280
|
-
sessionId: next.sessionId,
|
|
1281
|
-
threadId: next.threadId,
|
|
1282
|
-
publicKey: this.config.publicKey
|
|
1283
|
-
});
|
|
1284
|
-
this.config.showNotification({
|
|
1285
|
-
type: "success",
|
|
1286
|
-
iconType: "transaction",
|
|
1287
|
-
title: "Transaction Sent",
|
|
1288
|
-
message: `Hash: ${txHash2}`
|
|
1289
|
-
});
|
|
1290
|
-
await this.config.backendApiRef.current.postSystemMessage(
|
|
1291
|
-
next.sessionId,
|
|
1292
|
-
`Transaction sent: ${txHash2}`
|
|
1293
|
-
);
|
|
1294
|
-
await this.refreshThreadIfCurrent(next.sessionId, next.threadId);
|
|
1447
|
+
return null;
|
|
1448
|
+
};
|
|
1449
|
+
return {
|
|
1450
|
+
threadId: threadContext.currentThreadId,
|
|
1451
|
+
threads: regularThreads,
|
|
1452
|
+
archivedThreads,
|
|
1453
|
+
onSwitchToNewThread: async () => {
|
|
1454
|
+
var _a;
|
|
1455
|
+
const pendingId = findPendingThreadId();
|
|
1456
|
+
if (pendingId) {
|
|
1457
|
+
preparePendingThread(pendingId);
|
|
1295
1458
|
return;
|
|
1296
1459
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
type: "error",
|
|
1301
|
-
iconType: "wallet",
|
|
1302
|
-
title: "Wallet Not Found",
|
|
1303
|
-
message: "No wallet provider found (window.ethereum missing)."
|
|
1304
|
-
});
|
|
1305
|
-
await this.config.backendApiRef.current.postSystemMessage(
|
|
1306
|
-
next.sessionId,
|
|
1307
|
-
"No wallet provider found (window.ethereum missing)."
|
|
1460
|
+
if (backendState.createThreadPromise) {
|
|
1461
|
+
preparePendingThread(
|
|
1462
|
+
(_a = backendState.creatingThreadId) != null ? _a : crypto.randomUUID()
|
|
1308
1463
|
);
|
|
1309
1464
|
return;
|
|
1310
1465
|
}
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1466
|
+
const threadId = crypto.randomUUID();
|
|
1467
|
+
preparePendingThread(threadId);
|
|
1468
|
+
const createPromise = backendApiRef.current.createThread(threadId, userAddress).then(async (newThread) => {
|
|
1469
|
+
var _a2;
|
|
1470
|
+
const uiThreadId = (_a2 = backendState.creatingThreadId) != null ? _a2 : threadId;
|
|
1471
|
+
const backendId = newThread.session_id;
|
|
1472
|
+
if (uiThreadId !== backendId) {
|
|
1473
|
+
console.warn("[aomi][thread] backend id mismatch", {
|
|
1474
|
+
uiThreadId,
|
|
1475
|
+
backendId
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
markSkipInitialFetch(backendState, uiThreadId);
|
|
1479
|
+
threadContext.setThreadMetadata((prev) => {
|
|
1480
|
+
var _a3, _b;
|
|
1481
|
+
const next = new Map(prev);
|
|
1482
|
+
const existing = next.get(uiThreadId);
|
|
1483
|
+
const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
|
|
1484
|
+
next.set(uiThreadId, {
|
|
1485
|
+
title: (_a3 = existing == null ? void 0 : existing.title) != null ? _a3 : "New Chat",
|
|
1486
|
+
status: nextStatus,
|
|
1487
|
+
lastActiveAt: (_b = existing == null ? void 0 : existing.lastActiveAt) != null ? _b : (/* @__PURE__ */ new Date()).toISOString()
|
|
1488
|
+
});
|
|
1489
|
+
return next;
|
|
1327
1490
|
});
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
);
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1491
|
+
if (backendState.creatingThreadId === uiThreadId) {
|
|
1492
|
+
backendState.creatingThreadId = null;
|
|
1493
|
+
}
|
|
1494
|
+
const pendingMessages = backendState.pendingChat.get(uiThreadId);
|
|
1495
|
+
if (pendingMessages == null ? void 0 : pendingMessages.length) {
|
|
1496
|
+
backendState.pendingChat.delete(uiThreadId);
|
|
1497
|
+
for (const text of pendingMessages) {
|
|
1498
|
+
try {
|
|
1499
|
+
await backendApiRef.current.postChatMessage(backendId, text);
|
|
1500
|
+
} catch (error) {
|
|
1501
|
+
console.error("Failed to send queued message:", error);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
if (currentThreadIdRef.current === uiThreadId) {
|
|
1505
|
+
polling == null ? void 0 : polling.start(uiThreadId);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}).catch((error) => {
|
|
1509
|
+
var _a2;
|
|
1510
|
+
console.error("Failed to create new thread:", error);
|
|
1511
|
+
const failedId = (_a2 = backendState.creatingThreadId) != null ? _a2 : threadId;
|
|
1512
|
+
threadContext.setThreadMetadata((prev) => {
|
|
1513
|
+
const next = new Map(prev);
|
|
1514
|
+
next.delete(failedId);
|
|
1515
|
+
return next;
|
|
1516
|
+
});
|
|
1517
|
+
threadContext.setThreads((prev) => {
|
|
1518
|
+
const next = new Map(prev);
|
|
1519
|
+
next.delete(failedId);
|
|
1520
|
+
return next;
|
|
1521
|
+
});
|
|
1522
|
+
if (backendState.creatingThreadId === failedId) {
|
|
1523
|
+
backendState.creatingThreadId = null;
|
|
1524
|
+
}
|
|
1525
|
+
}).finally(() => {
|
|
1526
|
+
backendState.createThreadPromise = null;
|
|
1527
|
+
});
|
|
1528
|
+
backendState.createThreadPromise = createPromise;
|
|
1529
|
+
},
|
|
1530
|
+
onSwitchToThread: (threadId) => {
|
|
1531
|
+
threadContext.setCurrentThreadId(threadId);
|
|
1532
|
+
},
|
|
1533
|
+
onRename: async (threadId, newTitle) => {
|
|
1534
|
+
var _a, _b;
|
|
1535
|
+
const previousTitle = (_b = (_a = threadContext.getThreadMetadata(threadId)) == null ? void 0 : _a.title) != null ? _b : "";
|
|
1536
|
+
const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
|
|
1537
|
+
threadContext.updateThreadMetadata(threadId, {
|
|
1538
|
+
title: normalizedTitle
|
|
1539
|
+
});
|
|
1337
1540
|
try {
|
|
1338
|
-
|
|
1339
|
-
if (gas) gasHex = toHexQuantity(gas);
|
|
1541
|
+
await backendApiRef.current.renameThread(threadId, newTitle);
|
|
1340
1542
|
} catch (error) {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
title: "Invalid Transaction",
|
|
1345
|
-
message: error.message
|
|
1543
|
+
console.error("Failed to rename thread:", error);
|
|
1544
|
+
threadContext.updateThreadMetadata(threadId, {
|
|
1545
|
+
title: previousTitle
|
|
1346
1546
|
});
|
|
1347
|
-
await this.config.backendApiRef.current.postSystemMessage(
|
|
1348
|
-
next.sessionId,
|
|
1349
|
-
`Invalid wallet transaction request payload: ${error.message}`
|
|
1350
|
-
);
|
|
1351
|
-
return;
|
|
1352
1547
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
value: valueHex,
|
|
1357
|
-
data: next.request.data
|
|
1358
|
-
}, gasHex ? { gas: gasHex } : {});
|
|
1359
|
-
const txHash = await activeProvider.request({
|
|
1360
|
-
method: "eth_sendTransaction",
|
|
1361
|
-
params: [txParams]
|
|
1362
|
-
});
|
|
1363
|
-
this.config.showNotification({
|
|
1364
|
-
type: "success",
|
|
1365
|
-
title: "Transaction sent",
|
|
1366
|
-
message: `Transaction hash: ${txHash}`
|
|
1367
|
-
});
|
|
1368
|
-
await this.config.backendApiRef.current.postSystemMessage(
|
|
1369
|
-
next.sessionId,
|
|
1370
|
-
`Transaction sent: ${txHash}`
|
|
1371
|
-
);
|
|
1372
|
-
await this.refreshThreadIfCurrent(next.sessionId, next.threadId);
|
|
1373
|
-
} catch (error) {
|
|
1374
|
-
const normalized = normalizeWalletError(error);
|
|
1375
|
-
const final = normalized.rejected ? "Transaction rejected by user." : `Transaction failed: ${normalized.message}`;
|
|
1376
|
-
this.config.showNotification({
|
|
1377
|
-
type: normalized.rejected ? "notice" : "error",
|
|
1378
|
-
iconType: normalized.rejected ? "transaction" : "error",
|
|
1379
|
-
title: normalized.rejected ? "Transaction Rejected" : "Transaction Failed",
|
|
1380
|
-
message: normalized.rejected ? "Transaction was rejected by user." : normalized.message
|
|
1381
|
-
});
|
|
1548
|
+
},
|
|
1549
|
+
onArchive: async (threadId) => {
|
|
1550
|
+
threadContext.updateThreadMetadata(threadId, { status: "archived" });
|
|
1382
1551
|
try {
|
|
1383
|
-
await
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
);
|
|
1387
|
-
await this.refreshThreadIfCurrent(next.sessionId, next.threadId);
|
|
1388
|
-
} catch (postError) {
|
|
1389
|
-
console.error("Failed to report wallet tx result to backend:", postError);
|
|
1552
|
+
await backendApiRef.current.archiveThread(threadId);
|
|
1553
|
+
} catch (error) {
|
|
1554
|
+
console.error("Failed to archive thread:", error);
|
|
1555
|
+
threadContext.updateThreadMetadata(threadId, { status: "regular" });
|
|
1390
1556
|
}
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
const state = await this.config.backendApiRef.current.fetchState(sessionId);
|
|
1400
|
-
this.config.applySessionMessagesToThread(threadId, state.messages);
|
|
1401
|
-
} catch (refreshError) {
|
|
1402
|
-
console.error("Failed to refresh state after wallet tx:", refreshError);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
};
|
|
1406
|
-
|
|
1407
|
-
// src/runtime/event-controller.ts
|
|
1408
|
-
var EventController = class {
|
|
1409
|
-
constructor(config) {
|
|
1410
|
-
this.config = config;
|
|
1411
|
-
this.lastEventIdBySession = /* @__PURE__ */ new Map();
|
|
1412
|
-
this.eventsInFlight = /* @__PURE__ */ new Set();
|
|
1413
|
-
this.updateSubscriptions = /* @__PURE__ */ new Map();
|
|
1414
|
-
this.subscribableSessionId = null;
|
|
1415
|
-
}
|
|
1416
|
-
setSubscribableSessionId(sessionId) {
|
|
1417
|
-
console.log("\u{1F514} [updates] setSubscribableSessionId", { sessionId });
|
|
1418
|
-
this.subscribableSessionId = sessionId;
|
|
1419
|
-
this.syncSubscriptions();
|
|
1420
|
-
}
|
|
1421
|
-
syncSubscriptions() {
|
|
1422
|
-
console.log("\u{1F514} [updates] syncSubscriptions", {
|
|
1423
|
-
subscribableSessionId: this.subscribableSessionId,
|
|
1424
|
-
active: Array.from(this.updateSubscriptions.keys())
|
|
1425
|
-
});
|
|
1426
|
-
const nextSessions = /* @__PURE__ */ new Set();
|
|
1427
|
-
if (this.subscribableSessionId) {
|
|
1428
|
-
nextSessions.add(this.subscribableSessionId);
|
|
1429
|
-
}
|
|
1430
|
-
for (const sessionId of this.updateSubscriptions.keys()) {
|
|
1431
|
-
if (!nextSessions.has(sessionId)) {
|
|
1432
|
-
this.removeSubscription(sessionId);
|
|
1557
|
+
},
|
|
1558
|
+
onUnarchive: async (threadId) => {
|
|
1559
|
+
threadContext.updateThreadMetadata(threadId, { status: "regular" });
|
|
1560
|
+
try {
|
|
1561
|
+
await backendApiRef.current.unarchiveThread(threadId);
|
|
1562
|
+
} catch (error) {
|
|
1563
|
+
console.error("Failed to unarchive thread:", error);
|
|
1564
|
+
threadContext.updateThreadMetadata(threadId, { status: "archived" });
|
|
1433
1565
|
}
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
const unsubscribe = this.config.backendApiRef.current.subscribeToUpdates(
|
|
1443
|
-
sessionId,
|
|
1444
|
-
(update) => {
|
|
1445
|
-
console.log("\u{1F514} [updates] event_available", {
|
|
1446
|
-
sessionId: update.session_id,
|
|
1447
|
-
eventId: update.event_id,
|
|
1448
|
-
eventType: update.event_type
|
|
1566
|
+
},
|
|
1567
|
+
onDelete: async (threadId) => {
|
|
1568
|
+
try {
|
|
1569
|
+
await backendApiRef.current.deleteThread(threadId);
|
|
1570
|
+
threadContext.setThreadMetadata((prev) => {
|
|
1571
|
+
const next = new Map(prev);
|
|
1572
|
+
next.delete(threadId);
|
|
1573
|
+
return next;
|
|
1449
1574
|
});
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
console.error("Failed to handle system update SSE:", error);
|
|
1455
|
-
}
|
|
1456
|
-
);
|
|
1457
|
-
this.updateSubscriptions.set(sessionId, unsubscribe);
|
|
1458
|
-
}
|
|
1459
|
-
removeSubscription(sessionId) {
|
|
1460
|
-
const unsubscribe = this.updateSubscriptions.get(sessionId);
|
|
1461
|
-
if (!unsubscribe) return;
|
|
1462
|
-
unsubscribe();
|
|
1463
|
-
this.updateSubscriptions.delete(sessionId);
|
|
1464
|
-
}
|
|
1465
|
-
async drainEvents(sessionId) {
|
|
1466
|
-
var _a;
|
|
1467
|
-
if (this.eventsInFlight.has(sessionId)) {
|
|
1468
|
-
console.log("\u23F3 [events] drain already in flight", { sessionId });
|
|
1469
|
-
return;
|
|
1470
|
-
}
|
|
1471
|
-
this.eventsInFlight.add(sessionId);
|
|
1472
|
-
try {
|
|
1473
|
-
let afterId = (_a = this.lastEventIdBySession.get(sessionId)) != null ? _a : 0;
|
|
1474
|
-
console.log("\u{1F4E5} [events] start drain", { sessionId, afterId });
|
|
1475
|
-
for (; ; ) {
|
|
1476
|
-
const requestAfterId = afterId;
|
|
1477
|
-
const events = await this.config.backendApiRef.current.fetchEventsAfter(
|
|
1478
|
-
sessionId,
|
|
1479
|
-
requestAfterId,
|
|
1480
|
-
200
|
|
1481
|
-
);
|
|
1482
|
-
console.log("\u{1F4E5} [events] fetched batch", {
|
|
1483
|
-
sessionId,
|
|
1484
|
-
afterId: requestAfterId,
|
|
1485
|
-
count: events.length
|
|
1575
|
+
threadContext.setThreads((prev) => {
|
|
1576
|
+
const next = new Map(prev);
|
|
1577
|
+
next.delete(threadId);
|
|
1578
|
+
return next;
|
|
1486
1579
|
});
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
console.log("\u{1F3F7}\uFE0F [events] title_changed", {
|
|
1493
|
-
sessionId,
|
|
1494
|
-
eventId,
|
|
1495
|
-
newTitle: event.new_title
|
|
1496
|
-
});
|
|
1497
|
-
this.applyTitleChanged(sessionId, event.new_title);
|
|
1498
|
-
}
|
|
1499
|
-
if (event.type === "wallet_tx_request") {
|
|
1500
|
-
const payload = event.payload;
|
|
1501
|
-
if (payload && typeof payload === "object") {
|
|
1502
|
-
const req = payload;
|
|
1503
|
-
if (typeof req.to === "string" && typeof req.value === "string" && typeof req.data === "string") {
|
|
1504
|
-
const threadId = findTempIdForBackendId(
|
|
1505
|
-
this.config.backendStateRef.current,
|
|
1506
|
-
sessionId
|
|
1507
|
-
) || sessionId;
|
|
1508
|
-
this.config.handleWalletTxRequest(
|
|
1509
|
-
sessionId,
|
|
1510
|
-
threadId,
|
|
1511
|
-
req
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1580
|
+
backendState.pendingChat.delete(threadId);
|
|
1581
|
+
backendState.skipInitialFetch.delete(threadId);
|
|
1582
|
+
backendState.runningThreads.delete(threadId);
|
|
1583
|
+
if (backendState.creatingThreadId === threadId) {
|
|
1584
|
+
backendState.creatingThreadId = null;
|
|
1516
1585
|
}
|
|
1517
|
-
if (
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
});
|
|
1536
|
-
this.config.setThreadMetadata((prev) => {
|
|
1537
|
-
var _a;
|
|
1538
|
-
const next = new Map(prev);
|
|
1539
|
-
const existing = next.get(threadIdToUpdate);
|
|
1540
|
-
const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
|
|
1541
|
-
const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
|
|
1542
|
-
next.set(threadIdToUpdate, {
|
|
1543
|
-
title: normalizedTitle,
|
|
1544
|
-
status: nextStatus,
|
|
1545
|
-
lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString()
|
|
1546
|
-
});
|
|
1547
|
-
return next;
|
|
1548
|
-
});
|
|
1549
|
-
if (!isPlaceholderTitle(newTitle) && backendState.creatingThreadId === threadIdToUpdate) {
|
|
1550
|
-
backendState.creatingThreadId = null;
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
handleBackendSystemEvents(sessionId, threadId, rawEvents) {
|
|
1554
|
-
if (!(rawEvents == null ? void 0 : rawEvents.length)) return;
|
|
1555
|
-
for (const raw of rawEvents) {
|
|
1556
|
-
const parsed = this.parseBackendSystemEvent(raw);
|
|
1557
|
-
if (!parsed) continue;
|
|
1558
|
-
if ("InlineDisplay" in parsed) {
|
|
1559
|
-
const payload = parsed.InlineDisplay;
|
|
1560
|
-
if (!payload || typeof payload !== "object") continue;
|
|
1561
|
-
const type = payload.type;
|
|
1562
|
-
if (type !== "wallet_tx_request") continue;
|
|
1563
|
-
const requestValue = payload.payload;
|
|
1564
|
-
if (!requestValue || typeof requestValue !== "object") continue;
|
|
1565
|
-
const req = requestValue;
|
|
1566
|
-
if (typeof req.to !== "string" || typeof req.value !== "string" || typeof req.data !== "string") {
|
|
1567
|
-
continue;
|
|
1586
|
+
if (threadContext.currentThreadId === threadId) {
|
|
1587
|
+
const firstRegularThread = Array.from(
|
|
1588
|
+
threadContext.allThreadsMetadata.entries()
|
|
1589
|
+
).find(([id, meta]) => meta.status === "regular" && id !== threadId);
|
|
1590
|
+
if (firstRegularThread) {
|
|
1591
|
+
threadContext.setCurrentThreadId(firstRegularThread[0]);
|
|
1592
|
+
} else {
|
|
1593
|
+
const defaultId = "default-session";
|
|
1594
|
+
threadContext.setThreadMetadata(
|
|
1595
|
+
(prev) => new Map(prev).set(defaultId, {
|
|
1596
|
+
title: "New Chat",
|
|
1597
|
+
status: "regular",
|
|
1598
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1599
|
+
})
|
|
1600
|
+
);
|
|
1601
|
+
threadContext.setThreadMessages(defaultId, []);
|
|
1602
|
+
threadContext.setCurrentThreadId(defaultId);
|
|
1603
|
+
}
|
|
1568
1604
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
req
|
|
1573
|
-
);
|
|
1574
|
-
}
|
|
1575
|
-
if ("SystemError" in parsed) {
|
|
1576
|
-
this.config.showNotification({
|
|
1577
|
-
type: "error",
|
|
1578
|
-
iconType: "error",
|
|
1579
|
-
title: "Error",
|
|
1580
|
-
message: parsed.SystemError
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1583
|
-
if ("SystemNotice" in parsed) {
|
|
1584
|
-
this.config.showNotification({
|
|
1585
|
-
type: "notice",
|
|
1586
|
-
iconType: "notice",
|
|
1587
|
-
title: "Notice",
|
|
1588
|
-
message: parsed.SystemNotice
|
|
1589
|
-
});
|
|
1605
|
+
} catch (error) {
|
|
1606
|
+
console.error("Failed to delete thread:", error);
|
|
1607
|
+
throw error;
|
|
1590
1608
|
}
|
|
1591
1609
|
}
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
if (!value || typeof value !== "object") return null;
|
|
1595
|
-
const entries = Object.entries(value);
|
|
1596
|
-
if (entries.length !== 1) return null;
|
|
1597
|
-
const [key, payload] = entries[0];
|
|
1598
|
-
switch (key) {
|
|
1599
|
-
case "InlineDisplay":
|
|
1600
|
-
return { InlineDisplay: payload };
|
|
1601
|
-
case "SystemNotice":
|
|
1602
|
-
return {
|
|
1603
|
-
SystemNotice: typeof payload === "string" ? payload : String(payload)
|
|
1604
|
-
};
|
|
1605
|
-
case "SystemError":
|
|
1606
|
-
return {
|
|
1607
|
-
SystemError: typeof payload === "string" ? payload : String(payload)
|
|
1608
|
-
};
|
|
1609
|
-
case "AsyncUpdate":
|
|
1610
|
-
return { AsyncUpdate: payload };
|
|
1611
|
-
default:
|
|
1612
|
-
return null;
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
cleanup() {
|
|
1616
|
-
for (const unsubscribe of this.updateSubscriptions.values()) {
|
|
1617
|
-
unsubscribe();
|
|
1618
|
-
}
|
|
1619
|
-
this.updateSubscriptions.clear();
|
|
1620
|
-
}
|
|
1621
|
-
};
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1622
1612
|
|
|
1623
|
-
// src/
|
|
1624
|
-
var
|
|
1625
|
-
var
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
id,
|
|
1636
|
-
title: meta.title || "New Chat",
|
|
1637
|
-
status: "regular"
|
|
1638
|
-
}));
|
|
1639
|
-
const archivedThreads = entries.filter(([, meta]) => meta.status === "archived").sort(sortByLastActiveDesc).map(([id, meta]) => ({
|
|
1640
|
-
id,
|
|
1641
|
-
title: meta.title || "New Chat",
|
|
1642
|
-
status: "archived"
|
|
1643
|
-
}));
|
|
1644
|
-
return { regularThreads, archivedThreads };
|
|
1613
|
+
// src/interface.tsx
|
|
1614
|
+
var import_react6 = require("react");
|
|
1615
|
+
var AomiRuntimeContext = (0, import_react6.createContext)(null);
|
|
1616
|
+
var AomiRuntimeApiProvider = AomiRuntimeContext.Provider;
|
|
1617
|
+
function useAomiRuntime() {
|
|
1618
|
+
const context = (0, import_react6.useContext)(AomiRuntimeContext);
|
|
1619
|
+
if (!context) {
|
|
1620
|
+
throw new Error(
|
|
1621
|
+
"useAomiRuntime must be used within AomiRuntimeProvider. Wrap your app with <AomiRuntimeProvider>...</AomiRuntimeProvider>"
|
|
1622
|
+
);
|
|
1623
|
+
}
|
|
1624
|
+
return context;
|
|
1645
1625
|
}
|
|
1646
|
-
|
|
1626
|
+
|
|
1627
|
+
// src/runtime/core.tsx
|
|
1628
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1629
|
+
function AomiRuntimeCore({
|
|
1647
1630
|
children,
|
|
1648
|
-
|
|
1649
|
-
publicKey,
|
|
1650
|
-
onWalletTxRequest
|
|
1631
|
+
backendApi
|
|
1651
1632
|
}) {
|
|
1652
1633
|
const threadContext = useThreadContext();
|
|
1653
|
-
const
|
|
1654
|
-
|
|
1655
|
-
const
|
|
1656
|
-
|
|
1657
|
-
currentThreadIdRef.current = threadContext.currentThreadId;
|
|
1658
|
-
}, [threadContext.currentThreadId]);
|
|
1659
|
-
const publicKeyRef = (0, import_react6.useRef)(publicKey);
|
|
1660
|
-
(0, import_react6.useEffect)(() => {
|
|
1661
|
-
publicKeyRef.current = publicKey;
|
|
1662
|
-
}, [publicKey]);
|
|
1663
|
-
const getPublicKey = (0, import_react6.useCallback)(() => publicKeyRef.current, []);
|
|
1664
|
-
const lastSubscribedThreadRef = (0, import_react6.useRef)(null);
|
|
1665
|
-
const { showNotification } = useNotification();
|
|
1666
|
-
const eventControllerRef = (0, import_react6.useRef)(null);
|
|
1667
|
-
const walletHandlerRef = (0, import_react6.useRef)(null);
|
|
1634
|
+
const eventContext = useEventContext();
|
|
1635
|
+
const notificationContext = useNotification();
|
|
1636
|
+
const { dispatchInboundSystem: dispatchSystemEvents } = eventContext;
|
|
1637
|
+
const { user, onUserStateChange, getUserState } = useUser();
|
|
1668
1638
|
const {
|
|
1669
1639
|
backendStateRef,
|
|
1670
1640
|
polling,
|
|
@@ -1672,72 +1642,66 @@ function AomiRuntimeProvider({
|
|
|
1672
1642
|
isRunning,
|
|
1673
1643
|
setIsRunning,
|
|
1674
1644
|
ensureInitialState,
|
|
1675
|
-
setSystemEventsHandler,
|
|
1676
1645
|
backendApiRef
|
|
1677
|
-
} = useRuntimeOrchestrator(
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
handleWalletTxRequest: (sessionId, threadId, request) => {
|
|
1696
|
-
var _a;
|
|
1697
|
-
(_a = walletHandlerRef.current) == null ? void 0 : _a.handleRequest(sessionId, threadId, request);
|
|
1698
|
-
},
|
|
1699
|
-
setThreadMetadata: threadContext.setThreadMetadata
|
|
1646
|
+
} = useRuntimeOrchestrator(backendApi, {
|
|
1647
|
+
onSyncEvents: dispatchSystemEvents,
|
|
1648
|
+
getPublicKey: () => getUserState().address,
|
|
1649
|
+
getUserState
|
|
1650
|
+
});
|
|
1651
|
+
(0, import_react7.useEffect)(() => {
|
|
1652
|
+
const unsubscribe = onUserStateChange(async (newUser) => {
|
|
1653
|
+
const sessionId = threadContext.currentThreadId;
|
|
1654
|
+
const message = JSON.stringify({
|
|
1655
|
+
type: "wallet:state_changed",
|
|
1656
|
+
payload: {
|
|
1657
|
+
address: newUser.address,
|
|
1658
|
+
chainId: newUser.chainId,
|
|
1659
|
+
isConnected: newUser.isConnected,
|
|
1660
|
+
ensName: newUser.ensName
|
|
1661
|
+
}
|
|
1662
|
+
});
|
|
1663
|
+
await backendApiRef.current.postSystemMessage(sessionId, message);
|
|
1700
1664
|
});
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
);
|
|
1709
|
-
(0,
|
|
1710
|
-
setSystemEventsHandler(handleSystemEvents);
|
|
1711
|
-
return () => {
|
|
1712
|
-
setSystemEventsHandler(null);
|
|
1713
|
-
};
|
|
1714
|
-
}, [handleSystemEvents, setSystemEventsHandler]);
|
|
1715
|
-
const [updateSubscriptionsTick, setUpdateSubscriptionsTick] = (0, import_react6.useState)(0);
|
|
1716
|
-
const bumpUpdateSubscriptions = (0, import_react6.useCallback)(() => {
|
|
1717
|
-
setUpdateSubscriptionsTick((prev) => prev + 1);
|
|
1718
|
-
}, []);
|
|
1719
|
-
(0, import_react6.useEffect)(() => {
|
|
1665
|
+
return unsubscribe;
|
|
1666
|
+
}, [onUserStateChange, backendApiRef, threadContext.currentThreadId]);
|
|
1667
|
+
const threadContextRef = (0, import_react7.useRef)(threadContext);
|
|
1668
|
+
threadContextRef.current = threadContext;
|
|
1669
|
+
const currentThreadIdRef = (0, import_react7.useRef)(threadContext.currentThreadId);
|
|
1670
|
+
(0, import_react7.useEffect)(() => {
|
|
1671
|
+
currentThreadIdRef.current = threadContext.currentThreadId;
|
|
1672
|
+
}, [threadContext.currentThreadId]);
|
|
1673
|
+
(0, import_react7.useEffect)(() => {
|
|
1720
1674
|
void ensureInitialState(threadContext.currentThreadId);
|
|
1721
1675
|
}, [ensureInitialState, threadContext.currentThreadId]);
|
|
1722
|
-
(0,
|
|
1676
|
+
(0, import_react7.useEffect)(() => {
|
|
1723
1677
|
const threadId = threadContext.currentThreadId;
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1678
|
+
setIsRunning(isThreadRunning(backendStateRef.current, threadId));
|
|
1679
|
+
}, [backendStateRef, setIsRunning, threadContext.currentThreadId]);
|
|
1680
|
+
const currentMessages = threadContext.getThreadMessages(
|
|
1681
|
+
threadContext.currentThreadId
|
|
1682
|
+
);
|
|
1683
|
+
const resolvedSessionId = (0, import_react7.useMemo)(
|
|
1684
|
+
() => resolveThreadId(backendStateRef.current, threadContext.currentThreadId),
|
|
1685
|
+
[
|
|
1686
|
+
backendStateRef,
|
|
1687
|
+
threadContext.currentThreadId,
|
|
1688
|
+
threadContext.allThreadsMetadata
|
|
1689
|
+
]
|
|
1690
|
+
);
|
|
1691
|
+
(0, import_react7.useEffect)(() => {
|
|
1692
|
+
const userAddress = user.address;
|
|
1693
|
+
if (!userAddress) return;
|
|
1730
1694
|
const fetchThreadList = async () => {
|
|
1731
1695
|
var _a, _b;
|
|
1732
1696
|
try {
|
|
1733
|
-
const threadList = await backendApiRef.current.fetchThreads(
|
|
1697
|
+
const threadList = await backendApiRef.current.fetchThreads(userAddress);
|
|
1734
1698
|
const currentContext = threadContextRef.current;
|
|
1735
|
-
const newMetadata = new Map(currentContext.
|
|
1699
|
+
const newMetadata = new Map(currentContext.allThreadsMetadata);
|
|
1736
1700
|
let maxChatNum = currentContext.threadCnt;
|
|
1737
1701
|
for (const thread of threadList) {
|
|
1738
1702
|
const rawTitle = (_a = thread.title) != null ? _a : "";
|
|
1739
1703
|
const title = isPlaceholderTitle(rawTitle) ? "" : rawTitle;
|
|
1740
|
-
const lastActive =
|
|
1704
|
+
const lastActive = ((_b = newMetadata.get(thread.session_id)) == null ? void 0 : _b.lastActiveAt) || (/* @__PURE__ */ new Date()).toISOString();
|
|
1741
1705
|
newMetadata.set(thread.session_id, {
|
|
1742
1706
|
title,
|
|
1743
1707
|
status: thread.is_archived ? "archived" : "regular",
|
|
@@ -1760,248 +1724,128 @@ function AomiRuntimeProvider({
|
|
|
1760
1724
|
}
|
|
1761
1725
|
};
|
|
1762
1726
|
void fetchThreadList();
|
|
1763
|
-
}, [
|
|
1764
|
-
const threadListAdapter = (0,
|
|
1727
|
+
}, [user.address, backendApiRef]);
|
|
1728
|
+
const threadListAdapter = (0, import_react7.useMemo)(
|
|
1729
|
+
() => buildThreadListAdapter({
|
|
1730
|
+
backendStateRef,
|
|
1731
|
+
backendApiRef,
|
|
1732
|
+
threadContext,
|
|
1733
|
+
currentThreadIdRef,
|
|
1734
|
+
polling,
|
|
1735
|
+
userAddress: user.address,
|
|
1736
|
+
setIsRunning
|
|
1737
|
+
}),
|
|
1738
|
+
[
|
|
1739
|
+
backendApiRef,
|
|
1740
|
+
polling,
|
|
1741
|
+
user.address,
|
|
1742
|
+
backendStateRef,
|
|
1743
|
+
setIsRunning,
|
|
1744
|
+
threadContext,
|
|
1745
|
+
threadContext.currentThreadId,
|
|
1746
|
+
threadContext.allThreadsMetadata
|
|
1747
|
+
]
|
|
1748
|
+
);
|
|
1749
|
+
(0, import_react7.useEffect)(() => {
|
|
1765
1750
|
const backendState = backendStateRef.current;
|
|
1766
|
-
const
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1793
|
-
})
|
|
1794
|
-
);
|
|
1795
|
-
threadContext.setThreadMessages(threadId, []);
|
|
1796
|
-
threadContext.setCurrentThreadId(threadId);
|
|
1797
|
-
setIsRunning(false);
|
|
1798
|
-
threadContext.bumpThreadViewKey();
|
|
1799
|
-
};
|
|
1800
|
-
const findPendingThreadId = () => {
|
|
1801
|
-
if (backendState.creatingThreadId) return backendState.creatingThreadId;
|
|
1802
|
-
for (const [id, meta] of threadContext.threadMetadata.entries()) {
|
|
1803
|
-
if (meta.status === "pending") return id;
|
|
1804
|
-
}
|
|
1805
|
-
return null;
|
|
1806
|
-
};
|
|
1807
|
-
return {
|
|
1808
|
-
threadId: threadContext.currentThreadId,
|
|
1809
|
-
threads: regularThreads,
|
|
1810
|
-
archivedThreads,
|
|
1811
|
-
onSwitchToNewThread: async () => {
|
|
1812
|
-
var _a;
|
|
1813
|
-
const previousThreadId = currentThreadIdRef.current;
|
|
1814
|
-
polling.stopAll();
|
|
1815
|
-
if (isRunning && isThreadReady(backendState, previousThreadId)) {
|
|
1816
|
-
const backendId = resolveThreadId(backendState, previousThreadId);
|
|
1817
|
-
void backendApiRef.current.postInterrupt(backendId);
|
|
1818
|
-
}
|
|
1819
|
-
const pendingId = findPendingThreadId();
|
|
1820
|
-
if (pendingId) {
|
|
1821
|
-
preparePendingThread(pendingId);
|
|
1822
|
-
return;
|
|
1823
|
-
}
|
|
1824
|
-
if (backendState.createThreadPromise) {
|
|
1825
|
-
preparePendingThread((_a = backendState.creatingThreadId) != null ? _a : `temp-${crypto.randomUUID()}`);
|
|
1826
|
-
return;
|
|
1827
|
-
}
|
|
1828
|
-
const tempId = `temp-${crypto.randomUUID()}`;
|
|
1829
|
-
preparePendingThread(tempId);
|
|
1830
|
-
const createPromise = backendApiRef.current.createThread(publicKey, void 0).then(async (newThread) => {
|
|
1831
|
-
var _a2;
|
|
1832
|
-
const uiThreadId = (_a2 = backendState.creatingThreadId) != null ? _a2 : tempId;
|
|
1833
|
-
const backendId = newThread.session_id;
|
|
1834
|
-
setBackendMapping(backendState, uiThreadId, backendId);
|
|
1835
|
-
markSkipInitialFetch(backendState, uiThreadId);
|
|
1836
|
-
bumpUpdateSubscriptions();
|
|
1837
|
-
const backendTitle = newThread.title;
|
|
1838
|
-
if (backendTitle && !isPlaceholderTitle(backendTitle)) {
|
|
1839
|
-
threadContext.setThreadMetadata((prev) => {
|
|
1840
|
-
var _a3;
|
|
1841
|
-
const next = new Map(prev);
|
|
1842
|
-
const existing = next.get(uiThreadId);
|
|
1843
|
-
const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
|
|
1844
|
-
next.set(uiThreadId, {
|
|
1845
|
-
title: backendTitle,
|
|
1846
|
-
status: nextStatus,
|
|
1847
|
-
lastActiveAt: (_a3 = existing == null ? void 0 : existing.lastActiveAt) != null ? _a3 : (/* @__PURE__ */ new Date()).toISOString()
|
|
1848
|
-
});
|
|
1849
|
-
return next;
|
|
1751
|
+
const currentSessionId = threadContext.currentThreadId;
|
|
1752
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1753
|
+
console.debug("[aomi][sse] subscribe", {
|
|
1754
|
+
currentSessionId,
|
|
1755
|
+
resolvedSessionId,
|
|
1756
|
+
hasMapping: currentSessionId !== resolvedSessionId
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
const unsubscribe = backendApiRef.current.subscribeSSE(
|
|
1760
|
+
resolvedSessionId,
|
|
1761
|
+
(event) => {
|
|
1762
|
+
const eventType = event.type;
|
|
1763
|
+
const sessionId = event.session_id;
|
|
1764
|
+
if (eventType === "title_changed") {
|
|
1765
|
+
const newTitle = event.new_title;
|
|
1766
|
+
const targetThreadId = resolveThreadId(backendState, sessionId);
|
|
1767
|
+
const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
|
|
1768
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1769
|
+
console.debug("[aomi][sse] title_changed", {
|
|
1770
|
+
sessionId,
|
|
1771
|
+
newTitle,
|
|
1772
|
+
normalizedTitle,
|
|
1773
|
+
currentThreadId: threadContextRef.current.currentThreadId,
|
|
1774
|
+
targetThreadId,
|
|
1775
|
+
hasMapping: sessionId !== targetThreadId,
|
|
1776
|
+
creatingThreadId: backendState.creatingThreadId
|
|
1850
1777
|
});
|
|
1851
1778
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
}
|
|
1855
|
-
const pendingMessages = backendState.pendingChat.get(uiThreadId);
|
|
1856
|
-
if (pendingMessages == null ? void 0 : pendingMessages.length) {
|
|
1857
|
-
backendState.pendingChat.delete(uiThreadId);
|
|
1858
|
-
for (const text of pendingMessages) {
|
|
1859
|
-
try {
|
|
1860
|
-
const activePublicKey = publicKeyRef.current;
|
|
1861
|
-
if (activePublicKey) {
|
|
1862
|
-
await backendApiRef.current.postChatMessage(
|
|
1863
|
-
backendId,
|
|
1864
|
-
text,
|
|
1865
|
-
activePublicKey
|
|
1866
|
-
);
|
|
1867
|
-
} else {
|
|
1868
|
-
await backendApiRef.current.postChatMessage(backendId, text);
|
|
1869
|
-
}
|
|
1870
|
-
} catch (error) {
|
|
1871
|
-
console.error("Failed to send queued message:", error);
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
if (currentThreadIdRef.current === uiThreadId) {
|
|
1875
|
-
polling == null ? void 0 : polling.start(uiThreadId);
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
}).catch((error) => {
|
|
1879
|
-
var _a2;
|
|
1880
|
-
console.error("Failed to create new thread:", error);
|
|
1881
|
-
const failedId = (_a2 = backendState.creatingThreadId) != null ? _a2 : tempId;
|
|
1882
|
-
threadContext.setThreadMetadata((prev) => {
|
|
1883
|
-
const next = new Map(prev);
|
|
1884
|
-
next.delete(failedId);
|
|
1885
|
-
return next;
|
|
1886
|
-
});
|
|
1887
|
-
threadContext.setThreads((prev) => {
|
|
1888
|
-
const next = new Map(prev);
|
|
1889
|
-
next.delete(failedId);
|
|
1890
|
-
return next;
|
|
1891
|
-
});
|
|
1892
|
-
if (backendState.creatingThreadId === failedId) {
|
|
1893
|
-
backendState.creatingThreadId = null;
|
|
1894
|
-
}
|
|
1895
|
-
}).finally(() => {
|
|
1896
|
-
backendState.createThreadPromise = null;
|
|
1897
|
-
});
|
|
1898
|
-
backendState.createThreadPromise = createPromise;
|
|
1899
|
-
},
|
|
1900
|
-
onSwitchToThread: (threadId) => {
|
|
1901
|
-
const previousThreadId = currentThreadIdRef.current;
|
|
1902
|
-
polling.stopAll();
|
|
1903
|
-
if (isRunning && isThreadReady(backendState, previousThreadId)) {
|
|
1904
|
-
const backendId = resolveThreadId(backendState, previousThreadId);
|
|
1905
|
-
void backendApiRef.current.postInterrupt(backendId);
|
|
1906
|
-
}
|
|
1907
|
-
threadContext.setCurrentThreadId(threadId);
|
|
1908
|
-
},
|
|
1909
|
-
onRename: async (threadId, newTitle) => {
|
|
1910
|
-
var _a, _b;
|
|
1911
|
-
const previousTitle = (_b = (_a = threadContext.getThreadMetadata(threadId)) == null ? void 0 : _a.title) != null ? _b : "";
|
|
1912
|
-
const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
|
|
1913
|
-
threadContext.updateThreadMetadata(threadId, {
|
|
1914
|
-
title: normalizedTitle
|
|
1915
|
-
});
|
|
1916
|
-
try {
|
|
1917
|
-
await backendApiRef.current.renameThread(threadId, newTitle);
|
|
1918
|
-
} catch (error) {
|
|
1919
|
-
console.error("Failed to rename thread:", error);
|
|
1920
|
-
threadContext.updateThreadMetadata(threadId, { title: previousTitle });
|
|
1921
|
-
}
|
|
1922
|
-
},
|
|
1923
|
-
onArchive: async (threadId) => {
|
|
1924
|
-
threadContext.updateThreadMetadata(threadId, { status: "archived" });
|
|
1925
|
-
try {
|
|
1926
|
-
await backendApiRef.current.archiveThread(threadId);
|
|
1927
|
-
} catch (error) {
|
|
1928
|
-
console.error("Failed to archive thread:", error);
|
|
1929
|
-
threadContext.updateThreadMetadata(threadId, { status: "regular" });
|
|
1930
|
-
}
|
|
1931
|
-
},
|
|
1932
|
-
onUnarchive: async (threadId) => {
|
|
1933
|
-
threadContext.updateThreadMetadata(threadId, { status: "regular" });
|
|
1934
|
-
try {
|
|
1935
|
-
await backendApiRef.current.unarchiveThread(threadId);
|
|
1936
|
-
} catch (error) {
|
|
1937
|
-
console.error("Failed to unarchive thread:", error);
|
|
1938
|
-
threadContext.updateThreadMetadata(threadId, { status: "archived" });
|
|
1939
|
-
}
|
|
1940
|
-
},
|
|
1941
|
-
onDelete: async (threadId) => {
|
|
1942
|
-
try {
|
|
1943
|
-
await backendApiRef.current.deleteThread(threadId);
|
|
1944
|
-
threadContext.setThreadMetadata((prev) => {
|
|
1945
|
-
const next = new Map(prev);
|
|
1946
|
-
next.delete(threadId);
|
|
1947
|
-
return next;
|
|
1948
|
-
});
|
|
1949
|
-
threadContext.setThreads((prev) => {
|
|
1779
|
+
threadContextRef.current.setThreadMetadata((prev) => {
|
|
1780
|
+
var _a;
|
|
1950
1781
|
const next = new Map(prev);
|
|
1951
|
-
next.
|
|
1782
|
+
const existing = next.get(targetThreadId);
|
|
1783
|
+
const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
|
|
1784
|
+
next.set(targetThreadId, {
|
|
1785
|
+
title: normalizedTitle,
|
|
1786
|
+
status: nextStatus,
|
|
1787
|
+
lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString()
|
|
1788
|
+
});
|
|
1952
1789
|
return next;
|
|
1953
1790
|
});
|
|
1954
|
-
backendState.
|
|
1955
|
-
backendState.pendingSystem.delete(threadId);
|
|
1956
|
-
backendState.tempToBackendId.delete(threadId);
|
|
1957
|
-
backendState.skipInitialFetch.delete(threadId);
|
|
1958
|
-
backendState.runningThreads.delete(threadId);
|
|
1959
|
-
if (backendState.creatingThreadId === threadId) {
|
|
1791
|
+
if (!isPlaceholderTitle(newTitle) && backendState.creatingThreadId === targetThreadId) {
|
|
1960
1792
|
backendState.creatingThreadId = null;
|
|
1961
1793
|
}
|
|
1962
|
-
if (threadContext.currentThreadId === threadId) {
|
|
1963
|
-
const firstRegularThread = Array.from(threadContext.threadMetadata.entries()).find(
|
|
1964
|
-
([id, meta]) => meta.status === "regular" && id !== threadId
|
|
1965
|
-
);
|
|
1966
|
-
if (firstRegularThread) {
|
|
1967
|
-
threadContext.setCurrentThreadId(firstRegularThread[0]);
|
|
1968
|
-
} else {
|
|
1969
|
-
const defaultId = "default-session";
|
|
1970
|
-
threadContext.setThreadMetadata(
|
|
1971
|
-
(prev) => new Map(prev).set(defaultId, {
|
|
1972
|
-
title: "New Chat",
|
|
1973
|
-
status: "regular",
|
|
1974
|
-
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1975
|
-
})
|
|
1976
|
-
);
|
|
1977
|
-
threadContext.setThreadMessages(defaultId, []);
|
|
1978
|
-
threadContext.setCurrentThreadId(defaultId);
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
} catch (error) {
|
|
1982
|
-
console.error("Failed to delete thread:", error);
|
|
1983
|
-
throw error;
|
|
1984
1794
|
}
|
|
1985
1795
|
}
|
|
1796
|
+
);
|
|
1797
|
+
return () => {
|
|
1798
|
+
unsubscribe == null ? void 0 : unsubscribe();
|
|
1986
1799
|
};
|
|
1987
1800
|
}, [
|
|
1988
1801
|
backendApiRef,
|
|
1989
|
-
polling,
|
|
1990
|
-
publicKey,
|
|
1991
1802
|
backendStateRef,
|
|
1992
|
-
setIsRunning,
|
|
1993
|
-
threadContext,
|
|
1994
1803
|
threadContext.currentThreadId,
|
|
1995
|
-
|
|
1996
|
-
bumpUpdateSubscriptions
|
|
1804
|
+
resolvedSessionId
|
|
1997
1805
|
]);
|
|
1998
|
-
(0,
|
|
1806
|
+
(0, import_react7.useEffect)(() => {
|
|
1999
1807
|
const threadId = threadContext.currentThreadId;
|
|
2000
|
-
if (!isTempThreadId(threadId)) return;
|
|
2001
1808
|
if (!isThreadReady(backendStateRef.current, threadId)) return;
|
|
2002
1809
|
void messageController.flushPendingChat(threadId);
|
|
2003
1810
|
}, [messageController, backendStateRef, threadContext.currentThreadId]);
|
|
2004
|
-
|
|
1811
|
+
(0, import_react7.useEffect)(() => {
|
|
1812
|
+
const showToolNotification = (eventType) => (event) => {
|
|
1813
|
+
const payload = event.payload;
|
|
1814
|
+
const toolName = typeof (payload == null ? void 0 : payload.tool_name) === "string" ? payload.tool_name : void 0;
|
|
1815
|
+
const title = toolName ? `${eventType === "tool_update" ? "Tool update" : "Tool complete"}: ${toolName}` : eventType === "tool_update" ? "Tool update" : "Tool complete";
|
|
1816
|
+
const message = typeof (payload == null ? void 0 : payload.message) === "string" ? payload.message : typeof (payload == null ? void 0 : payload.result) === "string" ? payload.result : void 0;
|
|
1817
|
+
notificationContext.showNotification({
|
|
1818
|
+
type: "notice",
|
|
1819
|
+
title,
|
|
1820
|
+
message
|
|
1821
|
+
});
|
|
1822
|
+
};
|
|
1823
|
+
const unsubscribeUpdate = eventContext.subscribe(
|
|
1824
|
+
"tool_update",
|
|
1825
|
+
showToolNotification("tool_update")
|
|
1826
|
+
);
|
|
1827
|
+
const unsubscribeComplete = eventContext.subscribe(
|
|
1828
|
+
"tool_complete",
|
|
1829
|
+
showToolNotification("tool_complete")
|
|
1830
|
+
);
|
|
1831
|
+
return () => {
|
|
1832
|
+
unsubscribeUpdate();
|
|
1833
|
+
unsubscribeComplete();
|
|
1834
|
+
};
|
|
1835
|
+
}, [eventContext, notificationContext]);
|
|
1836
|
+
(0, import_react7.useEffect)(() => {
|
|
1837
|
+
const unsubscribe = eventContext.subscribe("system_notice", (event) => {
|
|
1838
|
+
const payload = event.payload;
|
|
1839
|
+
const message = payload == null ? void 0 : payload.message;
|
|
1840
|
+
notificationContext.showNotification({
|
|
1841
|
+
type: "notice",
|
|
1842
|
+
title: "System notice",
|
|
1843
|
+
message
|
|
1844
|
+
});
|
|
1845
|
+
});
|
|
1846
|
+
return unsubscribe;
|
|
1847
|
+
}, [eventContext, notificationContext]);
|
|
1848
|
+
const runtime = (0, import_react8.useExternalStoreRuntime)({
|
|
2005
1849
|
messages: currentMessages,
|
|
2006
1850
|
setMessages: (msgs) => threadContext.setThreadMessages(threadContext.currentThreadId, [...msgs]),
|
|
2007
1851
|
isRunning,
|
|
@@ -2010,83 +1854,284 @@ function AomiRuntimeProvider({
|
|
|
2010
1854
|
convertMessage: (msg) => msg,
|
|
2011
1855
|
adapters: { threadList: threadListAdapter }
|
|
2012
1856
|
});
|
|
2013
|
-
(0,
|
|
2014
|
-
const threadId = threadContext.currentThreadId;
|
|
2015
|
-
if (isTempThreadId(threadId)) return;
|
|
2016
|
-
const hasUserMessages = currentMessages.some((msg) => msg.role === "user");
|
|
2017
|
-
if (hasUserMessages) {
|
|
2018
|
-
void messageController.flushPendingSystem(threadId);
|
|
2019
|
-
}
|
|
2020
|
-
}, [currentMessages, messageController, threadContext.currentThreadId]);
|
|
2021
|
-
(0, import_react6.useEffect)(() => {
|
|
1857
|
+
(0, import_react7.useEffect)(() => {
|
|
2022
1858
|
return () => {
|
|
2023
|
-
var _a;
|
|
2024
1859
|
polling.stopAll();
|
|
2025
|
-
(_a = eventControllerRef.current) == null ? void 0 : _a.cleanup();
|
|
2026
1860
|
};
|
|
2027
1861
|
}, [polling]);
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
1862
|
+
const userContext = useUser();
|
|
1863
|
+
const sendMessage = (0, import_react7.useCallback)(
|
|
1864
|
+
async (text) => {
|
|
1865
|
+
const appendMessage = {
|
|
1866
|
+
role: "user",
|
|
1867
|
+
content: [{ type: "text", text }]
|
|
1868
|
+
};
|
|
1869
|
+
await messageController.outbound(
|
|
1870
|
+
appendMessage,
|
|
1871
|
+
threadContext.currentThreadId
|
|
1872
|
+
);
|
|
1873
|
+
},
|
|
1874
|
+
[messageController, threadContext.currentThreadId]
|
|
1875
|
+
);
|
|
1876
|
+
const cancelGeneration = (0, import_react7.useCallback)(() => {
|
|
1877
|
+
messageController.cancel(threadContext.currentThreadId);
|
|
1878
|
+
}, [messageController, threadContext.currentThreadId]);
|
|
1879
|
+
const getMessages = (0, import_react7.useCallback)(
|
|
1880
|
+
(threadId) => {
|
|
1881
|
+
const id = threadId != null ? threadId : threadContext.currentThreadId;
|
|
1882
|
+
return threadContext.getThreadMessages(id);
|
|
1883
|
+
},
|
|
1884
|
+
[threadContext]
|
|
1885
|
+
);
|
|
1886
|
+
const createThread = (0, import_react7.useCallback)(async () => {
|
|
1887
|
+
await threadListAdapter.onSwitchToNewThread();
|
|
1888
|
+
return threadContextRef.current.currentThreadId;
|
|
1889
|
+
}, [threadListAdapter]);
|
|
1890
|
+
const deleteThread = (0, import_react7.useCallback)(
|
|
1891
|
+
async (threadId) => {
|
|
1892
|
+
await threadListAdapter.onDelete(threadId);
|
|
1893
|
+
},
|
|
1894
|
+
[threadListAdapter]
|
|
1895
|
+
);
|
|
1896
|
+
const renameThread = (0, import_react7.useCallback)(
|
|
1897
|
+
async (threadId, title) => {
|
|
1898
|
+
await threadListAdapter.onRename(threadId, title);
|
|
1899
|
+
},
|
|
1900
|
+
[threadListAdapter]
|
|
1901
|
+
);
|
|
1902
|
+
const archiveThread = (0, import_react7.useCallback)(
|
|
1903
|
+
async (threadId) => {
|
|
1904
|
+
await threadListAdapter.onArchive(threadId);
|
|
1905
|
+
},
|
|
1906
|
+
[threadListAdapter]
|
|
1907
|
+
);
|
|
1908
|
+
const selectThread = (0, import_react7.useCallback)(
|
|
1909
|
+
(threadId) => {
|
|
1910
|
+
if (threadContext.allThreadsMetadata.has(threadId)) {
|
|
1911
|
+
threadListAdapter.onSwitchToThread(threadId);
|
|
1912
|
+
} else {
|
|
1913
|
+
void threadListAdapter.onSwitchToNewThread();
|
|
1914
|
+
}
|
|
1915
|
+
},
|
|
1916
|
+
[threadContext.allThreadsMetadata, threadListAdapter]
|
|
1917
|
+
);
|
|
1918
|
+
const aomiRuntimeApi = (0, import_react7.useMemo)(
|
|
1919
|
+
() => ({
|
|
1920
|
+
// User API
|
|
1921
|
+
user: userContext.user,
|
|
1922
|
+
getUserState: userContext.getUserState,
|
|
1923
|
+
setUser: userContext.setUser,
|
|
1924
|
+
onUserStateChange: userContext.onUserStateChange,
|
|
1925
|
+
// Thread API
|
|
1926
|
+
currentThreadId: threadContext.currentThreadId,
|
|
1927
|
+
threadViewKey: threadContext.threadViewKey,
|
|
1928
|
+
threadMetadata: threadContext.allThreadsMetadata,
|
|
1929
|
+
getThreadMetadata: threadContext.getThreadMetadata,
|
|
1930
|
+
createThread,
|
|
1931
|
+
deleteThread,
|
|
1932
|
+
renameThread,
|
|
1933
|
+
archiveThread,
|
|
1934
|
+
selectThread,
|
|
1935
|
+
// Chat API
|
|
1936
|
+
isRunning,
|
|
1937
|
+
getMessages,
|
|
1938
|
+
sendMessage,
|
|
1939
|
+
cancelGeneration,
|
|
1940
|
+
// Notification API
|
|
1941
|
+
notifications: notificationContext.notifications,
|
|
1942
|
+
showNotification: notificationContext.showNotification,
|
|
1943
|
+
dismissNotification: notificationContext.dismissNotification,
|
|
1944
|
+
clearAllNotifications: notificationContext.clearAll,
|
|
1945
|
+
// Event API
|
|
1946
|
+
subscribe: eventContext.subscribe,
|
|
1947
|
+
sendSystemCommand: eventContext.sendOutboundSystem,
|
|
1948
|
+
sseStatus: eventContext.sseStatus
|
|
1949
|
+
}),
|
|
1950
|
+
[
|
|
1951
|
+
userContext,
|
|
1952
|
+
threadContext.currentThreadId,
|
|
1953
|
+
threadContext.threadViewKey,
|
|
1954
|
+
threadContext.allThreadsMetadata,
|
|
1955
|
+
threadContext.getThreadMetadata,
|
|
1956
|
+
createThread,
|
|
1957
|
+
deleteThread,
|
|
1958
|
+
renameThread,
|
|
1959
|
+
archiveThread,
|
|
1960
|
+
selectThread,
|
|
1961
|
+
isRunning,
|
|
1962
|
+
getMessages,
|
|
1963
|
+
sendMessage,
|
|
1964
|
+
cancelGeneration,
|
|
1965
|
+
notificationContext,
|
|
1966
|
+
eventContext
|
|
1967
|
+
]
|
|
1968
|
+
);
|
|
1969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AomiRuntimeApiProvider, { value: aomiRuntimeApi, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react8.AssistantRuntimeProvider, { runtime, children }) });
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
// src/runtime/aomi-runtime.tsx
|
|
1973
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1974
|
+
function AomiRuntimeProvider({
|
|
1975
|
+
children,
|
|
1976
|
+
backendUrl = "http://localhost:8080"
|
|
1977
|
+
}) {
|
|
1978
|
+
const backendApi = (0, import_react9.useMemo)(() => new BackendApi(backendUrl), [backendUrl]);
|
|
1979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ThreadContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NotificationContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(UserContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AomiRuntimeInner, { backendApi, children }) }) }) });
|
|
1980
|
+
}
|
|
1981
|
+
function AomiRuntimeInner({
|
|
1982
|
+
children,
|
|
1983
|
+
backendApi
|
|
1984
|
+
}) {
|
|
1985
|
+
const threadContext = useThreadContext();
|
|
1986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1987
|
+
EventContextProvider,
|
|
2051
1988
|
{
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
}
|
|
2055
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react7.AssistantRuntimeProvider, { runtime, children })
|
|
1989
|
+
backendApi,
|
|
1990
|
+
sessionId: threadContext.currentThreadId,
|
|
1991
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AomiRuntimeCore, { backendApi, children })
|
|
2056
1992
|
}
|
|
2057
1993
|
);
|
|
2058
1994
|
}
|
|
2059
|
-
|
|
2060
|
-
|
|
1995
|
+
|
|
1996
|
+
// src/handlers/wallet-handler.ts
|
|
1997
|
+
var import_react10 = require("react");
|
|
1998
|
+
function useWalletHandler({
|
|
1999
|
+
sessionId,
|
|
2000
|
+
onTxRequest
|
|
2001
|
+
}) {
|
|
2002
|
+
const { subscribe: subscribe2, sendOutboundSystem: sendOutbound } = useEventContext();
|
|
2003
|
+
const { setUser, getUserState } = useUser();
|
|
2004
|
+
const [pendingTxRequests, setPendingTxRequests] = (0, import_react10.useState)(
|
|
2005
|
+
[]
|
|
2006
|
+
);
|
|
2007
|
+
(0, import_react10.useEffect)(() => {
|
|
2008
|
+
const unsubscribe = subscribe2(
|
|
2009
|
+
"wallet_tx_request",
|
|
2010
|
+
(event) => {
|
|
2011
|
+
const request = event.payload;
|
|
2012
|
+
setPendingTxRequests((prev) => [...prev, request]);
|
|
2013
|
+
onTxRequest == null ? void 0 : onTxRequest(request);
|
|
2014
|
+
}
|
|
2015
|
+
);
|
|
2016
|
+
return unsubscribe;
|
|
2017
|
+
}, [subscribe2, onTxRequest]);
|
|
2018
|
+
(0, import_react10.useEffect)(() => {
|
|
2019
|
+
const unsubscribe = subscribe2(
|
|
2020
|
+
"user_state_request",
|
|
2021
|
+
(event) => {
|
|
2022
|
+
sendOutbound({
|
|
2023
|
+
type: "user_state_response",
|
|
2024
|
+
sessionId,
|
|
2025
|
+
payload: getUserState()
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
);
|
|
2029
|
+
return unsubscribe;
|
|
2030
|
+
}, [subscribe2, onTxRequest]);
|
|
2031
|
+
const sendTxComplete = (0, import_react10.useCallback)(
|
|
2032
|
+
(tx) => {
|
|
2033
|
+
sendOutbound({
|
|
2034
|
+
type: "wallet:tx_complete",
|
|
2035
|
+
sessionId,
|
|
2036
|
+
payload: tx
|
|
2037
|
+
});
|
|
2038
|
+
},
|
|
2039
|
+
[sendOutbound, sessionId]
|
|
2040
|
+
);
|
|
2041
|
+
const sendConnectionChange = (0, import_react10.useCallback)(
|
|
2042
|
+
(status, address, chainId) => {
|
|
2043
|
+
if (status === "connected") {
|
|
2044
|
+
setUser({
|
|
2045
|
+
isConnected: true,
|
|
2046
|
+
address,
|
|
2047
|
+
chainId
|
|
2048
|
+
});
|
|
2049
|
+
} else {
|
|
2050
|
+
setUser({
|
|
2051
|
+
isConnected: false,
|
|
2052
|
+
address: void 0,
|
|
2053
|
+
chainId: void 0
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
sendOutbound({
|
|
2057
|
+
type: status === "connected" ? "wallet:connected" : "wallet:disconnected",
|
|
2058
|
+
sessionId,
|
|
2059
|
+
payload: { status, address }
|
|
2060
|
+
});
|
|
2061
|
+
},
|
|
2062
|
+
[setUser, sendOutbound, sessionId]
|
|
2063
|
+
);
|
|
2064
|
+
const clearTxRequest = (0, import_react10.useCallback)((index) => {
|
|
2065
|
+
setPendingTxRequests((prev) => prev.filter((_, i) => i !== index));
|
|
2066
|
+
}, []);
|
|
2067
|
+
return {
|
|
2068
|
+
sendTxComplete,
|
|
2069
|
+
sendConnectionChange,
|
|
2070
|
+
pendingTxRequests,
|
|
2071
|
+
clearTxRequest
|
|
2072
|
+
};
|
|
2061
2073
|
}
|
|
2062
2074
|
|
|
2063
|
-
// src/
|
|
2064
|
-
var
|
|
2065
|
-
var
|
|
2066
|
-
function
|
|
2067
|
-
return
|
|
2075
|
+
// src/handlers/notification-handler.ts
|
|
2076
|
+
var import_react11 = require("react");
|
|
2077
|
+
var notificationIdCounter2 = 0;
|
|
2078
|
+
function generateNotificationId() {
|
|
2079
|
+
return `notif-${Date.now()}-${++notificationIdCounter2}`;
|
|
2080
|
+
}
|
|
2081
|
+
function useNotificationHandler({
|
|
2082
|
+
onNotification
|
|
2083
|
+
} = {}) {
|
|
2084
|
+
const { subscribe: subscribe2 } = useEventContext();
|
|
2085
|
+
const [notifications, setNotifications] = (0, import_react11.useState)([]);
|
|
2086
|
+
(0, import_react11.useEffect)(() => {
|
|
2087
|
+
const unsubscribe = subscribe2("notification", (event) => {
|
|
2088
|
+
var _a, _b;
|
|
2089
|
+
const payload = event.payload;
|
|
2090
|
+
const notification = {
|
|
2091
|
+
id: generateNotificationId(),
|
|
2092
|
+
type: (_a = payload.type) != null ? _a : "notification",
|
|
2093
|
+
title: (_b = payload.title) != null ? _b : "Notification",
|
|
2094
|
+
body: payload.body,
|
|
2095
|
+
handled: false,
|
|
2096
|
+
timestamp: event.timestamp,
|
|
2097
|
+
sessionId: event.sessionId
|
|
2098
|
+
};
|
|
2099
|
+
setNotifications((prev) => [notification, ...prev]);
|
|
2100
|
+
onNotification == null ? void 0 : onNotification(notification);
|
|
2101
|
+
});
|
|
2102
|
+
return unsubscribe;
|
|
2103
|
+
}, [subscribe2, onNotification]);
|
|
2104
|
+
const unhandledCount = notifications.filter((n) => !n.handled).length;
|
|
2105
|
+
const markHandled = (0, import_react11.useCallback)((id) => {
|
|
2106
|
+
setNotifications(
|
|
2107
|
+
(prev) => prev.map((n) => n.id === id ? __spreadProps(__spreadValues({}, n), { handled: true }) : n)
|
|
2108
|
+
);
|
|
2109
|
+
}, []);
|
|
2110
|
+
return {
|
|
2111
|
+
notifications,
|
|
2112
|
+
unhandledCount,
|
|
2113
|
+
markDone: markHandled
|
|
2114
|
+
};
|
|
2068
2115
|
}
|
|
2069
2116
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2070
2117
|
0 && (module.exports = {
|
|
2071
2118
|
AomiRuntimeProvider,
|
|
2072
|
-
AomiRuntimeProviderWithNotifications,
|
|
2073
2119
|
BackendApi,
|
|
2074
|
-
|
|
2075
|
-
|
|
2120
|
+
EventContextProvider,
|
|
2121
|
+
NotificationContextProvider,
|
|
2076
2122
|
ThreadContextProvider,
|
|
2077
|
-
|
|
2123
|
+
UserContextProvider,
|
|
2078
2124
|
cn,
|
|
2079
|
-
constructSystemMessage,
|
|
2080
|
-
constructThreadMessage,
|
|
2081
2125
|
formatAddress,
|
|
2082
2126
|
getNetworkName,
|
|
2083
|
-
|
|
2084
|
-
pickInjectedProvider,
|
|
2085
|
-
toHexQuantity,
|
|
2127
|
+
useAomiRuntime,
|
|
2086
2128
|
useCurrentThreadMessages,
|
|
2087
2129
|
useCurrentThreadMetadata,
|
|
2130
|
+
useEventContext,
|
|
2088
2131
|
useNotification,
|
|
2089
|
-
|
|
2090
|
-
useThreadContext
|
|
2132
|
+
useNotificationHandler,
|
|
2133
|
+
useThreadContext,
|
|
2134
|
+
useUser,
|
|
2135
|
+
useWalletHandler
|
|
2091
2136
|
});
|
|
2092
2137
|
//# sourceMappingURL=index.cjs.map
|