@waniwani/sdk 0.20.0 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat/embed.js +70 -68
- package/dist/chat/embed.js.map +1 -1
- package/dist/chat/index.d.ts +128 -2
- package/dist/chat/index.js +9 -7
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/styles.css +1 -1
- package/dist/documents/index.d.ts +104 -0
- package/dist/documents/index.js +2 -0
- package/dist/documents/index.js.map +1 -0
- package/dist/index.d.ts +79 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +480 -1
- package/dist/mcp/index.js +5 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/react/skybridge.js +1 -1
- package/dist/mcp/react/skybridge.js.map +1 -1
- package/dist/mcp/react.js +1 -1
- package/dist/mcp/react.js.map +1 -1
- package/package.json +6 -1
package/dist/mcp/index.d.ts
CHANGED
|
@@ -6,6 +6,325 @@ import { z } from 'zod';
|
|
|
6
6
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
7
|
export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Reading a widget's view binding off MCP `_meta`.
|
|
11
|
+
*
|
|
12
|
+
* Kept in `shared/` because three surfaces ask the same question and none of
|
|
13
|
+
* them should own the answer: the chat resolves a tool part's view before
|
|
14
|
+
* rendering it, the WebMCP endpoint resolves a display tool's view before
|
|
15
|
+
* handing it to the page, and both have to agree or a widget renders in one
|
|
16
|
+
* place and not the other.
|
|
17
|
+
*
|
|
18
|
+
* The three spellings below are not alternatives to choose between. They are
|
|
19
|
+
* what three host generations actually emit, and a server built on any of them
|
|
20
|
+
* is a server we have to render.
|
|
21
|
+
*/
|
|
22
|
+
/** Anything carrying MCP `_meta`: a tool definition, a tool result, a resource. */
|
|
23
|
+
type MetaCarrier = {
|
|
24
|
+
_meta?: Record<string, unknown>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The view a `_meta` binds to, checking all three shapes in priority order:
|
|
28
|
+
*
|
|
29
|
+
* 1. `_meta.ui.resourceUri` — MCP Apps, nested (skybridge, ext-apps)
|
|
30
|
+
* 2. `_meta["ui/resourceUri"]` — MCP Apps, flat (earlier drafts, still in the wild)
|
|
31
|
+
* 3. `_meta["openai/outputTemplate"]` — OpenAI Apps SDK
|
|
32
|
+
*
|
|
33
|
+
* Order is priority, not preference: a server emitting more than one emits them
|
|
34
|
+
* as aliases of the same view, and the nested form is the one the current spec
|
|
35
|
+
* defines.
|
|
36
|
+
*/
|
|
37
|
+
declare function resourceUriFromMeta(meta: Record<string, unknown> | undefined): string | undefined;
|
|
38
|
+
/** Whether the host should size the frame from the view's content. */
|
|
39
|
+
declare function autoHeightFromMeta(meta: Record<string, unknown> | undefined): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The view a tool renders, read from its definition.
|
|
42
|
+
*
|
|
43
|
+
* Definition rather than result on purpose. A spec-compliant server binds the
|
|
44
|
+
* view on the tool, so a result carries the binding only by accident, and
|
|
45
|
+
* reading the result first means a tool whose view is declared correctly looks
|
|
46
|
+
* like a tool with no view at all.
|
|
47
|
+
*/
|
|
48
|
+
declare function viewUriFor(tool: MetaCarrier | undefined): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Whether a tool exists to render something rather than to be reasoned about.
|
|
51
|
+
*
|
|
52
|
+
* The distinction matters wherever a tool list crosses a boundary. A display
|
|
53
|
+
* tool advertised to a browsing agent is a tool it will try to call to make a
|
|
54
|
+
* widget appear, on a surface with no widget host in it, which burns a turn and
|
|
55
|
+
* strands the conversation on a render nobody performs.
|
|
56
|
+
*/
|
|
57
|
+
declare function isDisplayTool(tool: MetaCarrier | undefined): boolean;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The shapes crossing the WebMCP boundary.
|
|
61
|
+
*
|
|
62
|
+
* Structural rather than imported from `@modelcontextprotocol/sdk`, because
|
|
63
|
+
* everything here is also read by the browser bridge, and the MCP SDK is an
|
|
64
|
+
* optional peer dependency that has no business in a page bundle. What the
|
|
65
|
+
* server sends and what the page reads is JSON either way.
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* One MCP content block. `type` is the discriminator every block carries; the
|
|
69
|
+
* index signature keeps the rest of whichever block it is, since nothing on
|
|
70
|
+
* this path reads them and re-deriving the union would only restate a schema
|
|
71
|
+
* the server already validated on the way out.
|
|
72
|
+
*/
|
|
73
|
+
type WebMcpContentBlock = {
|
|
74
|
+
type: string;
|
|
75
|
+
text?: string;
|
|
76
|
+
[key: string]: unknown;
|
|
77
|
+
};
|
|
78
|
+
/** A tool as `tools/list` describes it. */
|
|
79
|
+
type WebMcpTool = {
|
|
80
|
+
name: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
inputSchema?: Record<string, unknown>;
|
|
83
|
+
annotations?: Record<string, unknown>;
|
|
84
|
+
_meta?: Record<string, unknown>;
|
|
85
|
+
};
|
|
86
|
+
/** A tool result as `tools/call` returns it. */
|
|
87
|
+
type WebMcpCallResult = {
|
|
88
|
+
content?: WebMcpContentBlock[];
|
|
89
|
+
structuredContent?: Record<string, unknown>;
|
|
90
|
+
isError?: boolean;
|
|
91
|
+
_meta?: Record<string, unknown>;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Everything the page needs to mount a widget itself.
|
|
95
|
+
*
|
|
96
|
+
* Assembled server-side because none of it is derivable on the page: the view
|
|
97
|
+
* URI carries a content hash that moves every deploy, and the display tool's
|
|
98
|
+
* result is what the view reads its own configuration from.
|
|
99
|
+
*/
|
|
100
|
+
type WebMcpWidgetPayload = {
|
|
101
|
+
/**
|
|
102
|
+
* The `ui://` the view was resolved from.
|
|
103
|
+
*
|
|
104
|
+
* Carries a content hash that moves on every deploy, which is why this is
|
|
105
|
+
* resolved server-side per call and why nothing on the page can cache it.
|
|
106
|
+
*
|
|
107
|
+
* The only half of the view the page is told. Where to fetch it from is the
|
|
108
|
+
* resource endpoint the page already derived from its token, the same one
|
|
109
|
+
* the chat's own widget iframes use.
|
|
110
|
+
*/
|
|
111
|
+
viewUri: string;
|
|
112
|
+
/** Display tool the view belongs to. */
|
|
113
|
+
tool: string;
|
|
114
|
+
/** Props, delivered to the view as `ui/notifications/tool-input`. */
|
|
115
|
+
data: Record<string, unknown>;
|
|
116
|
+
/** The display tool's own result, delivered as `ui/notifications/tool-result`. */
|
|
117
|
+
result: {
|
|
118
|
+
content: WebMcpContentBlock[];
|
|
119
|
+
structuredContent?: Record<string, unknown>;
|
|
120
|
+
_meta?: Record<string, unknown>;
|
|
121
|
+
};
|
|
122
|
+
/** Whether the flow is waiting on the visitor before it can advance. */
|
|
123
|
+
interactive: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Set by the preview endpoint. A real widget step is a flow waiting on the
|
|
126
|
+
* visitor and has no way out; a preview is something someone opened to look
|
|
127
|
+
* at, so the host can give it one.
|
|
128
|
+
*/
|
|
129
|
+
preview?: boolean;
|
|
130
|
+
};
|
|
131
|
+
/** What every page-facing request carries, whatever it is asking for. */
|
|
132
|
+
type WebMcpRequestBase = {
|
|
133
|
+
/**
|
|
134
|
+
* Tab-scoped, and the key the flow engine stores its state under.
|
|
135
|
+
*
|
|
136
|
+
* Must be stable for the tab and must not outlive it. A value that changes
|
|
137
|
+
* between calls silently restarts every flow; one that persists across days
|
|
138
|
+
* resumes a flow abandoned last week mid-question.
|
|
139
|
+
*/
|
|
140
|
+
sessionId: string;
|
|
141
|
+
/**
|
|
142
|
+
* The visitor's persistent id. Identity rather than state, and what lets a
|
|
143
|
+
* flow started here and a conversation continued in the chat bubble belong
|
|
144
|
+
* to one person.
|
|
145
|
+
*/
|
|
146
|
+
visitorId?: string;
|
|
147
|
+
/**
|
|
148
|
+
* The channel this page's embed belongs to.
|
|
149
|
+
*
|
|
150
|
+
* Sent because ingest rejects events it cannot attribute to a channel, and a
|
|
151
|
+
* token-only embed learns its channel from `/config` rather than from its
|
|
152
|
+
* own markup. Without it a tool call is attributed to nothing and the events
|
|
153
|
+
* behind it are dropped.
|
|
154
|
+
*/
|
|
155
|
+
channelId?: string;
|
|
156
|
+
/** Where the visitor was standing when the agent called. */
|
|
157
|
+
page?: WebMcpPageContext;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* `POST` body for the page-facing tools endpoint.
|
|
161
|
+
*
|
|
162
|
+
* The bridge builds exactly this, so a server implementing the other end is
|
|
163
|
+
* type-checked against what actually arrives rather than against a description
|
|
164
|
+
* of it.
|
|
165
|
+
*/
|
|
166
|
+
type WebMcpRequest = (WebMcpRequestBase & {
|
|
167
|
+
action: "list";
|
|
168
|
+
}) | (WebMcpRequestBase & {
|
|
169
|
+
action: "call";
|
|
170
|
+
name: string;
|
|
171
|
+
arguments?: Record<string, unknown>;
|
|
172
|
+
});
|
|
173
|
+
/** Where the visitor was standing when the agent called. */
|
|
174
|
+
type WebMcpPageContext = {
|
|
175
|
+
url?: string;
|
|
176
|
+
title?: string;
|
|
177
|
+
};
|
|
178
|
+
type WebMcpListResponse = {
|
|
179
|
+
tools: WebMcpTool[];
|
|
180
|
+
};
|
|
181
|
+
type WebMcpCallResponse = {
|
|
182
|
+
content: WebMcpContentBlock[];
|
|
183
|
+
structuredContent?: Record<string, unknown>;
|
|
184
|
+
isError?: boolean;
|
|
185
|
+
/** Present and non-null only when the call produced a resolvable widget step. */
|
|
186
|
+
widget: WebMcpWidgetPayload | null;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The WebMCP bridge.
|
|
191
|
+
*
|
|
192
|
+
* A browsing agent standing on a page never speaks to the MCP server. It speaks
|
|
193
|
+
* to the page, through `document.modelContext`, and this is what puts the
|
|
194
|
+
* server's tools there. Every `execute()` the agent calls lands on the endpoint
|
|
195
|
+
* below, which stamps attribution server-side and answers.
|
|
196
|
+
*
|
|
197
|
+
* Nothing here discovers its own configuration. The endpoint, both ids, and the
|
|
198
|
+
* widget callback are arguments, because there are two callers with two
|
|
199
|
+
* different ways of knowing them: the chat embed reads them from its remote
|
|
200
|
+
* config, and the standalone loader derives them from its own script tag.
|
|
201
|
+
* Sniffing `document.currentScript` inside a bundle that may be loaded twenty
|
|
202
|
+
* modules deep finds the wrong script or none.
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
type WebMcpBridgeOptions = {
|
|
206
|
+
/** Absolute URL of the server's page-facing tools endpoint. */
|
|
207
|
+
endpoint: string;
|
|
208
|
+
/**
|
|
209
|
+
* Extra request headers, merged over `content-type`.
|
|
210
|
+
*
|
|
211
|
+
* The hosted API authenticates with `Authorization: Bearer <public token>`
|
|
212
|
+
* here, the same as every other call the embed makes. A self-hosted server
|
|
213
|
+
* reached directly needs none.
|
|
214
|
+
*/
|
|
215
|
+
headers?: Record<string, string>;
|
|
216
|
+
/**
|
|
217
|
+
* Tab-scoped id, and the key the flow engine stores its state under.
|
|
218
|
+
*
|
|
219
|
+
* Must be stable for the tab and must not outlive it. A value that changes
|
|
220
|
+
* between calls silently restarts every flow; a value that persists across
|
|
221
|
+
* days resumes a flow abandoned last week mid-question.
|
|
222
|
+
*/
|
|
223
|
+
sessionId: string;
|
|
224
|
+
/**
|
|
225
|
+
* The visitor's persistent id, from `shared/visitor-id`.
|
|
226
|
+
*
|
|
227
|
+
* Identity rather than state. Sending it is what lets a flow started here
|
|
228
|
+
* and a conversation continued in the chat bubble belong to one person.
|
|
229
|
+
*/
|
|
230
|
+
visitorId?: string;
|
|
231
|
+
/**
|
|
232
|
+
* The channel this embed belongs to, from the script tag or `/config`.
|
|
233
|
+
*
|
|
234
|
+
* Ingest drops events it cannot attribute to a channel, so a tool call sent
|
|
235
|
+
* without this produces conversions nobody can see.
|
|
236
|
+
*/
|
|
237
|
+
channelId?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Called when a tool call resolves to a widget the page should mount.
|
|
240
|
+
*
|
|
241
|
+
* Optional, and the surface works without it: everything the visitor needs
|
|
242
|
+
* is also in the text the agent receives. A page with no host gets a flow
|
|
243
|
+
* carried in words.
|
|
244
|
+
*/
|
|
245
|
+
onWidget?: (widget: WebMcpWidgetPayload) => void;
|
|
246
|
+
/** Defaults to `console`. */
|
|
247
|
+
logger?: Pick<Console, "error" | "info">;
|
|
248
|
+
};
|
|
249
|
+
/** Live for as long as the bridge is registered. */
|
|
250
|
+
type WebMcpBridge = {
|
|
251
|
+
/** Tools successfully registered with the browser. */
|
|
252
|
+
readonly tools: WebMcpTool[];
|
|
253
|
+
/** Unregister everything. Idempotent. */
|
|
254
|
+
dispose: () => void;
|
|
255
|
+
};
|
|
256
|
+
/** Whether this browser can host site tools at all. Almost every visit: no. */
|
|
257
|
+
declare function supportsWebMcp(): boolean;
|
|
258
|
+
/**
|
|
259
|
+
* Register the server's tools with the browsing agent.
|
|
260
|
+
*
|
|
261
|
+
* Resolves once registration has been attempted for every advertised tool. A
|
|
262
|
+
* tool the browser refuses is logged and skipped rather than failing the rest,
|
|
263
|
+
* because a partial tool list is a working page and an exception here is a
|
|
264
|
+
* blank one.
|
|
265
|
+
*
|
|
266
|
+
* Returns `null` when the browser has no `modelContext`, which is the common
|
|
267
|
+
* case and not an error.
|
|
268
|
+
*/
|
|
269
|
+
declare function createWebMcpBridge(options: WebMcpBridgeOptions): Promise<WebMcpBridge | null>;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Structural stand-in for a Zod schema, so the package root's type graph does
|
|
273
|
+
* not reference `zod`, an optional peer. Pass a real Zod schema: `extract()`
|
|
274
|
+
* converts it with `z.toJSONSchema()`, which no other `parse`-shaped object
|
|
275
|
+
* survives.
|
|
276
|
+
*/
|
|
277
|
+
interface DocumentSchema<T> {
|
|
278
|
+
parse(value: unknown): T;
|
|
279
|
+
}
|
|
280
|
+
interface DocumentExtractResult<T> {
|
|
281
|
+
/** The document's contents, parsed with the schema you passed. A null field is one the document did not legibly answer. */
|
|
282
|
+
fields: T;
|
|
283
|
+
/** Pages the vendor processed and billed */
|
|
284
|
+
pageCount: number;
|
|
285
|
+
/** Mean per-page OCR confidence, null when none was reported */
|
|
286
|
+
pageConfidence: number | null;
|
|
287
|
+
/** Handle for this extraction, valid for the 7-day retention window */
|
|
288
|
+
documentId: string;
|
|
289
|
+
}
|
|
290
|
+
/** A document the visitor uploaded through the chat widget, already stored by the platform. */
|
|
291
|
+
interface AttachedDocument {
|
|
292
|
+
/** Pass to `documents.extract({ documentId, schema })` to read it. */
|
|
293
|
+
documentId: string;
|
|
294
|
+
/** Name the visitor's file had */
|
|
295
|
+
filename: string;
|
|
296
|
+
/** MIME type the browser declared on upload */
|
|
297
|
+
mediaType: string;
|
|
298
|
+
}
|
|
299
|
+
interface DocumentExtractCommon<T> {
|
|
300
|
+
/** The shape to return. Extraction runs in strict mode, so mark anything a document may not answer `.nullable()`. */
|
|
301
|
+
schema: DocumentSchema<T>;
|
|
302
|
+
/** Zero-based page indexes to read: `[0]` is the first page. Omit to read every page. Ignored for images. Billing is per page processed, so a narrower selection costs less. */
|
|
303
|
+
pages?: number[];
|
|
304
|
+
/** Conversation this document arrived in */
|
|
305
|
+
sessionId?: string;
|
|
306
|
+
/** Ties the extraction to one tool call */
|
|
307
|
+
correlationId?: string;
|
|
308
|
+
}
|
|
309
|
+
/** Read a document the platform has never seen, by fetching it. */
|
|
310
|
+
interface DocumentExtractUrlInput<T> extends DocumentExtractCommon<T> {
|
|
311
|
+
/** A publicly fetchable URL; private and loopback addresses are refused */
|
|
312
|
+
url: string;
|
|
313
|
+
/** Name of the file, used to refuse an unsupported type before fetching it */
|
|
314
|
+
filename: string;
|
|
315
|
+
documentId?: never;
|
|
316
|
+
}
|
|
317
|
+
/** Read a document the platform already holds, uploaded by a visitor through the chat widget. */
|
|
318
|
+
interface DocumentExtractStoredInput<T> extends DocumentExtractCommon<T> {
|
|
319
|
+
/** From `context.waniwani.attachedDocuments`, or `readAttachedDocuments()` on your own chat route. The platform kept the filename, so there is none to pass. */
|
|
320
|
+
documentId: string;
|
|
321
|
+
}
|
|
322
|
+
type DocumentExtractInput<T> = DocumentExtractUrlInput<T> | DocumentExtractStoredInput<T>;
|
|
323
|
+
interface DocumentsClient {
|
|
324
|
+
/** Read one document and get its contents shaped by `schema`. Accepts PDF, PNG, JPEG, TIFF, BMP, GIF and WEBP up to 50 MB. */
|
|
325
|
+
extract<T>(input: DocumentExtractInput<T>): Promise<DocumentExtractResult<T>>;
|
|
326
|
+
}
|
|
327
|
+
|
|
9
328
|
interface SearchResult {
|
|
10
329
|
source: string;
|
|
11
330
|
heading: string;
|
|
@@ -351,6 +670,12 @@ interface TrackingClient {
|
|
|
351
670
|
shutdown: (options?: TrackingShutdownOptions) => Promise<TrackingShutdownResult>;
|
|
352
671
|
}
|
|
353
672
|
|
|
673
|
+
/** A file the host bound to this tool call, resolved to something fetchable. */
|
|
674
|
+
interface AttachedFile {
|
|
675
|
+
url: string;
|
|
676
|
+
filename: string;
|
|
677
|
+
}
|
|
678
|
+
|
|
354
679
|
/**
|
|
355
680
|
* Well-known key used to attach the scoped client to the MCP `extra` object.
|
|
356
681
|
* Read by `createTool` and flow compilation to surface it in handler contexts.
|
|
@@ -397,6 +722,21 @@ interface ScopedWaniWaniClient {
|
|
|
397
722
|
}>;
|
|
398
723
|
/** Knowledge base client (no meta needed). */
|
|
399
724
|
readonly kb: KbClient;
|
|
725
|
+
/**
|
|
726
|
+
* Files the host attached to this tool call, each with a fetchable `url` and
|
|
727
|
+
* a `filename` — spread one straight into `documents.extract()`. Empty on
|
|
728
|
+
* hosts that attach nothing.
|
|
729
|
+
*/
|
|
730
|
+
readonly attachedFiles: AttachedFile[];
|
|
731
|
+
/**
|
|
732
|
+
* Documents the visitor uploaded through the chat widget on this turn. The
|
|
733
|
+
* platform holds the bytes, so each entry is a handle: spread one straight
|
|
734
|
+
* into `documents.extract({ documentId, schema })`. Empty on hosts that
|
|
735
|
+
* upload nothing.
|
|
736
|
+
*/
|
|
737
|
+
readonly attachedDocuments: AttachedDocument[];
|
|
738
|
+
/** Documents client; `sessionId` and `correlationId` are carried from the request. */
|
|
739
|
+
readonly documents: DocumentsClient;
|
|
400
740
|
/** @internal Resolved API config from withWaniwani(). */
|
|
401
741
|
readonly _config?: {
|
|
402
742
|
apiUrl?: string;
|
|
@@ -489,6 +829,10 @@ interface FlowStore {
|
|
|
489
829
|
}
|
|
490
830
|
|
|
491
831
|
declare const flowOutputSchema: {
|
|
832
|
+
intro: z.ZodOptional<z.ZodObject<{
|
|
833
|
+
verbatim: z.ZodOptional<z.ZodString>;
|
|
834
|
+
instructions: z.ZodOptional<z.ZodString>;
|
|
835
|
+
}, z.core.$strip>>;
|
|
492
836
|
status: z.ZodEnum<{
|
|
493
837
|
error: "error";
|
|
494
838
|
interrupt: "interrupt";
|
|
@@ -766,6 +1110,31 @@ type FlowGraph = {
|
|
|
766
1110
|
nodes: FlowGraphNode[];
|
|
767
1111
|
edges: FlowGraphEdge[];
|
|
768
1112
|
};
|
|
1113
|
+
/**
|
|
1114
|
+
* The intro delivered the first time a session touches the flow.
|
|
1115
|
+
*
|
|
1116
|
+
* A bare string is shorthand for `{ verbatim: "…" }`.
|
|
1117
|
+
*
|
|
1118
|
+
* - `verbatim` — reproduced word for word by the assistant. Use it for legal
|
|
1119
|
+
* notices (GDPR, data controller, retention) that must survive intact.
|
|
1120
|
+
* - `instructions` — guidance the assistant writes its own opening from.
|
|
1121
|
+
*
|
|
1122
|
+
* Set both and the assistant writes the surrounding prose from
|
|
1123
|
+
* `instructions` while keeping the `verbatim` text untouched.
|
|
1124
|
+
*/
|
|
1125
|
+
type FlowIntro = string | {
|
|
1126
|
+
/** Text the assistant must reproduce word for word. */
|
|
1127
|
+
verbatim?: string;
|
|
1128
|
+
/** How the assistant should write the introduction around it. */
|
|
1129
|
+
instructions?: string;
|
|
1130
|
+
};
|
|
1131
|
+
/** Normalized intro as it appears in the flow tool response. */
|
|
1132
|
+
type FlowIntroPayload = {
|
|
1133
|
+
/** Deliver word for word — no paraphrase, no translation, no reformatting. */
|
|
1134
|
+
verbatim?: string;
|
|
1135
|
+
/** Guidance for the assistant's own wording. */
|
|
1136
|
+
instructions?: string;
|
|
1137
|
+
};
|
|
769
1138
|
type FlowConfig = {
|
|
770
1139
|
/** Unique identifier for the flow (becomes the MCP tool name) */
|
|
771
1140
|
id: string;
|
|
@@ -773,6 +1142,26 @@ type FlowConfig = {
|
|
|
773
1142
|
title: string;
|
|
774
1143
|
/** Description for the AI (explains when to use this flow) */
|
|
775
1144
|
description: string;
|
|
1145
|
+
/**
|
|
1146
|
+
* Opening message for the session's first flow response — an introduction,
|
|
1147
|
+
* a GDPR notice, or both. Attached to whichever response the engine returns
|
|
1148
|
+
* first, so it lands even when pre-filled state skips the flow's opening
|
|
1149
|
+
* nodes, and it is never repeated once delivered.
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```ts
|
|
1153
|
+
* intro: "Acme is the data controller. Your answers are used for this quote only."
|
|
1154
|
+
* ```
|
|
1155
|
+
*
|
|
1156
|
+
* @example
|
|
1157
|
+
* ```ts
|
|
1158
|
+
* intro: {
|
|
1159
|
+
* verbatim: "Acme is the data controller. Your answers are deleted after 30 days.",
|
|
1160
|
+
* instructions: "Introduce yourself as Léa from Acme in one short sentence first.",
|
|
1161
|
+
* }
|
|
1162
|
+
* ```
|
|
1163
|
+
*/
|
|
1164
|
+
intro?: FlowIntro;
|
|
776
1165
|
/**
|
|
777
1166
|
* Define the flow's state — each field the flow collects.
|
|
778
1167
|
* Keys are the field names used in `interrupt({ field })`,
|
|
@@ -860,11 +1249,35 @@ type RegisteredFlow = {
|
|
|
860
1249
|
graph: () => string;
|
|
861
1250
|
flowGraph: FlowGraph;
|
|
862
1251
|
};
|
|
1252
|
+
/**
|
|
1253
|
+
* The engine's own state for a session, persisted in the same record as the
|
|
1254
|
+
* flow's state and kept strictly apart from it.
|
|
1255
|
+
*
|
|
1256
|
+
* Not flow state: nothing here is declared by the author, reaches a node, or
|
|
1257
|
+
* can be written through `stateUpdates`.
|
|
1258
|
+
*
|
|
1259
|
+
* One optional field per engine feature that carries something across calls. A
|
|
1260
|
+
* field is seeded when the session starts and taken off once the engine has
|
|
1261
|
+
* used it, so presence means "still pending" and absence means "done". Seeding,
|
|
1262
|
+
* reading and persisting all go through `internal-state.ts`, which carries
|
|
1263
|
+
* unrecognized fields through untouched: a field a newer version wrote survives
|
|
1264
|
+
* a call served by an older one, and adding a field never strands sessions
|
|
1265
|
+
* across a deploy.
|
|
1266
|
+
*/
|
|
1267
|
+
type FlowInternalState = {
|
|
1268
|
+
/**
|
|
1269
|
+
* The flow's intro, waiting to ride on the session's first response. Gone
|
|
1270
|
+
* once delivered, so later responses in the same conversation leave it out.
|
|
1271
|
+
*/
|
|
1272
|
+
intro?: FlowIntroPayload;
|
|
1273
|
+
};
|
|
863
1274
|
type FlowTokenContent = {
|
|
864
1275
|
step?: string;
|
|
865
1276
|
state: Record<string, unknown>;
|
|
866
1277
|
field?: string;
|
|
867
1278
|
widgetId?: string;
|
|
1279
|
+
/** The engine's own state for this session. Never flow state. */
|
|
1280
|
+
internal?: FlowInternalState;
|
|
868
1281
|
};
|
|
869
1282
|
type InterruptQuestionData = {
|
|
870
1283
|
question: string;
|
|
@@ -880,6 +1293,8 @@ type InterruptQuestionData = {
|
|
|
880
1293
|
};
|
|
881
1294
|
type FlowInterruptContent = {
|
|
882
1295
|
status: "interrupt";
|
|
1296
|
+
/** Opening message for the session's first flow response. */
|
|
1297
|
+
intro?: FlowIntroPayload;
|
|
883
1298
|
/** Single-question shorthand */
|
|
884
1299
|
question?: string;
|
|
885
1300
|
field?: string;
|
|
@@ -892,6 +1307,8 @@ type FlowInterruptContent = {
|
|
|
892
1307
|
};
|
|
893
1308
|
type FlowWidgetContent = {
|
|
894
1309
|
status: "widget";
|
|
1310
|
+
/** Opening message for the session's first flow response. */
|
|
1311
|
+
intro?: FlowIntroPayload;
|
|
895
1312
|
/** Display tool to call */
|
|
896
1313
|
tool: string;
|
|
897
1314
|
/** Data to pass to the display tool */
|
|
@@ -911,12 +1328,72 @@ type FlowWidgetContent = {
|
|
|
911
1328
|
};
|
|
912
1329
|
type FlowCompleteContent = {
|
|
913
1330
|
status: "complete";
|
|
1331
|
+
/** Opening message for the session's first flow response. */
|
|
1332
|
+
intro?: FlowIntroPayload;
|
|
914
1333
|
};
|
|
915
1334
|
type FlowErrorContent = {
|
|
916
1335
|
status: "error";
|
|
917
1336
|
error: string;
|
|
918
1337
|
};
|
|
919
1338
|
|
|
1339
|
+
/**
|
|
1340
|
+
* Widget steps on the WebMCP surface.
|
|
1341
|
+
*
|
|
1342
|
+
* In a chat host a flow's widget step is a two-call dance: the flow answers
|
|
1343
|
+
* `status: "widget"` naming a display tool, the model calls that tool, and the
|
|
1344
|
+
* host renders the `ui://` template it points at. None of that survives the
|
|
1345
|
+
* trip to a browsing agent. There is no widget host in the agent's window, the
|
|
1346
|
+
* display tool is not advertised on this surface, and the round trip would cost
|
|
1347
|
+
* a turn for a render nobody performs.
|
|
1348
|
+
*
|
|
1349
|
+
* So the step is resolved before the agent ever sees it. The server calls the
|
|
1350
|
+
* display tool, finds its view, and hands the page everything it needs to mount
|
|
1351
|
+
* the widget itself. The agent gets prose that never names a display tool. The
|
|
1352
|
+
* visitor gets the calendar on the page they are already looking at.
|
|
1353
|
+
*/
|
|
1354
|
+
|
|
1355
|
+
type WidgetStep = {
|
|
1356
|
+
/**
|
|
1357
|
+
* The flow's own response, carried whole.
|
|
1358
|
+
*
|
|
1359
|
+
* Typed as the engine's own `FlowWidgetContent` rather than a local shape, so
|
|
1360
|
+
* a field added to a widget step reaches this file as a type change instead
|
|
1361
|
+
* of being silently dropped. That has already happened once: `intro` was
|
|
1362
|
+
* added to the payload and the surface that hand-rolled this parse kept
|
|
1363
|
+
* working only because it spread the rest through.
|
|
1364
|
+
*/
|
|
1365
|
+
payload: FlowWidgetContent;
|
|
1366
|
+
tool: string;
|
|
1367
|
+
data: Record<string, unknown>;
|
|
1368
|
+
interactive: boolean;
|
|
1369
|
+
};
|
|
1370
|
+
/**
|
|
1371
|
+
* A flow's widget step, or `null` for every other tool result.
|
|
1372
|
+
*
|
|
1373
|
+
* Flow tools answer with a single JSON text block, so anything that does not
|
|
1374
|
+
* parse as JSON with `status: "widget"` and a `tool` to call belongs to someone
|
|
1375
|
+
* else and passes through untouched. That includes ordinary tools, which is
|
|
1376
|
+
* most of them.
|
|
1377
|
+
*/
|
|
1378
|
+
declare function readWidgetStep(result: WebMcpCallResult): WidgetStep | null;
|
|
1379
|
+
/** The status a rewritten widget step reports in place of `"widget"`. */
|
|
1380
|
+
type WidgetStepStatus = "widget_shown" | "widget_unavailable";
|
|
1381
|
+
/**
|
|
1382
|
+
* The step as the agent should read it.
|
|
1383
|
+
*
|
|
1384
|
+
* Built by editing the flow's own payload rather than composing a new object,
|
|
1385
|
+
* so the fields the protocol requires the agent to echo back survive. Dropping
|
|
1386
|
+
* `sessionId` here breaks the flow several turns later, which is the worst kind
|
|
1387
|
+
* of bug to go looking for.
|
|
1388
|
+
*
|
|
1389
|
+
* `tool` and `description` are the two that must not survive. Both name a
|
|
1390
|
+
* display tool the agent cannot call, and leaving either in place is an
|
|
1391
|
+
* instruction to attempt it.
|
|
1392
|
+
*/
|
|
1393
|
+
declare function rewriteForAgent(step: WidgetStep, rendered: boolean): Record<string, unknown> & {
|
|
1394
|
+
status: WidgetStepStatus;
|
|
1395
|
+
};
|
|
1396
|
+
|
|
920
1397
|
/**
|
|
921
1398
|
* A LangGraph-inspired state graph builder for MCP tools.
|
|
922
1399
|
*
|
|
@@ -1142,6 +1619,8 @@ interface WaniWaniClient extends TrackingClient {
|
|
|
1142
1619
|
readonly _config: InternalConfig;
|
|
1143
1620
|
/** Knowledge base client for ingestion, search, and source listing */
|
|
1144
1621
|
readonly kb: KbClient;
|
|
1622
|
+
/** Documents client for reading a file into typed fields */
|
|
1623
|
+
readonly documents: DocumentsClient;
|
|
1145
1624
|
}
|
|
1146
1625
|
interface InternalConfig {
|
|
1147
1626
|
apiUrl: string;
|
|
@@ -1240,4 +1719,4 @@ type WithWaniwaniOptions = {
|
|
|
1240
1719
|
*/
|
|
1241
1720
|
declare function withWaniwani(server: McpServer, options?: WithWaniwaniOptions): Promise<McpServer>;
|
|
1242
1721
|
|
|
1243
|
-
export { type AddNodeConfig, type ConditionFn, END, type FlowConfig, type FlowTestResult, type InferFlowState, type InterruptSignal, type KvStore, type KvStoreSetOptions, MemoryKvStore, type NodeContext, type NodeHandler, type RegisteredFlow, type RegisteredTool, SCOPED_CLIENT_KEY, START, type ScopedWaniWaniClient, StateGraph, type TrackingRouteOptions, type TypedInterrupt, type TypedShowWidget, WaniwaniKvStore, type WidgetSignal, type WithWaniwaniOptions, createFlow, createFlowTestHarness, createTrackingRoute, extractScopedClient, redacted, withWaniwani };
|
|
1722
|
+
export { type AddNodeConfig, type AttachedDocument, type AttachedFile, type ConditionFn, END, type FlowConfig, type FlowIntro, type FlowIntroPayload, type FlowTestResult, type InferFlowState, type InterruptSignal, type KvStore, type KvStoreSetOptions, MemoryKvStore, type MetaCarrier, type NodeContext, type NodeHandler, type RegisteredFlow, type RegisteredTool, SCOPED_CLIENT_KEY, START, type ScopedWaniWaniClient, StateGraph, type TrackingRouteOptions, type TypedInterrupt, type TypedShowWidget, WaniwaniKvStore, type WebMcpBridge, type WebMcpBridgeOptions, type WebMcpCallResponse, type WebMcpCallResult, type WebMcpContentBlock, type WebMcpListResponse, type WebMcpPageContext, type WebMcpRequest, type WebMcpTool, type WebMcpWidgetPayload, type WidgetSignal, type WidgetStep, type WidgetStepStatus, type WithWaniwaniOptions, autoHeightFromMeta, createFlow, createFlowTestHarness, createTrackingRoute, createWebMcpBridge, extractScopedClient, isDisplayTool, readWidgetStep, redacted, resourceUriFromMeta, rewriteForAgent, supportsWebMcp, viewUriFor, withWaniwani };
|