@agents24/react 0.2.21 → 0.2.23
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/compatibility.json +5 -5
- package/dist/chat-observation.d.ts +2 -0
- package/dist/index.js +128 -141
- package/dist/index.js.map +1 -1
- package/dist/refresh-chat-summaries.d.ts +12 -0
- package/package.json +2 -2
package/compatibility.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"contractHash": "
|
|
2
|
+
"contractHash": "904701fe1c173854cd4154f2156020da471397fbc6bb644cea60f44c71a1a0d2",
|
|
3
3
|
"contractVersion": "0.3.0",
|
|
4
4
|
"corpus": "conformance/v1/corpus.json",
|
|
5
5
|
"generatedBy": "@agents24/sdk-contract",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"reactDom": ">=19 <20"
|
|
16
16
|
},
|
|
17
17
|
"@agents24/client": {
|
|
18
|
-
"contract": "
|
|
18
|
+
"contract": "904701fe1c173854cd4154f2156020da471397fbc6bb644cea60f44c71a1a0d2",
|
|
19
19
|
"runtime": "run-stream.v3"
|
|
20
20
|
},
|
|
21
21
|
"@agents24/node": {
|
|
22
|
-
"contract": "
|
|
22
|
+
"contract": "904701fe1c173854cd4154f2156020da471397fbc6bb644cea60f44c71a1a0d2",
|
|
23
23
|
"node": "^22.0.0 || ^24.0.0"
|
|
24
24
|
},
|
|
25
25
|
"@agents24/react": {
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"react": ">=19 <20"
|
|
28
28
|
},
|
|
29
29
|
"@talmudpedia/runtime-sdk": {
|
|
30
|
-
"contract": "
|
|
30
|
+
"contract": "904701fe1c173854cd4154f2156020da471397fbc6bb644cea60f44c71a1a0d2",
|
|
31
31
|
"protocolOwner": "@agents24/client"
|
|
32
32
|
},
|
|
33
33
|
"agents24": {
|
|
34
|
-
"contract": "
|
|
34
|
+
"contract": "904701fe1c173854cd4154f2156020da471397fbc6bb644cea60f44c71a1a0d2",
|
|
35
35
|
"python": ">=3.10"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
@@ -8,6 +8,8 @@ export type ChatObservationState = {
|
|
|
8
8
|
paused: boolean;
|
|
9
9
|
degraded?: boolean;
|
|
10
10
|
mode?: "on-demand" | "realtime";
|
|
11
|
+
background?: boolean;
|
|
12
|
+
sidebar?: boolean;
|
|
11
13
|
};
|
|
12
14
|
/** One observation policy for SDK chats and platform transport adapters. */
|
|
13
15
|
export declare function createChatObservation(input: {
|
package/dist/index.js
CHANGED
|
@@ -17,32 +17,22 @@ function createChatObservation(input) {
|
|
|
17
17
|
let visible = input.visibility?.isVisible() ?? true;
|
|
18
18
|
let disposed = false;
|
|
19
19
|
let generation = 0;
|
|
20
|
-
let cursor;
|
|
21
|
-
let connection;
|
|
22
20
|
let recovery;
|
|
23
21
|
let refreshing;
|
|
24
22
|
let timer;
|
|
25
|
-
let reconnectTimer;
|
|
26
23
|
let failures = 0;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
const clearTimer = () => {
|
|
24
|
+
const needed = () => !disposed && visible && Boolean(state.threadId || state.sidebar);
|
|
25
|
+
const interval = () => failures ? Math.min(3e4, 5e3 * 2 ** Math.min(failures, 3)) : state.running || state.pending || state.degraded || state.waiting || state.paused || state.background ? 5e3 : 3e4;
|
|
26
|
+
const stop = () => {
|
|
31
27
|
clock.clearTimeout(timer);
|
|
32
28
|
timer = void 0;
|
|
33
29
|
};
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
clock.
|
|
37
|
-
connection?.abort();
|
|
38
|
-
connection = void 0;
|
|
39
|
-
};
|
|
40
|
-
const schedule = (callback, ms) => {
|
|
41
|
-
clearTimer();
|
|
42
|
-
timer = clock.setTimeout(callback, ms);
|
|
30
|
+
const schedule = () => {
|
|
31
|
+
stop();
|
|
32
|
+
if (needed()) timer = clock.setTimeout(poll, interval());
|
|
43
33
|
};
|
|
44
34
|
function refresh() {
|
|
45
|
-
if (
|
|
35
|
+
if (!needed()) return Promise.resolve();
|
|
46
36
|
if (refreshing) return refreshing;
|
|
47
37
|
const owned = generation;
|
|
48
38
|
const controller = input.createAbortController();
|
|
@@ -65,137 +55,51 @@ function createChatObservation(input) {
|
|
|
65
55
|
refreshing = promise;
|
|
66
56
|
return promise;
|
|
67
57
|
}
|
|
68
|
-
function recover() {
|
|
69
|
-
const owned = generation;
|
|
70
|
-
return refresh().then(() => {
|
|
71
|
-
if (owned === generation && !disposed && visible) {
|
|
72
|
-
failures = 0;
|
|
73
|
-
input.onResume();
|
|
74
|
-
}
|
|
75
|
-
}).catch((error) => {
|
|
76
|
-
if (owned !== generation || disposed || !visible) return;
|
|
77
|
-
failures += 1;
|
|
78
|
-
input.onError(error);
|
|
79
|
-
if (needed()) schedule(poll, 1e3);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
58
|
function poll() {
|
|
59
|
+
stop();
|
|
83
60
|
if (!needed()) return;
|
|
84
|
-
void recover().finally(() => {
|
|
85
|
-
if (needed() && (state.pending && !state.running || state.degraded || failures > 0)) schedule(poll, 1e3);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
function connect() {
|
|
89
|
-
if (!needed() || connection) return;
|
|
90
61
|
const owned = generation;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
let leased = false;
|
|
96
|
-
let hydration;
|
|
97
|
-
const hydrate = () => hydration ??= recover().finally(() => {
|
|
98
|
-
if (owned !== generation || controller.signal.aborted) return;
|
|
99
|
-
const notices = buffered || [];
|
|
100
|
-
buffered = void 0;
|
|
101
|
-
for (const event of notices) input.onEvent(event);
|
|
102
|
-
if (notices.length) void recover();
|
|
103
|
-
});
|
|
104
|
-
void input.events({
|
|
105
|
-
threadId: state.threadId,
|
|
106
|
-
cursor,
|
|
107
|
-
leaseSeconds: 60,
|
|
108
|
-
signal: controller.signal,
|
|
109
|
-
onControl(control) {
|
|
110
|
-
if (control.type === "lease_expired") leased = true;
|
|
111
|
-
if (control.type === "ready") {
|
|
112
|
-
ready = true;
|
|
113
|
-
cursor ??= control.cursor;
|
|
114
|
-
void hydrate().catch(input.onError);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}, (event) => {
|
|
118
|
-
if (owned !== generation || controller.signal.aborted) return;
|
|
119
|
-
if (event.event === "snapshot_required") {
|
|
120
|
-
cursor = void 0;
|
|
121
|
-
void refresh().catch(input.onError);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
cursor = Math.max(cursor ?? 0, event.cursor);
|
|
125
|
-
failures = 0;
|
|
126
|
-
if (buffered) buffered.push(event);
|
|
127
|
-
else {
|
|
128
|
-
input.onEvent(event);
|
|
129
|
-
void recover();
|
|
130
|
-
}
|
|
131
|
-
if (!ready) {
|
|
132
|
-
ready = true;
|
|
133
|
-
void hydrate().catch(input.onError);
|
|
134
|
-
}
|
|
135
|
-
}).then(() => {
|
|
136
|
-
if (owned !== generation || controller.signal.aborted) return;
|
|
137
|
-
connection = void 0;
|
|
138
|
-
if (needed()) {
|
|
139
|
-
if (leased) connect();
|
|
140
|
-
else {
|
|
141
|
-
void refresh().catch(input.onError);
|
|
142
|
-
reconnectTimer = clock.setTimeout(connect, 1e3);
|
|
143
|
-
}
|
|
62
|
+
void refresh().then(() => {
|
|
63
|
+
if (owned === generation && needed()) {
|
|
64
|
+
failures = 0;
|
|
65
|
+
input.onResume();
|
|
144
66
|
}
|
|
145
67
|
}).catch((error) => {
|
|
146
|
-
if (owned !== generation ||
|
|
147
|
-
connection = void 0;
|
|
68
|
+
if (owned !== generation || !needed()) return;
|
|
148
69
|
failures += 1;
|
|
149
70
|
input.onError(error);
|
|
150
|
-
|
|
151
|
-
|
|
71
|
+
}).finally(() => {
|
|
72
|
+
if (owned === generation) schedule();
|
|
152
73
|
});
|
|
153
74
|
}
|
|
154
|
-
function reconcile() {
|
|
155
|
-
if (!needed()) {
|
|
156
|
-
handoffAt = void 0;
|
|
157
|
-
stop();
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
connect();
|
|
161
|
-
if (state.pending && !state.running) {
|
|
162
|
-
handoffAt ??= Date.now() + 2e3;
|
|
163
|
-
schedule(poll, Math.max(0, handoffAt - Date.now()));
|
|
164
|
-
} else {
|
|
165
|
-
handoffAt = void 0;
|
|
166
|
-
if (state.degraded) schedule(poll, 1e3);
|
|
167
|
-
else if (!failures) clearTimer();
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
75
|
const unsubscribe = input.visibility?.subscribe(() => {
|
|
171
76
|
const next = input.visibility.isVisible();
|
|
172
77
|
if (next === visible) return;
|
|
173
78
|
visible = next;
|
|
174
79
|
if (!visible) {
|
|
80
|
+
generation += 1;
|
|
175
81
|
stop();
|
|
176
82
|
recovery?.abort();
|
|
177
83
|
refreshing = void 0;
|
|
178
84
|
input.onDetach();
|
|
179
|
-
} else
|
|
180
|
-
reconcile();
|
|
181
|
-
if (!needed()) void refresh().then(input.onResume).catch(input.onError);
|
|
182
|
-
}
|
|
85
|
+
} else poll();
|
|
183
86
|
});
|
|
184
87
|
return {
|
|
185
88
|
refresh,
|
|
186
89
|
update(next) {
|
|
187
|
-
|
|
90
|
+
const changed = next.threadId !== state.threadId;
|
|
91
|
+
const accelerated = !(state.running || state.pending || state.background || state.waiting) && Boolean(next.running || next.pending || next.background || next.waiting);
|
|
92
|
+
if (changed) {
|
|
188
93
|
generation += 1;
|
|
189
94
|
stop();
|
|
190
95
|
recovery?.abort();
|
|
191
96
|
refreshing = void 0;
|
|
192
|
-
cursor = void 0;
|
|
193
|
-
buffered = void 0;
|
|
194
97
|
failures = 0;
|
|
195
|
-
handoffAt = void 0;
|
|
196
98
|
}
|
|
197
99
|
state = next;
|
|
198
|
-
|
|
100
|
+
if (!needed()) stop();
|
|
101
|
+
else if (changed || accelerated) poll();
|
|
102
|
+
else if (timer === void 0 && !refreshing) schedule();
|
|
199
103
|
},
|
|
200
104
|
dispose() {
|
|
201
105
|
disposed = true;
|
|
@@ -232,10 +136,10 @@ function useChatObservation(input) {
|
|
|
232
136
|
if (owner.current === observation) owner.current = null;
|
|
233
137
|
};
|
|
234
138
|
}, [input.createAbortController, input.visibility]);
|
|
235
|
-
const { threadId, running, waiting, pending, paused, degraded, mode } = input.state;
|
|
139
|
+
const { threadId, running, waiting, pending, paused, degraded, mode, background, sidebar } = input.state;
|
|
236
140
|
React.useEffect(() => {
|
|
237
|
-
owner.current?.update({ threadId, running, waiting, pending, paused, degraded, mode });
|
|
238
|
-
}, [threadId, running, waiting, pending, paused, degraded, mode]);
|
|
141
|
+
owner.current?.update({ threadId, running, waiting, pending, paused, degraded, mode, background, sidebar });
|
|
142
|
+
}, [threadId, running, waiting, pending, paused, degraded, mode, background, sidebar]);
|
|
239
143
|
return React.useCallback(() => owner.current?.refresh() ?? Promise.resolve(), []);
|
|
240
144
|
}
|
|
241
145
|
|
|
@@ -258,7 +162,7 @@ function getThreadActivity(thread) {
|
|
|
258
162
|
return {
|
|
259
163
|
status,
|
|
260
164
|
runId: activeRun?.run_id || thread.last_run_id || null,
|
|
261
|
-
isSpinning: Boolean(activeRun) &&
|
|
165
|
+
isSpinning: Boolean(activeRun) && ["queued", "running", "cancelling"].includes(status || ""),
|
|
262
166
|
isPaused: status === "paused",
|
|
263
167
|
isFailed: status === "failed",
|
|
264
168
|
isCompleted: status === "completed",
|
|
@@ -1027,13 +931,23 @@ function applyRuntimeEvent(state, event) {
|
|
|
1027
931
|
...segment ? { durableId: segment.message_id } : {}
|
|
1028
932
|
};
|
|
1029
933
|
});
|
|
1030
|
-
const
|
|
934
|
+
const activityStatus = suspension || (paused ? "paused" : cancelling ? "cancelling" : "running");
|
|
935
|
+
const terminalThread = runId && !sealedAfterTerminal ? {
|
|
936
|
+
active_run: terminal ? null : {
|
|
937
|
+
run_id: runId,
|
|
938
|
+
status: activityStatus,
|
|
939
|
+
started_at: state.threads.find((thread) => thread.id === activeThreadId)?.active_run?.started_at ?? null,
|
|
940
|
+
created_at: state.threads.find((thread) => thread.id === activeThreadId && thread.active_run?.run_id === runId)?.active_run?.created_at ?? event.ts,
|
|
941
|
+
is_cancellable: !cancelling
|
|
942
|
+
},
|
|
943
|
+
last_run_status: terminal ? eventName.slice(4) : activityStatus
|
|
944
|
+
} : {};
|
|
1031
945
|
const threads = activeThreadId ? state.threads.some((thread) => thread.id === activeThreadId) ? state.threads.map((thread) => thread.id === activeThreadId ? {
|
|
1032
946
|
...thread,
|
|
1033
947
|
messages,
|
|
1034
948
|
isHydrated: true,
|
|
1035
949
|
last_run_id: terminal && thread.active_run && thread.active_run.run_id !== runId ? thread.last_run_id : runId ?? thread.last_run_id,
|
|
1036
|
-
...!thread.active_run || thread.active_run.run_id === runId ? terminalThread : {},
|
|
950
|
+
...!terminal || !thread.active_run || thread.active_run.run_id === runId ? terminalThread : {},
|
|
1037
951
|
contextWindow,
|
|
1038
952
|
contextCompression
|
|
1039
953
|
} : thread) : [{
|
|
@@ -1471,6 +1385,53 @@ function discardOptimisticSubmission(state, message) {
|
|
|
1471
1385
|
// src/use-agent-chat.ts
|
|
1472
1386
|
import * as React7 from "react";
|
|
1473
1387
|
|
|
1388
|
+
// src/refresh-chat-summaries.ts
|
|
1389
|
+
async function refreshChatSummaries(input) {
|
|
1390
|
+
const before = input.current();
|
|
1391
|
+
const page = await input.client.threads.list({ limit: input.limit, signal: input.signal });
|
|
1392
|
+
if (input.signal.aborted) return null;
|
|
1393
|
+
const summaries = [...page.items];
|
|
1394
|
+
const seen = new Set(summaries.map((thread) => thread.id));
|
|
1395
|
+
const missing = before.threads.filter((thread) => !seen.has(thread.id) && (thread.active_run || thread.id === before.activeThreadId)).map((thread) => thread.id);
|
|
1396
|
+
if (before.activeThreadId && !seen.has(before.activeThreadId) && !missing.includes(before.activeThreadId)) {
|
|
1397
|
+
missing.push(before.activeThreadId);
|
|
1398
|
+
}
|
|
1399
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
1400
|
+
const errors = [];
|
|
1401
|
+
for (let offset = 0; offset < missing.length && !input.signal.aborted; offset += 4) {
|
|
1402
|
+
const ids = missing.slice(offset, offset + 4);
|
|
1403
|
+
const results = await Promise.allSettled(ids.map((threadId) => input.client.threads.get({ threadId, limit: 1, signal: input.signal })));
|
|
1404
|
+
results.forEach((result, index) => {
|
|
1405
|
+
if (result.status === "fulfilled") summaries.push(result.value);
|
|
1406
|
+
else if (result.reason?.name === "Agents24ClientError" && result.reason.kind === "not_found" && result.reason.status === 404) {
|
|
1407
|
+
deleted.add(ids[index]);
|
|
1408
|
+
} else errors.push(result.reason);
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
if (input.signal.aborted) return null;
|
|
1412
|
+
const removed = [];
|
|
1413
|
+
input.update((current) => ({ ...current, threads: summaries.reduce((threads, thread) => {
|
|
1414
|
+
const previous = before.threads.find((item) => item.id === thread.id);
|
|
1415
|
+
const latest = current.threads.find((item) => item.id === thread.id);
|
|
1416
|
+
if (previous && !latest) return threads;
|
|
1417
|
+
if (latest && (previous?.last_run_id !== latest.last_run_id || previous?.active_run?.status !== latest.active_run?.status || previous?.last_run_status !== latest.last_run_status)) return threads;
|
|
1418
|
+
return applyThreadSummaryEvent(threads, {
|
|
1419
|
+
schema_version: "agents24.thread_summary_event.v1",
|
|
1420
|
+
event: "thread.summary.updated",
|
|
1421
|
+
cursor: 0,
|
|
1422
|
+
thread
|
|
1423
|
+
});
|
|
1424
|
+
}, current.threads.filter((thread) => {
|
|
1425
|
+
if (!deleted.has(thread.id) || before.threads.find((item) => item.id === thread.id) !== thread) return true;
|
|
1426
|
+
removed.push(thread.id);
|
|
1427
|
+
return false;
|
|
1428
|
+
})) }));
|
|
1429
|
+
if (before.activeThreadId && deleted.has(before.activeThreadId) && !input.current().threads.some((thread) => thread.id === before.activeThreadId) && !removed.includes(before.activeThreadId)) removed.push(before.activeThreadId);
|
|
1430
|
+
for (const id of removed) input.onDeleted?.(id);
|
|
1431
|
+
if (errors.length) throw errors[0];
|
|
1432
|
+
return input.current().threads.find((thread) => thread.id === before.activeThreadId) || null;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1474
1435
|
// src/use-agent-chat-thread-list.ts
|
|
1475
1436
|
import * as React4 from "react";
|
|
1476
1437
|
function summaryToStored(thread) {
|
|
@@ -1670,7 +1631,7 @@ function shouldHydrateSelectedThread(selectedThreadId, activeThreadId, activeThr
|
|
|
1670
1631
|
function activeRunIdFromThread(thread) {
|
|
1671
1632
|
if (!thread) return null;
|
|
1672
1633
|
const activity = getThreadActivity(thread);
|
|
1673
|
-
return
|
|
1634
|
+
return thread.active_run ? activity.runId : null;
|
|
1674
1635
|
}
|
|
1675
1636
|
function useAgentChat(options = {}) {
|
|
1676
1637
|
const runtime = useAgents24Runtime();
|
|
@@ -1746,7 +1707,16 @@ function useAgentChat(options = {}) {
|
|
|
1746
1707
|
const onQueuePromotion = React7.useCallback((message, runId) => {
|
|
1747
1708
|
if (stateRef.current.activeThreadId !== message.thread_id) return;
|
|
1748
1709
|
const userMessage = threadTimelineToMessages([{ ...message, run_id: runId, status: "delivered" }])[0];
|
|
1749
|
-
update((current) => current.activeThreadId === message.thread_id ? {
|
|
1710
|
+
update((current) => current.activeThreadId === message.thread_id ? {
|
|
1711
|
+
...current,
|
|
1712
|
+
messages: promoteThreadMessage(current.messages, userMessage, runId),
|
|
1713
|
+
threads: current.threads.map((thread) => thread.id === message.thread_id ? {
|
|
1714
|
+
...thread,
|
|
1715
|
+
last_run_id: runId,
|
|
1716
|
+
last_run_status: "running",
|
|
1717
|
+
active_run: { run_id: runId, status: "running", started_at: null, created_at: message.created_at, is_cancellable: true }
|
|
1718
|
+
} : thread)
|
|
1719
|
+
} : current);
|
|
1750
1720
|
attachPromotion(runId, message.thread_id);
|
|
1751
1721
|
}, [update, attachPromotion]);
|
|
1752
1722
|
const queue = useThreadMessageQueue({
|
|
@@ -1892,10 +1862,11 @@ function useAgentChat(options = {}) {
|
|
|
1892
1862
|
...context,
|
|
1893
1863
|
contextCompressionRevision: 0,
|
|
1894
1864
|
activeRunId: activeRunIdFromThread(stored),
|
|
1865
|
+
runState: getThreadActivity(stored).isSpinning ? "reconnecting" : stored.active_run?.status || "idle",
|
|
1895
1866
|
threads: current.threads.some((thread) => thread.id === threadId) ? current.threads.map((thread) => thread.id === threadId ? stored : thread) : [stored, ...current.threads]
|
|
1896
1867
|
} : current);
|
|
1897
1868
|
const activeRunId = activeRunIdFromThread(stored);
|
|
1898
|
-
if (activeRunId && isCurrent()) void attachRunRef.current(activeRunId).catch(() => void 0);
|
|
1869
|
+
if (activeRunId && getThreadActivity(stored).isSpinning && isCurrent()) void attachRunRef.current(activeRunId).catch(() => void 0);
|
|
1899
1870
|
} catch (error) {
|
|
1900
1871
|
if (!requestController.signal.aborted && !isAbortLike(error) && requestGeneration === threadOpenGenerationRef.current) {
|
|
1901
1872
|
failOperation("open_thread", error);
|
|
@@ -2254,6 +2225,8 @@ function useAgentChat(options = {}) {
|
|
|
2254
2225
|
threadId: state.activeThreadId,
|
|
2255
2226
|
running: Boolean(state.activeRunId) && !["idle", "completed", "failed", "cancelled"].includes(state.runState),
|
|
2256
2227
|
waiting: ["paused", "waiting", "interrupted"].includes(state.runState),
|
|
2228
|
+
sidebar: true,
|
|
2229
|
+
background: state.threads.some((thread) => thread.id !== state.activeThreadId && Boolean(thread.active_run || thread.message_queue?.pending_count)),
|
|
2257
2230
|
pending: pendingMessages.length > 0,
|
|
2258
2231
|
paused: Boolean(messageQueue?.paused),
|
|
2259
2232
|
degraded: state.runState === "reconnecting",
|
|
@@ -2264,22 +2237,36 @@ function useAgentChat(options = {}) {
|
|
|
2264
2237
|
events: (input, handler) => client.threads.events(input, handler),
|
|
2265
2238
|
async refresh(signal) {
|
|
2266
2239
|
const target = stateRef.current.activeThreadId;
|
|
2267
|
-
|
|
2240
|
+
const previous = stateRef.current.threads.find((thread) => thread.id === target);
|
|
2268
2241
|
const isCurrent = ownOperation();
|
|
2269
|
-
const
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2242
|
+
const summary = await refreshChatSummaries({
|
|
2243
|
+
client,
|
|
2244
|
+
limit: threadPageSize,
|
|
2245
|
+
signal,
|
|
2246
|
+
current: () => stateRef.current,
|
|
2247
|
+
update,
|
|
2248
|
+
onDeleted(threadId) {
|
|
2249
|
+
if (isCurrent() && stateRef.current.activeThreadId === threadId) startNewThread();
|
|
2250
|
+
}
|
|
2251
|
+
});
|
|
2252
|
+
if (!target || !summary || !isCurrent() || signal.aborted || threadOpenControllerRef.current) return;
|
|
2278
2253
|
const runId = activeRunIdFromThread(summary);
|
|
2279
|
-
|
|
2254
|
+
const changed = previous?.active_run?.run_id !== summary.active_run?.run_id || previous?.active_run?.status !== summary.active_run?.status;
|
|
2255
|
+
if (runId && getThreadActivity(summary).isSpinning && (!streamControllerRef.current || stateRef.current.activeRunId !== runId)) {
|
|
2280
2256
|
void attachRunRef.current(runId, runId === stateRef.current.activeRunId ? stateRef.current.cursor ?? void 0 : 0).catch(() => void 0);
|
|
2257
|
+
} else if (!getThreadActivity(summary).isSpinning && changed) {
|
|
2258
|
+
streamControllerRef.current?.abort();
|
|
2259
|
+
streamControllerRef.current = null;
|
|
2260
|
+
update((current) => ({
|
|
2261
|
+
...current,
|
|
2262
|
+
activeRunId: summary.active_run?.run_id || null,
|
|
2263
|
+
streamingMessageId: null,
|
|
2264
|
+
runState: summary.active_run?.status || summary.last_run_status || "idle"
|
|
2265
|
+
}));
|
|
2266
|
+
}
|
|
2267
|
+
if (changed || pendingMessages.length || stateRef.current.runState === "reconnecting" || !streamControllerRef.current) {
|
|
2268
|
+
await refreshMessages(target, runId || void 0, signal);
|
|
2281
2269
|
}
|
|
2282
|
-
await refreshMessages(target, runId || void 0, signal);
|
|
2283
2270
|
},
|
|
2284
2271
|
onEvent(event) {
|
|
2285
2272
|
if (event.event === "thread.deleted" && event.thread_id === stateRef.current.activeThreadId) startNewThread();
|
|
@@ -2305,7 +2292,7 @@ function useAgentChat(options = {}) {
|
|
|
2305
2292
|
onDetach: detach,
|
|
2306
2293
|
onResume() {
|
|
2307
2294
|
const current = stateRef.current;
|
|
2308
|
-
if (current.activeRunId && !streamControllerRef.current && !["paused", "waiting", "interrupted", "completed", "idle"].includes(current.runState)) {
|
|
2295
|
+
if (current.activeRunId && !streamControllerRef.current && !["paused", "waiting", "interrupted", "completed", "failed", "cancelled", "idle"].includes(current.runState)) {
|
|
2309
2296
|
void attachRunRef.current(current.activeRunId, current.cursor ?? void 0).catch(() => void 0);
|
|
2310
2297
|
}
|
|
2311
2298
|
}
|