@streamoid/agent 0.6.53 → 0.6.54
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 +124 -0
- package/dist/agentScope-BlOT7qMu.js +114 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +2437 -2534
- package/dist/pane.d.ts +73 -0
- package/dist/pane.js +581 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -63,3 +63,127 @@ back to `meta.outcome_summary`, then `meta.expected_output` (which stays the
|
|
|
63
63
|
agent's spec), optionally followed by authored `meta.ceiling_minutes`
|
|
64
64
|
and `meta.estimated_credits`. Unknown estimates are omitted. Scoped suggestions
|
|
65
65
|
use `deliverable` and `ceilingMinutes` from the host's outcome catalogue.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## The Ask CXO side pane — `@streamoid/agent/pane`
|
|
69
|
+
|
|
70
|
+
Every product app shows the chat the same way: rail | **pane** | page. The
|
|
71
|
+
shell for it ships here, so the apps stop hand-building it around
|
|
72
|
+
`AgentPanel` (they had drifted on width, unmount-on-close, workspace switch,
|
|
73
|
+
Escape, mobile and persistence).
|
|
74
|
+
|
|
75
|
+
`@streamoid/agent/pane` is a **light entry** (~16kB, React and
|
|
76
|
+
`@streamoid/ui` are yours). It never imports the 5MB chat statically — the
|
|
77
|
+
chat is `import()`ed when the pane first opens (or on `prefetch`), so import
|
|
78
|
+
the pane eagerly in your shell.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { useMemo } from "react";
|
|
82
|
+
import { AgentSidePane, useAgentPaneController, type AgentSidePaneAdapters } from "@streamoid/agent/pane";
|
|
83
|
+
|
|
84
|
+
export function Shell() {
|
|
85
|
+
const pane = useAgentPaneController({
|
|
86
|
+
workspaceId, // persisted per workspace
|
|
87
|
+
legacyWidthKey: "artifax.assistant.width", // your old width key, migrated once
|
|
88
|
+
// persistKey: "artifax-assistant-session", // keep an existing session key
|
|
89
|
+
// bindShortcut: false, // if ⌘K is bound elsewhere
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const adapters = useMemo<AgentSidePaneAdapters>(() => ({
|
|
93
|
+
auth, workspace: { current: { id: workspaceId, name } }, theme: { mode },
|
|
94
|
+
config: { apiBase, hide: { sidepane: true, newBrief: true, notifications: true }, widgetMode: "inline_ask" },
|
|
95
|
+
}), [/* … */]); // memoise it
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div style={{ display: "flex", height: "100vh" }}>
|
|
99
|
+
<Rail
|
|
100
|
+
askActive={pane.open} // the trigger's `active`
|
|
101
|
+
onAsk={pane.askCxo} // open + focus the composer (never a toggle)
|
|
102
|
+
onAskIntent={pane.prefetch} // hover / focus
|
|
103
|
+
onHelp={() => pane.requestSupport({ currentPage })}
|
|
104
|
+
/>
|
|
105
|
+
<AgentSidePane controller={pane} adapters={adapters}
|
|
106
|
+
hostContext={hostContext} scope={scope} support={{ appVersion }} canvas={canvas} />
|
|
107
|
+
{/* An artefact takes the page: hide main (display:none, not unmount). */}
|
|
108
|
+
<main style={{ flex: 1, minWidth: 0, display: pane.surface === "fullscreen" ? "none" : undefined }}>
|
|
109
|
+
<Outlet context={{ askAbout: pane.askAbout }} />
|
|
110
|
+
</main>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
What the pane does, identically in every app:
|
|
117
|
+
|
|
118
|
+
- **Geometry.** Docked at ≥768px: in flow beside the page, width
|
|
119
|
+
`SC_ASSISTANT_PANEL_WIDTH` (**510px**, from `@streamoid/ui`) within
|
|
120
|
+
`SC_ASSISTANT_PANEL_BOUNDS` (360–900), resizable with `ScPanelResizeHandle`,
|
|
121
|
+
persisted under `streamoid.askPane.width`. Below 768px: a full-screen sheet
|
|
122
|
+
(`role="dialog"`, focus trap, siblings `inert`, focus restored on close).
|
|
123
|
+
Geometry is inline style, so no utility class from either stylesheet can
|
|
124
|
+
move it.
|
|
125
|
+
- **Fullscreen.** `onSurfaceChange` reporting a non-text artefact widens the
|
|
126
|
+
pane over the page (`controller.surface === "fullscreen"` — hide your
|
|
127
|
+
`main`). Escape returns to the side pane and that artefact is not widened
|
|
128
|
+
again while it stays open (also across a close and reopen); a different one
|
|
129
|
+
still is. A pane closed over a live artefact — or one an artefact opened in
|
|
130
|
+
while closed — reopens fullscreen. No expand button.
|
|
131
|
+
- **Stays mounted** after the first open; closing hides it, so an answer still
|
|
132
|
+
streaming keeps going. Before the first open nothing loads.
|
|
133
|
+
- **Persistence.** Open state and the conversation, per workspace, survive a
|
|
134
|
+
reload (fullscreen comes back as the side pane). A workspace change closes
|
|
135
|
+
the pane, drops the old conversation, **remounts the chat** (no draft,
|
|
136
|
+
upload or selection chip carries over) and loads the new workspace's.
|
|
137
|
+
- **Escape** (bubble phase): docked, it closes only when focus is inside the
|
|
138
|
+
pane, no nested dialog holds the key, and nothing `preventDefault`ed it.
|
|
139
|
+
Fullscreen collapses to the side pane first. On the sheet, focus need not be
|
|
140
|
+
inside (the page is inert).
|
|
141
|
+
- **Back button** (phone): opening the sheet pushes one history entry (same
|
|
142
|
+
URL, your router's state kept); Back closes the sheet. Closing with × or
|
|
143
|
+
Escape removes the entry, so no stray Back is left behind.
|
|
144
|
+
- **Errors.** A pane-local error boundary: "Ask CXO couldn’t load" + Retry
|
|
145
|
+
(re-imports). Loading shows "Loading Ask CXO…".
|
|
146
|
+
- **Header** is the chat's own (title + context, New task, History, ×);
|
|
147
|
+
× calls `controller.close`.
|
|
148
|
+
|
|
149
|
+
Controller calls: `reveal()` / `close()` / `toggle()`, `askCxo()`,
|
|
150
|
+
`askAbout(prompt)` (new conversation + send, via `enqueueChatPrompt`),
|
|
151
|
+
`requestSupport({ currentPage }?)` (Get help home via `showAgentSupport`),
|
|
152
|
+
`prefetch()`, `width` / `setWidth` / `commitWidth`, and
|
|
153
|
+
`selectionSnapshot` — the selection the pane **holds** (its snapshot of
|
|
154
|
+
`scope.selection`: taken on open, on New task and on `askCxo` with no chat;
|
|
155
|
+
cleared when a chat opens or the chip is removed). Count or split suggestions
|
|
156
|
+
on that, with the pane's own rule: `paneSuggestionCount(sections,
|
|
157
|
+
pane.selectionSnapshot)` / `deriveScopeSuggestions(...)`, both exported here.
|
|
158
|
+
A host mounting `AgentPanel` directly gets the same value from
|
|
159
|
+
`adapters.onSelectionSnapshot`.
|
|
160
|
+
|
|
161
|
+
**Stylesheet.** Import the chat's CSS into its own cascade layer so its
|
|
162
|
+
compiled utilities cannot beat yours (the Catalogix / Photogenix pattern):
|
|
163
|
+
|
|
164
|
+
```css
|
|
165
|
+
@import "@streamoid/agent/style.css" layer(streamoid-agent);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Migrating each app (do it in the app's `@streamoid/agent` 0.6.54 bump PR)
|
|
169
|
+
|
|
170
|
+
**Artifax** (`apps/artifax/src/components/{AppShell,AssistantPanel}.tsx`)
|
|
171
|
+
- `useAgentPaneController({ workspaceId: workspaceID, persistKey: "artifax-assistant-session", legacyWidthKey: "artifax.assistant.width" })` in `AppShell`; render `<AgentSidePane>` in place of `AssistantPanel`, keeping its adapters/hostContext/scope.
|
|
172
|
+
- Delete `lib/assistantSurface.ts` (reducer + tests) and `lib/assistantSession.ts`, the shell's Escape effect, `prefetchAgentChunk`, `askCxo`, `requestSupport`, the `useStreamoidSearchShortcut` call. `main` hides on `pane.surface === "fullscreen"` (as now). `onAskCxoRequest(pane.askCxo)` stays.
|
|
173
|
+
- Delete `usePaneSelectionSnapshot` / `noteAssistantComposerFocus` (`lib/assistantScope.ts`) and the test copy `src/test/paneSuggestions.ts`; use `pane.selectionSnapshot` and `paneSuggestionCount` / `deriveScopeSuggestions`.
|
|
174
|
+
- Default width stays 510; a stored width migrates.
|
|
175
|
+
|
|
176
|
+
**Tactix** (`apps/tactix/src/components/{TactixShell,AssistantPanel}.tsx`)
|
|
177
|
+
- `useAgentPaneController({ workspaceId, legacyWidthKey: "tactix.assistant.width" })` in `TactixShell`; `<AgentSidePane>` replaces `AssistantPanel`. Outlet context `askCxoAbout` becomes `pane.askAbout`.
|
|
178
|
+
- Delete the shell's `askCxo` / `askCxoAbout` / `requestSupport` / `prefetchAgent` and the panel's unguarded Escape effect. Hide `main` on fullscreen (new: artefacts now widen). Gains: mobile sheet, persistence, workspace reset.
|
|
179
|
+
- Default width 480 → 510 (DS constant) for users who never resized.
|
|
180
|
+
|
|
181
|
+
**Catalogix** (`dashboard/app/containers/AskCxo/`)
|
|
182
|
+
- `useAgentPaneController({ workspaceId, legacyWidthKey: "catalogix.ask.width" })` where `useAppStore`'s ask slice is read; `<AgentSidePane>` replaces `AskCxo/index.jsx` + `AskCxoPanel.jsx`. The rail's trigger/⌘K/Help call the controller (pass `bindShortcut: false` if ⌘K stays bound in `LeftMenu`).
|
|
183
|
+
- Delete `askOpen` / `askChatId` from `useAppStore` (and the workspace-switch reset on its setter — the controller does it), `askCxo.js`'s `importAgent` / `prefetchAgent` / `askCxo`. Hide the page on fullscreen (new). Gains: persistence, Back button.
|
|
184
|
+
- Default width 480 → 510.
|
|
185
|
+
|
|
186
|
+
**Photogenix** (`dashboard/client/src/features/ask/`)
|
|
187
|
+
- `useAgentPaneController({ workspaceId, legacyWidthKey: "photogenix.ask.width" })` in the shell; `<AgentSidePane>` replaces `AskPane.tsx` + `AskCxoPanel.tsx`; `useAskConversation.ts` goes (the controller owns `chatId`).
|
|
188
|
+
- Delete the pane's own sheet/focus-trap/Escape code. Hide the page on fullscreen (new). Gains: stays mounted (no SSE abort on close), persistence, Back button.
|
|
189
|
+
- Default width 480 → 510.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { resolveStreamoidProduct as b, streamoidProductLabel as k } from "@streamoid/ui";
|
|
2
|
+
function a(e) {
|
|
3
|
+
if (typeof e != "string" || !e.trim()) return null;
|
|
4
|
+
const n = b(e.trim());
|
|
5
|
+
return n && n !== "cxo" ? n : null;
|
|
6
|
+
}
|
|
7
|
+
function d(e) {
|
|
8
|
+
return e && k(e) || "All apps";
|
|
9
|
+
}
|
|
10
|
+
function $(e, n) {
|
|
11
|
+
if (e === null || e !== a(n?.app)) return null;
|
|
12
|
+
const i = (Array.isArray(n?.breadcrumbs) ? n.breadcrumbs.filter((t) => typeof t == "string" && !!t.trim()).map((t) => t.trim()) : []).join(" › ") || (typeof n?.page == "string" ? n.page.trim() : "");
|
|
13
|
+
return i ? `${d(e)} · ${i}` : d(e);
|
|
14
|
+
}
|
|
15
|
+
function p(e, n) {
|
|
16
|
+
return !e.kinds || e.kinds.length === 0 || n === void 0 ? !0 : e.kinds.map((r) => r.toLowerCase()).includes(n.toLowerCase());
|
|
17
|
+
}
|
|
18
|
+
function h(e) {
|
|
19
|
+
return e.charAt(0).toUpperCase() + e.slice(1);
|
|
20
|
+
}
|
|
21
|
+
function m(e, n) {
|
|
22
|
+
const r = e.instruction?.includes("{subject}") ? e.instruction : `${e.label}: {subject}`;
|
|
23
|
+
return h(r.replace(/\{subject\}/g, n).trim());
|
|
24
|
+
}
|
|
25
|
+
function w(e, n) {
|
|
26
|
+
const r = [];
|
|
27
|
+
for (const i of e ?? []) {
|
|
28
|
+
if (!i?.outcomes?.length) continue;
|
|
29
|
+
const t = (i.samples ?? []).find(
|
|
30
|
+
(u) => i.outcomes.some((f) => p(f, u.kind))
|
|
31
|
+
), c = (u, f) => i.outcomes.find((l) => l.key === f && p(l, u)) ?? i.outcomes.find((l) => p(l, u)), s = n ? c(n.kind, t?.primaryOutcomeKey) : void 0;
|
|
32
|
+
if (n && s) {
|
|
33
|
+
r.push({
|
|
34
|
+
id: `${i.key}:${s.key}:selection`,
|
|
35
|
+
sectionKey: i.key,
|
|
36
|
+
outcomeKey: s.key,
|
|
37
|
+
subject: "selection",
|
|
38
|
+
text: m(s, n.subject || n.label),
|
|
39
|
+
ceilingMinutes: s.ceilingMinutes,
|
|
40
|
+
deliverable: s.deliverable
|
|
41
|
+
});
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (!t) continue;
|
|
45
|
+
const o = c(t.kind, t.primaryOutcomeKey);
|
|
46
|
+
o && r.push({
|
|
47
|
+
id: `${i.key}:${o.key}:${t.id}`,
|
|
48
|
+
sectionKey: i.key,
|
|
49
|
+
outcomeKey: o.key,
|
|
50
|
+
sampleId: t.id,
|
|
51
|
+
sampleTitle: t.subject || t.title,
|
|
52
|
+
subject: "sample",
|
|
53
|
+
text: m(o, t.subject || t.title),
|
|
54
|
+
ceilingMinutes: o.ceilingMinutes,
|
|
55
|
+
deliverable: o.deliverable,
|
|
56
|
+
imageUrl: t.imageUrl ?? null
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return r;
|
|
60
|
+
}
|
|
61
|
+
function O(e, n) {
|
|
62
|
+
return n ? e.length === 0 ? !1 : e.every((r) => a(r) === n) : !0;
|
|
63
|
+
}
|
|
64
|
+
const v = 3;
|
|
65
|
+
function A(e, n, r = v) {
|
|
66
|
+
const i = (s) => (s.value ?? s.title).trim().toLowerCase(), t = e.slice(0, r), c = new Set(t.map(i));
|
|
67
|
+
for (const s of n) {
|
|
68
|
+
if (t.length >= r) break;
|
|
69
|
+
const o = i(s);
|
|
70
|
+
c.has(o) || (c.add(o), t.push(s));
|
|
71
|
+
}
|
|
72
|
+
return t;
|
|
73
|
+
}
|
|
74
|
+
function S(e) {
|
|
75
|
+
return ["headline", "subline", "placeholder"].filter(
|
|
76
|
+
(n) => !e?.[n]?.trim()
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
let g = !1;
|
|
80
|
+
function C() {
|
|
81
|
+
try {
|
|
82
|
+
return process.env.NODE_ENV === "development";
|
|
83
|
+
} catch {
|
|
84
|
+
return !1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function L(e, n, r = C()) {
|
|
88
|
+
if (!r || g || !e) return !1;
|
|
89
|
+
const i = S(n);
|
|
90
|
+
return i.length === 0 ? !1 : (g = !0, console.warn(
|
|
91
|
+
`[@streamoid/agent] adapters.scope for "${e}" has no ${i.join(", ")}; the Ask CXO panel falls back to generic copy. Pass an app-specific question (headline), helper line (subline) and composer hint (placeholder).`
|
|
92
|
+
), !0);
|
|
93
|
+
}
|
|
94
|
+
function y(e) {
|
|
95
|
+
return a(e.meta?.origin_app);
|
|
96
|
+
}
|
|
97
|
+
function K(e) {
|
|
98
|
+
const n = e.meta?.scope;
|
|
99
|
+
return n === "all" ? null : a(n) ?? y(e);
|
|
100
|
+
}
|
|
101
|
+
function M(e, n) {
|
|
102
|
+
return n ? e.filter((r) => y(r) === n) : [...e];
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
M as a,
|
|
106
|
+
O as b,
|
|
107
|
+
K as c,
|
|
108
|
+
w as d,
|
|
109
|
+
$ as e,
|
|
110
|
+
A as f,
|
|
111
|
+
a as h,
|
|
112
|
+
d as s,
|
|
113
|
+
L as w
|
|
114
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -164,6 +164,19 @@ export interface AgentChatShellAdapters {
|
|
|
164
164
|
* Fires only on change, and only for the conversation on screen.
|
|
165
165
|
*/
|
|
166
166
|
onSurfaceChange?: (state: AgentSurfaceState) => void;
|
|
167
|
+
/**
|
|
168
|
+
* The selection the pane HOLDS — its snapshot of `scope.selection`, which its
|
|
169
|
+
* suggestions and composer chip are built from — reported whenever it
|
|
170
|
+
* changes, and once on mount.
|
|
171
|
+
*
|
|
172
|
+
* The pane does not follow `scope.selection` live: it snapshots it when it
|
|
173
|
+
* mounts, when the conversation goes back to none (New task), and on
|
|
174
|
+
* `focusAgentComposer()` while no conversation is open; it clears it when an
|
|
175
|
+
* existing conversation opens or the user removes the chip. A host that
|
|
176
|
+
* splits or counts its suggestions on the selection must use THIS value, not
|
|
177
|
+
* its live one. `AgentSidePane` wires it to `controller.selectionSnapshot`.
|
|
178
|
+
*/
|
|
179
|
+
onSelectionSnapshot?: (selection: AgentScopeSelection | null) => void;
|
|
167
180
|
/**
|
|
168
181
|
* Supply the canvas as a component and the Dreamer panel drops its iframe:
|
|
169
182
|
* no embedded page, so no cross-origin auth, no postMessage handshake, no
|
|
@@ -545,3 +558,123 @@ export interface ShowAgentSupportOptions {
|
|
|
545
558
|
*/
|
|
546
559
|
currentPage?: string | null;
|
|
547
560
|
}
|
|
561
|
+
|
|
562
|
+
/* ── Ask CXO side pane (`@streamoid/agent/pane`) ───────────────────────────
|
|
563
|
+
*
|
|
564
|
+
* The TYPES of the shared side pane live here, beside the adapters they are
|
|
565
|
+
* built from; its VALUES (`useAgentPaneController`, `AgentSidePane`, …) are
|
|
566
|
+
* declared in `pane.d.ts` and exported only from the `@streamoid/agent/pane`
|
|
567
|
+
* subpath — the light entry that does not pull in this 5MB bundle. Keep both
|
|
568
|
+
* in step with `src/embed/pane/`. */
|
|
569
|
+
|
|
570
|
+
/** `closed` → `pane` (the side pane) → `fullscreen` (a non-text artefact took
|
|
571
|
+
* the page). Fullscreen is never restored on reload. */
|
|
572
|
+
export type AgentPaneSurface = 'closed' | 'pane' | 'fullscreen';
|
|
573
|
+
|
|
574
|
+
export interface AgentPaneControllerOptions {
|
|
575
|
+
/** The workspace the pane's conversation belongs to. The open state and the
|
|
576
|
+
* conversation are persisted per workspace; a change closes the pane, drops
|
|
577
|
+
* the old workspace's conversation and loads the new one's saved state. An
|
|
578
|
+
* empty value (not resolved yet) persists nothing. */
|
|
579
|
+
workspaceId: string | null | undefined;
|
|
580
|
+
/** localStorage prefix for the per-workspace session
|
|
581
|
+
* (`<persistKey>:<workspaceId>`). Default `streamoid.askPane.session`.
|
|
582
|
+
* Artifax passes `artifax-assistant-session` to keep its users' open chats
|
|
583
|
+
* across the migration — its stored `{ surface: 'rail', chatId }` is read. */
|
|
584
|
+
persistKey?: string;
|
|
585
|
+
/** The app's old width key(s), copied once into `streamoid.askPane.width`
|
|
586
|
+
* while that key is still empty: `artifax.assistant.width`,
|
|
587
|
+
* `tactix.assistant.width`, `catalogix.ask.width`, `photogenix.ask.width`. */
|
|
588
|
+
legacyWidthKey?: string | readonly string[];
|
|
589
|
+
/** Bind ⌘K / Ctrl+K to `askCxo` (with a prefetch). Default `true`; pass
|
|
590
|
+
* `false` where the host binds the chord to something else. */
|
|
591
|
+
bindShortcut?: boolean;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/** Options for {@link AgentPaneController.requestSupport} — exactly
|
|
595
|
+
* {@link showAgentSupport}'s, passed straight through. */
|
|
596
|
+
export type AgentPaneSupportOptions = ShowAgentSupportOptions;
|
|
597
|
+
|
|
598
|
+
export interface AgentPaneController {
|
|
599
|
+
/** The pane is showing (side pane or fullscreen). Hand it to the rail's Ask
|
|
600
|
+
* CXO trigger as `active`. */
|
|
601
|
+
open: boolean;
|
|
602
|
+
/** `fullscreen` while a non-text artefact holds the page. A host whose page
|
|
603
|
+
* sits beside the pane HIDES it (`display: none`, not unmount — the page
|
|
604
|
+
* keeps its scroll and form state) for exactly as long:
|
|
605
|
+
* `<main style={{ display: controller.surface === 'fullscreen' ? 'none' : undefined }}>`. */
|
|
606
|
+
surface: AgentPaneSurface;
|
|
607
|
+
/** The conversation on screen; `null` lets the chat create one. Persisted
|
|
608
|
+
* per workspace with the open state. */
|
|
609
|
+
chatId: string | null;
|
|
610
|
+
/** Show the pane. Open, never toggle. Applies the chat's latest surface
|
|
611
|
+
* report: an artefact still live behind a closed pane reopens fullscreen,
|
|
612
|
+
* unless the user declined it with Escape. */
|
|
613
|
+
reveal(): void;
|
|
614
|
+
/** Hide the pane. It stays mounted: an answer still streaming keeps going,
|
|
615
|
+
* and an artefact stays live (reports arriving while closed are kept). */
|
|
616
|
+
close(): void;
|
|
617
|
+
toggle(): void;
|
|
618
|
+
/** The rail trigger / ⌘K: reveal and put the caret in the composer. */
|
|
619
|
+
askCxo(): void;
|
|
620
|
+
/** Reveal on a NEW conversation and send `prompt` in it, without waiting for
|
|
621
|
+
* the network (`enqueueChatPrompt`). `false` when the prompt is blank. */
|
|
622
|
+
askAbout(prompt: string): boolean;
|
|
623
|
+
/** Help & Support: reveal on the Get help home ({@link showAgentSupport});
|
|
624
|
+
* sends nothing. */
|
|
625
|
+
requestSupport(options?: AgentPaneSupportOptions | null): void;
|
|
626
|
+
/** Warm the agent chunk — wire to the trigger's hover and focus. */
|
|
627
|
+
prefetch(): void;
|
|
628
|
+
/** Docked width in px, from `SC_ASSISTANT_PANEL_WIDTH` within
|
|
629
|
+
* `SC_ASSISTANT_PANEL_BOUNDS`, persisted under `streamoid.askPane.width`. */
|
|
630
|
+
width: number;
|
|
631
|
+
/** Live width during a drag; not persisted. */
|
|
632
|
+
setWidth(width: number): void;
|
|
633
|
+
/** Persist a width (drag end). */
|
|
634
|
+
commitWidth(width: number): void;
|
|
635
|
+
bounds: { min: number; max: number };
|
|
636
|
+
/** The selection the pane HOLDS (see `adapters.onSelectionSnapshot`) —
|
|
637
|
+
* `null` until the chat mounts. Split or count suggestions on this, e.g.
|
|
638
|
+
* `paneSuggestionCount(sections, controller.selectionSnapshot)`, not on the
|
|
639
|
+
* host's live selection. */
|
|
640
|
+
selectionSnapshot: AgentScopeSelection | null;
|
|
641
|
+
/** Changes on every real workspace switch (not when an unresolved id first
|
|
642
|
+
* resolves). `AgentSidePane` keys the chat on it, so a switch remounts the
|
|
643
|
+
* chat — workspace A's draft, uploads and selection chip never reach B —
|
|
644
|
+
* and `selectionSnapshot` resets in the same update. */
|
|
645
|
+
workspaceEpoch: number;
|
|
646
|
+
/** Wiring for `AgentSidePane`; hosts do not need these. */
|
|
647
|
+
setChatId(chatId: string | null): void;
|
|
648
|
+
reportSurface(state: AgentSurfaceState): void;
|
|
649
|
+
collapse(): void;
|
|
650
|
+
reportSelectionSnapshot(selection: AgentScopeSelection | null): void;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/** The adapters a host still supplies to {@link AgentSidePaneProps}. The pane
|
|
654
|
+
* fills `navigation`, `onClose`, `onSurfaceChange` and `onSelectionSnapshot`
|
|
655
|
+
* from the controller and takes `hostContext`, `scope`, `support` and
|
|
656
|
+
* `canvas` as props. */
|
|
657
|
+
export type AgentSidePaneAdapters = Omit<
|
|
658
|
+
AgentPanelAdapters,
|
|
659
|
+
| 'navigation'
|
|
660
|
+
| 'onClose'
|
|
661
|
+
| 'onSurfaceChange'
|
|
662
|
+
| 'onSelectionSnapshot'
|
|
663
|
+
| 'hostContext'
|
|
664
|
+
| 'scope'
|
|
665
|
+
| 'support'
|
|
666
|
+
| 'canvas'
|
|
667
|
+
>;
|
|
668
|
+
|
|
669
|
+
export interface AgentSidePaneProps {
|
|
670
|
+
controller: AgentPaneController;
|
|
671
|
+
/** Memoise it: a new object every render re-renders the whole chat. */
|
|
672
|
+
adapters: AgentSidePaneAdapters;
|
|
673
|
+
hostContext?: AgentHostContext | null;
|
|
674
|
+
scope?: AgentScopeAdapter | null;
|
|
675
|
+
support?: AgentSupportAdapter | null;
|
|
676
|
+
canvas?: HostCanvasContextValue;
|
|
677
|
+
className?: string;
|
|
678
|
+
/** Accessible name of the pane landmark. Default "Ask CXO assistant". */
|
|
679
|
+
ariaLabel?: string;
|
|
680
|
+
}
|