@athenaintel/react 0.57.1 → 0.57.2
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/README.md +19 -0
- package/dist/chat/AthenaChat.cjs +47 -2
- package/dist/chat/AthenaChat.cjs.map +1 -1
- package/dist/chat/AthenaChat.js +47 -2
- package/dist/chat/AthenaChat.js.map +1 -1
- package/dist/provider/AthenaProvider.cjs +7 -0
- package/dist/provider/AthenaProvider.cjs.map +1 -1
- package/dist/provider/AthenaProvider.js +9 -2
- package/dist/provider/AthenaProvider.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/runtime/statewire-run-config.cjs +15 -0
- package/dist/runtime/statewire-run-config.cjs.map +1 -1
- package/dist/runtime/statewire-run-config.d.ts +13 -0
- package/dist/runtime/statewire-run-config.js +15 -0
- package/dist/runtime/statewire-run-config.js.map +1 -1
- package/dist/threads/SessionList.cjs +22 -19
- package/dist/threads/SessionList.cjs.map +1 -1
- package/dist/threads/SessionList.js +22 -19
- package/dist/threads/SessionList.js.map +1 -1
- package/dist/threads/live-session-rows.cjs +207 -0
- package/dist/threads/live-session-rows.cjs.map +1 -0
- package/dist/threads/live-session-rows.d.ts +175 -0
- package/dist/threads/live-session-rows.js +207 -0
- package/dist/threads/live-session-rows.js.map +1 -0
- package/dist/threads/statewire-thread-list.cjs +173 -20
- package/dist/threads/statewire-thread-list.cjs.map +1 -1
- package/dist/threads/statewire-thread-list.d.ts +44 -1
- package/dist/threads/statewire-thread-list.js +174 -21
- package/dist/threads/statewire-thread-list.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-session-rows.js","sources":["../../src/threads/live-session-rows.ts"],"sourcesContent":["/**\n * The rows the session list shows between one server answer and the next.\n *\n * The list's rows come from the fetched REST pages, and the signed-in user's\n * live conversation index updates them in place. Two gaps are filled here, so\n * the list follows what just happened without waiting for a re-read:\n *\n * - **Sessions the index pushed that the page does not list yet.** A session\n * just started (in this tab or anywhere else) reaches the index in about a\n * second; the re-read the list runs for it takes several more (measured on\n * staging 2026-11-06: push at +1.8 s, row drawn at +5.5 s). The pushed entry\n * is drawn at once, while the re-read still fills in what the index never\n * carries (pull requests, who started it).\n * - **A message this tab just sent.** The session moves to the top as working\n * the moment it is sent (a chat the server does not know yet gets a pending\n * row titled with the message), until the server reports the send.\n *\n * Rows are kept newest first by `updatedAt`, the server's own order, so a\n * session that just became active moves up instead of staying where its last\n * fetched copy was.\n *\n * Pure functions over the shared contract rows: the provider composes them,\n * and they are tested on their own.\n */\nimport {\n type ConversationIndexEntry,\n type ConversationSummary,\n summaryFromConversationIndexEntry,\n} from '@athenaintel/agent-runtime';\n\n/**\n * Start channels of an agent's sessions that the server leaves out when it lists the conversations\n * with a home agent (`home_agent_id`): the agent's tasks and the sessions an orchestrating agent\n * starts.\n */\nconst AGENT_HOME_EXCLUDED_START_CHANNELS: ReadonlySet<string> = new Set([\n 'task',\n 'agent_orchestration',\n]);\n\n/** The REST thread list only lists this asset type (`sdk_thread_list.py`); the index carries more. */\nconst LISTED_ASSET_TYPE = 'session';\n\n/**\n * Whether a pushed index entry is one of the conversations with `homeAgentId`'s agent that the\n * server lists beside the app scope: the agent's, and not one of its tasks or orchestration\n * sessions. An entry from a pod that predates `collab_agent_id` is not.\n */\nexport function isAgentHomeIndexEntry(\n entry: { collab_agent_id?: string | null; start_channel?: string | null },\n homeAgentId: string | undefined,\n): boolean {\n if (!homeAgentId || entry.collab_agent_id !== homeAgentId) return false;\n return !AGENT_HOME_EXCLUDED_START_CHANNELS.has(entry.start_channel ?? '');\n}\n\n/** Which sessions a list shows: its app scope, as the server applies it to every read. */\nexport interface SessionListScope {\n /** The provider's `appId`; the app's own sessions. */\n appId: string | undefined;\n /** Other apps whose sessions the list shows too (a union with `appId`). */\n additionalAppIds: readonly string[];\n /** The collab agent whose conversations the list also asks for (`home_agent_id`). */\n homeAgentId: string | undefined;\n /**\n * Whether the list's latest first page said the server widened it to the home agent's\n * conversations. A server that did not never lists them.\n */\n homeAgentApplied: boolean;\n}\n\n/**\n * Whether the server lists a session with these stamps in a list of this scope — the app filter\n * and the home-agent union exactly as `sdk_thread_list.py` applies them. With no app ids the list\n * holds every app's sessions, unless it was widened to an agent, which then makes it that agent's.\n */\nexport function inSessionListScope(\n entry: { app_id: string | null; collab_agent_id?: string | null; start_channel?: string | null },\n scope: SessionListScope,\n): boolean {\n const appIds = [...(scope.appId ? [scope.appId] : []), ...scope.additionalAppIds];\n const agentId = scope.homeAgentApplied ? scope.homeAgentId : undefined;\n if (appIds.length === 0) return agentId ? isAgentHomeIndexEntry(entry, agentId) : true;\n return appIds.includes(entry.app_id ?? '') || isAgentHomeIndexEntry(entry, agentId);\n}\n\nfunction timestampMs(value: string): number {\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\n/**\n * The listed rows plus every session the index pushed that the list should show and does not\n * list yet: in the list's scope, a listed asset type, and — while older pages remain unread — no\n * older than the oldest loaded row, so a row is never drawn below sessions that are not loaded\n * yet. Nothing is added while a search is active (the server matches it; the index cannot) or\n * before the first page has answered (the page decides what the list starts with). Identity is\n * kept when nothing is added. The rows are not re-sorted here ({@link sortNewestFirst}).\n */\nexport function withIndexedSessions({\n conversations,\n loadedConversations,\n entries,\n scope,\n searching,\n hasResolvedFirstPage,\n hasNextPage,\n}: {\n /** The rows the list shows (fetched pages, pinned rows, folded with the index). */\n conversations: readonly ConversationSummary[];\n /** The fetched pages' rows alone: the window older pages continue below. */\n loadedConversations: readonly ConversationSummary[];\n entries: readonly ConversationIndexEntry[] | null;\n scope: SessionListScope;\n searching: boolean;\n hasResolvedFirstPage: boolean;\n hasNextPage: boolean;\n}): readonly ConversationSummary[] {\n if (!entries || entries.length === 0 || searching || !hasResolvedFirstPage) return conversations;\n const listed = new Set(conversations.map((conversation) => conversation.threadId));\n let windowTailMs: number | null = null;\n if (hasNextPage) {\n for (const conversation of loadedConversations) {\n const ms = timestampMs(conversation.updatedAt);\n if (windowTailMs === null || ms < windowTailMs) windowTailMs = ms;\n }\n }\n const added: ConversationSummary[] = [];\n for (const entry of entries) {\n if (listed.has(entry.thread_id)) continue;\n if (entry.asset_type !== LISTED_ASSET_TYPE) continue;\n if (!inSessionListScope(entry, scope)) continue;\n if (windowTailMs !== null && timestampMs(entry.updated_at) < windowTailMs) continue;\n listed.add(entry.thread_id);\n added.push(summaryFromConversationIndexEntry(entry));\n }\n return added.length === 0 ? conversations : [...conversations, ...added];\n}\n\n/** How long a sent message holds its session's row before the server's own copy must take over. */\nexport const LOCAL_SEND_TTL_MS = 60_000;\n\n/** The longest provisional title kept from a sent message; the server's own title replaces it. */\nconst PENDING_TITLE_MAX_LENGTH = 200;\n\n/**\n * A message this tab sent that the server has not reported yet. Held by the provider; it\n * shapes the session's row until the server's copy of the session reflects the send.\n */\nexport interface LocalSessionSend {\n threadId: string;\n /** When this tab sent it (the client's clock, ms since the epoch). */\n sentAtMs: number;\n /**\n * The instant the row sorts at until the server reports the send: the send time, and never\n * older than the newest row the list showed when it was sent, so the session leads the list\n * even on a client whose clock runs behind the server's.\n */\n sortAt: string;\n /**\n * The session's `updatedAt` as the list showed it when the message was sent; `null` when the\n * list did not show the session (a new chat, or an older session the loaded pages do not\n * reach). The send is reported once the server's row differs.\n */\n baselineUpdatedAt: string | null;\n /**\n * Whether the session was a chat this tab started that the server had not listed yet. Only\n * such a send gets a pending row: a session missing from the loaded pages may well exist.\n */\n newChat: boolean;\n /** The message as one line, the pending title of a chat the server does not know yet. */\n title: string | null;\n /**\n * The provenance the session's first run stamps, when it is known here (the SDK's own `web`,\n * or a host's `extraRunConfig.start_channel`); `null` when the backend decides it (a collab\n * channel stamps its own kind). A new chat's pending row shows it as its origin.\n */\n startChannel: string | null;\n}\n\n/**\n * A sent message as the one-line provisional title of its session: markdown links reduced to\n * their text (a mention reads as its name), whitespace folded, and long messages cut. `null`\n * when nothing is left (an attachment sent alone).\n */\nexport function pendingSessionTitle(text: string | null | undefined): string | null {\n const line = (text ?? '')\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\s+/g, ' ')\n .trim();\n if (!line) return null;\n return line.length <= PENDING_TITLE_MAX_LENGTH\n ? line\n : `${line.slice(0, PENDING_TITLE_MAX_LENGTH - 1).trimEnd()}…`;\n}\n\n/**\n * Record a send against the rows the server last reported: the baseline the server must move\n * past, and the instant the row sorts at until it does.\n */\nexport function localSessionSend({\n threadId,\n text,\n sentAtMs,\n newChat,\n startChannel,\n serverConversations,\n}: {\n threadId: string;\n text: string | null | undefined;\n sentAtMs: number;\n /** The session was a chat this tab started that the server had not listed yet. */\n newChat: boolean;\n /** The `start_channel` the send stamps (`effectiveStatewireStartChannel`); `null` if unknown. */\n startChannel: string | null;\n /** The server's rows as the list shows them (fetched pages and pushed index entries). */\n serverConversations: readonly ConversationSummary[];\n}): LocalSessionSend {\n let newestMs = 0;\n let baselineUpdatedAt: string | null = null;\n for (const conversation of serverConversations) {\n const ms = timestampMs(conversation.updatedAt);\n if (ms > newestMs) newestMs = ms;\n if (conversation.threadId === threadId) baselineUpdatedAt = conversation.updatedAt;\n }\n return {\n threadId,\n sentAtMs,\n sortAt: new Date(Math.max(sentAtMs, newestMs + 1)).toISOString(),\n baselineUpdatedAt,\n newChat: newChat && baselineUpdatedAt === null,\n title: pendingSessionTitle(text),\n startChannel,\n };\n}\n\n/**\n * Whether the server's copy of the session reflects the send: a session the list did not show\n * is reported once the server lists it at all; a listed session once its `updatedAt` moved.\n */\nexport function isLocalSendReported(\n send: LocalSessionSend,\n serverRow: ConversationSummary | undefined,\n): boolean {\n if (!serverRow) return false;\n return send.baselineUpdatedAt === null || serverRow.updatedAt !== send.baselineUpdatedAt;\n}\n\n/** The sends without `threadIds`; the same map when it holds none of them. */\nexport function withoutLocalSends(\n sends: ReadonlyMap<string, LocalSessionSend>,\n threadIds: readonly string[],\n): ReadonlyMap<string, LocalSessionSend> {\n if (!threadIds.some((threadId) => sends.has(threadId))) return sends;\n const next = new Map(sends);\n for (const threadId of threadIds) next.delete(threadId);\n return next;\n}\n\n/** The sends to forget: reported by the server, or older than {@link LOCAL_SEND_TTL_MS}. */\nexport function settledLocalSends({\n sends,\n serverConversations,\n nowMs,\n ttlMs = LOCAL_SEND_TTL_MS,\n}: {\n sends: ReadonlyMap<string, LocalSessionSend>;\n serverConversations: readonly ConversationSummary[];\n nowMs: number;\n ttlMs?: number;\n}): string[] {\n if (sends.size === 0) return [];\n const byThread = new Map(serverConversations.map((row) => [row.threadId, row]));\n const settled: string[] = [];\n for (const send of sends.values()) {\n if (nowMs - send.sentAtMs >= ttlMs || isLocalSendReported(send, byThread.get(send.threadId))) {\n settled.push(send.threadId);\n }\n }\n return settled;\n}\n\n/** The session as working, sorted at the send, until the server reports the send. */\nfunction withSentMessage(row: ConversationSummary, send: LocalSessionSend): ConversationSummary {\n return {\n ...row,\n updatedAt: timestampMs(row.updatedAt) >= timestampMs(send.sortAt) ? row.updatedAt : send.sortAt,\n state: 'running',\n sessionStatus: 'active',\n runStatus: 'running',\n attention: 'working',\n nextAction: null,\n attentionSource: null,\n isUnread: false,\n };\n}\n\n/** The pending row of a chat the server does not know yet, as the server will first list it. */\nfunction pendingConversation(send: LocalSessionSend, appId: string | undefined): ConversationSummary {\n const sentAt = new Date(send.sentAtMs).toISOString();\n return {\n threadId: send.threadId,\n title: send.title ?? '',\n updatedAt: send.sortAt,\n createdAt: sentAt,\n state: 'running',\n runtime: null,\n // What the server stamps on the session's first run, when that is known here: the row's\n // origin badge reads as the server's row will, never as a label made from the app id.\n sourceChannel: send.startChannel,\n assetType: LISTED_ASSET_TYPE,\n assetId: null,\n appId: appId ?? null,\n triggerType: null,\n preview: send.title,\n messageCount: null,\n isUnread: false,\n sessionStatus: 'active',\n runStatus: 'running',\n attention: 'working',\n nextAction: null,\n attentionSource: null,\n isFavorited: false,\n createdByMe: true,\n };\n}\n\n/**\n * The rows with this tab's unreported sends applied: a listed session the server has not\n * reported the send for shows as working and sorts at the send; a new chat this tab started\n * gets a pending row, if the list's scope holds this app's new sessions and no search is\n * active. A session the loaded pages do not reach gets nothing here: it exists, and the\n * server's push (or re-read) brings it to the top. Returns the rows and the ids of the pending\n * rows (which the server does not know, so writes cannot be offered on them). Identity is kept\n * when no send applies.\n */\nexport function withLocalSends({\n conversations,\n sends,\n appId,\n showPendingSessions,\n}: {\n conversations: readonly ConversationSummary[];\n sends: ReadonlyMap<string, LocalSessionSend>;\n /** The app new sessions are tagged with (the provider's `appId`). */\n appId: string | undefined;\n /** Whether a new chat's pending row belongs in this list (its scope and search allow it). */\n showPendingSessions: boolean;\n}): { conversations: readonly ConversationSummary[]; pendingThreadIds: ReadonlySet<string> } {\n if (sends.size === 0) return { conversations, pendingThreadIds: EMPTY_IDS };\n const listed = new Set<string>();\n let changed = false;\n const rows = conversations.map((row) => {\n listed.add(row.threadId);\n const send = sends.get(row.threadId);\n if (!send || isLocalSendReported(send, row)) return row;\n changed = true;\n return withSentMessage(row, send);\n });\n const pendingThreadIds = new Set<string>();\n if (showPendingSessions) {\n for (const send of sends.values()) {\n if (!send.newChat || listed.has(send.threadId)) continue;\n pendingThreadIds.add(send.threadId);\n rows.push(pendingConversation(send, appId));\n changed = true;\n }\n }\n return {\n conversations: changed ? rows : conversations,\n pendingThreadIds: pendingThreadIds.size === 0 ? EMPTY_IDS : pendingThreadIds,\n };\n}\n\nconst EMPTY_IDS: ReadonlySet<string> = new Set();\n\n/**\n * The rows newest first by `updatedAt` (the order the server lists them in), keeping the given\n * order between rows of the same instant. Identity is kept when the rows are already in order.\n */\nexport function sortNewestFirst<T extends { updatedAt: string }>(rows: readonly T[]): readonly T[] {\n const keyed = rows.map((row, index) => ({ row, index, ms: timestampMs(row.updatedAt) }));\n let ordered = true;\n for (let i = 1; i < keyed.length; i++) {\n if ((keyed[i - 1]?.ms ?? 0) < (keyed[i]?.ms ?? 0)) {\n ordered = false;\n break;\n }\n }\n if (ordered) return rows;\n keyed.sort((a, b) => b.ms - a.ms || a.index - b.index);\n return keyed.map(({ row }) => row);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ const mintThreadId = require("./mint-thread-id.cjs");
|
|
|
15
15
|
const threadIdContext = require("./thread-id-context.cjs");
|
|
16
16
|
const threadPrefetcher = require("./thread-prefetcher.cjs");
|
|
17
17
|
const indexTriggeredRefresh = require("./index-triggered-refresh.cjs");
|
|
18
|
+
const liveSessionRows = require("./live-session-rows.cjs");
|
|
18
19
|
const sessionListTabShare = require("./session-list-tab-share.cjs");
|
|
19
20
|
const title = require("./title.cjs");
|
|
20
21
|
const authRefusalRestart = require("../runtime/auth-refusal-restart.cjs");
|
|
@@ -34,14 +35,6 @@ function useRefreshThreadList() {
|
|
|
34
35
|
var _a;
|
|
35
36
|
return ((_a = useAthenaStatewireThreadList()) == null ? void 0 : _a.refresh) ?? null;
|
|
36
37
|
}
|
|
37
|
-
const AGENT_HOME_EXCLUDED_START_CHANNELS = /* @__PURE__ */ new Set([
|
|
38
|
-
"task",
|
|
39
|
-
"agent_orchestration"
|
|
40
|
-
]);
|
|
41
|
-
function isAgentHomeIndexEntry(entry, homeAgentId) {
|
|
42
|
-
if (!homeAgentId || entry.collab_agent_id !== homeAgentId) return false;
|
|
43
|
-
return !AGENT_HOME_EXCLUDED_START_CHANNELS.has(entry.start_channel ?? "");
|
|
44
|
-
}
|
|
45
38
|
function indexedThreadsToRefreshFor({
|
|
46
39
|
entries,
|
|
47
40
|
listedThreadIds,
|
|
@@ -54,7 +47,7 @@ function indexedThreadsToRefreshFor({
|
|
|
54
47
|
const shownAppIds = appId || additionalAppIds.length > 0 ? /* @__PURE__ */ new Set([...appId ? [appId] : [], ...additionalAppIds]) : null;
|
|
55
48
|
const listedAgentId = homeAgentApplied ? homeAgentId : void 0;
|
|
56
49
|
return entries.filter(
|
|
57
|
-
(entry) => !shownAppIds || shownAppIds.has(entry.app_id ?? "") || isAgentHomeIndexEntry(entry, listedAgentId)
|
|
50
|
+
(entry) => !shownAppIds || shownAppIds.has(entry.app_id ?? "") || liveSessionRows.isAgentHomeIndexEntry(entry, listedAgentId)
|
|
58
51
|
).map((entry) => entry.thread_id).filter((threadId) => !listedThreadIds.has(threadId) && !refreshedThreadIds.has(threadId));
|
|
59
52
|
}
|
|
60
53
|
function threadSummaryFromConversation(conversation) {
|
|
@@ -100,9 +93,16 @@ function withPinnedConversations({
|
|
|
100
93
|
return unlisted.length === 0 ? conversations : [...conversations, ...unlisted];
|
|
101
94
|
}
|
|
102
95
|
const AthenaSessionsLiveContext = require$$0.createContext(null);
|
|
96
|
+
const AthenaThreadListSendContext = require$$0.createContext(null);
|
|
97
|
+
const POLL_REFRESH_AFTER_SEND_MS = [3e3, 1e4];
|
|
103
98
|
const THREAD_LIST_PAGE_SIZE = 50;
|
|
104
99
|
const EMPTY_THREAD_IDS = /* @__PURE__ */ new Set();
|
|
100
|
+
const EMPTY_LOCAL_SENDS = /* @__PURE__ */ new Map();
|
|
105
101
|
const MAX_PINNED_PAGES = 10;
|
|
102
|
+
function withoutLocalSends(state, threadIds) {
|
|
103
|
+
const sends = liveSessionRows.withoutLocalSends(state.sends, threadIds);
|
|
104
|
+
return sends === state.sends ? state : { ...state, sends };
|
|
105
|
+
}
|
|
106
106
|
function StatewireThreadListState({
|
|
107
107
|
backendUrl,
|
|
108
108
|
syncUrl,
|
|
@@ -251,6 +251,34 @@ function StatewireThreadListState({
|
|
|
251
251
|
() => foldConversationIndex(listedConversations, indexByThread),
|
|
252
252
|
[listedConversations, indexByThread]
|
|
253
253
|
);
|
|
254
|
+
const homeAgentApplied = list.homeAgentApplied;
|
|
255
|
+
const scope = require$$0.useMemo(
|
|
256
|
+
() => ({ appId, additionalAppIds: listedAppIds, homeAgentId, homeAgentApplied }),
|
|
257
|
+
[appId, listedAppIds, homeAgentId, homeAgentApplied]
|
|
258
|
+
);
|
|
259
|
+
const searching = trimmedSearch.length > 0;
|
|
260
|
+
const serverConversations = require$$0.useMemo(
|
|
261
|
+
() => liveSessionRows.sortNewestFirst(
|
|
262
|
+
liveSessionRows.withIndexedSessions({
|
|
263
|
+
conversations: mergedConversations,
|
|
264
|
+
loadedConversations: list.conversations,
|
|
265
|
+
entries: index.entries,
|
|
266
|
+
scope,
|
|
267
|
+
searching,
|
|
268
|
+
hasResolvedFirstPage: list.hasResolvedFirstPage,
|
|
269
|
+
hasNextPage: list.hasNextPage
|
|
270
|
+
})
|
|
271
|
+
),
|
|
272
|
+
[
|
|
273
|
+
mergedConversations,
|
|
274
|
+
list.conversations,
|
|
275
|
+
index.entries,
|
|
276
|
+
scope,
|
|
277
|
+
searching,
|
|
278
|
+
list.hasResolvedFirstPage,
|
|
279
|
+
list.hasNextPage
|
|
280
|
+
]
|
|
281
|
+
);
|
|
254
282
|
const queryClient = reactQuery.useQueryClient();
|
|
255
283
|
const patchEveryList = require$$0.useCallback(
|
|
256
284
|
(threadId, patch) => conversationList.patchConversationListCaches(queryClient, {
|
|
@@ -264,7 +292,7 @@ function StatewireThreadListState({
|
|
|
264
292
|
backendUrl,
|
|
265
293
|
principalId: principal,
|
|
266
294
|
getAuth,
|
|
267
|
-
rows:
|
|
295
|
+
rows: serverConversations,
|
|
268
296
|
onServerTruth: ({ threadId, isFavorited }) => {
|
|
269
297
|
patchEveryList(threadId, { isFavorited });
|
|
270
298
|
if (isFavorited) void pinnedListRefresh();
|
|
@@ -275,7 +303,7 @@ function StatewireThreadListState({
|
|
|
275
303
|
backendUrl,
|
|
276
304
|
principalId: principal,
|
|
277
305
|
getAuth,
|
|
278
|
-
rows:
|
|
306
|
+
rows: serverConversations,
|
|
279
307
|
onServerTruth: ({ threadId, title: title2 }) => patchEveryList(threadId, { title: title2 })
|
|
280
308
|
});
|
|
281
309
|
const titleOverrides = rename.overrides;
|
|
@@ -283,7 +311,7 @@ function StatewireThreadListState({
|
|
|
283
311
|
backendUrl,
|
|
284
312
|
principalId: principal,
|
|
285
313
|
getAuth,
|
|
286
|
-
rows:
|
|
314
|
+
rows: serverConversations,
|
|
287
315
|
onServerTruth: ({ threadId, isUnread }) => patchEveryList(threadId, { isUnread })
|
|
288
316
|
});
|
|
289
317
|
const readOverrides = readState.overrides;
|
|
@@ -316,9 +344,110 @@ function StatewireThreadListState({
|
|
|
316
344
|
).filter((conversation) => !hiddenThreadIds.has(conversation.threadId)),
|
|
317
345
|
[favoriteOverrides, titleOverrides, readOverrides, readCoveredUpdatedAt, hiddenThreadIds]
|
|
318
346
|
);
|
|
347
|
+
const sendsScopeKey = `${listScopeKey}::${credentialGeneration}::${conversationList.conversationListFilterKey({
|
|
348
|
+
...appId ? { appId } : {},
|
|
349
|
+
...listedAppIds.length > 0 ? { appIds: listedAppIds } : {},
|
|
350
|
+
...homeAgentId ? { homeAgentId } : {}
|
|
351
|
+
})}`;
|
|
352
|
+
const [localSendState, setLocalSendState] = require$$0.useState(() => ({ scopeKey: sendsScopeKey, sends: EMPTY_LOCAL_SENDS }));
|
|
353
|
+
const localSends = localSendState.scopeKey === sendsScopeKey ? localSendState.sends : EMPTY_LOCAL_SENDS;
|
|
354
|
+
const serverConversationsRef = require$$0.useRef(serverConversations);
|
|
355
|
+
serverConversationsRef.current = serverConversations;
|
|
356
|
+
const sendsScopeKeyRef = require$$0.useRef(sendsScopeKey);
|
|
357
|
+
sendsScopeKeyRef.current = sendsScopeKey;
|
|
358
|
+
const activeRef = require$$0.useRef(active);
|
|
359
|
+
activeRef.current = active;
|
|
360
|
+
const indexLiveRef = require$$0.useRef(index.entries !== null);
|
|
361
|
+
indexLiveRef.current = index.entries !== null;
|
|
362
|
+
const refreshAfterSendRef = require$$0.useRef(() => void 0);
|
|
363
|
+
const pollRefreshTimersRef = require$$0.useRef(/* @__PURE__ */ new Set());
|
|
364
|
+
require$$0.useEffect(() => {
|
|
365
|
+
const timers = pollRefreshTimersRef.current;
|
|
366
|
+
return () => {
|
|
367
|
+
for (const timer of timers) clearTimeout(timer);
|
|
368
|
+
timers.clear();
|
|
369
|
+
};
|
|
370
|
+
}, []);
|
|
371
|
+
const noteSend = require$$0.useCallback(({ threadId, text, startChannel }) => {
|
|
372
|
+
if (!threadId) return;
|
|
373
|
+
const rows = serverConversationsRef.current;
|
|
374
|
+
const send = liveSessionRows.localSessionSend({
|
|
375
|
+
threadId,
|
|
376
|
+
text,
|
|
377
|
+
sentAtMs: Date.now(),
|
|
378
|
+
newChat: activeRef.current.id === threadId && activeRef.current.isNew,
|
|
379
|
+
startChannel,
|
|
380
|
+
serverConversations: rows
|
|
381
|
+
});
|
|
382
|
+
const scopeKey = sendsScopeKeyRef.current;
|
|
383
|
+
setLocalSendState((current) => {
|
|
384
|
+
const sends = new Map(current.scopeKey === scopeKey ? current.sends : EMPTY_LOCAL_SENDS);
|
|
385
|
+
const previous = sends.get(threadId);
|
|
386
|
+
const serverRow = rows.find((row) => row.threadId === threadId);
|
|
387
|
+
sends.set(
|
|
388
|
+
threadId,
|
|
389
|
+
previous && !liveSessionRows.isLocalSendReported(previous, serverRow) ? {
|
|
390
|
+
...send,
|
|
391
|
+
baselineUpdatedAt: previous.baselineUpdatedAt,
|
|
392
|
+
newChat: previous.newChat,
|
|
393
|
+
title: previous.title ?? send.title,
|
|
394
|
+
startChannel: previous.startChannel
|
|
395
|
+
} : send
|
|
396
|
+
);
|
|
397
|
+
return { scopeKey, sends };
|
|
398
|
+
});
|
|
399
|
+
if (!indexLiveRef.current && !send.newChat) {
|
|
400
|
+
for (const delay of POLL_REFRESH_AFTER_SEND_MS) {
|
|
401
|
+
const timer = setTimeout(() => {
|
|
402
|
+
pollRefreshTimersRef.current.delete(timer);
|
|
403
|
+
refreshAfterSendRef.current();
|
|
404
|
+
}, delay);
|
|
405
|
+
pollRefreshTimersRef.current.add(timer);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}, []);
|
|
409
|
+
require$$0.useEffect(() => {
|
|
410
|
+
if (localSends.size === 0) return;
|
|
411
|
+
const settled = liveSessionRows.settledLocalSends({ sends: localSends, serverConversations, nowMs: Date.now() });
|
|
412
|
+
if (settled.length > 0) {
|
|
413
|
+
setLocalSendState((current) => withoutLocalSends(current, settled));
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
let oldestMs = Number.POSITIVE_INFINITY;
|
|
417
|
+
for (const send of localSends.values()) oldestMs = Math.min(oldestMs, send.sentAtMs);
|
|
418
|
+
const timer = setTimeout(
|
|
419
|
+
() => setLocalSendState(
|
|
420
|
+
(current) => withoutLocalSends(
|
|
421
|
+
current,
|
|
422
|
+
[...current.sends.values()].filter((send) => Date.now() - send.sentAtMs >= liveSessionRows.LOCAL_SEND_TTL_MS).map((send) => send.threadId)
|
|
423
|
+
)
|
|
424
|
+
),
|
|
425
|
+
Math.max(0, oldestMs + liveSessionRows.LOCAL_SEND_TTL_MS - Date.now()) + 1
|
|
426
|
+
);
|
|
427
|
+
return () => clearTimeout(timer);
|
|
428
|
+
}, [localSends, serverConversations]);
|
|
429
|
+
const showPendingSessions = require$$0.useMemo(
|
|
430
|
+
() => !searching && liveSessionRows.inSessionListScope(
|
|
431
|
+
{ app_id: appId ?? null, collab_agent_id: homeAgentId ?? null, start_channel: null },
|
|
432
|
+
scope
|
|
433
|
+
),
|
|
434
|
+
[searching, appId, homeAgentId, scope]
|
|
435
|
+
);
|
|
436
|
+
const liveRows = require$$0.useMemo(
|
|
437
|
+
() => liveSessionRows.withLocalSends({
|
|
438
|
+
conversations: serverConversations,
|
|
439
|
+
sends: localSends,
|
|
440
|
+
appId,
|
|
441
|
+
showPendingSessions
|
|
442
|
+
}),
|
|
443
|
+
[serverConversations, localSends, appId, showPendingSessions]
|
|
444
|
+
);
|
|
319
445
|
const data = require$$0.useMemo(
|
|
320
|
-
() => applyOverrides(
|
|
321
|
-
|
|
446
|
+
() => liveSessionRows.sortNewestFirst(applyOverrides(liveRows.conversations)).map((conversation) => {
|
|
447
|
+
const summary = threadSummaryFromConversation(conversation);
|
|
448
|
+
return liveRows.pendingThreadIds.has(conversation.threadId) ? { ...summary, isPending: true } : summary;
|
|
449
|
+
}),
|
|
450
|
+
[applyOverrides, liveRows]
|
|
322
451
|
);
|
|
323
452
|
const isLoading = list.isLoading;
|
|
324
453
|
const lastActiveConversationRef = require$$0.useRef(null);
|
|
@@ -354,6 +483,7 @@ function StatewireThreadListState({
|
|
|
354
483
|
void listRefresh();
|
|
355
484
|
if (!pinnedFetchingRef.current) void pinnedListRefresh();
|
|
356
485
|
}, [listRefresh, pinnedListRefresh]);
|
|
486
|
+
refreshAfterSendRef.current = refresh;
|
|
357
487
|
const listFetchNextPage = list.fetchNextPage;
|
|
358
488
|
const fetchNextPage = require$$0.useCallback(() => {
|
|
359
489
|
void listFetchNextPage();
|
|
@@ -362,7 +492,6 @@ function StatewireThreadListState({
|
|
|
362
492
|
() => new Set(list.conversations.map((conversation) => conversation.threadId)),
|
|
363
493
|
[list.conversations]
|
|
364
494
|
);
|
|
365
|
-
const homeAgentApplied = list.homeAgentApplied;
|
|
366
495
|
const unlistedIndexedThreads = require$$0.useMemo(
|
|
367
496
|
() => index.entries === null ? [] : indexedThreadsToRefreshFor({
|
|
368
497
|
entries: index.entries,
|
|
@@ -406,14 +535,14 @@ function StatewireThreadListState({
|
|
|
406
535
|
prefetchScopeRef.current = prefetchScope;
|
|
407
536
|
const prefetcher = require$$0.useMemo(() => {
|
|
408
537
|
if (!snapshotCache) return null;
|
|
409
|
-
const
|
|
538
|
+
const scope2 = prefetchScope;
|
|
410
539
|
return threadPrefetcher.createThreadPrefetcher({
|
|
411
540
|
cache: snapshotCache,
|
|
412
541
|
fetchState: async (threadId) => credentialRenewal.withCredentialRenewal(
|
|
413
542
|
getAuth,
|
|
414
543
|
(auth) => api.getThreadState(backendUrl, auth, threadId, { skipCache: false })
|
|
415
544
|
),
|
|
416
|
-
isCurrent: () => prefetchScopeRef.current ===
|
|
545
|
+
isCurrent: () => prefetchScopeRef.current === scope2
|
|
417
546
|
});
|
|
418
547
|
}, [snapshotCache, prefetchScope, backendUrl, getAuth]);
|
|
419
548
|
const activeIdRef = require$$0.useRef(active.id);
|
|
@@ -428,7 +557,7 @@ function StatewireThreadListState({
|
|
|
428
557
|
const newThread = require$$0.useCallback(() => {
|
|
429
558
|
setActive({ id: mintThreadId.mintThreadId(), isNew: true });
|
|
430
559
|
}, []);
|
|
431
|
-
const isPersisted =
|
|
560
|
+
const isPersisted = mergedConversations.some((conversation) => conversation.threadId === active.id) || indexByThread.has(active.id);
|
|
432
561
|
require$$0.useEffect(() => {
|
|
433
562
|
if (isPersisted) {
|
|
434
563
|
setActive((current) => current.isNew ? { ...current, isNew: false } : current);
|
|
@@ -536,7 +665,7 @@ function StatewireThreadListState({
|
|
|
536
665
|
tabShare
|
|
537
666
|
]
|
|
538
667
|
);
|
|
539
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AthenaStatewireThreadListContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(AthenaSessionsLiveContext.Provider, { value: live, children }) });
|
|
668
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AthenaStatewireThreadListContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(AthenaSessionsLiveContext.Provider, { value: live, children: /* @__PURE__ */ jsxRuntime.jsx(AthenaThreadListSendContext.Provider, { value: noteSend, children }) }) });
|
|
540
669
|
}
|
|
541
670
|
function AthenaStatewireThreadListProvider({
|
|
542
671
|
backendUrl,
|
|
@@ -585,7 +714,7 @@ function StatewireThreadTitlePoller() {
|
|
|
585
714
|
return (((_a2 = s.optional.thread) == null ? void 0 : _a2.messages.length) ?? 0) > 0;
|
|
586
715
|
});
|
|
587
716
|
const titleSource = (list == null ? void 0 : list.titleSource) ?? "poll";
|
|
588
|
-
const entry = list == null ? void 0 : list.threads.find((thread) => thread.id === activeThreadId);
|
|
717
|
+
const entry = list == null ? void 0 : list.threads.find((thread) => thread.id === activeThreadId && !thread.isPending);
|
|
589
718
|
const title$1 = ((_a = entry == null ? void 0 : entry.title) == null ? void 0 : _a.trim()) ?? "";
|
|
590
719
|
const hasTitle = title$1.length > 0 && !title.isSerializedContentPartsTitle(title$1);
|
|
591
720
|
const visitRef = require$$0.useRef(null);
|
|
@@ -620,9 +749,33 @@ function StatewireThreadTitlePoller() {
|
|
|
620
749
|
}, [activeThreadId, hasMessages, hasTitle, titleSource]);
|
|
621
750
|
return null;
|
|
622
751
|
}
|
|
752
|
+
function StatewireThreadListSendSync({
|
|
753
|
+
startChannel = null
|
|
754
|
+
} = {}) {
|
|
755
|
+
const noteSend = require$$0.useContext(AthenaThreadListSendContext);
|
|
756
|
+
const threadId = threadIdContext.useAthenaStatewireThreadId();
|
|
757
|
+
const typedRef = require$$0.useRef(/* @__PURE__ */ new Map());
|
|
758
|
+
require$$0.useEffect(() => {
|
|
759
|
+
typedRef.current.clear();
|
|
760
|
+
}, [threadId]);
|
|
761
|
+
react.useAuiEvent({ scope: "thread", event: "composer.textChange" }, (event) => {
|
|
762
|
+
if (event.origin === "send") return;
|
|
763
|
+
typedRef.current.set(event.messageId ?? "", event.text ?? "");
|
|
764
|
+
});
|
|
765
|
+
react.useAuiEvent({ scope: "thread", event: "composer.send" }, (event) => {
|
|
766
|
+
const composer = event.messageId ?? "";
|
|
767
|
+
const typed = typedRef.current.get(composer) ?? null;
|
|
768
|
+
typedRef.current.delete(composer);
|
|
769
|
+
if (!noteSend || !threadId) return;
|
|
770
|
+
noteSend({ threadId, text: event.chars > 0 ? typed : null, startChannel });
|
|
771
|
+
});
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
623
774
|
exports.AthenaSessionsLiveContext = AthenaSessionsLiveContext;
|
|
624
775
|
exports.AthenaStatewireThreadListContext = AthenaStatewireThreadListContext;
|
|
625
776
|
exports.AthenaStatewireThreadListProvider = AthenaStatewireThreadListProvider;
|
|
777
|
+
exports.AthenaThreadListSendContext = AthenaThreadListSendContext;
|
|
778
|
+
exports.StatewireThreadListSendSync = StatewireThreadListSendSync;
|
|
626
779
|
exports.StatewireThreadTitlePoller = StatewireThreadTitlePoller;
|
|
627
780
|
exports.TITLE_POLL_DELAY_MS = TITLE_POLL_DELAY_MS;
|
|
628
781
|
exports.foldConversationIndex = foldConversationIndex;
|