@opengeni/react 0.23.0 → 0.25.5
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/{chunk-UQS7OQDE.js → chunk-F4CFWKVI.js} +334 -64
- package/dist/chunk-F4CFWKVI.js.map +1 -0
- package/dist/chunk-GQN2QIR2.js +3767 -0
- package/dist/chunk-GQN2QIR2.js.map +1 -0
- package/dist/{chunk-I3BJZIG5.js → chunk-HIWPQYWI.js} +2 -120
- package/dist/chunk-HIWPQYWI.js.map +1 -0
- package/dist/chunk-M7X4JZOD.js +121 -0
- package/dist/chunk-M7X4JZOD.js.map +1 -0
- package/dist/{chunk-UAHPKLB6.js → chunk-MP6237JB.js} +571 -975
- package/dist/chunk-MP6237JB.js.map +1 -0
- package/dist/chunk-OZDLELJQ.js +937 -0
- package/dist/chunk-OZDLELJQ.js.map +1 -0
- package/dist/{chunk-CATATY77.js → chunk-TMH6HZWF.js} +8 -7
- package/dist/chunk-TMH6HZWF.js.map +1 -0
- package/dist/{chunk-6XUS5VFM.js → chunk-YU5PGUK7.js} +6 -4
- package/dist/{chunk-6XUS5VFM.js.map → chunk-YU5PGUK7.js.map} +1 -1
- package/dist/{composer-CVm5uoUI.d.ts → composer-DoC4veX1.d.ts} +6 -63
- package/dist/composer.d.ts +3 -2
- package/dist/composer.js +4 -3
- package/dist/fleet-decision-projection-SLNZMS42.js +241 -0
- package/dist/fleet-decision-projection-SLNZMS42.js.map +1 -0
- package/dist/fleet-decision-row-GGCAT4E4.js +351 -0
- package/dist/fleet-decision-row-GGCAT4E4.js.map +1 -0
- package/dist/index.d.ts +17 -259
- package/dist/index.js +1042 -5058
- package/dist/index.js.map +1 -1
- package/dist/machines.js +3 -2
- package/dist/session-Du_FsrZ1.d.ts +264 -0
- package/dist/session-ui-BqQDH7YV.d.ts +183 -0
- package/dist/session-ui.d.ts +7 -0
- package/dist/session-ui.js +17 -0
- package/dist/session-ui.js.map +1 -0
- package/dist/session.d.ts +4 -2
- package/dist/session.js +26 -9
- package/dist/{use-composer-By1wn3MM.d.ts → use-composer-BnEzheSk.d.ts} +8 -2
- package/dist/use-file-attachments-C0kpHrs9.d.ts +76 -0
- package/dist/use-turn-queue-3rkJwjFv.d.ts +290 -0
- package/package.json +6 -2
- package/src/components/composer.tsx +7 -6
- package/src/components/message-timeline.tsx +94 -54
- package/src/hooks/use-composer.ts +470 -73
- package/src/hooks/use-file-attachments.ts +96 -3
- package/src/hooks/use-goal.ts +23 -5
- package/src/hooks/use-session-events.ts +5 -0
- package/src/hooks/use-session-lineage.ts +1 -1
- package/src/hooks/use-session.ts +9 -6
- package/src/hooks/use-workspace-sessions.ts +30 -5
- package/src/session-ui.ts +13 -0
- package/src/session.ts +15 -0
- package/src/timeline/activity-rail.tsx +18 -2
- package/src/timeline/fleet-decision-projection.ts +366 -0
- package/src/timeline/fleet-decision-row.tsx +412 -0
- package/src/timeline/index.ts +2 -0
- package/src/timeline/projection.ts +19 -8
- package/src/timeline/tool-display-name.ts +16 -0
- package/src/timeline/tool-renderers.tsx +1 -1
- package/src/timeline/types.ts +68 -1
- package/dist/chunk-CATATY77.js.map +0 -1
- package/dist/chunk-I3BJZIG5.js.map +0 -1
- package/dist/chunk-UAHPKLB6.js.map +0 -1
- package/dist/chunk-UQS7OQDE.js.map +0 -1
- package/dist/session-Db00TRwl.d.ts +0 -446
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FileAsset, FileResourceRef } from "@opengeni/sdk";
|
|
2
2
|
import { useCallback, useRef, useState } from "react";
|
|
3
|
-
import { useOpenGeni, type ClientOverride } from "../
|
|
3
|
+
import { useOpenGeni, type ClientOverride } from "../session-context";
|
|
4
4
|
|
|
5
5
|
export type UseFileAttachmentsOptions = ClientOverride & {
|
|
6
6
|
/**
|
|
@@ -33,12 +33,20 @@ export type UseFileAttachmentsResult = {
|
|
|
33
33
|
* straight into `useComposer`'s `sendExtras.resources`.
|
|
34
34
|
*/
|
|
35
35
|
readyResources: FileResourceRef[];
|
|
36
|
-
/** True while any attachment is still uploading (drives
|
|
36
|
+
/** True while any attachment is still uploading (drives progress UI). */
|
|
37
37
|
uploading: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* True while any attachment still needs an explicit outcome: wait for an
|
|
40
|
+
* upload, retry a failure, or remove it. This is the loss-prevention send
|
|
41
|
+
* gate; failed cards must never be silently omitted from a message.
|
|
42
|
+
*/
|
|
43
|
+
hasUnresolved: boolean;
|
|
38
44
|
/** Explicit picker / drop path — uploads every file, no filter. */
|
|
39
45
|
addFiles: (files: Iterable<File>) => void;
|
|
40
46
|
/** Clipboard path — applies `pasteFilter` (default `image/*`) then uploads. */
|
|
41
47
|
addFromPaste: (event: { clipboardData: DataTransfer | null }) => void;
|
|
48
|
+
/** Restore already-ready server assets without recreating browser-local bytes. */
|
|
49
|
+
restoreReadyFiles: (files: Iterable<FileAsset>) => void;
|
|
42
50
|
/**
|
|
43
51
|
* Re-run the upload for a `failed` attachment, in place (same id, same
|
|
44
52
|
* source file). No-op for an id that isn't a known failed upload.
|
|
@@ -46,7 +54,13 @@ export type UseFileAttachmentsResult = {
|
|
|
46
54
|
retry: (id: string) => void;
|
|
47
55
|
/** Remove one attachment; revokes its object-URL. */
|
|
48
56
|
remove: (id: string) => void;
|
|
49
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Remove only finalized files whose durable ids were accepted by a send.
|
|
59
|
+
* Attachments added while that request was in flight remain queued for the
|
|
60
|
+
* next message.
|
|
61
|
+
*/
|
|
62
|
+
removeReadyFiles: (fileIds: Iterable<string>) => void;
|
|
63
|
+
/** Remove all attachments and revoke every object-URL. */
|
|
50
64
|
clear: () => void;
|
|
51
65
|
};
|
|
52
66
|
|
|
@@ -83,6 +97,10 @@ export function useFileAttachments(
|
|
|
83
97
|
data: file,
|
|
84
98
|
})
|
|
85
99
|
.then((asset) => {
|
|
100
|
+
// Retry bytes are useful only until durable finalization succeeds.
|
|
101
|
+
// Drop the source File immediately; restored/ready attachments must
|
|
102
|
+
// never retain browser-local byte authority.
|
|
103
|
+
sources.current.delete(id);
|
|
86
104
|
setAttachments((current) =>
|
|
87
105
|
current.map((attachment) =>
|
|
88
106
|
attachment.id === id
|
|
@@ -171,6 +189,60 @@ export function useFileAttachments(
|
|
|
171
189
|
[addFiles, pasteFilter],
|
|
172
190
|
);
|
|
173
191
|
|
|
192
|
+
const restoreReadyFiles = useCallback(
|
|
193
|
+
(files: Iterable<FileAsset>) => {
|
|
194
|
+
const incoming = new Map<string, FileAsset>();
|
|
195
|
+
for (const file of files) {
|
|
196
|
+
if (file.status === "ready" && file.workspaceId === workspaceId) {
|
|
197
|
+
incoming.set(file.id, file);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
setAttachments((current) => {
|
|
201
|
+
const unresolved = current.filter((attachment) => attachment.status !== "ready");
|
|
202
|
+
const existingReady = new Map(
|
|
203
|
+
current.flatMap((attachment) =>
|
|
204
|
+
attachment.status === "ready" && attachment.file
|
|
205
|
+
? ([[attachment.file.id, attachment]] as const)
|
|
206
|
+
: [],
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
const restored = [...incoming.values()].map((file): FileAttachment => {
|
|
210
|
+
const existing = existingReady.get(file.id);
|
|
211
|
+
return existing
|
|
212
|
+
? {
|
|
213
|
+
...existing,
|
|
214
|
+
name: file.filename,
|
|
215
|
+
contentType: file.contentType,
|
|
216
|
+
sizeBytes: file.sizeBytes,
|
|
217
|
+
status: "ready",
|
|
218
|
+
file,
|
|
219
|
+
error: undefined,
|
|
220
|
+
}
|
|
221
|
+
: {
|
|
222
|
+
id: `restored:${file.id}`,
|
|
223
|
+
name: file.filename,
|
|
224
|
+
contentType: file.contentType,
|
|
225
|
+
sizeBytes: file.sizeBytes,
|
|
226
|
+
status: "ready",
|
|
227
|
+
file,
|
|
228
|
+
// No source File and no object URL: server metadata is the
|
|
229
|
+
// only authority restored across page/device boundaries.
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
for (const [fileId, attachment] of existingReady) {
|
|
233
|
+
if (!incoming.has(fileId) && attachment.previewUrl) {
|
|
234
|
+
URL.revokeObjectURL(attachment.previewUrl);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// A server restoration is authoritative for finalized assets, but an
|
|
238
|
+
// upload that has not finalized still belongs to the local actor. Keep
|
|
239
|
+
// those unresolved entries while replacing the ready set exactly.
|
|
240
|
+
return [...unresolved, ...restored];
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
[workspaceId],
|
|
244
|
+
);
|
|
245
|
+
|
|
174
246
|
const remove = useCallback((id: string) => {
|
|
175
247
|
sources.current.delete(id);
|
|
176
248
|
setAttachments((current) => {
|
|
@@ -182,6 +254,24 @@ export function useFileAttachments(
|
|
|
182
254
|
});
|
|
183
255
|
}, []);
|
|
184
256
|
|
|
257
|
+
const removeReadyFiles = useCallback((fileIds: Iterable<string>) => {
|
|
258
|
+
const accepted = new Set(fileIds);
|
|
259
|
+
if (accepted.size === 0) return;
|
|
260
|
+
setAttachments((current) =>
|
|
261
|
+
current.filter((attachment) => {
|
|
262
|
+
const removeAccepted =
|
|
263
|
+
attachment.status === "ready" &&
|
|
264
|
+
attachment.file !== undefined &&
|
|
265
|
+
accepted.has(attachment.file.id);
|
|
266
|
+
if (removeAccepted) {
|
|
267
|
+
sources.current.delete(attachment.id);
|
|
268
|
+
if (attachment.previewUrl) URL.revokeObjectURL(attachment.previewUrl);
|
|
269
|
+
}
|
|
270
|
+
return !removeAccepted;
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
}, []);
|
|
274
|
+
|
|
185
275
|
const clear = useCallback(() => {
|
|
186
276
|
sources.current.clear();
|
|
187
277
|
setAttachments((current) => {
|
|
@@ -202,10 +292,13 @@ export function useFileAttachments(
|
|
|
202
292
|
: [],
|
|
203
293
|
),
|
|
204
294
|
uploading: attachments.some((attachment) => attachment.status === "uploading"),
|
|
295
|
+
hasUnresolved: attachments.some((attachment) => attachment.status !== "ready"),
|
|
205
296
|
addFiles,
|
|
206
297
|
addFromPaste,
|
|
298
|
+
restoreReadyFiles,
|
|
207
299
|
retry,
|
|
208
300
|
remove,
|
|
301
|
+
removeReadyFiles,
|
|
209
302
|
clear,
|
|
210
303
|
};
|
|
211
304
|
}
|
package/src/hooks/use-goal.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OpenGeniApiError, type SessionEvent, type SessionGoal } from "@opengeni/sdk";
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
-
import { useOpenGeni, type ClientOverride } from "../
|
|
3
|
+
import { useOpenGeni, type ClientOverride } from "../session-context";
|
|
4
4
|
import {
|
|
5
5
|
useDebouncedCallback,
|
|
6
6
|
useMutationRunner,
|
|
@@ -13,9 +13,26 @@ export function isGoalEvent(event: Pick<SessionEvent, "type">): boolean {
|
|
|
13
13
|
return event.type.startsWith("goal.");
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Events that can change the server-authoritative continuation projection.
|
|
18
|
+
* The projection is derived from durable turn, session, control, and system
|
|
19
|
+
* update state, so those events refresh the goal without model polling.
|
|
20
|
+
*/
|
|
21
|
+
export function isGoalRefreshEvent(event: Pick<SessionEvent, "type">): boolean {
|
|
22
|
+
const type = event.type;
|
|
23
|
+
return (
|
|
24
|
+
isGoalEvent(event) ||
|
|
25
|
+
type.startsWith("turn.") ||
|
|
26
|
+
type.startsWith("session.") ||
|
|
27
|
+
type.startsWith("system.update.") ||
|
|
28
|
+
type.startsWith("workspace.inference.") ||
|
|
29
|
+
type.startsWith("user.")
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
16
33
|
export type UseGoalOptions = ClientOverride &
|
|
17
34
|
SessionEventFeedOptions & {
|
|
18
|
-
/** Optional safety-net polling (ms). Off by default —
|
|
35
|
+
/** Optional safety-net polling (ms). Off by default — event refreshes drive updates. */
|
|
19
36
|
pollIntervalMs?: number | undefined;
|
|
20
37
|
};
|
|
21
38
|
|
|
@@ -46,8 +63,9 @@ export type UseGoalResult = {
|
|
|
46
63
|
/**
|
|
47
64
|
* The session's goal: state, the autonomy counters (`autoContinuations`,
|
|
48
65
|
* `noProgressStreak`), and pause/resume control. A goal-less session yields
|
|
49
|
-
* `goal: null` (the 404 is absorbed). Live-updates on
|
|
50
|
-
* pass `options.events` from
|
|
66
|
+
* `goal: null` (the 404 is absorbed). Live-updates on goal, turn, session,
|
|
67
|
+
* control, and system-update events — pass `options.events` from
|
|
68
|
+
* `useSessionEvents` to reuse its stream.
|
|
51
69
|
*/
|
|
52
70
|
export function useGoal(
|
|
53
71
|
sessionId: string | null | undefined,
|
|
@@ -124,7 +142,7 @@ export function useGoal(
|
|
|
124
142
|
}, [load, enabled, workspaceId, sessionId, options.pollIntervalMs, sharedFeed]);
|
|
125
143
|
|
|
126
144
|
const scheduleRefresh = useDebouncedCallback(() => void load());
|
|
127
|
-
useSessionEventTrigger(client, workspaceId, sessionId,
|
|
145
|
+
useSessionEventTrigger(client, workspaceId, sessionId, isGoalRefreshEvent, scheduleRefresh, {
|
|
128
146
|
enabled,
|
|
129
147
|
...(sharedEvents !== undefined ? { events: sharedEvents } : {}),
|
|
130
148
|
});
|
|
@@ -858,6 +858,11 @@ async function loadPreviousPage(
|
|
|
858
858
|
before,
|
|
859
859
|
limit: requested,
|
|
860
860
|
compact: true,
|
|
861
|
+
// Monitoring summaries omit correlation fields once a bounded durable
|
|
862
|
+
// payload exceeds their preview threshold. The browser timeline needs the
|
|
863
|
+
// sanitized stored payload so persisted tool outputs still match their
|
|
864
|
+
// calls and expose truthful truncation telemetry after a reload.
|
|
865
|
+
payloadMode: "full",
|
|
861
866
|
});
|
|
862
867
|
if (options.signal?.aborted) {
|
|
863
868
|
throw abortError();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SessionEvent, SessionLineageResponse } from "@opengeni/sdk";
|
|
2
2
|
import { useCallback, useEffect, useRef } from "react";
|
|
3
|
-
import { useOpenGeni, type ClientOverride } from "../
|
|
3
|
+
import { useOpenGeni, type ClientOverride } from "../session-context";
|
|
4
4
|
import { useDebouncedCallback, usePolledValue, useSessionEventTrigger } from "./internal";
|
|
5
5
|
|
|
6
6
|
export type UseSessionLineageOptions = ClientOverride & {
|
package/src/hooks/use-session.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Session, SessionEvent } from "@opengeni/sdk";
|
|
2
|
-
import { useCallback, useEffect, useState } from "react";
|
|
3
|
-
import { useOpenGeni, type ClientOverride } from "../
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { useOpenGeni, type ClientOverride } from "../session-context";
|
|
4
4
|
import {
|
|
5
5
|
useMutationRunner,
|
|
6
6
|
usePolledValue,
|
|
@@ -66,10 +66,13 @@ export function useSession(
|
|
|
66
66
|
const base = data ?? null;
|
|
67
67
|
// The override only ever carries title/titleSource patches; it is reset on
|
|
68
68
|
// every fresh load so it can never go stale against the server snapshot.
|
|
69
|
-
const session =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
const session = useMemo(
|
|
70
|
+
() =>
|
|
71
|
+
base && override && override.id === base.id
|
|
72
|
+
? { ...base, title: override.title, titleSource: override.titleSource }
|
|
73
|
+
: base,
|
|
74
|
+
[base, override],
|
|
75
|
+
);
|
|
73
76
|
|
|
74
77
|
// Live-patch the title on auto (agent) + cross-client (user/agent) renames so
|
|
75
78
|
// the UI reflects the new title without polling or a full re-fetch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Session } from "@opengeni/sdk";
|
|
2
|
-
import { useCallback } from "react";
|
|
2
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
3
3
|
import { useOpenGeni, type ClientOverride } from "../provider";
|
|
4
4
|
import { usePolledValue } from "./internal";
|
|
5
5
|
|
|
@@ -8,6 +8,8 @@ export type UseWorkspaceSessionsOptions = ClientOverride & {
|
|
|
8
8
|
parentSessionId?: string | null | undefined;
|
|
9
9
|
cursor?: string | undefined;
|
|
10
10
|
search?: string | undefined;
|
|
11
|
+
/** Return only the complete personal pinned projection. */
|
|
12
|
+
pinsOnly?: boolean | undefined;
|
|
11
13
|
/** Refresh interval (ms) for fleet/manager views. Off by default. */
|
|
12
14
|
pollIntervalMs?: number | undefined;
|
|
13
15
|
enabled?: boolean | undefined;
|
|
@@ -38,7 +40,21 @@ export function useWorkspaceSessions(
|
|
|
38
40
|
const parentSessionId = options.parentSessionId;
|
|
39
41
|
const cursor = options.cursor;
|
|
40
42
|
const search = options.search;
|
|
41
|
-
const
|
|
43
|
+
const pinsOnly = options.pinsOnly;
|
|
44
|
+
const enabled = options.enabled ?? true;
|
|
45
|
+
const queryKey = [
|
|
46
|
+
workspaceId,
|
|
47
|
+
limit ?? "",
|
|
48
|
+
parentSessionId === null ? "null" : (parentSessionId ?? ""),
|
|
49
|
+
cursor ?? "",
|
|
50
|
+
search ?? "",
|
|
51
|
+
pinsOnly ? "1" : "",
|
|
52
|
+
].join("\u0000");
|
|
53
|
+
const previousQueryKey = useRef(queryKey);
|
|
54
|
+
const queryKeyTransition = previousQueryKey.current !== queryKey;
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
previousQueryKey.current = queryKey;
|
|
57
|
+
}, [queryKey]);
|
|
42
58
|
const load = useCallback(
|
|
43
59
|
async () => ({
|
|
44
60
|
queryKey,
|
|
@@ -47,13 +63,14 @@ export function useWorkspaceSessions(
|
|
|
47
63
|
...(parentSessionId !== undefined ? { parentSessionId } : {}),
|
|
48
64
|
...(cursor !== undefined ? { cursor } : {}),
|
|
49
65
|
...(search !== undefined ? { search } : {}),
|
|
66
|
+
...(pinsOnly ? { pinsOnly: true } : {}),
|
|
50
67
|
}),
|
|
51
68
|
}),
|
|
52
|
-
[client, workspaceId, limit, parentSessionId, cursor, search, queryKey],
|
|
69
|
+
[client, workspaceId, limit, parentSessionId, cursor, search, pinsOnly, queryKey],
|
|
53
70
|
);
|
|
54
71
|
const state = usePolledValue(load, {
|
|
55
72
|
pollIntervalMs: options.pollIntervalMs,
|
|
56
|
-
enabled
|
|
73
|
+
enabled,
|
|
57
74
|
});
|
|
58
75
|
// usePolledValue drops stale async completions, while the explicit query key
|
|
59
76
|
// also prevents the previous query's cached value from painting for the one
|
|
@@ -69,7 +86,15 @@ export function useWorkspaceSessions(
|
|
|
69
86
|
pinned,
|
|
70
87
|
pinnedTruncated: page?.pinnedTruncated ?? false,
|
|
71
88
|
nextCursor: page?.nextCursor ?? null,
|
|
72
|
-
|
|
89
|
+
// `usePolledValue` clears the old data and starts the new request in an
|
|
90
|
+
// effect. During that query-key transition render, its old loading flag
|
|
91
|
+
// can still be false; expose loading immediately so consumers do not
|
|
92
|
+
// announce a transient false zero-match result.
|
|
93
|
+
loading:
|
|
94
|
+
enabled &&
|
|
95
|
+
(state.loading ||
|
|
96
|
+
queryKeyTransition ||
|
|
97
|
+
(state.data !== null && state.data.queryKey !== queryKey)),
|
|
73
98
|
error: state.error,
|
|
74
99
|
refresh: state.refresh,
|
|
75
100
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @opengeni/react/session-ui — styled surfaces used by the session route.
|
|
2
|
+
// Keep these separate from the hook-only session entry and the broad root barrel
|
|
3
|
+
// so session hosts do not pay for unrelated React surfaces.
|
|
4
|
+
export { HumanInputForm } from "./components/human-input-form";
|
|
5
|
+
export type {
|
|
6
|
+
HumanInputAnswerDraft,
|
|
7
|
+
HumanInputFormMessages,
|
|
8
|
+
HumanInputFormProps,
|
|
9
|
+
} from "./components/human-input-form";
|
|
10
|
+
export { MessageTimeline, TimelineRow } from "./components/message-timeline";
|
|
11
|
+
export type { MessageTimelineProps } from "./components/message-timeline";
|
|
12
|
+
export { QueueSurface } from "./components/queue-surface";
|
|
13
|
+
export type { QueueSurfaceProps } from "./components/queue-surface";
|
package/src/session.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type {
|
|
|
15
15
|
EmbeddedSessionClientOverride as ClientOverride,
|
|
16
16
|
} from "./session-context";
|
|
17
17
|
|
|
18
|
+
export { useSession, isTitleEvent } from "./hooks/use-session";
|
|
19
|
+
export type { UseSessionOptions, UseSessionResult } from "./hooks/use-session";
|
|
18
20
|
export { useSessionEvents } from "./hooks/use-session-events";
|
|
19
21
|
export type {
|
|
20
22
|
SessionEventsConnectionState,
|
|
@@ -29,12 +31,25 @@ export {
|
|
|
29
31
|
FILE_ONLY_MESSAGE_TEXT,
|
|
30
32
|
} from "./hooks/use-composer";
|
|
31
33
|
export type { ComposerSendExtras, ComposerState, UseComposerOptions } from "./hooks/use-composer";
|
|
34
|
+
export { useFileAttachments } from "./hooks/use-file-attachments";
|
|
35
|
+
export type {
|
|
36
|
+
FileAttachment,
|
|
37
|
+
UseFileAttachmentsOptions,
|
|
38
|
+
UseFileAttachmentsResult,
|
|
39
|
+
} from "./hooks/use-file-attachments";
|
|
32
40
|
export { useTurnQueue, isTurnQueueEvent } from "./hooks/use-turn-queue";
|
|
33
41
|
export type {
|
|
34
42
|
QueueMutationKind,
|
|
35
43
|
UseTurnQueueOptions,
|
|
36
44
|
UseTurnQueueResult,
|
|
37
45
|
} from "./hooks/use-turn-queue";
|
|
46
|
+
export { useGoal, isGoalEvent } from "./hooks/use-goal";
|
|
47
|
+
export type { UseGoalOptions, UseGoalResult } from "./hooks/use-goal";
|
|
48
|
+
export { useSessionLineage, isLineageRefreshEvent } from "./hooks/use-session-lineage";
|
|
49
|
+
export type {
|
|
50
|
+
UseSessionLineageOptions,
|
|
51
|
+
UseSessionLineageResult,
|
|
52
|
+
} from "./hooks/use-session-lineage";
|
|
38
53
|
export { useSessionControl } from "./hooks/use-session-control";
|
|
39
54
|
export type {
|
|
40
55
|
UseSessionControlOptions,
|
|
@@ -5,15 +5,19 @@ import {
|
|
|
5
5
|
BrainIcon,
|
|
6
6
|
SquareTerminalIcon,
|
|
7
7
|
} from "lucide-react";
|
|
8
|
+
import { lazy, Suspense } from "react";
|
|
9
|
+
import { jsx as rowJsx, jsxs as rowJsxs } from "react/jsx-runtime";
|
|
8
10
|
import { cn } from "../lib/cn";
|
|
9
11
|
import { truncate } from "../lib/format";
|
|
10
12
|
import { defaultToolRegistry } from "./tool-renderers";
|
|
11
13
|
import { useEntranceAnimation } from "./entrance";
|
|
12
14
|
import type { ToolRegistry } from "./registry";
|
|
13
15
|
import { BodyNote, PayloadBlock, ActivityDisclosure } from "./shared";
|
|
14
|
-
import { toolDisplayName } from "./
|
|
16
|
+
import { toolDisplayName } from "./tool-display-name";
|
|
15
17
|
import type { ActivityItem, MemoryItem, ReasoningItem, SandboxItem, WorkerItem } from "./types";
|
|
16
18
|
|
|
19
|
+
const LazyFleetDecisionRow = lazy(() => import("./fleet-decision-row"));
|
|
20
|
+
|
|
17
21
|
/* ----------------------------------------------------------------------------
|
|
18
22
|
Activity rail
|
|
19
23
|
|
|
@@ -79,7 +83,7 @@ export function ActivityRail({
|
|
|
79
83
|
const newFamily = index > 0 && familyOf(item) !== familyOf(items[index - 1]!);
|
|
80
84
|
const row = renderActivity(item, toolRegistry, onOpenSession, onMemoryClick);
|
|
81
85
|
return (
|
|
82
|
-
<div key={item.id} className={cn(newFamily && "mt-3")}>
|
|
86
|
+
<div key={item.id} data-og-timeline-row-anchor="" className={cn(newFamily && "mt-3")}>
|
|
83
87
|
{row}
|
|
84
88
|
</div>
|
|
85
89
|
);
|
|
@@ -112,6 +116,18 @@ function renderActivity(
|
|
|
112
116
|
return <SandboxRow item={item} />;
|
|
113
117
|
case "memory":
|
|
114
118
|
return <MemoryRow item={item} onMemoryClick={onMemoryClick} />;
|
|
119
|
+
case "fleet-decision":
|
|
120
|
+
return (
|
|
121
|
+
<Suspense fallback={null}>
|
|
122
|
+
<LazyFleetDecisionRow
|
|
123
|
+
item={item}
|
|
124
|
+
d={ActivityDisclosure}
|
|
125
|
+
b={BodyNote}
|
|
126
|
+
j={rowJsx}
|
|
127
|
+
s={rowJsxs}
|
|
128
|
+
/>
|
|
129
|
+
</Suspense>
|
|
130
|
+
);
|
|
115
131
|
default:
|
|
116
132
|
return assertNever(item);
|
|
117
133
|
}
|