@tangle-network/agent-app 0.44.40 → 0.44.42

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.
@@ -1,4 +1,4 @@
1
- import { SandboxInstance, ProvisionEvent, StorageConfig, ScopedTokenScope, TurnDriveResult, Sandbox, MintScopedTokenOptions } from '@tangle-network/sandbox';
1
+ import { SandboxInstance, ProvisionEvent, EgressPolicy, StorageConfig, ScopedTokenScope, TurnDriveResult, Sandbox, MintScopedTokenOptions } from '@tangle-network/sandbox';
2
2
  export { StorageConfig } from '@tangle-network/sandbox';
3
3
  import { ReasoningEffort, AgentProfileMcpServer, AgentProfileFileMount, AgentProfile } from '@tangle-network/agent-interface';
4
4
  import { T as ToolHeaderNames } from '../auth-DJs6lfAs.js';
@@ -940,6 +940,15 @@ interface SandboxRuntimeConfig {
940
940
  permissionRole?: (workspaceRole: string) => SandboxPermissionLevel;
941
941
  resources?: SandboxResourceConfig;
942
942
  provider?: ProviderResolutionConfig;
943
+ /**
944
+ * Product-declared outbound network policy. Applied when a sandbox is
945
+ * created and reconciled before a reused or resumed sandbox is returned.
946
+ * This keeps product tools and other required endpoints reachable without
947
+ * product-local lifecycle calls. Adopting or changing the policy on an
948
+ * existing sandbox restarts its egress proxy once; matching explicit
949
+ * policies are left untouched.
950
+ */
951
+ egressPolicy?: EgressPolicy;
943
952
  storage?: (ctx: SandboxBuildContext) => StorageConfig | undefined;
944
953
  restore?: (ctx: SandboxBuildContext) => SandboxRestoreSpec | undefined;
945
954
  boxKey?: (scope: SandboxScope) => string;
@@ -70,7 +70,7 @@ import {
70
70
  verifySandboxTerminalToken,
71
71
  verifyTerminalProxyToken,
72
72
  writeProfileFilesToBox
73
- } from "../chunk-JYHMNFFU.js";
73
+ } from "../chunk-HUBACCOP.js";
74
74
  import "../chunk-LWSJK546.js";
75
75
  import "../chunk-CQZSAR77.js";
76
76
  import "../chunk-ICOHEZK6.js";
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Session shell — the app-shell mechanism every agent product needs around the
3
+ * chat surface: a list of past sessions in the rail, an entry point for a new
4
+ * one, and a paged history view behind it.
5
+ *
6
+ * `/web-react` already owns the chat SURFACE (composer, transcript, cards); it
7
+ * owned no session SHELL, so all four products hand-rolled one and drifted.
8
+ * This module is the shell's pure half: no React, no DOM, no peer imports, so a
9
+ * server loader can call `readRailCollapsedCookie` without dragging React into
10
+ * a worker bundle (`/web-react` holds the rendered half).
11
+ *
12
+ * Domain stays a parameter. A "session" here is only an id, a title and a
13
+ * timestamp — a gtm thread, a tax session and a legal matter are all the same
14
+ * shape to the shell, and the product supplies routing through `hrefForSession`
15
+ * rather than the shell knowing any URL.
16
+ */
17
+ /** One session as the shell needs to see it. Products map their own row
18
+ * (thread / session / matter) onto this before handing it over. */
19
+ interface SessionSummary {
20
+ id: string;
21
+ /** `null`/empty renders as the untitled placeholder rather than a blank row. */
22
+ title: string | null;
23
+ /** ISO-8601. `null` when the product has no timestamp to show. */
24
+ updatedAt: string | null;
25
+ isPinned?: boolean;
26
+ /** Unread for the viewer. Use `resolveSessionUnread` to fold live overlays in. */
27
+ unread?: boolean;
28
+ /** Free-form product label (gtm categories, legal matter types). Passed
29
+ * through untouched — the shell never interprets it. */
30
+ category?: string | null;
31
+ }
32
+ /** One fetched page of sessions with an optional continuation cursor. */
33
+ interface SessionPage {
34
+ items: SessionSummary[];
35
+ /** Opaque continuation token; absent/null ⇒ no further pages. */
36
+ nextCursor?: string | null;
37
+ }
38
+ /** Sort order for the history view. The product's fetcher decides what these
39
+ * mean against its own storage; the shell only round-trips the value. */
40
+ type SessionSort = 'newest' | 'oldest';
41
+ /**
42
+ * These mirror `@tangle-network/sandbox-ui/dashboard`'s `SidebarLayoutNavItem`
43
+ * / `RailExpandableSubItem` STRUCTURALLY rather than importing them, so this
44
+ * module stays free of the optional peer (invariant 3 — structural over
45
+ * hard-dep when the surface is small). `tests/session-shell/rail-contract.test.ts`
46
+ * assigns the builder output to the real sandbox-ui types, so a drift in either
47
+ * direction fails CI instead of silently dropping a field at runtime.
48
+ *
49
+ * `TIcon` is the product's icon component type (lucide, custom, anything) —
50
+ * generic so this file needs no React types.
51
+ */
52
+ interface SessionRailAction<TIcon = unknown> {
53
+ id: string;
54
+ label: string;
55
+ icon?: TIcon;
56
+ destructive?: boolean;
57
+ onSelect: () => void;
58
+ }
59
+ type RailPrefetch = 'none' | 'intent' | 'render' | 'viewport';
60
+ interface SessionRailSubItem<TIcon = unknown> {
61
+ id: string;
62
+ label: string;
63
+ href: string;
64
+ prefetch?: RailPrefetch;
65
+ /** Live working indicator — the session is mid-turn. */
66
+ isLoading?: boolean;
67
+ /** Bold + leading dot. sandbox-ui suppresses it while `isLoading`. */
68
+ unread?: boolean;
69
+ /** Emphasised row, used for the trailing "view all" overflow link. */
70
+ emphasis?: boolean;
71
+ actions?: SessionRailAction<TIcon>[];
72
+ }
73
+ interface SessionRailNavItem<TIcon = unknown> {
74
+ id: string;
75
+ /** REQUIRED, mirroring sandbox-ui — the rail renders `<Icon />` unguarded, so
76
+ * an omitted icon is a blank/crashing row rather than a styling nit. */
77
+ icon: TIcon;
78
+ label: string;
79
+ href: string;
80
+ badge?: number;
81
+ expandable?: boolean;
82
+ defaultOpen?: boolean;
83
+ subItems?: SessionRailSubItem<TIcon>[];
84
+ subActiveIds?: string[];
85
+ emptyLabel?: string;
86
+ prefetch?: RailPrefetch;
87
+ }
88
+ /** Per-row rename/delete wiring. Supplied by the layout that owns the dialogs;
89
+ * omitted (or `canEdit: false`) leaves rows read-only. */
90
+ interface SessionRowActions<TIcon = unknown> {
91
+ canEdit: boolean;
92
+ renameIcon?: TIcon;
93
+ deleteIcon?: TIcon;
94
+ renameLabel?: string;
95
+ deleteLabel?: string;
96
+ onRename: (session: SessionSummary) => void;
97
+ onDelete: (session: SessionSummary) => void;
98
+ }
99
+ declare const UNTITLED_SESSION_LABEL = "Untitled chat";
100
+ /** Display title for a session row — trims, and falls back rather than
101
+ * rendering an empty row the user cannot aim at. */
102
+ declare function sessionLabel(session: SessionSummary, untitled?: string): string;
103
+ interface BuildSessionSubItemsOptions<TIcon = unknown> {
104
+ sessions: SessionSummary[];
105
+ /** The product's route for one session. The shell never builds a URL itself. */
106
+ hrefForSession: (sessionId: string) => string;
107
+ /** Ids currently mid-turn — renders the working indicator. */
108
+ respondingSessionIds?: ReadonlySet<string>;
109
+ actions?: SessionRowActions<TIcon>;
110
+ untitledLabel?: string;
111
+ prefetch?: RailPrefetch;
112
+ /** Trailing "view all" row, appended when the capped list hides sessions. */
113
+ overflow?: {
114
+ href: string;
115
+ label?: string;
116
+ };
117
+ }
118
+ /** Session rows for the rail's expandable history item. */
119
+ declare function buildSessionSubItems<TIcon = unknown>({ sessions, hrefForSession, respondingSessionIds, actions, untitledLabel, prefetch, overflow, }: BuildSessionSubItemsOptions<TIcon>): SessionRailSubItem<TIcon>[];
120
+ interface BuildSessionNavItemOptions<TIcon = unknown> extends BuildSessionSubItemsOptions<TIcon> {
121
+ /** Nav id the product highlights against (`activeNavId === id`). */
122
+ id?: string;
123
+ label?: string;
124
+ /** The product's icon component. Required — see `SessionRailNavItem.icon`. */
125
+ icon: TIcon;
126
+ /** The expandable row's own destination — the full history page. */
127
+ href: string;
128
+ /** Session currently open, highlighted inside the expandable. */
129
+ activeSessionId?: string | null;
130
+ emptyLabel?: string;
131
+ defaultOpen?: boolean;
132
+ }
133
+ /**
134
+ * The rail's session entry: one expandable nav row whose sub-items are the
135
+ * recent sessions. This is the structure the owner asked for — history lives IN
136
+ * the rail, not in a second sidebar panel beside it.
137
+ */
138
+ declare function buildSessionNavItem<TIcon = unknown>({ id, label, icon, href, activeSessionId, emptyLabel, defaultOpen, ...subItemOptions }: BuildSessionNavItemOptions<TIcon>): SessionRailNavItem<TIcon>;
139
+ interface ActiveSessionIdOptions {
140
+ pathname: string;
141
+ /** Workspace-scoped route base, e.g. `/app/ws_123`. */
142
+ base: string;
143
+ /** Route segment sessions live under. Default `chat` ⇒ `${base}/chat/:id`.
144
+ * Pass `''` when sessions sit DIRECTLY under the base (`/app/:sessionId`),
145
+ * which is how one product routes them — then `reserved` is mandatory. */
146
+ segment?: string;
147
+ /** Segment that means "composing a new session", not an id. Default `new`. */
148
+ newSegment?: string;
149
+ /**
150
+ * First segments that are OTHER routes, not session ids. Only meaningful
151
+ * with `segment: ''`, where `/app/settings` is otherwise indistinguishable
152
+ * from a session called `settings` — and resolving it as one would highlight
153
+ * and prefetch a session that does not exist. Pass the product's own nav
154
+ * paths; unknown-but-reserved is a routing bug, so this fails closed.
155
+ */
156
+ reserved?: readonly string[];
157
+ }
158
+ /**
159
+ * The session id the current route has open, or `null` on the new-session
160
+ * composer / anywhere else.
161
+ *
162
+ * Anchored at `base` on purpose. A bare `/\/chat\/([^/]+)/` scan — the shape
163
+ * three products shipped — matches the FIRST `/chat/` anywhere in the path, so
164
+ * a workspace or vault folder named `chat` resolves a neighbouring segment as a
165
+ * session id and the rail highlights (and prefetches) a session the user is not
166
+ * in. Same class as attaching to a stale box: it looks right and points at the
167
+ * wrong row.
168
+ */
169
+ declare function activeSessionIdFromPath({ pathname, base, segment, newSegment, reserved, }: ActiveSessionIdOptions): string | null;
170
+ /** One rail destination. `path` is relative to the workspace base. */
171
+ interface NavRouteDef {
172
+ id: string;
173
+ path: string;
174
+ }
175
+ interface ResolveActiveNavIdOptions {
176
+ pathname: string;
177
+ base: string;
178
+ /** The product's rail rows, in any order — resolution is longest-prefix. */
179
+ routes: NavRouteDef[];
180
+ /** Extra prefixes that light an existing row: `{ '/agents': 'integrations' }`.
181
+ * Participates in the same longest-prefix contest. */
182
+ aliases?: Record<string, string>;
183
+ /** Prefixes that deliberately highlight NOTHING, beating any shorter match.
184
+ * gtm uses this so an open chat lights no rail row while `/chat/new` still
185
+ * lights "New". */
186
+ claimsNothing?: string[];
187
+ }
188
+ /**
189
+ * The rail row to highlight for the current route.
190
+ *
191
+ * Longest-prefix wins, so declaration order cannot change the answer. The
192
+ * per-product versions this replaces were first-match over an array, which made
193
+ * `/chat/new` vs `/chat` an ordering accident rather than a rule.
194
+ */
195
+ declare function resolveActiveNavId({ pathname, base, routes, aliases, claimsNothing, }: ResolveActiveNavIdOptions): string | undefined;
196
+ interface ResolveSessionUnreadOptions {
197
+ sessionId: string;
198
+ /** Server-computed unread from the route loader. */
199
+ loaderUnread: boolean;
200
+ /** Live "went unread" ids from the workspace channel. */
201
+ liveUnreadIds?: ReadonlySet<string>;
202
+ /** Ids this tab has already opened since the loader ran. */
203
+ locallyReadIds?: ReadonlySet<string>;
204
+ /** The open session is never unread to its own viewer. */
205
+ currentSessionId?: string | null;
206
+ }
207
+ /**
208
+ * Effective unread for one row. The loader's value can be stale — a layout
209
+ * loader that survives same-workspace navigation keeps reporting a session as
210
+ * unread after the user opened it — so live and local overlays win over it, and
211
+ * the currently-open session always reads as read.
212
+ */
213
+ declare function resolveSessionUnread({ sessionId, loaderUnread, liveUnreadIds, locallyReadIds, currentSessionId, }: ResolveSessionUnreadOptions): boolean;
214
+ interface ComposeSidebarSessionsOptions {
215
+ /** Server-rendered rows, already ordered by the product's query. */
216
+ loaderSessions: SessionSummary[];
217
+ /** Optimistic rows from the live channel (a chat created in another tab). */
218
+ optimisticSessions?: SessionSummary[];
219
+ /** Rail cap. The full list lives on the history page. */
220
+ limit: number;
221
+ /** Total sessions the product holds, used to decide the overflow row. */
222
+ totalCount?: number;
223
+ liveUnreadIds?: ReadonlySet<string>;
224
+ locallyReadIds?: ReadonlySet<string>;
225
+ currentSessionId?: string | null;
226
+ }
227
+ interface ComposedSidebarSessions {
228
+ sessions: SessionSummary[];
229
+ /** More sessions exist than the rail shows ⇒ render the "view all" row. */
230
+ hasMore: boolean;
231
+ }
232
+ /**
233
+ * The rail's session list: optimistic rows first, then the loader's, capped,
234
+ * with unread resolved per row.
235
+ *
236
+ * Optimistic rows are deduped against the loader by id — once a revalidation
237
+ * brings a live-created session back from the server it must not appear twice
238
+ * (duplicate React keys, and the row's actions would target the same session
239
+ * from two places).
240
+ */
241
+ declare function composeSidebarSessions({ loaderSessions, optimisticSessions, limit, totalCount, liveUnreadIds, locallyReadIds, currentSessionId, }: ComposeSidebarSessionsOptions): ComposedSidebarSessions;
242
+ /**
243
+ * Append a fetched page to held rows, dropping ids already shown. A session
244
+ * bumped to the top between two page fetches otherwise arrives twice — once in
245
+ * the page it moved out of and once in the page it moved into.
246
+ */
247
+ declare function mergeSessionPages(existing: SessionSummary[], incoming: SessionSummary[]): SessionSummary[];
248
+ declare const DEFAULT_RAIL_COOKIE_NAME = "agent-sidebar-rail-collapsed";
249
+ /**
250
+ * Read the persisted rail-collapse state from a request's `Cookie` header, so
251
+ * the server renders the rail in the state the user left it and the first
252
+ * client render does not re-flow.
253
+ *
254
+ * Parses the header rather than building a `RegExp` from the cookie name (the
255
+ * shape the products shipped): a name containing a regex metacharacter would
256
+ * silently match the wrong cookie or none at all.
257
+ */
258
+ declare function readRailCollapsedCookie(cookieHeader: string | null | undefined, name?: string): boolean;
259
+ interface RailCookieOptions {
260
+ name?: string;
261
+ /** Seconds. Default one year. */
262
+ maxAge?: number;
263
+ path?: string;
264
+ /** Omit to auto-detect: `secure` on https, off on http://localhost — a Secure
265
+ * cookie is dropped there and the rail state would not persist in dev. */
266
+ secure?: boolean;
267
+ }
268
+ /** The cookie string for a collapse state. Usable as `document.cookie` or as a
269
+ * `Set-Cookie` value. Exported separately so it is testable without a DOM. */
270
+ declare function railCollapsedCookie(collapsed: boolean, { name, maxAge, path, secure }?: RailCookieOptions): string;
271
+ /** Persist the rail-collapse state from the browser. No-op without a document
272
+ * so a shared toggle handler is safe to call during SSR. */
273
+ declare function writeRailCollapsedCookie(collapsed: boolean, options?: RailCookieOptions): void;
274
+
275
+ export { type ActiveSessionIdOptions, type BuildSessionNavItemOptions, type BuildSessionSubItemsOptions, type ComposeSidebarSessionsOptions, type ComposedSidebarSessions, DEFAULT_RAIL_COOKIE_NAME, type NavRouteDef, type RailCookieOptions, type RailPrefetch, type ResolveActiveNavIdOptions, type ResolveSessionUnreadOptions, type SessionPage, type SessionRailAction, type SessionRailNavItem, type SessionRailSubItem, type SessionRowActions, type SessionSort, type SessionSummary, UNTITLED_SESSION_LABEL, activeSessionIdFromPath, buildSessionNavItem, buildSessionSubItems, composeSidebarSessions, mergeSessionPages, railCollapsedCookie, readRailCollapsedCookie, resolveActiveNavId, resolveSessionUnread, sessionLabel, writeRailCollapsedCookie };
@@ -0,0 +1,31 @@
1
+ import {
2
+ DEFAULT_RAIL_COOKIE_NAME,
3
+ UNTITLED_SESSION_LABEL,
4
+ activeSessionIdFromPath,
5
+ buildSessionNavItem,
6
+ buildSessionSubItems,
7
+ composeSidebarSessions,
8
+ mergeSessionPages,
9
+ railCollapsedCookie,
10
+ readRailCollapsedCookie,
11
+ resolveActiveNavId,
12
+ resolveSessionUnread,
13
+ sessionLabel,
14
+ writeRailCollapsedCookie
15
+ } from "../chunk-3E4MW5LR.js";
16
+ export {
17
+ DEFAULT_RAIL_COOKIE_NAME,
18
+ UNTITLED_SESSION_LABEL,
19
+ activeSessionIdFromPath,
20
+ buildSessionNavItem,
21
+ buildSessionSubItems,
22
+ composeSidebarSessions,
23
+ mergeSessionPages,
24
+ railCollapsedCookie,
25
+ readRailCollapsedCookie,
26
+ resolveActiveNavId,
27
+ resolveSessionUnread,
28
+ sessionLabel,
29
+ writeRailCollapsedCookie
30
+ };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,12 +1,12 @@
1
+ import {
2
+ MembersPanel
3
+ } from "../chunk-S564OFTL.js";
1
4
  import {
2
5
  InvitationsPanel
3
6
  } from "../chunk-5SXS3YAB.js";
4
7
  import {
5
8
  InviteAcceptPage
6
9
  } from "../chunk-VCPZ3HTN.js";
7
- import {
8
- MembersPanel
9
- } from "../chunk-S564OFTL.js";
10
10
  import "../chunk-6XIAPIW6.js";
11
11
  export {
12
12
  InvitationsPanel,
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, RefObject } from 'react';
3
3
  import { C as ChatInteractionField, I as InteractionAnswers, a as ChatInteractionStatus, b as ChatInteraction, c as InteractionCancelData, d as ChatSelectField, e as InteractionRequestWire } from '../contract-CQNvv5th.js';
4
4
  export { f as ChatFreeTextField, g as ComposerAnswerDelivery, h as INTERACTION_CANCEL_EVENT, i as INTERACTION_EVENT, j as INTERACTION_RESOLVED_EVENT, k as InteractionAnswerValue, l as InteractionPersistedPart, N as NoticeKind, m as NoticePersistedPart, P as ParseInteractionAnswersResult, n as ParseInteractionResult, o as canTransitionInteractionStatus, p as cancelStatusFor, q as composerAnswerData, r as composerAnswerDeliveries, s as dedupeQuestionInteractionsByContent, t as fieldAcceptsFreeText, u as interactionFromWireRequest, v as interactionPartKey, w as interactionToPersistedPart, x as isRenderableInteractionKind, y as isSafeInteractionFieldKey, z as isTerminalInteractionStatus, A as noticePart, B as noticePartKey, D as parseInteractionAnswers, E as parseInteractionCancel, F as parseInteractionRequest, G as persistedPartToInteraction, H as questionInteractionContentSignature, J as stampInteractionAnswers } from '../contract-CQNvv5th.js';
5
5
  import { ChatPlan } from '../plans/index.js';
@@ -17,6 +17,7 @@ import { a as ReviewQueueItem, c as ReviewQueueState } from '../queue-VTBA5ONX.j
17
17
  export { p as parseReviewQueueItem } from '../queue-VTBA5ONX.js';
18
18
  export { S as SandboxTerminalConnection, a as SandboxTerminalConnectionResponse, U as UseSandboxTerminalConnectionOptions, b as UseSandboxTerminalConnectionResult, t as tabTerminalConnectionId, u as useSandboxTerminalConnection } from '../sandbox-terminal-ChNEdHF8.js';
19
19
  import { i as ProductSeatOffer } from '../billing-BibxgALe.js';
20
+ import { SessionSort, SessionPage, SessionSummary } from '../session-shell/index.js';
20
21
  import { CatalogModel } from '../catalog/index.js';
21
22
  import { Harness } from '../harness/index.js';
22
23
  export { a as ATTACHMENT_ACCEPT, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse } from '../attachment-validation-CsmUzuI3.js';
@@ -1089,6 +1090,163 @@ interface SeatPaywallProps {
1089
1090
  */
1090
1091
  declare function SeatPaywall({ product, onCheckout, priceUsd, includedUsageUsd, offer, tagline, ctaLabel, benefits, footnote, }: SeatPaywallProps): ReactNode;
1091
1092
 
1093
+ interface UseInfiniteScrollOptions {
1094
+ /** Only fire `onLoadMore` while true (a next page exists, none in flight). */
1095
+ enabled: boolean;
1096
+ /** Scroll container the sentinel lives in. Defaults to the viewport. */
1097
+ root?: RefObject<HTMLElement | null>;
1098
+ /** Prefetch distance before the sentinel is actually reached. */
1099
+ rootMargin?: string;
1100
+ }
1101
+ /**
1102
+ * Fires `onLoadMore` when a sentinel element scrolls into view. Returns a ref
1103
+ * callback for that sentinel (typically the last element in a list).
1104
+ *
1105
+ * The observer is re-created whenever `enabled` flips, so a short first page
1106
+ * that leaves the sentinel on-screen keeps loading: when a load finishes and
1107
+ * `enabled` returns to true, the fresh observer re-reads the current
1108
+ * intersection state and fires again until the sentinel is pushed off-screen.
1109
+ */
1110
+ declare function useInfiniteScroll(onLoadMore: () => void, { enabled, root, rootMargin }: UseInfiniteScrollOptions): (node: HTMLElement | null) => void;
1111
+ interface SessionPageQuery {
1112
+ /** Trimmed search term; empty string means no filter. */
1113
+ q: string;
1114
+ sort: SessionSort;
1115
+ /** `null` for the first page. */
1116
+ cursor: string | null;
1117
+ /** Aborted when the view changes or the component unmounts. */
1118
+ signal: AbortSignal;
1119
+ }
1120
+ /** Data port — one page of sessions for the current view. */
1121
+ type FetchSessionPage = (query: SessionPageQuery) => Promise<SessionPage>;
1122
+ interface UseSessionHistoryOptions {
1123
+ fetchPage: FetchSessionPage;
1124
+ /** Trimmed search term driving the fetch. */
1125
+ q: string;
1126
+ sort: SessionSort;
1127
+ /** SSR page 1 of the default view, so the first paint costs no request. */
1128
+ initialPage: SessionPage;
1129
+ /** The sort `initialPage` was rendered for. Default `'newest'`. */
1130
+ defaultSort?: SessionSort;
1131
+ }
1132
+ interface SessionHistoryState {
1133
+ items: SessionSummary[];
1134
+ hasMore: boolean;
1135
+ isLoadingFirst: boolean;
1136
+ isLoadingMore: boolean;
1137
+ isError: boolean;
1138
+ loadMore: () => void;
1139
+ /** Re-run whichever load failed. */
1140
+ retry: () => void;
1141
+ /** Refetch page 1 — call after a client-side mutation (e.g. a delete). */
1142
+ reload: () => void;
1143
+ }
1144
+ /**
1145
+ * Infinite-scroll data source for the history view. Seeds from `initialPage`
1146
+ * for the default view (no fetch) and otherwise fetches page 1 for the current
1147
+ * search/sort; `loadMore` appends the next cursor page.
1148
+ *
1149
+ * Raw promises + `AbortController` rather than a router fetcher, so a filter
1150
+ * change cancels in-flight requests, pages accumulate, and a late response from
1151
+ * a superseded view is dropped by the monotonic `seq` guard.
1152
+ */
1153
+ declare function useSessionHistory({ fetchPage, q, sort, initialPage, defaultSort, }: UseSessionHistoryOptions): SessionHistoryState;
1154
+ interface SessionActionsOptions {
1155
+ /** Persist a new title. Reject to surface the error in the dialog. */
1156
+ renameSession: (sessionId: string, title: string) => Promise<void>;
1157
+ deleteSession: (sessionId: string) => Promise<void>;
1158
+ /** Called after a successful rename/delete — revalidate the rail here. */
1159
+ onChanged?: () => void;
1160
+ /** Called after deleting the session the user is currently viewing, so the
1161
+ * product can navigate away from a route that no longer resolves. */
1162
+ onDeletedCurrent?: () => void;
1163
+ /** The open session, compared against the delete target. */
1164
+ currentSessionId?: string | null;
1165
+ /** Product toast/log seam. Errors also render inside the dialog. */
1166
+ notify?: (level: 'success' | 'error', message: string) => void;
1167
+ labels?: Partial<SessionActionLabels>;
1168
+ }
1169
+ interface SessionActionLabels {
1170
+ renameTitle: string;
1171
+ renameField: string;
1172
+ renameSubmit: string;
1173
+ deleteTitle: string;
1174
+ deleteBody: (title: string) => string;
1175
+ deleteSubmit: string;
1176
+ cancel: string;
1177
+ renamed: string;
1178
+ deleted: string;
1179
+ renameFailed: string;
1180
+ deleteFailed: string;
1181
+ }
1182
+ interface SessionActions {
1183
+ openRename: (session: SessionSummary) => void;
1184
+ openDelete: (session: SessionSummary) => void;
1185
+ /** Render once, anywhere that survives navigation (the layout). */
1186
+ dialogs: ReactNode;
1187
+ busy: boolean;
1188
+ }
1189
+ /**
1190
+ * Rename + delete for one session, shared by the rail kebab and the history
1191
+ * row menu so both drive the same dialogs and the same product mutations.
1192
+ *
1193
+ * Dialogs are owned here rather than returned as raw state: two surfaces
1194
+ * needing the same confirm step is exactly how a product ends up with two
1195
+ * subtly different delete confirmations.
1196
+ */
1197
+ declare function useSessionActions({ renameSession, deleteSession, onChanged, onDeletedCurrent, currentSessionId, notify, labels, }: SessionActionsOptions): SessionActions;
1198
+ interface SessionHistoryPanelProps {
1199
+ history: SessionHistoryState;
1200
+ /** Whether the workspace has any sessions at all — decided by the SSR page,
1201
+ * independent of the active search, so filtering to zero shows "no matches"
1202
+ * rather than the first-run empty state. */
1203
+ hasAnySessions: boolean;
1204
+ query: string;
1205
+ onQueryChange: (value: string) => void;
1206
+ sort: SessionSort;
1207
+ onSortChange: (value: SessionSort) => void;
1208
+ /** Product route for one session row. */
1209
+ hrefForSession: (sessionId: string) => string;
1210
+ /** Rendered as the row link. Defaults to an `<a>`; pass a router Link to keep
1211
+ * client-side navigation. */
1212
+ linkComponent?: LinkLikeComponent;
1213
+ /** Ids currently mid-turn — renders the responding treatment. */
1214
+ respondingSessionIds?: ReadonlySet<string>;
1215
+ onRename?: (session: SessionSummary) => void;
1216
+ onDelete?: (session: SessionSummary) => void;
1217
+ /** New-session destination for the header action. Omitted ⇒ no button. */
1218
+ newSessionHref?: string;
1219
+ title?: string;
1220
+ untitledLabel?: string;
1221
+ emptyTitle?: string;
1222
+ emptyDescription?: string;
1223
+ /** Absolute → relative timestamp. Defaults to a compact built-in. */
1224
+ formatTimestamp?: (isoDate: string | null) => string;
1225
+ /** Max width of the reading column. `'full'` opts out for a product whose
1226
+ * surface really is a wide table. Default keeps title and timestamp inside
1227
+ * one scannable line rather than at opposite edges of a 1440px viewport. */
1228
+ contentWidth?: 'reading' | 'full';
1229
+ className?: string;
1230
+ }
1231
+ interface LinkLikeProps {
1232
+ to: string;
1233
+ className?: string;
1234
+ children?: ReactNode;
1235
+ }
1236
+ type LinkLikeComponent = (props: LinkLikeProps) => ReactNode;
1237
+ /** Compact relative time. Overridable — a product with its own i18n passes
1238
+ * `formatTimestamp` rather than this being the only option. */
1239
+ declare function formatSessionTimestamp(isoDate: string | null): string;
1240
+ /**
1241
+ * The full session history: search, sort, cursor-paged rows with per-row
1242
+ * actions, and the states in between (first-run empty, loading, no matches,
1243
+ * error + retry).
1244
+ *
1245
+ * This is the surface the rail's capped list overflows into — the reason the
1246
+ * rail can stay short without hiding the user's work.
1247
+ */
1248
+ declare function SessionHistoryPanel({ history, hasAnySessions, query, onQueryChange, sort, onSortChange, hrefForSession, linkComponent: Link, respondingSessionIds, onRename, onDelete, newSessionHref, title, untitledLabel, emptyTitle, emptyDescription, formatTimestamp, contentWidth, className, }: SessionHistoryPanelProps): react.JSX.Element;
1249
+
1092
1250
  /**
1093
1251
  * Keyboard + pointer model for a trigger-and-popover pair, dependency-free.
1094
1252
  * Outside-mousedown and Escape both close; Escape also returns focus to the
@@ -1384,4 +1542,4 @@ declare function useThinkingSeconds(active: boolean): number;
1384
1542
  */
1385
1543
  declare function ChatMessages({ messages, messageSize, models, renderMarkdown, renderExtras, durableCards, userLabel, agentLabel, loading, approval, onToolCallClick, toolRenderers, error, onRetry, renderEmpty, emptyState, header, resolveAttachmentUrl, workProductCards, }: ChatMessagesProps): react.JSX.Element;
1386
1544
 
1387
- export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, type AttachmentFileResult, CatalogModel, ChatAttachmentInput, ChatAttachmentKind, ChatAttachmentPart, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, ChatInteraction, ChatInteractionField, type ChatInteractionRestoreMode, ChatInteractionStatus, ChatMentionPart, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, ChatSelectField, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ComposerFilePart, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, type DurableChatCard, DurableChatCards, type DurableChatCardsProps, type DurableInteractionAnswerSubmitterOptions, DurablePlanCard, type DurablePlanCardProps, DurablePlanClientError, type DurablePlanCurrentInput, type DurablePlanDecision, type DurablePlanDecisionClient, type DurablePlanDecisionClientOptions, type DurablePlanDecisionInput, type DurablePlanDecisionResult, type DurablePlanFollowUpReceipt, type EffortLevel, EffortPicker, type EffortPickerProps, EvidenceLineageTable, type EvidenceLineageTableProps, ExceptionList, type ExceptionListProps, type FieldValues, FlowWaterfall, type FlowWaterfallProps, INTERACTION_SUBMIT_TIMEOUT_MESSAGE, INTERACTION_SUBMIT_TIMEOUT_MS, InteractionActionButton, type InteractionAnswerSubmission, type InteractionAnswerSubmitterOptions, InteractionAnswers, type InteractionAttemptStore, InteractionBadge, type InteractionBadgeVariant, InteractionCancelData, InteractionPlanCard, type InteractionPlanCardProps, InteractionQuestionCard, type InteractionQuestionCardProps, InteractionRequestWire, type InteractionSubmitResult, type MentionTextSegment, MessageAttachments, type MessageAttachmentsProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProvenanceStamp, type ProvenanceStampProps, ProviderLogo, type ProviderLogoProps, QualityCheckList, type QualityCheckListProps, QuestionOptionList, type QuestionOptionListProps, type RestoreChatInteractionsOptions, ReviewQueueItem, type ReviewQueuePage, ReviewQueuePanel, type ReviewQueuePanelProps, ReviewQueueState, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type SubmitInteractionAnswer, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseChatInteractionsOptions, type UseChatInteractionsResult, type UseComposerAttachmentsOptions, type UseComposerAttachmentsResult, type UseDurablePlanFlowOptions, type UseDurablePlanFlowResult, type WaterfallRow, WorkProductCard, type WorkProductCardProps, __resetAttachmentFileCacheForTests, activityTone, buildAnswerData, cancelChatInteraction, consumeChatStream, createDurableInteractionAnswerSubmitter, createDurablePlanDecisionClient, createInteractionAnswerSubmitter, createMemoryInteractionAttemptStore, createSessionInteractionAttemptStore, dispatchChatStreamLine, durableChatCardsFromParts, fieldAnswer, fieldValuesFromAnswers, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, hasSecretField, hydrateChatInteractions, interactionStatusLabels, interactionSubmissionSignature, interactionTerminalNotes, isLateAnswerableStatus, lateAnswerMessage, loadAttachmentFile, mergeActivityPages, mergeReviewQueuePages, nextRevealCount, pendingApprovalOf, resolveChatInteraction, responseErrorMessage, restoreChatInteractions, reviewQueueStateLabel, segmentMentionContent, settleInteractionSubmit, streamChatTurn, terminalizePendingChatInteractions, triggerAttachmentDownload, upsertChatInteraction, useChatInteractions, useComposerAttachments, useDurablePlanFlow, usePending, usePopover, useSmoothText, useThinkingSeconds, waterfallLayout, workProductPartsFromMessageParts, workProductStatusLabel };
1545
+ export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, type AttachmentFileResult, CatalogModel, ChatAttachmentInput, ChatAttachmentKind, ChatAttachmentPart, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, ChatInteraction, ChatInteractionField, type ChatInteractionRestoreMode, ChatInteractionStatus, ChatMentionPart, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, ChatSelectField, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ComposerFilePart, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, type DurableChatCard, DurableChatCards, type DurableChatCardsProps, type DurableInteractionAnswerSubmitterOptions, DurablePlanCard, type DurablePlanCardProps, DurablePlanClientError, type DurablePlanCurrentInput, type DurablePlanDecision, type DurablePlanDecisionClient, type DurablePlanDecisionClientOptions, type DurablePlanDecisionInput, type DurablePlanDecisionResult, type DurablePlanFollowUpReceipt, type EffortLevel, EffortPicker, type EffortPickerProps, EvidenceLineageTable, type EvidenceLineageTableProps, ExceptionList, type ExceptionListProps, type FetchSessionPage, type FieldValues, FlowWaterfall, type FlowWaterfallProps, INTERACTION_SUBMIT_TIMEOUT_MESSAGE, INTERACTION_SUBMIT_TIMEOUT_MS, InteractionActionButton, type InteractionAnswerSubmission, type InteractionAnswerSubmitterOptions, InteractionAnswers, type InteractionAttemptStore, InteractionBadge, type InteractionBadgeVariant, InteractionCancelData, InteractionPlanCard, type InteractionPlanCardProps, InteractionQuestionCard, type InteractionQuestionCardProps, InteractionRequestWire, type InteractionSubmitResult, type LinkLikeComponent, type LinkLikeProps, type MentionTextSegment, MessageAttachments, type MessageAttachmentsProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProvenanceStamp, type ProvenanceStampProps, ProviderLogo, type ProviderLogoProps, QualityCheckList, type QualityCheckListProps, QuestionOptionList, type QuestionOptionListProps, type RestoreChatInteractionsOptions, ReviewQueueItem, type ReviewQueuePage, ReviewQueuePanel, type ReviewQueuePanelProps, ReviewQueueState, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SessionActionLabels, type SessionActions, type SessionActionsOptions, SessionHistoryPanel, type SessionHistoryPanelProps, type SessionHistoryState, type SessionPageQuery, type SmoothRevealOptions, type StreamChatOptions, type SubmitInteractionAnswer, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseChatInteractionsOptions, type UseChatInteractionsResult, type UseComposerAttachmentsOptions, type UseComposerAttachmentsResult, type UseDurablePlanFlowOptions, type UseDurablePlanFlowResult, type UseInfiniteScrollOptions, type UseSessionHistoryOptions, type WaterfallRow, WorkProductCard, type WorkProductCardProps, __resetAttachmentFileCacheForTests, activityTone, buildAnswerData, cancelChatInteraction, consumeChatStream, createDurableInteractionAnswerSubmitter, createDurablePlanDecisionClient, createInteractionAnswerSubmitter, createMemoryInteractionAttemptStore, createSessionInteractionAttemptStore, dispatchChatStreamLine, durableChatCardsFromParts, fieldAnswer, fieldValuesFromAnswers, formatActivityCost, formatActivityDuration, formatModelCost, formatSessionTimestamp, formatTokensPerSecond, hasSecretField, hydrateChatInteractions, interactionStatusLabels, interactionSubmissionSignature, interactionTerminalNotes, isLateAnswerableStatus, lateAnswerMessage, loadAttachmentFile, mergeActivityPages, mergeReviewQueuePages, nextRevealCount, pendingApprovalOf, resolveChatInteraction, responseErrorMessage, restoreChatInteractions, reviewQueueStateLabel, segmentMentionContent, settleInteractionSubmit, streamChatTurn, terminalizePendingChatInteractions, triggerAttachmentDownload, upsertChatInteraction, useChatInteractions, useComposerAttachments, useDurablePlanFlow, useInfiniteScroll, usePending, usePopover, useSessionActions, useSessionHistory, useSmoothText, useThinkingSeconds, waterfallLayout, workProductPartsFromMessageParts, workProductStatusLabel };
@@ -26,6 +26,7 @@ import {
26
26
  QuestionOptionList,
27
27
  RunDrillIn,
28
28
  SeatPaywall,
29
+ SessionHistoryPanel,
29
30
  __resetAttachmentFileCacheForTests,
30
31
  activityTone,
31
32
  buildAnswerData,
@@ -43,6 +44,7 @@ import {
43
44
  formatActivityCost,
44
45
  formatActivityDuration,
45
46
  formatModelCost,
47
+ formatSessionTimestamp,
46
48
  formatTokensPerSecond,
47
49
  hasSecretField,
48
50
  hydrateChatInteractions,
@@ -68,13 +70,17 @@ import {
68
70
  useChatInteractions,
69
71
  useDurablePlanFlow,
70
72
  useFileMentions,
73
+ useInfiniteScroll,
71
74
  usePending,
72
75
  usePopover,
76
+ useSessionActions,
77
+ useSessionHistory,
73
78
  useSmoothText,
74
79
  useThinkingSeconds,
75
80
  waterfallLayout
76
- } from "../chunk-LNRDDXME.js";
81
+ } from "../chunk-YYV3EZSF.js";
77
82
  import "../chunk-FBVLEGEG.js";
83
+ import "../chunk-3E4MW5LR.js";
78
84
  import {
79
85
  EvidenceLineageTable,
80
86
  ExceptionList,
@@ -193,6 +199,7 @@ export {
193
199
  ReviewQueuePanel,
194
200
  RunDrillIn,
195
201
  SeatPaywall,
202
+ SessionHistoryPanel,
196
203
  WorkProductCard,
197
204
  __resetAttachmentFileCacheForTests,
198
205
  activityTone,
@@ -225,6 +232,7 @@ export {
225
232
  formatActivityCost,
226
233
  formatActivityDuration,
227
234
  formatModelCost,
235
+ formatSessionTimestamp,
228
236
  formatTokensPerSecond,
229
237
  hasSecretField,
230
238
  hydrateChatInteractions,
@@ -274,9 +282,12 @@ export {
274
282
  useComposerAttachments,
275
283
  useDurablePlanFlow,
276
284
  useFileMentions,
285
+ useInfiniteScroll,
277
286
  usePending,
278
287
  usePopover,
279
288
  useSandboxTerminalConnection,
289
+ useSessionActions,
290
+ useSessionHistory,
280
291
  useSmoothText,
281
292
  useThinkingSeconds,
282
293
  waterfallLayout,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.44.40",
3
+ "version": "0.44.42",
4
4
  "packageManager": "pnpm@10.33.4",
5
5
  "description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
6
6
  "keywords": [
@@ -207,6 +207,11 @@
207
207
  "import": "./dist/missions/index.js",
208
208
  "default": "./dist/missions/index.js"
209
209
  },
210
+ "./session-shell": {
211
+ "types": "./dist/session-shell/index.d.ts",
212
+ "import": "./dist/session-shell/index.js",
213
+ "default": "./dist/session-shell/index.js"
214
+ },
210
215
  "./web": {
211
216
  "types": "./dist/web/index.d.ts",
212
217
  "import": "./dist/web/index.js",