@guideai/react-native 0.0.0-stage → 0.1.0
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 +94 -2
- package/dist/index.cjs +86 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1043 -0
- package/dist/index.mjs +87 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ui.cjs +1525 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.d.ts +212 -0
- package/dist/ui.mjs +1525 -0
- package/dist/ui.mjs.map +1 -0
- package/dist/useOnboarding-C7eFhp2o.cjs +3498 -0
- package/dist/useOnboarding-C7eFhp2o.cjs.map +1 -0
- package/dist/useOnboarding-DhVtf0U2.js +3499 -0
- package/dist/useOnboarding-DhVtf0U2.js.map +1 -0
- package/package.json +60 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1043 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface ToolCallResponse {
|
|
4
|
+
tool: string;
|
|
5
|
+
method: string;
|
|
6
|
+
path: string;
|
|
7
|
+
params?: Record<string, unknown>;
|
|
8
|
+
body?: Record<string, unknown>;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
requires_confirm: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Human-readable phrase for the UI ("Retrieving site information"), supplied
|
|
13
|
+
* by the model. `describeToolCall()` derives one when it is missing — the
|
|
14
|
+
* chat UI never shows the raw tool/endpoint name.
|
|
15
|
+
*/
|
|
16
|
+
label?: string | null;
|
|
17
|
+
}
|
|
18
|
+
interface NavigationAction {
|
|
19
|
+
url: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
}
|
|
22
|
+
interface ToolExecutionResult {
|
|
23
|
+
success: boolean;
|
|
24
|
+
data?: unknown;
|
|
25
|
+
error?: string;
|
|
26
|
+
error_type?: string;
|
|
27
|
+
status?: number;
|
|
28
|
+
}
|
|
29
|
+
interface CopilotToolDef {
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
method: string;
|
|
33
|
+
path: string;
|
|
34
|
+
params?: {
|
|
35
|
+
name: string;
|
|
36
|
+
in: string;
|
|
37
|
+
type: string;
|
|
38
|
+
required: boolean;
|
|
39
|
+
description?: string;
|
|
40
|
+
}[];
|
|
41
|
+
body_schema?: Record<string, unknown>;
|
|
42
|
+
risk_level: 'read' | 'write' | 'destructive';
|
|
43
|
+
}
|
|
44
|
+
/** A host/browser tool advertised to the planner but executed only by the SDK. */
|
|
45
|
+
interface ClientToolDefinition {
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
parameters: Record<string, unknown>;
|
|
49
|
+
consequential?: boolean;
|
|
50
|
+
}
|
|
51
|
+
interface CopilotConfig {
|
|
52
|
+
siteId: string;
|
|
53
|
+
/** Runtime label from the SDK script; this is the assistant's visible name. */
|
|
54
|
+
assistantLabel?: string;
|
|
55
|
+
/** Host-owned rule describing which requests another assistant should handle. */
|
|
56
|
+
delegationInstruction?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The analytics session this chat belongs to. Sent with each question so a
|
|
59
|
+
* repeated "how do I …" can be correlated with whether the user then got
|
|
60
|
+
* there — the question alone says something is hard, the pairing says
|
|
61
|
+
* whether anything fixed it. Carries no message content.
|
|
62
|
+
*/
|
|
63
|
+
analyticsSessionId?: string;
|
|
64
|
+
/**
|
|
65
|
+
* The product-analytics bundle's own ids, read at send time because that
|
|
66
|
+
* bundle can load after the chat and rotates its session when idle. Its
|
|
67
|
+
* session is the one the visitor's events are recorded under, so it wins
|
|
68
|
+
* over analyticsSessionId when present. Ids only, never content.
|
|
69
|
+
*/
|
|
70
|
+
analyticsIds?: () => {
|
|
71
|
+
session_id?: string;
|
|
72
|
+
distinct_id?: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* What this runtime can render beyond plain answers and walkthroughs. The
|
|
76
|
+
* server only sends a richer reply (a coach run for "coach") to a client
|
|
77
|
+
* that lists it, so a runtime that cannot play one keeps getting what it can.
|
|
78
|
+
*/
|
|
79
|
+
clientCapabilities?: string[];
|
|
80
|
+
memoryTtlMs?: number;
|
|
81
|
+
maxMemoryMessages?: number;
|
|
82
|
+
}
|
|
83
|
+
/** A published interactive demo the assistant suggests playing inline (Storylane-style). */
|
|
84
|
+
interface DemoSuggestion {
|
|
85
|
+
share_token: string;
|
|
86
|
+
title: string;
|
|
87
|
+
description?: string | null;
|
|
88
|
+
/** Player URL with embed=1&autostart=1 — for in-chat iframe playback. */
|
|
89
|
+
embed_url: string;
|
|
90
|
+
/** Plain player URL — for "open in new tab". */
|
|
91
|
+
share_url: string;
|
|
92
|
+
thumbnail_url?: string | null;
|
|
93
|
+
step_count?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* One element on the visitor's page the reply rings, with a caption. Only
|
|
97
|
+
* from a turn whose skill grants `can_point`; the server checked the page
|
|
98
|
+
* snapshot listed it.
|
|
99
|
+
*/
|
|
100
|
+
interface PagePoint {
|
|
101
|
+
selector: string;
|
|
102
|
+
text?: string;
|
|
103
|
+
caption: string;
|
|
104
|
+
}
|
|
105
|
+
/** A button to a page the site has. Only from a skill with `cta_buttons`. */
|
|
106
|
+
interface ChatAction {
|
|
107
|
+
label: string;
|
|
108
|
+
url: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* A checkout offer from the site's payment connector (agent flow). Name, price
|
|
112
|
+
* and currency come from the site's settings, never from the model; the
|
|
113
|
+
* checkout itself is created only when the visitor presses Pay.
|
|
114
|
+
*/
|
|
115
|
+
interface ChatPayment {
|
|
116
|
+
item_id: string;
|
|
117
|
+
name: string;
|
|
118
|
+
/** Smallest currency unit (cents, kobo). */
|
|
119
|
+
amount_minor: number;
|
|
120
|
+
currency: string;
|
|
121
|
+
provider: 'stripe' | 'paystack' | 'flutterwave' | string;
|
|
122
|
+
}
|
|
123
|
+
/** One stop on a coach run: reach a screen ("go"), or work through it ("do"). */
|
|
124
|
+
interface CoachMilestone {
|
|
125
|
+
title: string;
|
|
126
|
+
/**
|
|
127
|
+
* A route from the site's scanned map: the screen this stop happens on.
|
|
128
|
+
* Plans from servers before Oct 2026 may leave it null.
|
|
129
|
+
*/
|
|
130
|
+
route: string | null;
|
|
131
|
+
/** The page's name in the scan ("Onboarding"): what a link to it says. */
|
|
132
|
+
page?: string | null;
|
|
133
|
+
kind: 'go' | 'do';
|
|
134
|
+
/** The task can succeed without it; the visitor may skip it. */
|
|
135
|
+
optional?: boolean;
|
|
136
|
+
/** The link the site's skill and KB agree leads to this stop's page. */
|
|
137
|
+
way?: CoachTarget | null;
|
|
138
|
+
/** This stop's controls in the skill's order, each found in the KB. */
|
|
139
|
+
targets?: CoachTarget[];
|
|
140
|
+
/** Inputs the task cannot finish without (labels), held before Done. */
|
|
141
|
+
needs?: string[];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* One step of a site skill's flow, checked against the scanned app: the
|
|
145
|
+
* skill says it is needed, the KB says where it is.
|
|
146
|
+
*/
|
|
147
|
+
interface CoachTarget {
|
|
148
|
+
label: string;
|
|
149
|
+
kind: 'link' | 'control' | 'field' | 'toggle' | 'section';
|
|
150
|
+
route: string;
|
|
151
|
+
/** What the visitor does with it. */
|
|
152
|
+
action: 'go' | 'open' | 'fill' | 'choose' | 'switch';
|
|
153
|
+
/** The section or menu it sits in. */
|
|
154
|
+
under?: string;
|
|
155
|
+
/** The folded group to open first when it is hidden. */
|
|
156
|
+
reveal?: string;
|
|
157
|
+
/** For a link: the page it opens. */
|
|
158
|
+
opens?: string;
|
|
159
|
+
required?: boolean;
|
|
160
|
+
/** The scanned fingerprint, when the KB has one. */
|
|
161
|
+
fingerprint?: Record<string, unknown>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A coach run: "how do I…" answered by taking the visitor to the screen and
|
|
165
|
+
* talking them through it, rather than only pointing.
|
|
166
|
+
*/
|
|
167
|
+
interface CoachPlan {
|
|
168
|
+
goal: string;
|
|
169
|
+
intro: string;
|
|
170
|
+
/** Asked first when the task has more than one path; options are chips. */
|
|
171
|
+
question: {
|
|
172
|
+
text: string;
|
|
173
|
+
options: string[];
|
|
174
|
+
} | null;
|
|
175
|
+
milestones: CoachMilestone[];
|
|
176
|
+
/** The page the task itself is done on — the run is never coached elsewhere. */
|
|
177
|
+
task_route?: string | null;
|
|
178
|
+
/**
|
|
179
|
+
* "site", "workspace"…: the plan wanted the visitor to switch it. They are
|
|
180
|
+
* asked once to check they are in the right one instead of switching.
|
|
181
|
+
*/
|
|
182
|
+
confirm_context?: string | null;
|
|
183
|
+
/**
|
|
184
|
+
* Set when this plan is new: sent back to /chat/coach/confirm once the run
|
|
185
|
+
* finishes on the task's page, and only then shared with the next visitor.
|
|
186
|
+
*/
|
|
187
|
+
proof_key?: string | null;
|
|
188
|
+
done_when: {
|
|
189
|
+
route: string | null;
|
|
190
|
+
text: string | null;
|
|
191
|
+
};
|
|
192
|
+
settings?: {
|
|
193
|
+
voice: 'off' | 'browser' | 'neural';
|
|
194
|
+
explain_options: boolean;
|
|
195
|
+
offer_help: boolean;
|
|
196
|
+
vision_per_run: number;
|
|
197
|
+
};
|
|
198
|
+
cached?: boolean;
|
|
199
|
+
}
|
|
200
|
+
/** Escalation signal from the AI assistant. */
|
|
201
|
+
interface EscalationSignal {
|
|
202
|
+
offered: boolean;
|
|
203
|
+
reason?: 'low_confidence' | 'cannot_resolve' | 'user_requested';
|
|
204
|
+
confidence?: number;
|
|
205
|
+
}
|
|
206
|
+
/** Callback for reporting agent loop progress to the UI. */
|
|
207
|
+
type AgentStatusCallback = (status: string) => void;
|
|
208
|
+
/** One step of the plan the assistant stated before it started working. */
|
|
209
|
+
interface AssistantPlanStep {
|
|
210
|
+
title: string;
|
|
211
|
+
/** Endpoint this step uses; absent when the assistant does it itself. */
|
|
212
|
+
tool?: string | null;
|
|
213
|
+
/** Set when nothing available can do this step. */
|
|
214
|
+
blocked_reason?: string | null;
|
|
215
|
+
}
|
|
216
|
+
interface AssistantPlan {
|
|
217
|
+
steps: AssistantPlanStep[];
|
|
218
|
+
note?: string | null;
|
|
219
|
+
}
|
|
220
|
+
type PlanCallback = (plan: AssistantPlan) => void;
|
|
221
|
+
interface HarnessResponse {
|
|
222
|
+
mode: 'answer' | 'guide' | 'execute' | 'coach';
|
|
223
|
+
answer: string;
|
|
224
|
+
/** What the assistant said it would do, shown while it works. */
|
|
225
|
+
plan?: AssistantPlan;
|
|
226
|
+
intent?: 'delegate';
|
|
227
|
+
intentReason?: string;
|
|
228
|
+
guideSteps?: Record<string, unknown>[];
|
|
229
|
+
guideTitle?: string;
|
|
230
|
+
navigation?: NavigationAction;
|
|
231
|
+
toolResult?: ToolExecutionResult;
|
|
232
|
+
confirmationNeeded?: boolean;
|
|
233
|
+
pendingToolCall?: ToolCallResponse;
|
|
234
|
+
/** Full concurrent batch when the model requested more than one tool. */
|
|
235
|
+
pendingToolCalls?: ToolCallResponse[];
|
|
236
|
+
/** When true, the ChatManager should auto-execute the pendingToolCall (read-only action). */
|
|
237
|
+
autoExecuteToolCall?: boolean;
|
|
238
|
+
autoExecute: boolean;
|
|
239
|
+
/** Escalation signal from the AI. */
|
|
240
|
+
escalation?: EscalationSignal;
|
|
241
|
+
/** Interactive demo suggestion the chat UI can play inline. */
|
|
242
|
+
demo?: DemoSuggestion;
|
|
243
|
+
point?: PagePoint;
|
|
244
|
+
actions?: ChatAction[];
|
|
245
|
+
payment?: ChatPayment;
|
|
246
|
+
coach?: CoachPlan;
|
|
247
|
+
/** One-tap replies; a tap sends the label as the next message. */
|
|
248
|
+
quickReplies?: string[];
|
|
249
|
+
}
|
|
250
|
+
interface ConversationMessage {
|
|
251
|
+
id?: string;
|
|
252
|
+
role: 'user' | 'assistant';
|
|
253
|
+
content: string;
|
|
254
|
+
toolResult?: ToolExecutionResult;
|
|
255
|
+
toolCalls?: ToolCallRecord[];
|
|
256
|
+
timestamp: number;
|
|
257
|
+
/** Guide steps generated by the assistant (for walkthrough buttons). */
|
|
258
|
+
guideSteps?: Record<string, unknown>[];
|
|
259
|
+
/** Title for the guide walkthrough. */
|
|
260
|
+
guideTitle?: string;
|
|
261
|
+
/** Navigation action returned by the assistant. */
|
|
262
|
+
navigation?: NavigationAction;
|
|
263
|
+
/** Response mode (answer, guide, execute). */
|
|
264
|
+
mode?: 'answer' | 'guide' | 'execute' | 'coach';
|
|
265
|
+
/** Whether this message has a pending tool call needing confirmation. */
|
|
266
|
+
confirmationNeeded?: boolean;
|
|
267
|
+
/** The pending tool call awaiting user confirmation. */
|
|
268
|
+
pendingToolCall?: ToolCallResponse;
|
|
269
|
+
/** Escalation signal from the AI. */
|
|
270
|
+
escalation?: EscalationSignal;
|
|
271
|
+
/** Interactive demo suggestion attached to this assistant message. */
|
|
272
|
+
demo?: DemoSuggestion;
|
|
273
|
+
}
|
|
274
|
+
/** Record of a tool call for conversation history context. */
|
|
275
|
+
interface ToolCallRecord {
|
|
276
|
+
tool: string;
|
|
277
|
+
description?: string;
|
|
278
|
+
success: boolean;
|
|
279
|
+
summary?: string;
|
|
280
|
+
/** Present when the record came from a client-executed call rather than SSE. */
|
|
281
|
+
method?: string;
|
|
282
|
+
path?: string;
|
|
283
|
+
}
|
|
284
|
+
/** Callback for streaming text deltas to the UI. */
|
|
285
|
+
type TextDeltaCallback = (delta: string) => void;
|
|
286
|
+
/** Callback for tool call lifecycle events. */
|
|
287
|
+
type ToolCallEventCallback = (event: ToolCallDisplayEvent) => void;
|
|
288
|
+
/** Event describing tool call progress for UI display. */
|
|
289
|
+
interface ToolCallDisplayEvent {
|
|
290
|
+
type: 'start' | 'done';
|
|
291
|
+
tool: string;
|
|
292
|
+
description?: string;
|
|
293
|
+
success?: boolean;
|
|
294
|
+
summary?: string;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Shared onboarding contract. UI targets are interpreted by each platform. */
|
|
298
|
+
/** One highlighted action "Show me" plays, in order, on the step's page. */
|
|
299
|
+
interface OnboardingAction {
|
|
300
|
+
id: string;
|
|
301
|
+
title: string;
|
|
302
|
+
instruction: string;
|
|
303
|
+
action: 'click' | 'fill' | 'select' | 'check';
|
|
304
|
+
/** Words on the control; the page is searched for them when no fingerprint matches. */
|
|
305
|
+
target_label: string;
|
|
306
|
+
target_fingerprint: Record<string, unknown>;
|
|
307
|
+
kind: string;
|
|
308
|
+
context: string;
|
|
309
|
+
}
|
|
310
|
+
interface OnboardingStepState {
|
|
311
|
+
id: string;
|
|
312
|
+
title: string;
|
|
313
|
+
instruction: string;
|
|
314
|
+
required: boolean;
|
|
315
|
+
state: 'complete' | 'skipped' | 'available' | 'locked';
|
|
316
|
+
/** Complete on the person's own tick (a manual step), not on evidence. */
|
|
317
|
+
self_reported?: boolean;
|
|
318
|
+
location: {
|
|
319
|
+
surface: 'web' | 'mobile' | 'desktop' | 'other';
|
|
320
|
+
screen: string;
|
|
321
|
+
target_label: string;
|
|
322
|
+
target_fingerprint: Record<string, unknown>;
|
|
323
|
+
/** A help hint on `screen` that "Show me" plays instead of highlighting a control. */
|
|
324
|
+
hint_id?: string | null;
|
|
325
|
+
};
|
|
326
|
+
completion: {
|
|
327
|
+
type: 'event' | 'screen' | 'text_visible' | 'manual';
|
|
328
|
+
value: string;
|
|
329
|
+
};
|
|
330
|
+
actions?: OnboardingAction[];
|
|
331
|
+
}
|
|
332
|
+
/** The button that opens the checklist; every field falls back to the card-matching default. */
|
|
333
|
+
interface OnboardingLauncher {
|
|
334
|
+
label?: string;
|
|
335
|
+
invite_label?: string;
|
|
336
|
+
complete_label?: string;
|
|
337
|
+
show_progress?: boolean;
|
|
338
|
+
shape?: 'rounded' | 'pill';
|
|
339
|
+
background_color?: string | null;
|
|
340
|
+
text_color?: string | null;
|
|
341
|
+
}
|
|
342
|
+
interface OnboardingAppearance {
|
|
343
|
+
template: 'classic' | 'minimal' | 'bold';
|
|
344
|
+
accent_color: string;
|
|
345
|
+
/** Missing means the default card; position missing means left. */
|
|
346
|
+
layout?: 'card' | 'modal' | 'side';
|
|
347
|
+
position?: 'left' | 'right';
|
|
348
|
+
launcher?: OnboardingLauncher;
|
|
349
|
+
}
|
|
350
|
+
interface OnboardingState {
|
|
351
|
+
id: string;
|
|
352
|
+
title: string;
|
|
353
|
+
goal: string;
|
|
354
|
+
start_mode: 'automatic' | 'ask' | 'checklist';
|
|
355
|
+
chat_policy: 'unrestricted' | 'setup_only';
|
|
356
|
+
allow_dismissal: boolean;
|
|
357
|
+
appearance?: OnboardingAppearance;
|
|
358
|
+
completed: boolean;
|
|
359
|
+
dismissed: boolean;
|
|
360
|
+
completed_required: number;
|
|
361
|
+
total_required: number;
|
|
362
|
+
/** Every step, optional ones included; a skipped optional step counts as done. Missing from older servers. */
|
|
363
|
+
completed_steps?: number;
|
|
364
|
+
total_steps?: number;
|
|
365
|
+
steps: OnboardingStepState[];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** A picture drawn for an answer: a PNG to show, and the SVG it was drawn as. */
|
|
369
|
+
interface HeadlessImage {
|
|
370
|
+
url: string;
|
|
371
|
+
svg: string | null;
|
|
372
|
+
alt: string;
|
|
373
|
+
width: number;
|
|
374
|
+
height: number;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
interface PageElement {
|
|
378
|
+
tag: string;
|
|
379
|
+
text: string;
|
|
380
|
+
selector: string;
|
|
381
|
+
aria_label?: string;
|
|
382
|
+
name?: string;
|
|
383
|
+
role?: string;
|
|
384
|
+
type?: string;
|
|
385
|
+
placeholder?: string;
|
|
386
|
+
/** href attribute for anchor elements */
|
|
387
|
+
href?: string;
|
|
388
|
+
/** Current value of input/textarea/select elements */
|
|
389
|
+
value?: string;
|
|
390
|
+
/** Associated label text (from <label> or aria-labelledby) */
|
|
391
|
+
label?: string;
|
|
392
|
+
/** More descriptive form label when available. */
|
|
393
|
+
form_label?: string;
|
|
394
|
+
/** True when element exists in DOM but is not currently visible */
|
|
395
|
+
hidden?: boolean;
|
|
396
|
+
/** Describes the container: "hamburger menu", "dropdown", "sidebar", etc. */
|
|
397
|
+
container?: string;
|
|
398
|
+
/** State of the container: "collapsed", "closed", etc. */
|
|
399
|
+
containerState?: string;
|
|
400
|
+
/** Nearby descriptive text from the element's parent container. */
|
|
401
|
+
parent_text?: string;
|
|
402
|
+
/** Title of the nearest visible section heading. */
|
|
403
|
+
section_title?: string;
|
|
404
|
+
/** Source URL when the element is inside an iframe */
|
|
405
|
+
iframe_src?: string;
|
|
406
|
+
}
|
|
407
|
+
interface PageSectionLink {
|
|
408
|
+
text: string;
|
|
409
|
+
href: string;
|
|
410
|
+
selector: string;
|
|
411
|
+
}
|
|
412
|
+
interface PageSection {
|
|
413
|
+
title: string;
|
|
414
|
+
selector: string;
|
|
415
|
+
text?: string;
|
|
416
|
+
links: PageSectionLink[];
|
|
417
|
+
elements: PageElement[];
|
|
418
|
+
}
|
|
419
|
+
interface PageSnapshot {
|
|
420
|
+
url: string;
|
|
421
|
+
title: string;
|
|
422
|
+
page_text?: string;
|
|
423
|
+
sections?: PageSection[];
|
|
424
|
+
elements: PageElement[];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
interface ClientToolRegistry {
|
|
428
|
+
/** Tools this host can run, in the shape the backend expects. */
|
|
429
|
+
definitions(): ClientToolDefinition[];
|
|
430
|
+
/** The same tools shaped for the copilot planner and the validator. */
|
|
431
|
+
copilotDefinitions(): CopilotToolDef[];
|
|
432
|
+
/** Whether a tool name belongs to this registry. */
|
|
433
|
+
canExecute(name: string): boolean;
|
|
434
|
+
/** Whether a specific planned call is one this registry should run. */
|
|
435
|
+
canExecuteCall(toolCall: ToolCallResponse): boolean;
|
|
436
|
+
/** Run one call. Never throws — failures come back as a result. */
|
|
437
|
+
execute(toolCall: ToolCallResponse): Promise<ToolExecutionResult>;
|
|
438
|
+
/**
|
|
439
|
+
* Run several calls, reporting each as it lands.
|
|
440
|
+
*
|
|
441
|
+
* `onComplete` fires per call so a slow one cannot hold back the others'
|
|
442
|
+
* progress in the UI.
|
|
443
|
+
*/
|
|
444
|
+
executeBatch(toolCalls: ToolCallResponse[], onComplete?: (toolCall: ToolCallResponse, result: ToolExecutionResult) => void): Promise<ToolExecutionResult[]>;
|
|
445
|
+
/**
|
|
446
|
+
* Release anything the registry is holding (timers, highlights).
|
|
447
|
+
*
|
|
448
|
+
* Optional: the harness has no teardown path today, so requiring it
|
|
449
|
+
* would force every registry to implement code nothing calls.
|
|
450
|
+
*/
|
|
451
|
+
destroy?(): void;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* A synchronous key/value store.
|
|
456
|
+
*
|
|
457
|
+
* Synchronous on purpose: the conversation memory reads storage inside
|
|
458
|
+
* `getMessages()`, which the agent loop calls from ~20 sync places.
|
|
459
|
+
* Making reads async would push `await` through the whole loop and change
|
|
460
|
+
* its public signatures for no functional gain.
|
|
461
|
+
*
|
|
462
|
+
* Web: `localStorage` already *is* this shape.
|
|
463
|
+
* React Native: MMKV or `expo-sqlite/kv-store` (both sync). A host whose
|
|
464
|
+
* only store is AsyncStorage must hydrate a snapshot at boot and write
|
|
465
|
+
* through — the honest cost of not rewriting the loop.
|
|
466
|
+
*/
|
|
467
|
+
interface KVStore {
|
|
468
|
+
getItem(key: string): string | null;
|
|
469
|
+
setItem(key: string, value: string): void;
|
|
470
|
+
removeItem(key: string): void;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Where a host keeps credentials the copilot may read, named by the
|
|
474
|
+
* source a site configured (`localStorage`, `sessionStorage`, `cookie`).
|
|
475
|
+
*
|
|
476
|
+
* Returns null for a source this platform does not have. A mobile app has
|
|
477
|
+
* no cookie jar, and saying so plainly is better than returning an empty
|
|
478
|
+
* string that reads as "present but blank".
|
|
479
|
+
*/
|
|
480
|
+
interface CredentialSource {
|
|
481
|
+
read(source: string, key: string): string | null;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Decoded text chunks arriving as the response streams.
|
|
486
|
+
*
|
|
487
|
+
* Text, not bytes, on purpose. Decoding UTF-8 incrementally is the one
|
|
488
|
+
* part of stream handling that is easy to get subtly wrong: a multi-byte
|
|
489
|
+
* character split across a chunk boundary is corrupted unless the decoder
|
|
490
|
+
* carries state between chunks. Browsers have a spec-correct
|
|
491
|
+
* `TextDecoder`; React Native's polyfills vary, and one that ignores
|
|
492
|
+
* incremental mode mangles non-ASCII text silently, at runtime, past
|
|
493
|
+
* every typecheck and test.
|
|
494
|
+
*
|
|
495
|
+
* So each platform decodes where it knows the answer, and core consumes
|
|
496
|
+
* strings. **Implementations MUST handle characters split across chunk
|
|
497
|
+
* boundaries** — that is a contract, not a hint.
|
|
498
|
+
*/
|
|
499
|
+
type TextStream = AsyncIterable<string>;
|
|
500
|
+
/** A request, already serialized. */
|
|
501
|
+
interface HttpRequest {
|
|
502
|
+
url: string;
|
|
503
|
+
/**
|
|
504
|
+
* Customer toolsets declare their own verbs — a `destructive` tool is
|
|
505
|
+
* typically a DELETE — so this cannot be narrowed to GET/POST without
|
|
506
|
+
* silently rewriting those calls.
|
|
507
|
+
*/
|
|
508
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD';
|
|
509
|
+
headers: Record<string, string>;
|
|
510
|
+
/** Pre-serialized body. Multipart stays platform-side; see HttpTransport. */
|
|
511
|
+
body?: string;
|
|
512
|
+
signal?: AbortSignal;
|
|
513
|
+
/**
|
|
514
|
+
* Best-effort delivery while the app is tearing down. Platforms without
|
|
515
|
+
* an equivalent ignore it — the semantics are already "may be dropped".
|
|
516
|
+
*/
|
|
517
|
+
keepalive?: boolean;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* What the agent loop actually reads off a response.
|
|
521
|
+
*
|
|
522
|
+
* Deliberately narrower than `Response`. `ok` is absent because nothing
|
|
523
|
+
* reads it and its presence invites `if (!res.ok)` to drift between
|
|
524
|
+
* platforms; `blob`/`arrayBuffer`/`redirected` are absent because they
|
|
525
|
+
* have no callers.
|
|
526
|
+
*/
|
|
527
|
+
interface HttpResponse {
|
|
528
|
+
readonly status: number;
|
|
529
|
+
/**
|
|
530
|
+
* Header lookup. Shaped as `{ get() }` rather than a flat record to
|
|
531
|
+
* match `Headers`, so a browser transport can forward it directly.
|
|
532
|
+
*/
|
|
533
|
+
readonly headers: {
|
|
534
|
+
get(name: string): string | null;
|
|
535
|
+
};
|
|
536
|
+
json<T = unknown>(): Promise<T>;
|
|
537
|
+
text(): Promise<string>;
|
|
538
|
+
/**
|
|
539
|
+
* Present only when this response carries a readable stream. Absent is
|
|
540
|
+
* normal and handled: the caller falls back to `json()`.
|
|
541
|
+
*/
|
|
542
|
+
stream?: TextStream;
|
|
543
|
+
}
|
|
544
|
+
interface HttpTransport {
|
|
545
|
+
request(req: HttpRequest): Promise<HttpResponse>;
|
|
546
|
+
/**
|
|
547
|
+
* Whether this platform can deliver progressive bytes at all.
|
|
548
|
+
*
|
|
549
|
+
* Read by the agent loop to decide what to *ask the backend for*. It is
|
|
550
|
+
* a property of the transport rather than a setting, so a host cannot
|
|
551
|
+
* request streaming its platform physically cannot read — that would
|
|
552
|
+
* produce an empty answer with no error.
|
|
553
|
+
*
|
|
554
|
+
* Note both browsers and React Native can stream (fetch bodies and
|
|
555
|
+
* progressive XHR respectively), so this is true on both. It exists for
|
|
556
|
+
* the runtime that genuinely cannot.
|
|
557
|
+
*/
|
|
558
|
+
readonly supportsStreaming: boolean;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
interface CopilotApi {
|
|
562
|
+
/** JSON GET with the platform's default time budget. */
|
|
563
|
+
get<T>(path: string, timeoutMs?: number): Promise<T>;
|
|
564
|
+
/** JSON POST. Encrypts the body when the client has crypto configured. */
|
|
565
|
+
post<T>(path: string, body?: unknown, timeoutMs?: number): Promise<T>;
|
|
566
|
+
/**
|
|
567
|
+
* POST returning the response unparsed, so the caller can stream it or
|
|
568
|
+
* branch on content-type. Not time-budgeted: a stream is long-lived by
|
|
569
|
+
* design and the caller owns cancellation through `signal`.
|
|
570
|
+
*/
|
|
571
|
+
postRaw(path: string, body?: unknown, signal?: AbortSignal): Promise<HttpResponse>;
|
|
572
|
+
/** Whether this platform can read a response progressively. */
|
|
573
|
+
readonly supportsStreaming: boolean;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Copilot Agent Harness — client-side orchestrator.
|
|
578
|
+
*
|
|
579
|
+
* Architecture:
|
|
580
|
+
* - Backend plans the next step and formats final answers
|
|
581
|
+
* - Backend streams progress via SSE events during the loop
|
|
582
|
+
* - SDK can execute safe read tools in the browser and continue the chain
|
|
583
|
+
* - SDK reads the stream, shows status updates, and displays the final answer
|
|
584
|
+
* - For confirmed tool calls, SDK executes the customer API request in the browser
|
|
585
|
+
*
|
|
586
|
+
* Memory persists through an injected KVStore with TTL (localStorage on
|
|
587
|
+
* the web, MMKV on mobile). Multi-tenant safe via site_id scoping.
|
|
588
|
+
*/
|
|
589
|
+
|
|
590
|
+
declare class CopilotHarness {
|
|
591
|
+
private api;
|
|
592
|
+
private config;
|
|
593
|
+
private memory;
|
|
594
|
+
private validator;
|
|
595
|
+
private toolExecutor;
|
|
596
|
+
private tools;
|
|
597
|
+
private readonly credentials;
|
|
598
|
+
private readonly transport;
|
|
599
|
+
private activeTools;
|
|
600
|
+
private initialized;
|
|
601
|
+
/** Told about the assistant's plan as soon as the server states one. */
|
|
602
|
+
private onPlan?;
|
|
603
|
+
private lastPlanFingerprint;
|
|
604
|
+
/** The plan in force for the message being answered. */
|
|
605
|
+
private currentPlan?;
|
|
606
|
+
/** Tool inputs the host page supplies — whatever the user has open. */
|
|
607
|
+
private toolContext?;
|
|
608
|
+
/**
|
|
609
|
+
* @param tools How this platform actually touches the screen. Defaults to
|
|
610
|
+
* the browser registry so every existing caller is unaffected; a mobile
|
|
611
|
+
* runtime passes one that dispatches native effects instead. The loop
|
|
612
|
+
* below never learns which it is holding.
|
|
613
|
+
*/
|
|
614
|
+
constructor(api: CopilotApi, config: CopilotConfig, tools: ClientToolRegistry, storage: KVStore, transport: HttpTransport, credentials: CredentialSource);
|
|
615
|
+
/** Hear every turn the conversation records (typed, spoken, replies). */
|
|
616
|
+
onMessageRecorded(listener: ((message: ConversationMessage) => void) | null): void;
|
|
617
|
+
/** Initialize the harness — fetch active tools for the site. */
|
|
618
|
+
initialize(): Promise<boolean>;
|
|
619
|
+
/**
|
|
620
|
+
* Register the listener that renders the assistant's plan.
|
|
621
|
+
*
|
|
622
|
+
* Set on the harness rather than passed per message: `processMessage` is
|
|
623
|
+
* already called positionally from several places, and a plan belongs to
|
|
624
|
+
* the UI for the whole session, not to one call.
|
|
625
|
+
*/
|
|
626
|
+
setPlanCallback(callback: PlanCallback | undefined): void;
|
|
627
|
+
/**
|
|
628
|
+
* Values the host page supplies for tool inputs.
|
|
629
|
+
*
|
|
630
|
+
* Sent with every turn, including chain rounds — a later round builds calls
|
|
631
|
+
* too, and dropping it there is how a chain that started on the right
|
|
632
|
+
* record finishes on the default one.
|
|
633
|
+
*/
|
|
634
|
+
/** Bind to the SDK's analytics session. Carries no message content. */
|
|
635
|
+
setAnalyticsSessionId(sessionId: string): void;
|
|
636
|
+
/** Read the analytics bundle's ids on every question. Ids only. */
|
|
637
|
+
setAnalyticsIds(read: () => {
|
|
638
|
+
session_id?: string;
|
|
639
|
+
distinct_id?: string;
|
|
640
|
+
}): void;
|
|
641
|
+
setToolContext(values: Record<string, string> | undefined): void;
|
|
642
|
+
/** Whether copilot action tools are available for this site. */
|
|
643
|
+
isEnabled(): boolean;
|
|
644
|
+
/**
|
|
645
|
+
* Process a user message through the harness.
|
|
646
|
+
*
|
|
647
|
+
* 1. Sends question + history + page context to backend /ask
|
|
648
|
+
* 2. If backend returns SSE stream (agent loop running), reads events in real-time
|
|
649
|
+
* 3. Calls onStatus callback with progress updates during the loop
|
|
650
|
+
* 4. Returns the final response when the stream completes
|
|
651
|
+
* 5. For non-tool queries, returns JSON response directly
|
|
652
|
+
*/
|
|
653
|
+
processMessage(question: string, pageUrl?: string, pageSnapshot?: PageSnapshot, chatMode?: string, onStatus?: AgentStatusCallback, onTextDelta?: TextDeltaCallback, onToolCallEvent?: ToolCallEventCallback, abortSignal?: AbortSignal, userContext?: Record<string, unknown>, onboardingUserId?: string): Promise<HarnessResponse>;
|
|
654
|
+
/**
|
|
655
|
+
* Execute a confirmed tool call after user approval.
|
|
656
|
+
* Called when user clicks "Yes, do it" for write/destructive actions.
|
|
657
|
+
* Executes in the browser when possible, then formats the result with LLM.
|
|
658
|
+
*/
|
|
659
|
+
executeToolCall(toolCall: ToolCallResponse, originalQuestion: string, onStatus?: AgentStatusCallback, onTextDelta?: TextDeltaCallback): Promise<HarnessResponse>;
|
|
660
|
+
/** Alias for executeToolCall. */
|
|
661
|
+
confirmAndExecute(toolCall: ToolCallResponse, originalQuestion: string): Promise<HarnessResponse>;
|
|
662
|
+
/** Get conversation history for display in chat. */
|
|
663
|
+
getConversationHistory(): ConversationMessage[];
|
|
664
|
+
/** Recent redacted context for semantic conversational follow-ups. */
|
|
665
|
+
getRecentConversationContext(count?: number): {
|
|
666
|
+
role: string;
|
|
667
|
+
content: string;
|
|
668
|
+
}[];
|
|
669
|
+
/** Persist a completed Realtime turn so voice and text share one history. */
|
|
670
|
+
recordRealtimeTurn(role: 'user' | 'assistant', content: string): void;
|
|
671
|
+
/** Check if there is existing conversation history. */
|
|
672
|
+
hasHistory(): boolean;
|
|
673
|
+
/** Clear conversation history. */
|
|
674
|
+
clearHistory(): void;
|
|
675
|
+
/**
|
|
676
|
+
* Read SSE events from the backend agent loop stream.
|
|
677
|
+
* Supports incremental text streaming, tool call display events, and cancellation.
|
|
678
|
+
* Updates status via callback and resolves with the final response.
|
|
679
|
+
*/
|
|
680
|
+
private _readSSEStream;
|
|
681
|
+
/**
|
|
682
|
+
* Parse the ChatAskResponse from a streamed "done" event into HarnessResponse.
|
|
683
|
+
*/
|
|
684
|
+
/**
|
|
685
|
+
* Strip tool_call artifacts from streamed text so raw JSON is never shown.
|
|
686
|
+
*
|
|
687
|
+
* Handles:
|
|
688
|
+
* - Fenced code blocks: ```tool_call\n{...}```
|
|
689
|
+
* - Bare JSON objects with a "tool" key: {"tool":"list_guides","params":{}}
|
|
690
|
+
* - Standalone mode: lines (mode: execute)
|
|
691
|
+
*/
|
|
692
|
+
private _stripToolCallArtifacts;
|
|
693
|
+
private _parseStreamedResponse;
|
|
694
|
+
/**
|
|
695
|
+
* Handle a regular JSON response (non-streaming).
|
|
696
|
+
*/
|
|
697
|
+
/**
|
|
698
|
+
* Surface a plan to the UI once per chain.
|
|
699
|
+
*
|
|
700
|
+
* The chain revisits the server on every round, and a mid-chain response
|
|
701
|
+
* may restate the plan. Re-announcing an identical plan would redraw it and
|
|
702
|
+
* make the assistant look like it had started over, so only a changed plan
|
|
703
|
+
* is emitted.
|
|
704
|
+
*/
|
|
705
|
+
private _announcePlan;
|
|
706
|
+
private _handleJsonResponse;
|
|
707
|
+
private _continueToolChain;
|
|
708
|
+
/**
|
|
709
|
+
* Remove calls that have already been made in this chain.
|
|
710
|
+
*
|
|
711
|
+
* The model is told not to repeat itself, and mostly does not, but a long
|
|
712
|
+
* chain occasionally re-requests an endpoint it already has — which costs a
|
|
713
|
+
* request and a model round trip to learn nothing new.
|
|
714
|
+
*/
|
|
715
|
+
private _dropRepeats;
|
|
716
|
+
/**
|
|
717
|
+
* Run a client-executed tool chain.
|
|
718
|
+
*
|
|
719
|
+
* Each round the model may request either one tool or a batch of
|
|
720
|
+
* independent tools. A batch is executed concurrently, so the wall-clock
|
|
721
|
+
* cost of gathering four unrelated resources is one request plus one model
|
|
722
|
+
* round trip, rather than four of each. Dependent calls still arrive one at
|
|
723
|
+
* a time — the model only batches what it can run without waiting.
|
|
724
|
+
*/
|
|
725
|
+
private _runClientToolChain;
|
|
726
|
+
private hasAnyLocalTools;
|
|
727
|
+
private canExecuteTool;
|
|
728
|
+
private executeLocalTool;
|
|
729
|
+
private executeLocalToolBatch;
|
|
730
|
+
private _formatToolResult;
|
|
731
|
+
private _readFormatToolResultStream;
|
|
732
|
+
private _executePendingToolCall;
|
|
733
|
+
/**
|
|
734
|
+
* Emit a fully-buffered answer to the UI.
|
|
735
|
+
*
|
|
736
|
+
* This used to fake a typing effect by releasing one word every 12ms. The
|
|
737
|
+
* response has already arrived in full by this point, so that delay was pure
|
|
738
|
+
* added latency — a 250-word answer sat behind three seconds of animation
|
|
739
|
+
* after the data was on the client. Real streaming still arrives token by
|
|
740
|
+
* token over SSE; a buffered answer is shown as soon as we have it.
|
|
741
|
+
*/
|
|
742
|
+
private _emitAnswerText;
|
|
743
|
+
private _errorResponse;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* The slice of MMKV this needs. Declared structurally so `new MMKV()`
|
|
748
|
+
* satisfies it without this package depending on react-native-mmkv.
|
|
749
|
+
*/
|
|
750
|
+
interface SyncNativeStore {
|
|
751
|
+
getString(key: string): string | undefined;
|
|
752
|
+
set(key: string, value: string): void;
|
|
753
|
+
delete(key: string): void;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/** Returns the signed-in user's token, or null when signed out. May be async. */
|
|
757
|
+
type AuthTokenGetter = () => string | null | undefined | Promise<string | null | undefined>;
|
|
758
|
+
|
|
759
|
+
/** What a host says about one control on screen. */
|
|
760
|
+
interface DeclaredElement {
|
|
761
|
+
/**
|
|
762
|
+
* Stable id, unique within the screen. Becomes the snapshot's
|
|
763
|
+
* `selector` — legitimate because the backend treats `selector` as an
|
|
764
|
+
* opaque round-trip token: it renders elements to the model as numbered
|
|
765
|
+
* [ID]s and only checks the string is specific (not the word "button").
|
|
766
|
+
*/
|
|
767
|
+
id: string;
|
|
768
|
+
/** Visible text. What the model matches the user's words against. */
|
|
769
|
+
label: string;
|
|
770
|
+
/** Coarse kind, mapped to the `tag` the backend's prompt expects. */
|
|
771
|
+
kind?: 'button' | 'link' | 'input' | 'text' | 'toggle' | 'image';
|
|
772
|
+
/** Current value, for inputs. */
|
|
773
|
+
value?: string;
|
|
774
|
+
/** Accessibility label when it says more than the visible text. */
|
|
775
|
+
accessibilityLabel?: string;
|
|
776
|
+
/** Placeholder text for an empty input. */
|
|
777
|
+
placeholder?: string;
|
|
778
|
+
/** True when mounted but off-screen or collapsed. */
|
|
779
|
+
hidden?: boolean;
|
|
780
|
+
/** Heading of the group this sits in, e.g. "Sharing options". */
|
|
781
|
+
sectionTitle?: string;
|
|
782
|
+
}
|
|
783
|
+
/** Actions a declared element can perform, supplied by the host at registration. */
|
|
784
|
+
interface ElementHandlers {
|
|
785
|
+
/** Invoked by guideai_click_element. */
|
|
786
|
+
press?: () => void | Promise<void>;
|
|
787
|
+
/** Invoked by guideai_fill_field / guideai_fill_form. */
|
|
788
|
+
setValue?: (value: string) => void | Promise<void>;
|
|
789
|
+
/** Invoked by guideai_scroll_to_element. */
|
|
790
|
+
scrollTo?: () => void | Promise<void>;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/** The slice of React Navigation's ref this needs. */
|
|
794
|
+
interface NavigationRefLike {
|
|
795
|
+
isReady?(): boolean;
|
|
796
|
+
navigate(screen: string, params?: object): void;
|
|
797
|
+
goBack(): void;
|
|
798
|
+
canGoBack?(): boolean;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
interface GuideAIConfig {
|
|
802
|
+
/**
|
|
803
|
+
* The site's public token, from the dashboard. The only required
|
|
804
|
+
* field: it identifies the site, and everything else about that site
|
|
805
|
+
* — its tools, knowledge base, model and prompts — is resolved
|
|
806
|
+
* server-side from it.
|
|
807
|
+
*/
|
|
808
|
+
apiKey: string;
|
|
809
|
+
/** The application's stable user ID after login, if already known. */
|
|
810
|
+
visitorId?: string;
|
|
811
|
+
/**
|
|
812
|
+
* A domain registered on this site (its own domain, or one of its
|
|
813
|
+
* `domain_aliases`).
|
|
814
|
+
*
|
|
815
|
+
* Required in practice, and it cannot be fetched from the dashboard:
|
|
816
|
+
* the backend uses it to AUTHORIZE the request, so it must accompany
|
|
817
|
+
* the very first call. A native app sends no `Origin` header, so this
|
|
818
|
+
* travels as `x-guideai-request-origin`. Set it once; a mismatch is
|
|
819
|
+
* answered with 403.
|
|
820
|
+
*/
|
|
821
|
+
origin?: string;
|
|
822
|
+
/**
|
|
823
|
+
* Where the GuideAI backend lives. Defaults to the hosted service, so
|
|
824
|
+
* only self-hosted deployments set it.
|
|
825
|
+
*/
|
|
826
|
+
baseUrl?: string;
|
|
827
|
+
/**
|
|
828
|
+
* How the assistant navigates between screens — a React Navigation
|
|
829
|
+
* ref, or a getter for one. Omitted, the assistant simply does not
|
|
830
|
+
* offer navigation rather than offering it and failing.
|
|
831
|
+
*/
|
|
832
|
+
navigation?: NavigationRefLike | (() => NavigationRefLike | null | undefined);
|
|
833
|
+
/**
|
|
834
|
+
* A synchronous key/value store (MMKV, or `expo-sqlite/kv-store`) for
|
|
835
|
+
* conversation history across launches. Omitted, history is kept in
|
|
836
|
+
* memory and resets on relaunch.
|
|
837
|
+
*/
|
|
838
|
+
store?: SyncNativeStore;
|
|
839
|
+
/** The assistant's visible name in its own replies. */
|
|
840
|
+
assistantName?: string;
|
|
841
|
+
/**
|
|
842
|
+
* Which of the site's agents (Agent Blueprints) answers, by its key —
|
|
843
|
+
* e.g. 'tutor'. Omitted: the site's main agent.
|
|
844
|
+
*/
|
|
845
|
+
agent?: string;
|
|
846
|
+
/**
|
|
847
|
+
* The signed-in user's token for the site's own API. Read before every
|
|
848
|
+
* turn; may be async (AsyncStorage, SecureStore). Return null when
|
|
849
|
+
* signed out. The assistant then calls your endpoints as that user,
|
|
850
|
+
* from the device.
|
|
851
|
+
*/
|
|
852
|
+
getAuthToken?: AuthTokenGetter;
|
|
853
|
+
/**
|
|
854
|
+
* Called once when your API answers 401 to a tool call. Refresh the
|
|
855
|
+
* session and return the new token; the call is repeated with it.
|
|
856
|
+
* Omitted: getAuthToken() is asked again.
|
|
857
|
+
*/
|
|
858
|
+
onAuthExpired?: AuthTokenGetter;
|
|
859
|
+
/**
|
|
860
|
+
* Facts about the signed-in user for the agent to pitch answers to —
|
|
861
|
+
* `{ age: 12, class: 'JSS1', country: 'Nigeria', language: 'en' }`.
|
|
862
|
+
* Sent with every turn; change it with GuideAI.setUserProfile().
|
|
863
|
+
*/
|
|
864
|
+
userProfile?: GuideAIUserProfile;
|
|
865
|
+
/**
|
|
866
|
+
* Log the full conversation and every request. Development only —
|
|
867
|
+
* it prints message content to the console.
|
|
868
|
+
*/
|
|
869
|
+
debug?: boolean;
|
|
870
|
+
}
|
|
871
|
+
/** Short facts about the user: strings, numbers, booleans or short lists of them. */
|
|
872
|
+
type GuideAIUserProfile = Record<string, string | number | boolean | Array<string | number>>;
|
|
873
|
+
/**
|
|
874
|
+
* Configure the assistant. Call once, at app startup.
|
|
875
|
+
*
|
|
876
|
+
* Deliberately a function rather than a provider or a module constant:
|
|
877
|
+
* `apiKey` often arrives from a remote config or an env fetch, and a
|
|
878
|
+
* constructor running at import time cannot wait for it.
|
|
879
|
+
*/
|
|
880
|
+
declare function configure(config: GuideAIConfig): void;
|
|
881
|
+
/** Call after login so chat and the checklist use the same person. */
|
|
882
|
+
declare function identify(userId: string | null): void;
|
|
883
|
+
/** Replace what the agent knows about the user (after login, or a profile edit). */
|
|
884
|
+
declare function setUserProfile(profile: GuideAIUserProfile | null): void;
|
|
885
|
+
/** Whether configure() has run. Lets a host render its own fallback. */
|
|
886
|
+
declare function isConfigured(): boolean;
|
|
887
|
+
/** Test seam, and for hosts that switch sites at runtime. */
|
|
888
|
+
declare function reset(): void;
|
|
889
|
+
declare const GuideAI: {
|
|
890
|
+
configure: typeof configure;
|
|
891
|
+
identify: typeof identify;
|
|
892
|
+
setUserProfile: typeof setUserProfile;
|
|
893
|
+
isConfigured: typeof isConfigured;
|
|
894
|
+
reset: typeof reset;
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
interface GuideAIScreenProps {
|
|
898
|
+
/** React Navigation screen name, e.g. "ShareForm". Used by navigate(). */
|
|
899
|
+
name: string;
|
|
900
|
+
/** Scanner route path, e.g. "/share". Used for grounding. */
|
|
901
|
+
path: string;
|
|
902
|
+
/** Human title shown to the model. Defaults to `name`. */
|
|
903
|
+
title?: string;
|
|
904
|
+
/**
|
|
905
|
+
* Whether this screen is the one currently on top.
|
|
906
|
+
*
|
|
907
|
+
* Defaults to true. React Navigation keeps previous screens MOUNTED in
|
|
908
|
+
* the stack, so without this a backgrounded screen would keep claiming
|
|
909
|
+
* to be active and the model would be told about controls the user
|
|
910
|
+
* cannot see. Hosts using React Navigation should pass
|
|
911
|
+
* `useIsFocused()`.
|
|
912
|
+
*/
|
|
913
|
+
active?: boolean;
|
|
914
|
+
children: React.ReactNode;
|
|
915
|
+
}
|
|
916
|
+
declare function GuideAIScreen({ name, path, title, active, children, }: GuideAIScreenProps): React.ReactElement;
|
|
917
|
+
|
|
918
|
+
type UseGuideAIElementOptions = Omit<DeclaredElement, 'id'> & ElementHandlers;
|
|
919
|
+
/**
|
|
920
|
+
* Declare one element to the assistant.
|
|
921
|
+
*
|
|
922
|
+
* Registration is an effect, so it runs after mount and unwinds on
|
|
923
|
+
* unmount. Handlers are kept in a ref and read through a stable wrapper:
|
|
924
|
+
* without that, an inline `press={() => …}` would be a new function on
|
|
925
|
+
* every render and re-register the element on every render with it.
|
|
926
|
+
*/
|
|
927
|
+
declare function useGuideAIElement(id: string, options: UseGuideAIElementOptions): void;
|
|
928
|
+
|
|
929
|
+
interface GuideAIMessage {
|
|
930
|
+
id: string;
|
|
931
|
+
role: 'user' | 'assistant';
|
|
932
|
+
content: string;
|
|
933
|
+
/** True while tokens are still arriving for this message. */
|
|
934
|
+
streaming?: boolean;
|
|
935
|
+
error?: boolean;
|
|
936
|
+
/**
|
|
937
|
+
* Follow-up suggestions to draw as chips. A tap is just
|
|
938
|
+
* `send(suggestion)`.
|
|
939
|
+
*/
|
|
940
|
+
suggestions?: string[];
|
|
941
|
+
/**
|
|
942
|
+
* Pictures the agent drew. They are also in `content` as Markdown
|
|
943
|
+
* images where they belong; use this list to place them yourself.
|
|
944
|
+
*/
|
|
945
|
+
images?: HeadlessImage[];
|
|
946
|
+
/**
|
|
947
|
+
* A change to the user's data waiting for their yes ("Create the
|
|
948
|
+
* course"). Draw Approve / Cancel and call `confirm(id)` or `cancel(id)`.
|
|
949
|
+
*/
|
|
950
|
+
pendingAction?: {
|
|
951
|
+
label: string;
|
|
952
|
+
tool: string;
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
/** A recording the host made (expo-audio or any recorder) and saved to a file. */
|
|
956
|
+
interface GuideAIVoiceRecording {
|
|
957
|
+
/** `file://…` URI of the finished recording. */
|
|
958
|
+
uri: string;
|
|
959
|
+
/** e.g. 'audio/m4a'. Omitted: guessed from the file extension. */
|
|
960
|
+
mimeType?: string;
|
|
961
|
+
/** BCP-47 language the user spoke, e.g. 'en-NG'. Defaults to 'en-US'. */
|
|
962
|
+
languageCode?: string;
|
|
963
|
+
}
|
|
964
|
+
interface GuideAIVoiceResult {
|
|
965
|
+
/** What was heard, already sent as the next message; null when nothing was. */
|
|
966
|
+
text: string | null;
|
|
967
|
+
/** Why nothing was sent, in words to show the user. */
|
|
968
|
+
error?: string;
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Everything a custom chat UI needs, and nothing about how to draw it.
|
|
972
|
+
*
|
|
973
|
+
* A host owns two things — their design, and the text the user typed.
|
|
974
|
+
* This hook owns the rest: the conversation, the streaming, the tool
|
|
975
|
+
* calls, the transport. That split is what lets the agent be upgraded
|
|
976
|
+
* underneath a host's UI without them changing a line.
|
|
977
|
+
*/
|
|
978
|
+
interface UseGuideAIResult {
|
|
979
|
+
/** The conversation so far, oldest first. */
|
|
980
|
+
messages: GuideAIMessage[];
|
|
981
|
+
/**
|
|
982
|
+
* The current input text, and its setter.
|
|
983
|
+
*
|
|
984
|
+
* Managed here so a host binds it straight to their TextInput rather
|
|
985
|
+
* than reimplementing "clear on send, block while busy" — the two
|
|
986
|
+
* rules every chat UI needs and each one gets subtly wrong.
|
|
987
|
+
*/
|
|
988
|
+
input: string;
|
|
989
|
+
setInput(text: string): void;
|
|
990
|
+
/**
|
|
991
|
+
* Send `input`, or an explicit string.
|
|
992
|
+
*
|
|
993
|
+
* Ignores empty text and calls made while a turn is in flight, so a
|
|
994
|
+
* host does not have to guard their send button.
|
|
995
|
+
*/
|
|
996
|
+
send(question?: string): Promise<void>;
|
|
997
|
+
/** True from send() until the turn settles. Drives a disabled state. */
|
|
998
|
+
busy: boolean;
|
|
999
|
+
/** Whether `send()` would do anything right now. */
|
|
1000
|
+
canSend: boolean;
|
|
1001
|
+
/** Status text from the agent loop ("Thinking", "Reading cart"). */
|
|
1002
|
+
status: string | null;
|
|
1003
|
+
/** Re-send the last user message. Useful after a failed turn. */
|
|
1004
|
+
retry(): Promise<void>;
|
|
1005
|
+
/** Drop the conversation and start over. */
|
|
1006
|
+
clear(): void;
|
|
1007
|
+
/** Approve the message's `pendingAction`; the agent carries it out. */
|
|
1008
|
+
confirm(messageId: string): Promise<void>;
|
|
1009
|
+
/** Decline the message's `pendingAction`. Nothing is changed. */
|
|
1010
|
+
cancel(messageId: string): void;
|
|
1011
|
+
/**
|
|
1012
|
+
* Push-to-talk: transcribe a recording and send it as the next message.
|
|
1013
|
+
* Recording is the host's (no native module here); this uploads it.
|
|
1014
|
+
*/
|
|
1015
|
+
sendVoice(recording: GuideAIVoiceRecording): Promise<GuideAIVoiceResult>;
|
|
1016
|
+
/** True while a recording is being transcribed. */
|
|
1017
|
+
transcribing: boolean;
|
|
1018
|
+
}
|
|
1019
|
+
interface UseGuideAIOptions {
|
|
1020
|
+
/**
|
|
1021
|
+
* Log the full conversation and every request. Defaults to whatever
|
|
1022
|
+
* GuideAI.configure({ debug }) was given, so a host sets it once.
|
|
1023
|
+
*/
|
|
1024
|
+
trace?: boolean;
|
|
1025
|
+
/**
|
|
1026
|
+
* The harness, for tests and for a host running two assistants at
|
|
1027
|
+
* once. Omitted — the normal case — it comes from GuideAI.configure(),
|
|
1028
|
+
* so a host never holds a reference to it.
|
|
1029
|
+
*/
|
|
1030
|
+
harness?: CopilotHarness;
|
|
1031
|
+
}
|
|
1032
|
+
declare function useGuideAI(options?: UseGuideAIOptions): UseGuideAIResult;
|
|
1033
|
+
|
|
1034
|
+
/** Reads the same durable checklist as the browser adapter. */
|
|
1035
|
+
declare function useOnboarding(): {
|
|
1036
|
+
checklist: OnboardingState | null;
|
|
1037
|
+
loading: boolean;
|
|
1038
|
+
refresh: () => Promise<void>;
|
|
1039
|
+
dismiss: () => Promise<void>;
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
export { GuideAI, GuideAIScreen, useGuideAI, useGuideAIElement, useOnboarding };
|
|
1043
|
+
export type { AuthTokenGetter, DeclaredElement, ElementHandlers, GuideAIConfig, HeadlessImage as GuideAIImage, GuideAIMessage, GuideAIScreenProps, GuideAIUserProfile, GuideAIVoiceRecording, GuideAIVoiceResult, NavigationRefLike, OnboardingState, OnboardingStepState, SyncNativeStore, UseGuideAIElementOptions, UseGuideAIResult };
|