@tangle-network/agent-app 0.42.15 → 0.42.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assistant/index.d.ts +619 -0
- package/dist/assistant/index.js +2706 -0
- package/dist/assistant/index.js.map +1 -0
- package/dist/{chunk-ILCF6KBD.js → chunk-FNFCDSEB.js} +3 -2
- package/dist/chunk-FNFCDSEB.js.map +1 -0
- package/dist/chunk-WV2U5UIB.js +2158 -0
- package/dist/chunk-WV2U5UIB.js.map +1 -0
- package/dist/index.js +57 -57
- package/dist/sandbox/index.js +1 -1
- package/dist/web-react/index.d.ts +56 -2
- package/dist/web-react/index.js +36 -1839
- package/dist/web-react/index.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-ILCF6KBD.js.map +0 -1
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ToolDetailRenderers, ChatUiMessage } from '../web-react/index.js';
|
|
4
|
+
import '../agent-activity-C8ZG0F0M.js';
|
|
5
|
+
import '../flow-types-Cb_AblZs.js';
|
|
6
|
+
import '../model-catalog-BEAEVDaa.js';
|
|
7
|
+
import '../harness/index.js';
|
|
8
|
+
import '@tangle-network/agent-interface';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Wire + UI types for the in-app assistant panel. The wire shapes mirror the
|
|
12
|
+
* SSE contract emitted by `POST /v1/assistant/chat` (platform-api
|
|
13
|
+
* `routes/assistant.ts`). Drift here only mis-renders the client; the server
|
|
14
|
+
* is the source of truth for what it accepts and emits.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Request body for `POST /api/v1/assistant/chat`. */
|
|
18
|
+
interface ChatRequest {
|
|
19
|
+
message: string;
|
|
20
|
+
/** Model slug to run this turn against; omit to use the server default. */
|
|
21
|
+
model?: string;
|
|
22
|
+
/** Omit to start a new thread; pass to continue an existing one. */
|
|
23
|
+
threadId?: string;
|
|
24
|
+
/** Per-turn idempotency key — guards against double-charge on retry. */
|
|
25
|
+
turnKey?: string;
|
|
26
|
+
}
|
|
27
|
+
interface ThreadEventData {
|
|
28
|
+
threadId: string;
|
|
29
|
+
turnId: string;
|
|
30
|
+
/** The model slug this turn ran against, when the server reports it. */
|
|
31
|
+
model?: string | null;
|
|
32
|
+
}
|
|
33
|
+
interface DeltaEventData {
|
|
34
|
+
text: string;
|
|
35
|
+
}
|
|
36
|
+
/** A chunk of the model's reasoning/thinking, streamed BEFORE the answer for
|
|
37
|
+
* reasoning models. Surfaced as a dim "thinking" block so a long reasoning gap
|
|
38
|
+
* doesn't read as a frozen panel. Absent for non-reasoning models. */
|
|
39
|
+
interface ReasoningEventData {
|
|
40
|
+
text: string;
|
|
41
|
+
}
|
|
42
|
+
/** Emitted when a read-only tool STARTS running, before its result. Lets the
|
|
43
|
+
* panel show live "running <tool>…" progress instead of a silent gap. */
|
|
44
|
+
interface ToolCallEventData {
|
|
45
|
+
callId: string;
|
|
46
|
+
name: string;
|
|
47
|
+
/** The parsed arguments the agent invoked the tool with. Lets a renderer show
|
|
48
|
+
* exactly what was called. Omitted by servers predating the field. */
|
|
49
|
+
args?: Record<string, unknown>;
|
|
50
|
+
}
|
|
51
|
+
interface ToolResultEventData {
|
|
52
|
+
callId: string;
|
|
53
|
+
name: string;
|
|
54
|
+
ok: boolean;
|
|
55
|
+
output?: unknown;
|
|
56
|
+
error?: {
|
|
57
|
+
code: string;
|
|
58
|
+
message: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** What kind of connection a requirement names — drives the card's label and
|
|
62
|
+
* connect target. "integration" is an OAuth/api-key connection on the
|
|
63
|
+
* integrations page; "github_app" is the GitHub App installed on the repo (the
|
|
64
|
+
* event source for a GitHub trigger), connected via the App install flow. */
|
|
65
|
+
type ConnectionRequirementKind = "integration" | "github_app";
|
|
66
|
+
/** A connection a proposed workflow references, and whether the user has it
|
|
67
|
+
* connected right now. Surfaced on an authoring proposal so the card can show
|
|
68
|
+
* what must be connected — and WHERE — before the workflow can be created. */
|
|
69
|
+
interface ConnectionRequirement {
|
|
70
|
+
provider: string;
|
|
71
|
+
connected: boolean;
|
|
72
|
+
/** What must be connected. Absent on proposals predating the field — treated
|
|
73
|
+
* as "integration" by the card. */
|
|
74
|
+
kind?: ConnectionRequirementKind;
|
|
75
|
+
/** Where the user connects this requirement, supplied by the server (the
|
|
76
|
+
* GitHub App install URL is deploy config the client can't derive). Null when
|
|
77
|
+
* there's no link to offer (e.g. a github_app requirement on a deploy with no
|
|
78
|
+
* app slug); the card then shows the requirement without a connect link. */
|
|
79
|
+
connectUrl?: string | null;
|
|
80
|
+
}
|
|
81
|
+
interface ToolProposalEventData {
|
|
82
|
+
/** Null only if the server has no proposal store wired (tools then unusable). */
|
|
83
|
+
proposalId: string | null;
|
|
84
|
+
callId: string;
|
|
85
|
+
name: string;
|
|
86
|
+
args: unknown;
|
|
87
|
+
/** Present on a workflow-authoring proposal: the integrations it references
|
|
88
|
+
* and their current connection status. Omitted for non-authoring tools. */
|
|
89
|
+
requirements?: ConnectionRequirement[];
|
|
90
|
+
}
|
|
91
|
+
interface UsageEventData {
|
|
92
|
+
promptTokens: number | null;
|
|
93
|
+
completionTokens: number | null;
|
|
94
|
+
costUsd: number | null;
|
|
95
|
+
balanceUsd: number | null;
|
|
96
|
+
/** Wall-clock duration of the turn in milliseconds, when the server measures
|
|
97
|
+
* it. Drives the renderer's tokens/sec figure. Omitted by older servers. */
|
|
98
|
+
durationMs?: number | null;
|
|
99
|
+
/** True when a completed turn was replayed from storage (no charge). */
|
|
100
|
+
replayed?: boolean;
|
|
101
|
+
}
|
|
102
|
+
interface DoneEventData {
|
|
103
|
+
turnId: string;
|
|
104
|
+
status: string;
|
|
105
|
+
/** True when a mutating tool was proposed and is awaiting confirmation. */
|
|
106
|
+
proposed?: boolean;
|
|
107
|
+
/** True when the agentic loop hit its tool-round cap. */
|
|
108
|
+
capped?: boolean;
|
|
109
|
+
}
|
|
110
|
+
interface ErrorEventData {
|
|
111
|
+
code: string;
|
|
112
|
+
message: string;
|
|
113
|
+
}
|
|
114
|
+
/** Discriminated union the stream reader hands to the reducer. */
|
|
115
|
+
type AssistantStreamEvent = {
|
|
116
|
+
type: "thread";
|
|
117
|
+
data: ThreadEventData;
|
|
118
|
+
} | {
|
|
119
|
+
type: "delta";
|
|
120
|
+
data: DeltaEventData;
|
|
121
|
+
} | {
|
|
122
|
+
type: "reasoning";
|
|
123
|
+
data: ReasoningEventData;
|
|
124
|
+
} | {
|
|
125
|
+
type: "tool_call";
|
|
126
|
+
data: ToolCallEventData;
|
|
127
|
+
} | {
|
|
128
|
+
type: "tool_result";
|
|
129
|
+
data: ToolResultEventData;
|
|
130
|
+
} | {
|
|
131
|
+
type: "tool_proposal";
|
|
132
|
+
data: ToolProposalEventData;
|
|
133
|
+
} | {
|
|
134
|
+
type: "usage";
|
|
135
|
+
data: UsageEventData;
|
|
136
|
+
} | {
|
|
137
|
+
type: "done";
|
|
138
|
+
data: DoneEventData;
|
|
139
|
+
} | {
|
|
140
|
+
type: "error";
|
|
141
|
+
data: ErrorEventData;
|
|
142
|
+
};
|
|
143
|
+
/** A `tool` message is the inline activity chip for a read-only tool the agent
|
|
144
|
+
* ran during a turn (e.g. "Validating workflow… ✓"). */
|
|
145
|
+
type ChatRole = "user" | "assistant" | "status" | "tool";
|
|
146
|
+
/** Live status of a tool-activity chip. */
|
|
147
|
+
type ToolActivityStatus = "running" | "ok" | "failed";
|
|
148
|
+
/** The outcome of a finished read-only tool, retained on the chip so a renderer
|
|
149
|
+
* can show the result body (not just the name + status). Mirrors the
|
|
150
|
+
* `tool_result` event: a success carries the tool's `result`; a failure carries
|
|
151
|
+
* the error. Absent while the tool is still running. */
|
|
152
|
+
type ToolOutcome = {
|
|
153
|
+
ok: true;
|
|
154
|
+
result?: unknown;
|
|
155
|
+
} | {
|
|
156
|
+
ok: false;
|
|
157
|
+
error?: {
|
|
158
|
+
code: string;
|
|
159
|
+
message: string;
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
interface ChatMessage {
|
|
163
|
+
id: string;
|
|
164
|
+
role: ChatRole;
|
|
165
|
+
text: string;
|
|
166
|
+
/** Present only on `tool` messages — the activity's tool name, the arguments it
|
|
167
|
+
* was called with, its state, and (once finished) its outcome. */
|
|
168
|
+
tool?: {
|
|
169
|
+
name: string;
|
|
170
|
+
status: ToolActivityStatus;
|
|
171
|
+
args?: Record<string, unknown>;
|
|
172
|
+
outcome?: ToolOutcome;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** A mutating action the assistant proposed, awaiting the user's confirmation. */
|
|
176
|
+
interface PendingProposal {
|
|
177
|
+
proposalId: string | null;
|
|
178
|
+
callId: string;
|
|
179
|
+
name: string;
|
|
180
|
+
args: unknown;
|
|
181
|
+
/** Integration requirements for a workflow-authoring proposal (each provider
|
|
182
|
+
* + whether it's connected); omitted for non-authoring proposals. */
|
|
183
|
+
requirements?: ConnectionRequirement[];
|
|
184
|
+
/** Inline error shown ON the card after a RETRYABLE confirm failure (an
|
|
185
|
+
* unconnected integration): the card stays so the user can connect and
|
|
186
|
+
* confirm again. Null/absent when the card has not failed a retry. */
|
|
187
|
+
retryError?: string | null;
|
|
188
|
+
}
|
|
189
|
+
interface UsageInfo {
|
|
190
|
+
costUsd: number | null;
|
|
191
|
+
balanceUsd: number | null;
|
|
192
|
+
/** Token counts + wall-clock duration for the settled turn, when the server
|
|
193
|
+
* reports them — drive per-message tokens/sec + cost in a renderer. Optional
|
|
194
|
+
* so a consumer constructing this on the prior `{ costUsd, balanceUsd,
|
|
195
|
+
* replayed }` shape stays valid; a renderer treats a missing value as null. */
|
|
196
|
+
promptTokens?: number | null;
|
|
197
|
+
completionTokens?: number | null;
|
|
198
|
+
durationMs?: number | null;
|
|
199
|
+
replayed: boolean;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The transcript slice handed to a host-supplied `renderTranscript` (see
|
|
203
|
+
* {@link AssistantPanelProps}). It lets a host swap ONLY the conversation
|
|
204
|
+
* rendering — to use its own message renderer — while the panel keeps owning the
|
|
205
|
+
* dock chrome, composer, model picker, history, transport, and proposal
|
|
206
|
+
* orchestration. The bound `renderProposal` returns the panel's own proposal
|
|
207
|
+
* card so the host can place it (e.g. inline after the proposing turn) without
|
|
208
|
+
* re-implementing the confirm/cancel flow.
|
|
209
|
+
*/
|
|
210
|
+
interface AssistantTranscriptView {
|
|
211
|
+
messages: ChatMessage[];
|
|
212
|
+
/** The current turn's reasoning/thinking text, if any (streamed before the
|
|
213
|
+
* answer for reasoning models). */
|
|
214
|
+
reasoning: string | null;
|
|
215
|
+
/** Id of the assistant message currently accumulating deltas, if any. */
|
|
216
|
+
streamingId: string | null;
|
|
217
|
+
/** Model slug the current/most-recent turn ran against, or null. */
|
|
218
|
+
model: string | null;
|
|
219
|
+
/** True while a turn is streaming. */
|
|
220
|
+
isStreaming: boolean;
|
|
221
|
+
/** True while the agent is working but has produced no visible output yet
|
|
222
|
+
* (drives a "thinking" affordance). */
|
|
223
|
+
isThinking: boolean;
|
|
224
|
+
pendingProposals: PendingProposal[];
|
|
225
|
+
/** Cost/tokens/duration for the most recently settled turn, or null before any
|
|
226
|
+
* turn settles. Optional so a host predating the field stays a valid consumer;
|
|
227
|
+
* a renderer treats a missing value the same as null. */
|
|
228
|
+
usage?: UsageInfo | null;
|
|
229
|
+
/** The panel's bound proposal card for a pending proposal — render it where the
|
|
230
|
+
* confirm/cancel UI should appear. */
|
|
231
|
+
renderProposal: (proposal: PendingProposal) => ReactNode;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Configurable network client for the assistant panel: the chat SSE stream, the
|
|
236
|
+
* model/thread/history reads, and the proposal-confirmation call.
|
|
237
|
+
*
|
|
238
|
+
* The transport is injected via {@link AssistantClientConfig} so the same UI can
|
|
239
|
+
* run in different hosts: a same-origin app authenticates with the session
|
|
240
|
+
* cookie (`credentials: "include"`) and an `X-Requested-With` marker, while a
|
|
241
|
+
* cross-origin host points `baseUrl` at the API and supplies a bearer token via
|
|
242
|
+
* `headers`. The request shapes and the defensive wire parsing are identical
|
|
243
|
+
* across hosts — only the base URL and the auth headers vary.
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
/** Host-supplied transport configuration for {@link createAssistantClient}. */
|
|
247
|
+
interface AssistantClientConfig {
|
|
248
|
+
/**
|
|
249
|
+
* Base URL the five assistant endpoints hang off, with no trailing slash —
|
|
250
|
+
* e.g. `"/api/v1/assistant"` for a same-origin SSR edge, or
|
|
251
|
+
* `"https://id.tangle.tools/api/v1/assistant"` cross-origin. Each method
|
|
252
|
+
* appends its own path (`/chat`, `/models`, `/threads`, …).
|
|
253
|
+
*/
|
|
254
|
+
baseUrl: string;
|
|
255
|
+
/**
|
|
256
|
+
* `fetch` credentials mode. Defaults to `"include"` so a same-origin cookie
|
|
257
|
+
* session authenticates; a token-based cross-origin host may pass `"omit"`
|
|
258
|
+
* and carry the credential in {@link AssistantClientConfig.headers}.
|
|
259
|
+
*/
|
|
260
|
+
credentials?: RequestCredentials;
|
|
261
|
+
/**
|
|
262
|
+
* Headers applied to every request — the auth token and/or the CSRF marker.
|
|
263
|
+
* Called per request so a rotating token is read fresh, never captured once.
|
|
264
|
+
*/
|
|
265
|
+
headers?: () => Record<string, string>;
|
|
266
|
+
}
|
|
267
|
+
interface AssistantModelOption {
|
|
268
|
+
slug: string;
|
|
269
|
+
label: string;
|
|
270
|
+
/** USD per million prompt tokens, when the catalog carries pricing. */
|
|
271
|
+
promptUsdPerMillion?: number;
|
|
272
|
+
/** Context window in tokens, when known. */
|
|
273
|
+
contextTokens?: number;
|
|
274
|
+
}
|
|
275
|
+
interface AssistantModels {
|
|
276
|
+
/** The slug the server uses when a turn selects no model. */
|
|
277
|
+
default: string | null;
|
|
278
|
+
models: AssistantModelOption[];
|
|
279
|
+
}
|
|
280
|
+
/** One past conversation in the history switcher. */
|
|
281
|
+
interface AssistantThreadSummary {
|
|
282
|
+
id: string;
|
|
283
|
+
/** Truncated first user message; may be null for an untitled thread. */
|
|
284
|
+
title: string | null;
|
|
285
|
+
createdAt: string;
|
|
286
|
+
updatedAt: string;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Outcome of a model-list fetch. `ok` drives caching: the caller caches on `ok`
|
|
290
|
+
* and retries on `!ok`. An EMPTY list is reported as `!ok` — the server always
|
|
291
|
+
* offers at least the default model when the router is reachable, so an empty
|
|
292
|
+
* menu means the catalog couldn't be loaded and should be retried, not cached
|
|
293
|
+
* for the whole session.
|
|
294
|
+
*/
|
|
295
|
+
interface AssistantModelsResult {
|
|
296
|
+
ok: boolean;
|
|
297
|
+
data: AssistantModels;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Outcome of a thread-history restore. The three cases drive different recovery:
|
|
301
|
+
* `ok` rehydrates the transcript; `gone` (the thread 404s — deleted or from a
|
|
302
|
+
* reset DB) tells the caller to drop the dead thread id so the next turn starts
|
|
303
|
+
* fresh; `error` (transient/network/aborted) keeps the thread id and simply
|
|
304
|
+
* doesn't restore, so a later attempt or send still targets the live thread.
|
|
305
|
+
*/
|
|
306
|
+
type ThreadHistoryResult = {
|
|
307
|
+
status: "ok";
|
|
308
|
+
messages: ChatMessage[];
|
|
309
|
+
proposals: PendingProposal[];
|
|
310
|
+
} | {
|
|
311
|
+
status: "gone";
|
|
312
|
+
} | {
|
|
313
|
+
status: "error";
|
|
314
|
+
};
|
|
315
|
+
type ConfirmResult = {
|
|
316
|
+
ok: true;
|
|
317
|
+
output: unknown;
|
|
318
|
+
retryable?: boolean;
|
|
319
|
+
} | {
|
|
320
|
+
ok: false;
|
|
321
|
+
error: string;
|
|
322
|
+
};
|
|
323
|
+
/** The assistant network surface, bound to one host's transport config. */
|
|
324
|
+
interface AssistantClient {
|
|
325
|
+
fetchModels(signal?: AbortSignal): Promise<AssistantModelsResult>;
|
|
326
|
+
fetchThreads(signal?: AbortSignal): Promise<AssistantThreadSummary[] | null>;
|
|
327
|
+
fetchThreadHistory(threadId: string, signal?: AbortSignal): Promise<ThreadHistoryResult>;
|
|
328
|
+
streamChat(req: ChatRequest, onEvent: (event: AssistantStreamEvent) => void, signal: AbortSignal): Promise<void>;
|
|
329
|
+
confirmProposal(proposalId: string): Promise<ConfirmResult>;
|
|
330
|
+
/** Delete a thread and its server-side turns/proposals. Resolves `{ ok }`; a
|
|
331
|
+
* 404 (already gone) is treated as success so a double-delete is harmless.
|
|
332
|
+
* Optional so a host with no delete endpoint stays a valid client — the panel
|
|
333
|
+
* hides the delete affordance when it's absent (see `useAssistantThreads`). */
|
|
334
|
+
deleteThread?(threadId: string): Promise<{
|
|
335
|
+
ok: boolean;
|
|
336
|
+
}>;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Build an assistant client bound to one host's transport. The returned methods
|
|
340
|
+
* carry no module state, so a host may create one client per config (or share a
|
|
341
|
+
* single same-origin client for the whole app).
|
|
342
|
+
*/
|
|
343
|
+
declare function createAssistantClient(config: AssistantClientConfig): AssistantClient;
|
|
344
|
+
|
|
345
|
+
declare function AssistantClientProvider({ client, children, }: {
|
|
346
|
+
client: AssistantClient;
|
|
347
|
+
children: ReactNode;
|
|
348
|
+
}): react.JSX.Element;
|
|
349
|
+
/**
|
|
350
|
+
* The assistant client for the current host. Throws when no provider is mounted
|
|
351
|
+
* rather than silently falling back to a default transport — a missing provider
|
|
352
|
+
* is a wiring bug, and a hidden default would mask it (and could target the
|
|
353
|
+
* wrong origin).
|
|
354
|
+
*/
|
|
355
|
+
declare function useAssistantClient(): AssistantClient;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Pure state machine driving the assistant panel. Every UI transition — a user
|
|
359
|
+
* message, each streamed SSE event, a stream failure, a confirmed/cancelled
|
|
360
|
+
* proposal, a manual stop — is modeled as an action here, so the panel's
|
|
361
|
+
* behavior can be verified without a DOM or a live stream.
|
|
362
|
+
*/
|
|
363
|
+
|
|
364
|
+
type ChatStatus = "idle" | "streaming" | "awaiting_confirm";
|
|
365
|
+
interface AssistantState {
|
|
366
|
+
/** The signed-in user this conversation belongs to. Carried in state so it
|
|
367
|
+
* moves atomically with the data it labels — persistence keys off it, and a
|
|
368
|
+
* render whose owner doesn't match the current user is masked (see
|
|
369
|
+
* `selectVisibleState`), preventing a one-frame cross-account leak. */
|
|
370
|
+
ownerId: string | null;
|
|
371
|
+
/** Persisted across reloads to continue the same server-side thread. */
|
|
372
|
+
threadId: string | null;
|
|
373
|
+
messages: ChatMessage[];
|
|
374
|
+
status: ChatStatus;
|
|
375
|
+
/** Id of the assistant message currently accumulating deltas, if any. Set to
|
|
376
|
+
* null mid-turn when a tool runs, so the next text delta opens a fresh
|
|
377
|
+
* assistant bubble — keeping each reasoning segment visually distinct. */
|
|
378
|
+
streamingId: string | null;
|
|
379
|
+
/** Base id for the current turn's assistant bubbles (the `send` assistant id).
|
|
380
|
+
* Post-tool segments derive a unique id from it; null between turns. */
|
|
381
|
+
streamBaseId: string | null;
|
|
382
|
+
/** How many assistant bubbles the current turn has opened (0 = just the first).
|
|
383
|
+
* Drives the per-segment bubble id so segments never collide across turns. */
|
|
384
|
+
segmentSeq: number;
|
|
385
|
+
pendingProposals: PendingProposal[];
|
|
386
|
+
/** Cost/balance from the most recently settled turn. */
|
|
387
|
+
usage: UsageInfo | null;
|
|
388
|
+
/** Model slug the current/most-recent turn ran against (from the thread
|
|
389
|
+
* event), or null before any turn this session. */
|
|
390
|
+
model: string | null;
|
|
391
|
+
/** The current turn's accumulated reasoning/thinking text (reasoning models
|
|
392
|
+
* stream this before the answer). Shown dim while the answer is still pending;
|
|
393
|
+
* reset at the start of each turn. Null when the model emits no reasoning. */
|
|
394
|
+
reasoning: string | null;
|
|
395
|
+
error: {
|
|
396
|
+
code: string;
|
|
397
|
+
message: string;
|
|
398
|
+
} | null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* React binding for the assistant panel: owns the reducer, drives the chat SSE
|
|
403
|
+
* stream and the proposal-confirmation call, and persists the thread across
|
|
404
|
+
* reloads. All rendering decisions live in the pure reducer + presentation
|
|
405
|
+
* helpers; this hook is the glue between them and the network.
|
|
406
|
+
*/
|
|
407
|
+
|
|
408
|
+
/** Host integration callbacks for {@link useAssistantChat}. */
|
|
409
|
+
interface UseAssistantChatOptions {
|
|
410
|
+
/**
|
|
411
|
+
* Called after a workflow-mutating tool (`create_workflow`, `author_workflow`,
|
|
412
|
+
* …) is confirmed successfully — the host re-fetches its workflow list so the
|
|
413
|
+
* result appears without a manual reload. Replaces the in-app cross-module
|
|
414
|
+
* signal the platform used.
|
|
415
|
+
*/
|
|
416
|
+
onWorkflowMutation?: () => void;
|
|
417
|
+
}
|
|
418
|
+
interface AssistantChat {
|
|
419
|
+
state: AssistantState;
|
|
420
|
+
/** Proposal ids whose confirmation is currently in flight (for disabling). */
|
|
421
|
+
confirmingIds: ReadonlySet<string>;
|
|
422
|
+
/** The user's selected model slug, or null to use the server default. */
|
|
423
|
+
selectedModel: string | null;
|
|
424
|
+
/** Choose the model for subsequent turns (persisted per user). */
|
|
425
|
+
setModel: (model: string | null) => void;
|
|
426
|
+
send: (message: string) => void;
|
|
427
|
+
stop: () => void;
|
|
428
|
+
confirm: (proposal: PendingProposal) => Promise<void>;
|
|
429
|
+
cancel: (proposal: PendingProposal) => void;
|
|
430
|
+
reset: () => void;
|
|
431
|
+
/** Open an existing thread from history, loading its transcript. */
|
|
432
|
+
switchThread: (threadId: string) => void;
|
|
433
|
+
/** True while a switched-to thread's transcript is loading — the composer is
|
|
434
|
+
* held closed until it resolves so a turn can't run against hidden context. */
|
|
435
|
+
restoring: boolean;
|
|
436
|
+
}
|
|
437
|
+
declare function useAssistantChat(userId: string | null, options?: UseAssistantChatOptions): AssistantChat;
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* The assistant's selectable models for the composer's picker. The list is
|
|
441
|
+
* deployment config (not per-user), so it is fetched once per transport and
|
|
442
|
+
* shared across panel mounts via a cache keyed by the `AssistantClient`.
|
|
443
|
+
*
|
|
444
|
+
* The cache has no TTL: it lives for the page session and is revalidated by a
|
|
445
|
+
* page refresh — acceptable for deployment-config data that changes only on a
|
|
446
|
+
* redeploy. An empty/failed fetch is NOT cached, so it retries on the next mount.
|
|
447
|
+
*
|
|
448
|
+
* Keyed by client so a host that swaps the transport (a tenant/origin/account
|
|
449
|
+
* change) never serves the previous client's catalog or skips the fetch for the
|
|
450
|
+
* new one. A WeakMap lets a discarded client's bucket be collected with it.
|
|
451
|
+
*
|
|
452
|
+
* Client-only by design (a `createRoot` SPA, no React SSR), so the cache lives
|
|
453
|
+
* in one browser tab and is never shared across server requests. Under Strict
|
|
454
|
+
* Mode's double-mount the two effect runs share the one in-flight fetch; the
|
|
455
|
+
* first run's `active = false` makes its callback a no-op, the second commits —
|
|
456
|
+
* dedup holds, no torn state.
|
|
457
|
+
*/
|
|
458
|
+
|
|
459
|
+
declare function useAssistantModels(): AssistantModels;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* The user's recent assistant chat threads for the history switcher. Unlike the
|
|
463
|
+
* model list (deployment config, fetched once), the thread list changes as the
|
|
464
|
+
* user chats, so it is fetched ON DEMAND — call `refresh()` to (re)load it; the
|
|
465
|
+
* panel does so when the history view opens and after a turn settles a new
|
|
466
|
+
* thread into being. It does NOT fetch on mount, so `threads` stays empty and
|
|
467
|
+
* `loaded` false until the first `refresh()`.
|
|
468
|
+
*
|
|
469
|
+
* Self-protective across account AND transport swaps. The list is tagged with the
|
|
470
|
+
* (user, client) it belongs to and is masked to empty on the SAME commit if that
|
|
471
|
+
* no longer matches the current props — so a swap never shows the prior scope's
|
|
472
|
+
* threads for even one frame. In flight, a late result is dropped if either the
|
|
473
|
+
* user or the client changed, and the request is aborted on the swap.
|
|
474
|
+
*/
|
|
475
|
+
|
|
476
|
+
interface AssistantThreads {
|
|
477
|
+
threads: AssistantThreadSummary[];
|
|
478
|
+
loading: boolean;
|
|
479
|
+
/** True once a fetch has settled at least once (drives empty-vs-loading copy). */
|
|
480
|
+
loaded: boolean;
|
|
481
|
+
/** Load (or reload) the thread list. Must be called to populate `threads` —
|
|
482
|
+
* the hook never fetches on mount (the panel calls this when history opens). */
|
|
483
|
+
refresh: () => void;
|
|
484
|
+
/** Delete a thread. Optimistically drops it from the list (within the current
|
|
485
|
+
* owner scope); on failure the list is reloaded to restore the true state. A
|
|
486
|
+
* no-op resolving `{ ok: false }` when the client has no `deleteThread`. */
|
|
487
|
+
remove: (threadId: string) => Promise<{
|
|
488
|
+
ok: boolean;
|
|
489
|
+
}>;
|
|
490
|
+
/** Whether the configured client supports deletion — drives whether a host
|
|
491
|
+
* shows the delete affordance. */
|
|
492
|
+
canRemove: boolean;
|
|
493
|
+
}
|
|
494
|
+
declare function useAssistantThreads(userId: string | null): AssistantThreads;
|
|
495
|
+
|
|
496
|
+
interface AssistantDockProps {
|
|
497
|
+
/** The signed-in user this conversation belongs to (null when signed out). */
|
|
498
|
+
userId: string | null;
|
|
499
|
+
/** Host navigation for error CTAs and connect targets. */
|
|
500
|
+
navigate?: (path: string) => void;
|
|
501
|
+
balanceUsd?: number | null;
|
|
502
|
+
formatMoney?: (usd: number | null) => string;
|
|
503
|
+
/** Render workflow YAML as a node graph in a proposal card. */
|
|
504
|
+
renderGraph?: (yaml: string) => ReactNode;
|
|
505
|
+
/** Called after a workflow-mutating tool is confirmed (host re-fetches its list). */
|
|
506
|
+
onWorkflowMutation?: () => void;
|
|
507
|
+
/** Markdown renderer for assistant message content (plain text when absent). */
|
|
508
|
+
renderMarkdown?: (content: string) => ReactNode;
|
|
509
|
+
/** Per-tool custom detail renderers for expanded tool cards in the transcript. */
|
|
510
|
+
toolRenderers?: ToolDetailRenderers;
|
|
511
|
+
/** Swap the conversation rendering for a host-supplied renderer (see
|
|
512
|
+
* {@link AssistantPanelProps.renderTranscript}); the dock chrome, composer,
|
|
513
|
+
* transport, and proposal flow stay owned by the panel. */
|
|
514
|
+
renderTranscript?: (view: AssistantTranscriptView) => ReactNode;
|
|
515
|
+
}
|
|
516
|
+
declare function AssistantDock({ userId, navigate, balanceUsd, formatMoney, renderGraph, onWorkflowMutation, renderMarkdown, toolRenderers, renderTranscript, }: AssistantDockProps): react.JSX.Element;
|
|
517
|
+
|
|
518
|
+
interface AssistantPanelProps {
|
|
519
|
+
chat: AssistantChat;
|
|
520
|
+
userId: string | null;
|
|
521
|
+
onClose: () => void;
|
|
522
|
+
/** Host navigation for error CTAs and connect targets. */
|
|
523
|
+
navigate?: (path: string) => void;
|
|
524
|
+
/** The user's credit balance, for the header tile + low-balance nudge. */
|
|
525
|
+
balanceUsd?: number | null;
|
|
526
|
+
/** Format a USD amount; defaults to Intl currency formatting. */
|
|
527
|
+
formatMoney?: (usd: number | null) => string;
|
|
528
|
+
/** Render workflow YAML as a node graph in a proposal card (the `./workflows`
|
|
529
|
+
* WorkflowGraph). When absent, proposals show YAML as text. */
|
|
530
|
+
renderGraph?: (yaml: string) => ReactNode;
|
|
531
|
+
/** Markdown renderer for assistant message content. When absent, content
|
|
532
|
+
* renders as plain pre-wrapped text. */
|
|
533
|
+
renderMarkdown?: (content: string) => ReactNode;
|
|
534
|
+
/** Per-tool custom detail renderers for expanded tool cards in the transcript. */
|
|
535
|
+
toolRenderers?: ToolDetailRenderers;
|
|
536
|
+
/** Swap ONLY the conversation rendering for a host-supplied renderer (e.g. a
|
|
537
|
+
* different chat-message component), while the panel keeps owning the header,
|
|
538
|
+
* composer, model picker, history, transport, and proposal orchestration.
|
|
539
|
+
* Receives the transcript slice plus a bound proposal card to place. When
|
|
540
|
+
* absent, the built-in transcript (web-react `ChatMessages`) renders the
|
|
541
|
+
* conversation. */
|
|
542
|
+
renderTranscript?: (view: AssistantTranscriptView) => ReactNode;
|
|
543
|
+
}
|
|
544
|
+
declare function AssistantPanel({ chat, userId, onClose, navigate, balanceUsd, formatMoney, renderGraph, renderMarkdown, toolRenderers, renderTranscript, }: AssistantPanelProps): react.JSX.Element;
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* True while a turn is streaming but the model hasn't emitted its first answer
|
|
548
|
+
* token yet — drives the "thinking" affordance so a reasoning gap reads as
|
|
549
|
+
* working, not a frozen panel.
|
|
550
|
+
*/
|
|
551
|
+
declare function assistantIsThinking(state: AssistantState): boolean;
|
|
552
|
+
interface AdaptedTranscript {
|
|
553
|
+
messages: ChatUiMessage[];
|
|
554
|
+
/** The assistant message under which pending proposals should render, or null
|
|
555
|
+
* when there are none. */
|
|
556
|
+
proposalHostId: string | null;
|
|
557
|
+
/** The current/most-recent turn's assistant message — where the turn cost line
|
|
558
|
+
* renders (it carries the turn's metrics), or null when there is none. */
|
|
559
|
+
metricsHostId: string | null;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Fold the transcript view into web-react `ChatUiMessage[]`: each user message is
|
|
563
|
+
* 1:1; the assistant/`tool`/`status` messages between two user turns collapse
|
|
564
|
+
* into one assistant message whose ordered `segments` carry the turn's text runs
|
|
565
|
+
* and tool chips IN EMISSION ORDER (with each finished tool's outcome as the chip
|
|
566
|
+
* `result`). The joined text is also kept on `content` — web-react reads it as the
|
|
567
|
+
* "answer has started" signal that gates the reasoning box. The live turn's
|
|
568
|
+
* reasoning preview and model label hang on the last assistant message, and
|
|
569
|
+
* `proposalHostId` names the message the pending proposals render under.
|
|
570
|
+
*/
|
|
571
|
+
declare function adaptTranscript(view: AssistantTranscriptView): AdaptedTranscript;
|
|
572
|
+
interface AssistantTranscriptProps {
|
|
573
|
+
view: AssistantTranscriptView;
|
|
574
|
+
/** Markdown renderer for assistant content; defaults to plain pre-wrapped text. */
|
|
575
|
+
renderMarkdown?: (content: string) => ReactNode;
|
|
576
|
+
/** Per-tool custom detail renderers for expanded tool cards. */
|
|
577
|
+
toolRenderers?: ToolDetailRenderers;
|
|
578
|
+
/** Zero-state shown for a fresh, non-streaming thread. */
|
|
579
|
+
emptyState?: ReactNode;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Render the assistant conversation with web-react's `ChatMessages`. Pending
|
|
583
|
+
* proposals render via the panel's bound `view.renderProposal`, placed inline
|
|
584
|
+
* after the proposing turn through `renderExtras`; the settled turn cost renders
|
|
585
|
+
* once under its assistant bubble.
|
|
586
|
+
*/
|
|
587
|
+
declare function AssistantTranscript({ view, renderMarkdown, toolRenderers, emptyState, }: AssistantTranscriptProps): react.JSX.Element;
|
|
588
|
+
|
|
589
|
+
interface ProposalCardProps {
|
|
590
|
+
proposal: PendingProposal;
|
|
591
|
+
/** True while this proposal's confirmation is in flight (disables the buttons). */
|
|
592
|
+
confirming: boolean;
|
|
593
|
+
onConfirm: () => void;
|
|
594
|
+
onCancel: () => void;
|
|
595
|
+
/** Host navigation for connect targets / the integrations page. */
|
|
596
|
+
navigate?: (path: string) => void;
|
|
597
|
+
/** Render the workflow YAML as a node graph (the `./workflows` WorkflowGraph).
|
|
598
|
+
* When absent, the YAML is shown as text. */
|
|
599
|
+
renderGraph?: (yaml: string) => ReactNode;
|
|
600
|
+
}
|
|
601
|
+
declare function ProposalCard({ proposal, confirming, onConfirm, onCancel, navigate, renderGraph, }: ProposalCardProps): react.JSX.Element;
|
|
602
|
+
|
|
603
|
+
interface AssistantLauncher {
|
|
604
|
+
/** Whether the assistant drawer is open. */
|
|
605
|
+
open: boolean;
|
|
606
|
+
/** A one-shot starter prompt to prefill the composer with, or null. */
|
|
607
|
+
seed: string | null;
|
|
608
|
+
/** Open the drawer; optionally prefill the composer with `seed`. */
|
|
609
|
+
openAssistant: (seed?: string) => void;
|
|
610
|
+
closeAssistant: () => void;
|
|
611
|
+
/** Clear the pending seed once the composer has applied it (consume-once). */
|
|
612
|
+
clearSeed: () => void;
|
|
613
|
+
}
|
|
614
|
+
declare function AssistantLauncherProvider({ children, }: {
|
|
615
|
+
children: ReactNode;
|
|
616
|
+
}): react.JSX.Element;
|
|
617
|
+
declare function useAssistantLauncher(): AssistantLauncher;
|
|
618
|
+
|
|
619
|
+
export { type AssistantChat, type AssistantClient, type AssistantClientConfig, AssistantClientProvider, AssistantDock, type AssistantDockProps, type AssistantLauncher, AssistantLauncherProvider, type AssistantModelOption, type AssistantModels, type AssistantModelsResult, AssistantPanel, type AssistantPanelProps, type AssistantStreamEvent, type AssistantThreadSummary, type AssistantThreads, AssistantTranscript, type AssistantTranscriptProps, type AssistantTranscriptView, type ChatMessage, type ChatRequest, type ChatRole, type ConfirmResult, type ConnectionRequirement, type ConnectionRequirementKind, type DeltaEventData, type DoneEventData, type ErrorEventData, type PendingProposal, ProposalCard, type ProposalCardProps, type ReasoningEventData, type ThreadEventData, type ThreadHistoryResult, type ToolActivityStatus, type ToolCallEventData, type ToolOutcome, type ToolProposalEventData, type ToolResultEventData, type UsageEventData, type UsageInfo, type UseAssistantChatOptions, adaptTranscript, assistantIsThinking, createAssistantClient, useAssistantChat, useAssistantClient, useAssistantLauncher, useAssistantModels, useAssistantThreads };
|