@xano-sdk/chatbot 1.0.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.
@@ -0,0 +1,1811 @@
1
+ import * as _xano_sdk from '@xano/sdk';
2
+ import { TableDef, LlmSettings, ToolsetToolEntry, InferRow, Xano, InferInput, InferResponse } from '@xano/sdk';
3
+
4
+ /**
5
+ * The public configuration surface, plus the resolver that turns a caller's
6
+ * partial options into the fully-defaulted `ResolvedOptions` every def factory
7
+ * reads.
8
+ *
9
+ * Everything in this package is a **factory** rather than a module singleton,
10
+ * and `authTable` is why. `f.tableRef` resolves its target's guid eagerly, at
11
+ * column-construction time (core's `src/fields/catalog.ts` — `resolveRef("dbo",
12
+ * table)` runs inside the field builder), so a module-level `conversation` def
13
+ * would bake in one particular user reference the moment this module evaluated
14
+ * and could never be re-pointed by a later `registerChatbot` call.
15
+ *
16
+ * That divergence from `@xano-sdk/auth`'s layout costs the
17
+ * `import { conversationTable }` cherry-pick, and buys two things back. The
18
+ * obvious one is a configurable auth table. The subtler one is that the ~100
19
+ * lines of conflict guards in `@xano-sdk/auth`'s `register.ts` have no analogue
20
+ * here: those exist because `authenticationGroup` is a process-wide singleton a
21
+ * second `registerAuth` could silently retarget. Fresh defs per call cannot have
22
+ * that bug, so this package needs no cross-call agreement checks.
23
+ */
24
+
25
+ /**
26
+ * The auth table, as this package accepts it: a `table()` def handle or a bare
27
+ * table name.
28
+ *
29
+ * Deliberately NARROWER than core's `AuthRef`, which also allows a raw numeric
30
+ * `dbo.id`. That escape hatch is unusable here: the same table is both the
31
+ * endpoints' `auth` (which takes a number happily) and the target of
32
+ * `conversation.user_id`, and `f.tableRef` resolves through `ObjectRef` —
33
+ * `string | { name, guid? }` — which has no numeric form. Accepting a number
34
+ * would mean silently dropping the foreign key or demanding a second option
35
+ * naming the same table twice, so it is refused at the type level instead.
36
+ */
37
+ type ChatbotAuthTable = TableDef | string;
38
+ /**
39
+ * The LLM settings a caller may supply: core's `LlmSettings` with the run prompt
40
+ * removed from every member of the union.
41
+ *
42
+ * Distributive on purpose — a plain `Omit<LlmSettings, …>` on a union collapses it
43
+ * to the keys all members share, which would erase every provider-specific field
44
+ * and make `{ type: "anthropic", thinkingTokens }` a type error.
45
+ *
46
+ * The removal makes `llm.prompt` a COMPILE error rather than only a runtime one.
47
+ * `resolveOptions` still throws, because a JS caller (or options read from untyped
48
+ * config) reaches neither check — but a TypeScript author finds out at the call
49
+ * site, which is the whole point of the package being typed.
50
+ *
51
+ * ⚠ The two banned keys are re-declared as `?: never` rather than merely
52
+ * `Omit`ted. Omission alone makes the rejection an EXCESS-PROPERTY check, which
53
+ * fires for a direct object-literal assignment and silently stops firing the
54
+ * moment the argument is inferred into a generic type parameter — as it now is,
55
+ * so `createChatbot`/`registerChatbot` can tell which endpoint families a given
56
+ * options object produces. `?: never` is a real assignability failure and
57
+ * survives that inference.
58
+ */
59
+ type ChatbotLlmOptions = LlmSettings extends infer U ? U extends unknown ? Partial<Omit<U, "prompt" | "messages">> & {
60
+ prompt?: never;
61
+ messages?: never;
62
+ } : never : never;
63
+ /**
64
+ * Per-caller rate limiting on the endpoints that invoke the model.
65
+ *
66
+ * ON by default, because the guest family is **public and every send costs an
67
+ * LLM call** — an unauthenticated, metered endpoint with no ceiling is the one
68
+ * configuration a turnkey package should never ship. Same reasoning as request
69
+ * history being off by default.
70
+ *
71
+ * Applied to the two `send` endpoints and to `guest/conversations/create` (the
72
+ * only unauthenticated write). Reads are not limited: they are cheap and
73
+ * limiting them mostly breaks legitimate UIs.
74
+ *
75
+ * Keys are per caller and per install:
76
+ *
77
+ * - authenticated → `auth("id")`, a real identity;
78
+ * - guest → `sys.remoteIp()`, because `auth()` is null on a public endpoint and
79
+ * every caller would otherwise share ONE bucket — core warns about exactly
80
+ * this collapse.
81
+ *
82
+ * ⚠ An IP key is the best available signal on a public endpoint, not a strong
83
+ * one: callers behind one NAT share a bucket, and a distributed source gets a
84
+ * fresh bucket per address. Treat it as a cost ceiling, not an anti-abuse
85
+ * control.
86
+ *
87
+ * Pass `false` to remove it entirely.
88
+ */
89
+ interface ChatbotRateLimit {
90
+ /** Requests per window, per caller. Default {@link DEFAULT_RATE_LIMIT_MAX}. */
91
+ max?: number;
92
+ /** Window length in seconds. Default {@link DEFAULT_RATE_LIMIT_TTL}. */
93
+ ttl?: number;
94
+ /** Message returned when the limit is hit. */
95
+ error?: string;
96
+ }
97
+ /**
98
+ * The default system prompt — deliberately bland, meant to be replaced.
99
+ *
100
+ * The markdown sentence is the one part that is not filler. Replies read far
101
+ * better in a chat UI when the frontend renders them as markdown, and that only
102
+ * works if the model is actually told to produce it, so the shipped default and
103
+ * the rendering advice in README.md are two halves of one decision.
104
+ *
105
+ * **Light** markdown on purpose. A model told simply to "use markdown" reaches
106
+ * for headings and tables in a two-line answer, which reads worse than prose in a
107
+ * chat bubble — and every element it uses is one more thing a frontend has to
108
+ * style. Emphasis, lists and code spans cover what a conversational reply needs.
109
+ *
110
+ * If your frontend renders replies as PLAIN TEXT, override this: unrendered
111
+ * markdown shows the reader literal `**asterisks**`, which is worse than the
112
+ * prose it replaced. Pass your own `llm.systemPrompt` — that is the field this
113
+ * package expects most installs to set.
114
+ */
115
+ declare const DEFAULT_SYSTEM_PROMPT: string;
116
+ /**
117
+ * Appended to the system prompt when — and only when — `tools` are configured.
118
+ *
119
+ * Two clauses, each earning its place from observed behaviour:
120
+ *
121
+ * 1. **"call the tool rather than saying you do not know."** Verified live: with
122
+ * a correctly wired tool but no mention of it in the prompt, the model
123
+ * answered "I do not know the secret word" and never called it — the default
124
+ * prompt's own "if you do not know something, say so rather than guessing"
125
+ * steers it away from trying. Asked by name it called the tool immediately.
126
+ * 2. **"answer in your own words, never paste the raw tool response."** A tool
127
+ * result arrives wrapped in an engine envelope
128
+ * (`{"<tool>_response": {"content": …, "name": …}}`), and the model will
129
+ * happily paste that verbatim into `reply` — which then renders as a JSON
130
+ * blob in the UI. Observed exactly that before this clause existed.
131
+ *
132
+ * Kept to two sentences so it composes with a caller's own `systemPrompt`
133
+ * instead of arguing with it.
134
+ */
135
+ declare const TOOLS_SYSTEM_PROMPT: string;
136
+ /** How many prior turns the send endpoint replays into the model. */
137
+ declare const DEFAULT_HISTORY_LIMIT = 20;
138
+ /** How many conversations the list endpoint returns. */
139
+ declare const DEFAULT_LIST_LIMIT = 100;
140
+ /** How many messages a transcript endpoint returns. */
141
+ declare const DEFAULT_TRANSCRIPT_LIMIT = 200;
142
+ /** Default stored-object names. */
143
+ declare const DEFAULT_NAMES: {
144
+ readonly conversation: "conversation";
145
+ readonly message: "conversation_message";
146
+ readonly replyFn: "chatbot/generate_reply";
147
+ readonly agent: "chatbot_agent";
148
+ readonly apiGroup: "Chatbot";
149
+ };
150
+ /** Overridable stored-object names — see {@link ChatbotOptions.names}. */
151
+ interface ChatbotNames {
152
+ /** The conversation table. Default `"conversation"`. */
153
+ conversation?: string;
154
+ /**
155
+ * The message table. Default `"conversation_message"` rather than the more
156
+ * obvious `"message"`: a bare `message` is a name a realtime or notification
157
+ * workspace plausibly already holds, and a collision surfaces as a duplicate
158
+ * -guid throw at export rather than anything self-explanatory.
159
+ */
160
+ message?: string;
161
+ /** The shared reply function. Default `"chatbot/generate_reply"`. */
162
+ replyFn?: string;
163
+ /** The agent. Default `"chatbot_agent"`. */
164
+ agent?: string;
165
+ /** The API group. Default `"Chatbot"`. */
166
+ apiGroup?: string;
167
+ }
168
+ /** Options for `createChatbot` / `registerChatbot`. */
169
+ interface ChatbotOptions {
170
+ /**
171
+ * The table conversations belong to, and the table the authenticated
172
+ * endpoints authenticate against. Required whenever `authenticated` is on
173
+ * (the default).
174
+ *
175
+ * Takes a `table()` def handle or a bare table name (see
176
+ * {@link ChatbotAuthTable} for why a numeric `dbo.id` is not accepted).
177
+ * **Nothing in this package imports `@xano-sdk/auth`**; handing it that
178
+ * package's `userTable` is just the documented happy path:
179
+ *
180
+ * ```ts
181
+ * import { userTable } from "@xano-sdk/auth";
182
+ * registerChatbot(xano, { authTable: userTable });
183
+ * ```
184
+ *
185
+ * Your own table works identically. `table({ auth: true })` is the convention,
186
+ * not a mechanism: the engine gates a request by comparing the token's `dbo`
187
+ * against the endpoint's configured `dbo` **by name**, and mints a token for
188
+ * any table by name — neither side reads the flag, which is only an editor
189
+ * concern (see core's `src/refs/auth.ts`). So a table without `auth: true`
190
+ * authenticates fine; core merely warns at export.
191
+ *
192
+ * Prefer the **handle** over a bare name. A name carries no schema, so core
193
+ * cannot check the referenced primary-key type against the `user_id` column —
194
+ * an int/uuid mismatch then surfaces as a Xano import failure instead of an
195
+ * author-time throw. Pass `{ userIdType: "uuid" }` alongside a uuid-keyed
196
+ * table referenced by name.
197
+ */
198
+ authTable?: ChatbotAuthTable;
199
+ /**
200
+ * The primary-key type of `authTable`, and so the type of
201
+ * `conversation.user_id`. Default `"int"`.
202
+ *
203
+ * Only needed when `authTable` is a bare **name** — a name carries no schema.
204
+ * With a handle, core reads the target's `idType` and throws on a mismatch by
205
+ * itself, so this option is redundant there (but still checked for agreement).
206
+ */
207
+ userIdType?: "int" | "uuid";
208
+ /**
209
+ * Register the token-authenticated endpoint family (`chat/*`), scoped by
210
+ * `auth("id")`. Default `true`.
211
+ *
212
+ * Set `false` for a purely anonymous bot, in which case `authTable` may be
213
+ * omitted entirely and `user_id` is dropped from the conversation table.
214
+ */
215
+ authenticated?: boolean;
216
+ /**
217
+ * Register the public guest endpoint family (`chat/guest/*`), scoped by an
218
+ * unguessable `session_token`. Default `false`.
219
+ *
220
+ * Two families rather than one because a Xano endpoint's `auth` is **binary**
221
+ * and there is no optional-auth flag: an authenticated endpoint returns 401
222
+ * without a token, and referencing `auth()` inside a *public* stack raises
223
+ * `ACCESS_DENIED` outright (verified against a live instance — see
224
+ * AGENTS.md). One endpoint therefore cannot serve both callers, so each family
225
+ * gets its own, and each has exactly one authorization rule to audit.
226
+ *
227
+ * ⚠ A guest conversation is protected by a bearer capability, not a login.
228
+ * See the security notes in README.md before enabling this on a public site.
229
+ */
230
+ guest?: boolean;
231
+ /**
232
+ * The agent's LLM settings, passed through to core's `agent({ llm })`.
233
+ *
234
+ * Defaults to `{ type: "xano-free" }` — Xano's keyless provider, so a fresh
235
+ * install answers a message without any credential wiring.
236
+ *
237
+ * `systemPrompt` defaults to {@link DEFAULT_SYSTEM_PROMPT} and is the one
238
+ * field most installs will set. The **run prompt is not yours to set**: this
239
+ * package owns it, because the conversation transcript is delivered through
240
+ * it. Passing `prompt` or `messages` throws rather than silently losing the
241
+ * history (core stores one prompt behind a `prompt_type` discriminator, so a
242
+ * caller-supplied one would replace the transcript, not add to it).
243
+ */
244
+ llm?: ChatbotLlmOptions;
245
+ /**
246
+ * How many prior messages to replay into the model on each send. Default
247
+ * {@link DEFAULT_HISTORY_LIMIT}. Must be a positive integer.
248
+ *
249
+ * The window is applied in the database (`db.query` + `sort` + `paging`), so a
250
+ * long conversation costs a bounded read and a bounded context, not a growing
251
+ * one. Raising it raises per-message token spend on every turn.
252
+ */
253
+ /**
254
+ * How many messages of the thread are replayed to the model on each send.
255
+ * Default {@link DEFAULT_HISTORY_LIMIT}.
256
+ *
257
+ * ⚠ A count of **messages (rows), including the turn being sent** — not of
258
+ * exchanges. The user's message is written before the history is read, so the
259
+ * usable memory is `historyLimit - 1` PRIOR messages, and a user+assistant
260
+ * exchange costs two.
261
+ *
262
+ * Verified live: at `historyLimit: 2` the model is given
263
+ * `[previous assistant reply, current user message]` — the user's own previous
264
+ * statement is already outside the window, so "the codeword is X" followed by
265
+ * "what was the codeword?" cannot be answered. The default of 20 is ~10
266
+ * exchanges; treat anything below ~6 as effectively memoryless.
267
+ *
268
+ * Independent of `transcriptLimit`, so a user can see a message on screen that
269
+ * the model was never shown.
270
+ */
271
+ historyLimit?: number;
272
+ /**
273
+ * How many conversations `GET chat/conversations` returns, newest-active first.
274
+ * Default {@link DEFAULT_LIST_LIMIT}. Must be a positive integer.
275
+ *
276
+ * A fixed cap rather than caller-supplied paging: input-bound paging would let
277
+ * an omitted `per_page` reach the engine as null, and a chat sidebar is not the
278
+ * surface where that trade is worth making. A consumer who needs real paging
279
+ * registers their own list endpoint over the same table.
280
+ */
281
+ listLimit?: number;
282
+ /**
283
+ * Per-caller rate limiting on the model-invoking endpoints. Defaults to
284
+ * `{ max: 20, ttl: 60 }`; pass `false` to disable. See {@link ChatbotRateLimit}.
285
+ */
286
+ rateLimit?: false | ChatbotRateLimit;
287
+ /**
288
+ * Tools the chat agent may call — a `tool()` def handle, its name, or a
289
+ * `{ tool, enabled?, auth? }` wrapper.
290
+ *
291
+ * Empty by default: a tool-less assistant is the right shape for a plain
292
+ * chatbot, and a tool the model can call is a capability, not a decoration.
293
+ *
294
+ * ⚠ **This package references your tools; it never registers them.** Same rule
295
+ * as `authTable`. Register them yourself:
296
+ *
297
+ * ```ts
298
+ * const lookupOrder = tool({ name: "lookup_order", … });
299
+ *
300
+ * const bot = registerChatbot(xano, { authTable: userTable, tools: [lookupOrder] });
301
+ * bot.xano.registerTools([lookupOrder]);
302
+ * ```
303
+ *
304
+ * A reference resolves to a name-derived guid with no registry lookup, so a
305
+ * tool you forget to register is caught at **export**, which THROWS naming the
306
+ * tool and the fix — deliberately, since a mistyped name would otherwise
307
+ * produce a valid-looking guid that only fails once the import has begun.
308
+ *
309
+ * Two things follow from adding tools:
310
+ *
311
+ * - **`llm.maxSteps` starts to matter.** It bounds reasoning/tool steps and
312
+ * defaults to 5; a chain needing more calls than that stops early.
313
+ * - **A tool runs with the caller's request context.** If it reads data, scope
314
+ * it yourself — the agent will call it whenever the model decides to, on
315
+ * behalf of whoever is chatting, including an anonymous guest when the guest
316
+ * family is enabled.
317
+ *
318
+ * ## Per-tool auth is applied for you
319
+ *
320
+ * A toolset entry carries its own `auth`, and the engine's default is
321
+ * `auth: false` — a **public** tool stack. `auth("id")` inside a public stack
322
+ * does not resolve to null: it raises `ERROR_CODE_ACCESS_DENIED` on the first
323
+ * statement that reads it. The agent swallows that throw, so the model still
324
+ * answers "I saved your note" and nothing is written — no 500, no error in the
325
+ * reply, no export warning (a live failure, recorded in AGENTS.md).
326
+ *
327
+ * So when {@link ChatbotOptions.authTable} is set, every entry that does not
328
+ * name an `auth` of its own is given **that table**:
329
+ *
330
+ * ```ts
331
+ * tools: [saveNote] // → { tool: saveNote, auth: userTable }
332
+ * tools: [{ tool: saveNote }] // → { tool: saveNote, auth: userTable }
333
+ * tools: [{ tool: ping, auth: false }] // → left public, the explicit opt-out
334
+ * tools: [{ tool: saveNote, auth: other }] // → left alone
335
+ * ```
336
+ *
337
+ * The tools belong to a bot whose endpoints are already token-gated, so a
338
+ * public tool is almost never the intent. `{ tool, auth: false }` remains the
339
+ * way to say it deliberately — and such a tool must not call `auth()`.
340
+ *
341
+ * ⚠ A **guest-only** install (`{ authenticated: false, guest: true }`) has no
342
+ * auth table, so nothing is defaulted and every tool is public. A tool reached
343
+ * from the guest family has no caller identity: do not write `auth()` in it,
344
+ * and scope what it reads by the arguments the model supplies instead.
345
+ */
346
+ tools?: ToolsetToolEntry[];
347
+ /**
348
+ * How many messages the transcript endpoints return, oldest-first within the
349
+ * window. Default {@link DEFAULT_TRANSCRIPT_LIMIT}. Must be a positive integer.
350
+ *
351
+ * The window takes the NEWEST messages, so a thread longer than this loses its
352
+ * oldest turns from the response — the right end to drop for a UI that renders
353
+ * from the bottom. Independent of `historyLimit`: what a human reads back and
354
+ * what the model is given are different budgets.
355
+ */
356
+ transcriptLimit?: number;
357
+ /**
358
+ * Pin the API group's canonical — the `<canonical>` in
359
+ * `/api:<canonical>/chat/conversations`.
360
+ *
361
+ * Omitted, identity comes from the consumer's `xano.lock` (or, with no lock, a
362
+ * random segment assigned at import) and a bare `getPath()` throws. Pinning it
363
+ * lets a browser resolve `getPath()` with no lock file. Must match
364
+ * `[A-Za-z0-9_-]+`, and must be unique across the instance's API groups —
365
+ * which this package cannot check, so a collision surfaces at Xano import.
366
+ */
367
+ canonical?: string;
368
+ /**
369
+ * Request-history capture for the API group the endpoints inherit from.
370
+ * Default `false`.
371
+ *
372
+ * `false` rather than the engine's inherit-on for the same reason
373
+ * `@xano-sdk/auth` overrides it: request history records the request body, and
374
+ * on this package that body is the user's message text plus — on the guest
375
+ * family — the `session_token` that grants access to the whole thread. A
376
+ * turnkey install should not persist either into the workspace's history
377
+ * store. `true` opts back in at the engine's default depth; a positive integer
378
+ * sets the capture depth; `"all"` is unlimited.
379
+ */
380
+ history?: boolean | number | "all";
381
+ /**
382
+ * The leading path segment of every endpoint — `chat` in
383
+ * `chat/conversations/{id}/send`. Default {@link DEFAULT_ROUTE_PREFIX}.
384
+ *
385
+ * This is the second half of running TWO chatbots in one workspace. `names`
386
+ * renames the stored objects, but a query's identity derives from its **route
387
+ * name**, so a second install also needs its own prefix or every endpoint
388
+ * collides on guid. Slashes are allowed (`"support/chat"`); braces are not,
389
+ * since a prefix is not a place for a path param.
390
+ */
391
+ routePrefix?: string;
392
+ /** Override the stored object names — see {@link ChatbotNames}. */
393
+ names?: ChatbotNames;
394
+ /** Tags applied to every def this package creates. Default `["xano:chatbot"]`. */
395
+ tags?: string[];
396
+ }
397
+ /** Fully-defaulted options, as the def factories consume them. */
398
+ interface ResolvedOptions {
399
+ /** `undefined` exactly when the authenticated family is off. */
400
+ authTable: ChatbotAuthTable | undefined;
401
+ userIdType: "int" | "uuid";
402
+ authenticated: boolean;
403
+ guest: boolean;
404
+ llm: LlmSettings;
405
+ historyLimit: number;
406
+ listLimit: number;
407
+ /** Resolved rate limit, or `false` when disabled. */
408
+ rateLimit: false | {
409
+ max: number;
410
+ ttl: number;
411
+ error: string;
412
+ };
413
+ /**
414
+ * Tools the agent may call. Empty unless the caller supplied some.
415
+ *
416
+ * Normalized, not verbatim: with an auth table, every entry that named no
417
+ * `auth` of its own is now `{ tool, auth: <authTable> }` — see
418
+ * {@link ChatbotOptions.tools}. An explicit `auth: false` survives.
419
+ */
420
+ tools: ToolsetToolEntry[];
421
+ transcriptLimit: number;
422
+ canonical: string | undefined;
423
+ history: boolean | number | "all";
424
+ routePrefix: string;
425
+ names: Required<ChatbotNames>;
426
+ tags: string[];
427
+ }
428
+ /**
429
+ * Resolve and validate options. Every check lives here, before any def is
430
+ * built, so a bad call produces one clear error rather than a half-built
431
+ * workspace or an opaque throw from deep inside core's encoder.
432
+ */
433
+ declare function resolveOptions(opts?: ChatbotOptions): ResolvedOptions;
434
+ /**
435
+ * The agent's run prompt: the whole conversation, as a rendered `messages`
436
+ * template. See `src/agent/chat-agent.ts` for the verification behind it.
437
+ */
438
+ declare const MESSAGES_TEMPLATE = "{{ $args.messages }}";
439
+
440
+ /** Build the `conversation` def for the given resolved options. */
441
+ declare function conversationTable(opts: ResolvedOptions): _xano_sdk.TableDef<_xano_sdk.SchemaCols<{
442
+ title: _xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<string, {
443
+ readonly methods: readonly ["trim"];
444
+ readonly description: "Human-readable thread title. Seeded from the first user message.";
445
+ }, "text">;
446
+ last_message_at: _xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<number, {
447
+ readonly nullable: true;
448
+ readonly description: "When the most recent message was appended. Null until the first send.";
449
+ }, "epochms">;
450
+ session_token?: (_xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<string, {
451
+ readonly access: "internal";
452
+ readonly description: "Opaque bearer capability for guest access to this thread. Treat it like a password.";
453
+ }, "text">) | undefined;
454
+ user_id?: (_xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<number, {
455
+ readonly description: "The user this conversation belongs to. Null until a guest thread is claimed.";
456
+ readonly nullable?: true | undefined;
457
+ readonly type: "int" | "uuid";
458
+ }, "int" | "uuid">) | undefined;
459
+ }>, {
460
+ id: number;
461
+ created_at: number;
462
+ title: string;
463
+ last_message_at: number | null;
464
+ session_token?: unknown;
465
+ user_id?: unknown;
466
+ }, never>;
467
+ /** The `conversation` def type, for consumers naming it explicitly. */
468
+ type ConversationTable = ReturnType<typeof conversationTable>;
469
+ /**
470
+ * A `conversation` row.
471
+ *
472
+ * Declared rather than `InferRow`-derived off a factory result, because which
473
+ * columns exist depends on the options passed — an inferred type would be
474
+ * per-call and unnameable. `user_id` and `session_token` are therefore optional
475
+ * here: present in the store exactly when their family is enabled.
476
+ */
477
+ interface Conversation {
478
+ id: number;
479
+ created_at: number;
480
+ /** Present when the authenticated family is enabled; null on an unclaimed guest thread. */
481
+ user_id?: number | string | null;
482
+ /** Present when the guest family is enabled. `internal` access — never returned by this package's endpoints. */
483
+ session_token?: string;
484
+ title: string;
485
+ last_message_at: number | null;
486
+ }
487
+ /**
488
+ * The columns this package's endpoints return for a conversation — the single
489
+ * source of truth for their `output` lists and for {@link PublicConversation},
490
+ * so the two cannot drift.
491
+ *
492
+ * `session_token` is deliberately absent: it is the guest bearer capability and
493
+ * is handed back exactly once, by the create endpoint that mints it, from that
494
+ * statement's own binding — never re-read and re-served afterwards.
495
+ */
496
+ declare const PUBLIC_CONVERSATION_FIELDS: readonly ["id", "created_at", "title", "last_message_at"];
497
+ /** The conversation projection this package's endpoints hand back. */
498
+ type PublicConversation = Pick<Conversation, (typeof PUBLIC_CONVERSATION_FIELDS)[number]>;
499
+
500
+ /**
501
+ * The roles the engine accepts in a decoded `messages` array. Exported because
502
+ * it is simultaneously the column's enum, the {@link MessageRole} type, and the
503
+ * set the reply function is allowed to write — one reviewed list, not three.
504
+ */
505
+ declare const MESSAGE_ROLES: readonly ["user", "assistant", "system"];
506
+ /** A stored message's role. */
507
+ type MessageRole = (typeof MESSAGE_ROLES)[number];
508
+ /** Build the `conversation_message` def for the given resolved options. */
509
+ declare function messageTable(opts: ResolvedOptions, conversation: ConversationTable): _xano_sdk.TableDef<_xano_sdk.SchemaCols<{
510
+ conversation_id: _xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<number, {
511
+ readonly required: true;
512
+ readonly description: "The thread this message belongs to.";
513
+ }, "int">;
514
+ role: _xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<"system" | "user" | "assistant", {
515
+ readonly required: true;
516
+ readonly description: "Who produced this turn. The engine rejects any other value when replaying it.";
517
+ }, "enum">;
518
+ content: _xano_sdk.FieldDescriptor & _xano_sdk.TypeBrand<string, {
519
+ readonly required: true;
520
+ readonly methods: readonly ["min:1"];
521
+ readonly description: "The message text. Must be non-empty — a blank turn makes the model confabulate.";
522
+ }, "text">;
523
+ }>, {
524
+ id: number;
525
+ created_at: number;
526
+ conversation_id: number;
527
+ role: "system" | "user" | "assistant";
528
+ content: string;
529
+ }, never>;
530
+ /** The `conversation_message` def type. */
531
+ type MessageTable = ReturnType<typeof messageTable>;
532
+ /** A `conversation_message` row. */
533
+ type Message = InferRow<ReturnType<typeof messageTable>>;
534
+ /**
535
+ * The columns this package's endpoints return for a message — the single source
536
+ * of truth for their `output` lists and for {@link PublicMessage}.
537
+ */
538
+ declare const PUBLIC_MESSAGE_FIELDS: readonly ["id", "created_at", "conversation_id", "role", "content"];
539
+ /** The message projection this package's endpoints hand back. */
540
+ interface PublicMessage {
541
+ id: number;
542
+ created_at: number;
543
+ conversation_id: number;
544
+ role: MessageRole;
545
+ content: string;
546
+ }
547
+
548
+ /**
549
+ * Build the agent def.
550
+ *
551
+ * `llm` arrives already merged and validated by `resolveOptions`, which also
552
+ * pins `messages` to the template and refuses a caller-supplied `prompt` /
553
+ * `messages` — see `src/options.ts`.
554
+ *
555
+ * `tools` comes from `opts.tools` and is empty by default — a tool-less agent is
556
+ * the right shape for a plain conversational assistant. When a consumer supplies
557
+ * tools, this package REFERENCES them and never registers them, exactly as it
558
+ * treats `authTable`; see `ChatbotOptions.tools`.
559
+ *
560
+ * No `output` schema, and that one is not configurable. `ChatReply.reply` is
561
+ * declared `string` and the send endpoints hand `run.result` straight back, so a
562
+ * structured-output schema would make `.result` an object where every consumer's
563
+ * type — and every markdown renderer — expects text. A caller who wants
564
+ * structured data should give the agent a TOOL that writes it, and keep the
565
+ * reply itself free text.
566
+ */
567
+ declare function chatAgent(opts: ResolvedOptions): _xano_sdk.AgentHandle<{
568
+ readonly name: string;
569
+ readonly description: "Conversational assistant. Receives the thread's recent turns as decoded LLM messages and returns the next one.";
570
+ readonly tags: string[];
571
+ readonly tools: _xano_sdk.ToolsetToolEntry[];
572
+ readonly llm: _xano_sdk.LlmSettings;
573
+ }>;
574
+ /** The agent def type. */
575
+ type ChatAgent = ReturnType<typeof chatAgent>;
576
+
577
+ /**
578
+ * Response shapes this package hand-declares.
579
+ *
580
+ * Only one, and only because core's static walk genuinely cannot see it. Every
581
+ * other endpoint's response IS derived — a projection off a `db.query`, a
582
+ * `db.add`, or a `db.edit`, all of which the walk can read off the table schema
583
+ * and the `output` list. Those stay underived on purpose, so editing a
584
+ * `PUBLIC_*_FIELDS` array moves the consumer's type with it.
585
+ */
586
+
587
+ /**
588
+ * What the send endpoints (and the reply function) hand back.
589
+ *
590
+ * Declared rather than derived because `reply` is `ref("run.result")` — the
591
+ * completion from `s.ai.agent.run`. The agent carries no `output.schema` (a chat
592
+ * reply is free text), so core resolves the run envelope's `.result` to `unknown`,
593
+ * and `unknown` propagating into every consumer's send call is the one place a
594
+ * declaration earns itself here.
595
+ *
596
+ * `string` is an assumption about the provider's completion, not something core
597
+ * pins — the same class of hand-maintained contract as `@xano-sdk/auth`'s
598
+ * `authToken: string`. The type tests pin the declared *keys* against the keys the
599
+ * walk does see, which is the part that can drift silently.
600
+ */
601
+ interface ChatReply {
602
+ /** The thread the turn was appended to — echoed back for client-side routing. */
603
+ conversation_id: number;
604
+ /**
605
+ * The assistant's reply.
606
+ *
607
+ * **Markdown.** The default system prompt asks for light markdown, because a
608
+ * chat reply reads better rendered than as a wall of plain text. Render it with
609
+ * a markdown component rather than dropping it into a text node — otherwise the
610
+ * reader sees literal `**asterisks**`. (Using a plain-text UI? Override
611
+ * `llm.systemPrompt` so the model stops emitting markup at all.)
612
+ *
613
+ * ⚠ **Render it as untrusted input.** This string is model output shaped by
614
+ * whatever the user typed, so a prompt-injection attempt can try to steer it
615
+ * into `<script>` or a `javascript:` link. Use a renderer with raw HTML
616
+ * disabled (the default in `react-markdown` and `marked`), or sanitize before
617
+ * `dangerouslySetInnerHTML`. The default prompt says not to emit raw HTML,
618
+ * which is a nudge to a model, not a guarantee — the renderer is the control.
619
+ */
620
+ reply: string;
621
+ /** The primary key of the stored assistant message. */
622
+ message_id: number;
623
+ /**
624
+ * The NAMES of the tools the agent executed on this turn, in call order —
625
+ * `[]` when the model answered directly, and `[]` on every turn of a
626
+ * tool-less install.
627
+ *
628
+ * Names only, and deliberately. A tool call also carries the arguments the
629
+ * model produced and whatever the tool returned; both are model-shaped, and a
630
+ * tool that reads data would put that data on the wire for a client that only
631
+ * asked "did anything run?". The name answers that and leaks nothing.
632
+ *
633
+ * ⚠ **Not an audit log.** A tool that THREW still appears here or does not,
634
+ * according to what the engine records for the run — the field says which
635
+ * tools the model reached for, not which of them succeeded. Read the rows a
636
+ * tool should have written if you need to know it worked.
637
+ */
638
+ tool_calls: string[];
639
+ }
640
+
641
+ /** How many characters of the first message become the auto-generated title. */
642
+ declare const TITLE_LENGTH = 60;
643
+ declare function generateReplyFn(opts: ResolvedOptions, conversation: ConversationTable, message: MessageTable, chatAgent: ChatAgent): _xano_sdk.FunctionDef<{
644
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
645
+ readonly required: true;
646
+ readonly description: "The thread to append to. NOT authorized here — the caller must have checked ownership.";
647
+ }, "int">;
648
+ readonly content: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
649
+ readonly required: true;
650
+ readonly description: "The user's message text. Must be non-empty.";
651
+ }, "text">;
652
+ }, ChatReply, {
653
+ conversation_id: _xano_sdk.InpValue<"conversation_id">;
654
+ reply: _xano_sdk.RefValue<"run.result">;
655
+ message_id: _xano_sdk.RefValue<"assistant_message.id">;
656
+ tool_calls: _xano_sdk.ConstValue<readonly []> | (_xano_sdk.TaggedValue & {
657
+ readonly __filtered: true;
658
+ readonly __base?: _xano_sdk.RefValue<"tool_call_names"> | undefined;
659
+ readonly __chain?: [_xano_sdk.FilterXdo<"filter_null">] | undefined;
660
+ });
661
+ }, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"user_message", {
662
+ id: number;
663
+ created_at: number;
664
+ conversation_id: number;
665
+ role: "system" | "user" | "assistant";
666
+ content: string;
667
+ }>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
668
+ id: number;
669
+ created_at: number;
670
+ conversation_id: number;
671
+ role: "system" | "user" | "assistant";
672
+ content: string;
673
+ }, "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"turns", _xano_sdk.ArrayMapShape<_xano_sdk.TaggedValue & {
674
+ readonly __filtered: true;
675
+ readonly __base?: _xano_sdk.RefValue<"recent"> | undefined;
676
+ readonly __chain?: [_xano_sdk.FilterXdo<"reverse">] | undefined;
677
+ }, {
678
+ readonly role: _xano_sdk.RefValue<"$this.role">;
679
+ readonly content: _xano_sdk.RefValue<"$this.content">;
680
+ }>>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages_json", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"run", _xano_sdk.AgentRunResult<string>>, ...((_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"run_steps", unknown>) | (_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"tool_call_names", readonly []>) | (_xano_sdk.Statement & _xano_sdk.MaybeBodyBrand<readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"step_calls", unknown>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"step_names", _xano_sdk.ArrayMapShape<_xano_sdk.RefValue<"step_calls">, _xano_sdk.TaggedValue & {
681
+ readonly __filtered: true;
682
+ readonly __base?: _xano_sdk.RefValue<"$this.toolName"> | undefined;
683
+ readonly __chain?: [_xano_sdk.FilterXdo<"first_notnull">, _xano_sdk.FilterXdo<"first_notnull">] | undefined;
684
+ }>>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"tool_call_names", unknown>]>))[], _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"assistant_message", {
685
+ id: number;
686
+ created_at: number;
687
+ conversation_id: number;
688
+ role: "system" | "user" | "assistant";
689
+ content: string;
690
+ }>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
691
+ id: number;
692
+ created_at: number;
693
+ title: string;
694
+ last_message_at: number | null;
695
+ session_token?: unknown;
696
+ user_id?: unknown;
697
+ }, "id" | "title"> | null>, _xano_sdk.Statement & _xano_sdk.MaybeBodyBrand<[_xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, {
698
+ id: number;
699
+ created_at: number;
700
+ title: string;
701
+ last_message_at: number | null;
702
+ session_token?: unknown;
703
+ user_id?: unknown;
704
+ }>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, {
705
+ id: number;
706
+ created_at: number;
707
+ title: string;
708
+ last_message_at: number | null;
709
+ session_token?: unknown;
710
+ user_id?: unknown;
711
+ }>]> & _xano_sdk.BranchesBrand<[readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, {
712
+ id: number;
713
+ created_at: number;
714
+ title: string;
715
+ last_message_at: number | null;
716
+ session_token?: unknown;
717
+ user_id?: unknown;
718
+ }>], readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, {
719
+ id: number;
720
+ created_at: number;
721
+ title: string;
722
+ last_message_at: number | null;
723
+ session_token?: unknown;
724
+ user_id?: unknown;
725
+ }>]]>]>;
726
+ /** The reply function's def type. */
727
+ type GenerateReplyFn = ReturnType<typeof generateReplyFn>;
728
+
729
+ declare function chatbotGroup(opts: ResolvedOptions): _xano_sdk.ApiGroupDef;
730
+ /** The API group def type. */
731
+ type ChatbotGroup = ReturnType<typeof chatbotGroup>;
732
+
733
+ declare function authenticatedQueries(opts: ResolvedOptions, group: ChatbotGroup, conversation: ConversationTable, message: MessageTable, replyFn: GenerateReplyFn): {
734
+ createConversation: _xano_sdk.QueryDef<{
735
+ readonly title: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
736
+ readonly methods: readonly ["trim"];
737
+ readonly description: "Optional thread title. Left blank, the first message's opening words become the title.";
738
+ }, "text">;
739
+ }, never, _xano_sdk.RefValue<"conversation">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"session_token", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
740
+ id: number;
741
+ created_at: number;
742
+ title: string;
743
+ last_message_at: number | null;
744
+ session_token?: unknown;
745
+ user_id?: unknown;
746
+ }, "id" | "title" | "last_message_at" | "created_at">>] | readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
747
+ id: number;
748
+ created_at: number;
749
+ title: string;
750
+ last_message_at: number | null;
751
+ session_token?: unknown;
752
+ user_id?: unknown;
753
+ }, "id" | "title" | "last_message_at" | "created_at">>], `${string}/conversations/create`, "POST"> & {
754
+ getPath: (opts?: {
755
+ canonical?: string;
756
+ }) => string;
757
+ toSearchParams: {
758
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
759
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
760
+ };
761
+ } & {
762
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
763
+ };
764
+ listConversations: _xano_sdk.QueryDef<{}, never, _xano_sdk.RefValue<"conversations">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversations", Pick<{
765
+ id: number;
766
+ created_at: number;
767
+ title: string;
768
+ last_message_at: number | null;
769
+ session_token?: unknown;
770
+ user_id?: unknown;
771
+ }, "id" | "title" | "last_message_at" | "created_at">[]>], `${string}/conversations`, "GET"> & {
772
+ getPath: (opts?: {
773
+ canonical?: string;
774
+ }) => string;
775
+ toSearchParams: {
776
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
777
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
778
+ };
779
+ } & {
780
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
781
+ };
782
+ listMessages: _xano_sdk.QueryDef<{
783
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
784
+ readonly required: true;
785
+ }, "int">;
786
+ }, PublicMessage[], _xano_sdk.RefValue<"messages">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
787
+ id: number;
788
+ created_at: number;
789
+ title: string;
790
+ last_message_at: number | null;
791
+ session_token?: unknown;
792
+ user_id?: unknown;
793
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
794
+ id: number;
795
+ created_at: number;
796
+ conversation_id: number;
797
+ role: "system" | "user" | "assistant";
798
+ content: string;
799
+ }, "id" | "created_at" | "conversation_id" | "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages", unknown>], `${string}/conversations/{conversation_id}/messages`, "GET"> & {
800
+ getPath: (opts: {
801
+ canonical?: string;
802
+ params: {
803
+ conversation_id: string | number;
804
+ };
805
+ }) => string;
806
+ toSearchParams: {
807
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
808
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
809
+ };
810
+ } & {
811
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
812
+ };
813
+ sendMessage: _xano_sdk.QueryDef<{
814
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
815
+ readonly required: true;
816
+ }, "int">;
817
+ readonly content: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
818
+ readonly required: false;
819
+ readonly methods: readonly ["trim"];
820
+ readonly description: "The user's message. Must be non-empty after trimming.";
821
+ }, "text">;
822
+ readonly message: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
823
+ readonly required: false;
824
+ readonly methods: readonly ["trim"];
825
+ readonly description: "Alias for `content`.";
826
+ }, "text">;
827
+ readonly prompt: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
828
+ readonly required: false;
829
+ readonly methods: readonly ["trim"];
830
+ readonly description: "Alias for `content`.";
831
+ }, "text">;
832
+ }, ChatReply, _xano_sdk.RefValue<"reply">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
833
+ id: number;
834
+ created_at: number;
835
+ title: string;
836
+ last_message_at: number | null;
837
+ session_token?: unknown;
838
+ user_id?: unknown;
839
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
840
+ id: number;
841
+ created_at: number;
842
+ title: string;
843
+ last_message_at: number | null;
844
+ session_token?: unknown;
845
+ user_id?: unknown;
846
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>], `${string}/conversations/{conversation_id}/send`, "POST"> & {
847
+ getPath: (opts: {
848
+ canonical?: string;
849
+ params: {
850
+ conversation_id: string | number;
851
+ };
852
+ }) => string;
853
+ toSearchParams: {
854
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
855
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
856
+ };
857
+ } & {
858
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
859
+ };
860
+ deleteConversation: _xano_sdk.QueryDef<{
861
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
862
+ readonly required: true;
863
+ }, "int">;
864
+ }, never, _xano_sdk.ConstValue<null>, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
865
+ id: number;
866
+ created_at: number;
867
+ title: string;
868
+ last_message_at: number | null;
869
+ session_token?: unknown;
870
+ user_id?: unknown;
871
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, number>, _xano_sdk.Statement], `${string}/conversations/{conversation_id}`, "DELETE"> & {
872
+ getPath: (opts: {
873
+ canonical?: string;
874
+ params: {
875
+ conversation_id: string | number;
876
+ };
877
+ }) => string;
878
+ toSearchParams: {
879
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
880
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
881
+ };
882
+ } & {
883
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
884
+ };
885
+ /** `undefined` unless the guest family is also enabled — see above. */
886
+ claimConversation: (_xano_sdk.QueryDef<{
887
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
888
+ readonly required: true;
889
+ }, "int">;
890
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
891
+ readonly required: true;
892
+ readonly description: "The guest session token the thread was created with.";
893
+ }, "text">;
894
+ }, never, _xano_sdk.RefValue<"claimed">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
895
+ id: number;
896
+ created_at: number;
897
+ title: string;
898
+ last_message_at: number | null;
899
+ session_token?: unknown;
900
+ user_id?: unknown;
901
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"claimed", Pick<{
902
+ id: number;
903
+ created_at: number;
904
+ title: string;
905
+ last_message_at: number | null;
906
+ session_token?: unknown;
907
+ user_id?: unknown;
908
+ }, "id" | "title" | "last_message_at" | "created_at">>], `${string}/conversations/{conversation_id}/claim`, "POST"> & {
909
+ getPath: (opts: {
910
+ canonical?: string;
911
+ params: {
912
+ conversation_id: string | number;
913
+ };
914
+ }) => string;
915
+ toSearchParams: {
916
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
917
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
918
+ };
919
+ } & {
920
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
921
+ }) | undefined;
922
+ /**
923
+ * Every def above that actually exists, ready to register. Built as one array
924
+ * literal rather than a `push`, so the element type is the union of the
925
+ * handles rather than the first one's — each `query()` handle carries its own
926
+ * literal `name` in its type, so a mutable array would fix that type to
927
+ * whichever def happened to be first.
928
+ */
929
+ all: ((_xano_sdk.QueryDef<{
930
+ readonly title: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
931
+ readonly methods: readonly ["trim"];
932
+ readonly description: "Optional thread title. Left blank, the first message's opening words become the title.";
933
+ }, "text">;
934
+ }, never, _xano_sdk.RefValue<"conversation">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"session_token", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
935
+ id: number;
936
+ created_at: number;
937
+ title: string;
938
+ last_message_at: number | null;
939
+ session_token?: unknown;
940
+ user_id?: unknown;
941
+ }, "id" | "title" | "last_message_at" | "created_at">>] | readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
942
+ id: number;
943
+ created_at: number;
944
+ title: string;
945
+ last_message_at: number | null;
946
+ session_token?: unknown;
947
+ user_id?: unknown;
948
+ }, "id" | "title" | "last_message_at" | "created_at">>], `${string}/conversations/create`, "POST"> & {
949
+ getPath: (opts?: {
950
+ canonical?: string;
951
+ }) => string;
952
+ toSearchParams: {
953
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
954
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
955
+ };
956
+ } & {
957
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
958
+ }) | (_xano_sdk.QueryDef<{}, never, _xano_sdk.RefValue<"conversations">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversations", Pick<{
959
+ id: number;
960
+ created_at: number;
961
+ title: string;
962
+ last_message_at: number | null;
963
+ session_token?: unknown;
964
+ user_id?: unknown;
965
+ }, "id" | "title" | "last_message_at" | "created_at">[]>], `${string}/conversations`, "GET"> & {
966
+ getPath: (opts?: {
967
+ canonical?: string;
968
+ }) => string;
969
+ toSearchParams: {
970
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
971
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
972
+ };
973
+ } & {
974
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
975
+ }) | (_xano_sdk.QueryDef<{
976
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
977
+ readonly required: true;
978
+ }, "int">;
979
+ }, PublicMessage[], _xano_sdk.RefValue<"messages">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
980
+ id: number;
981
+ created_at: number;
982
+ title: string;
983
+ last_message_at: number | null;
984
+ session_token?: unknown;
985
+ user_id?: unknown;
986
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
987
+ id: number;
988
+ created_at: number;
989
+ conversation_id: number;
990
+ role: "system" | "user" | "assistant";
991
+ content: string;
992
+ }, "id" | "created_at" | "conversation_id" | "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages", unknown>], `${string}/conversations/{conversation_id}/messages`, "GET"> & {
993
+ getPath: (opts: {
994
+ canonical?: string;
995
+ params: {
996
+ conversation_id: string | number;
997
+ };
998
+ }) => string;
999
+ toSearchParams: {
1000
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1001
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1002
+ };
1003
+ } & {
1004
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
1005
+ }) | (_xano_sdk.QueryDef<{
1006
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1007
+ readonly required: true;
1008
+ }, "int">;
1009
+ readonly content: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1010
+ readonly required: false;
1011
+ readonly methods: readonly ["trim"];
1012
+ readonly description: "The user's message. Must be non-empty after trimming.";
1013
+ }, "text">;
1014
+ readonly message: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1015
+ readonly required: false;
1016
+ readonly methods: readonly ["trim"];
1017
+ readonly description: "Alias for `content`.";
1018
+ }, "text">;
1019
+ readonly prompt: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1020
+ readonly required: false;
1021
+ readonly methods: readonly ["trim"];
1022
+ readonly description: "Alias for `content`.";
1023
+ }, "text">;
1024
+ }, ChatReply, _xano_sdk.RefValue<"reply">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1025
+ id: number;
1026
+ created_at: number;
1027
+ title: string;
1028
+ last_message_at: number | null;
1029
+ session_token?: unknown;
1030
+ user_id?: unknown;
1031
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1032
+ id: number;
1033
+ created_at: number;
1034
+ title: string;
1035
+ last_message_at: number | null;
1036
+ session_token?: unknown;
1037
+ user_id?: unknown;
1038
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>], `${string}/conversations/{conversation_id}/send`, "POST"> & {
1039
+ getPath: (opts: {
1040
+ canonical?: string;
1041
+ params: {
1042
+ conversation_id: string | number;
1043
+ };
1044
+ }) => string;
1045
+ toSearchParams: {
1046
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1047
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1048
+ };
1049
+ } & {
1050
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
1051
+ }) | (_xano_sdk.QueryDef<{
1052
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1053
+ readonly required: true;
1054
+ }, "int">;
1055
+ }, never, _xano_sdk.ConstValue<null>, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1056
+ id: number;
1057
+ created_at: number;
1058
+ title: string;
1059
+ last_message_at: number | null;
1060
+ session_token?: unknown;
1061
+ user_id?: unknown;
1062
+ }, "id" | "user_id"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, number>, _xano_sdk.Statement], `${string}/conversations/{conversation_id}`, "DELETE"> & {
1063
+ getPath: (opts: {
1064
+ canonical?: string;
1065
+ params: {
1066
+ conversation_id: string | number;
1067
+ };
1068
+ }) => string;
1069
+ toSearchParams: {
1070
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1071
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1072
+ };
1073
+ } & {
1074
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
1075
+ }) | (_xano_sdk.QueryDef<{
1076
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1077
+ readonly required: true;
1078
+ }, "int">;
1079
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1080
+ readonly required: true;
1081
+ readonly description: "The guest session token the thread was created with.";
1082
+ }, "text">;
1083
+ }, never, _xano_sdk.RefValue<"claimed">, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1084
+ id: number;
1085
+ created_at: number;
1086
+ title: string;
1087
+ last_message_at: number | null;
1088
+ session_token?: unknown;
1089
+ user_id?: unknown;
1090
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"claimed", Pick<{
1091
+ id: number;
1092
+ created_at: number;
1093
+ title: string;
1094
+ last_message_at: number | null;
1095
+ session_token?: unknown;
1096
+ user_id?: unknown;
1097
+ }, "id" | "title" | "last_message_at" | "created_at">>], `${string}/conversations/{conversation_id}/claim`, "POST"> & {
1098
+ getPath: (opts: {
1099
+ canonical?: string;
1100
+ params: {
1101
+ conversation_id: string | number;
1102
+ };
1103
+ }) => string;
1104
+ toSearchParams: {
1105
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1106
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1107
+ };
1108
+ } & {
1109
+ auth?: string | _xano_sdk.TableDef<string, unknown, string> | undefined;
1110
+ }))[];
1111
+ };
1112
+
1113
+ declare function guestQueries(opts: ResolvedOptions, group: ChatbotGroup, conversation: ConversationTable, message: MessageTable, replyFn: GenerateReplyFn): {
1114
+ createConversation: _xano_sdk.QueryDef<{
1115
+ readonly title: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1116
+ readonly methods: readonly ["trim"];
1117
+ readonly description: "Optional thread title. Left blank, the first message's opening words become the title.";
1118
+ }, "text">;
1119
+ }, never, {
1120
+ id: _xano_sdk.RefValue<"conversation.id">;
1121
+ created_at: _xano_sdk.RefValue<"conversation.created_at">;
1122
+ title: _xano_sdk.RefValue<"conversation.title">;
1123
+ last_message_at: _xano_sdk.RefValue<"conversation.last_message_at">;
1124
+ session_token: _xano_sdk.RefValue<"session_token">;
1125
+ }, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"session_token", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1126
+ id: number;
1127
+ created_at: number;
1128
+ title: string;
1129
+ last_message_at: number | null;
1130
+ session_token?: unknown;
1131
+ user_id?: unknown;
1132
+ }, "id" | "title" | "last_message_at" | "created_at">>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"session_token", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1133
+ id: number;
1134
+ created_at: number;
1135
+ title: string;
1136
+ last_message_at: number | null;
1137
+ session_token?: unknown;
1138
+ user_id?: unknown;
1139
+ }, "id" | "title" | "last_message_at" | "created_at">>], `${string}/guest/conversations/create`, "POST"> & {
1140
+ getPath: (opts?: {
1141
+ canonical?: string;
1142
+ }) => string;
1143
+ toSearchParams: {
1144
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1145
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1146
+ };
1147
+ } & {
1148
+ auth?: unknown;
1149
+ };
1150
+ listMessages: _xano_sdk.QueryDef<{
1151
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1152
+ readonly required: true;
1153
+ }, "int">;
1154
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1155
+ readonly required: true;
1156
+ readonly description: "The token returned when the conversation was created.";
1157
+ }, "text">;
1158
+ }, PublicMessage[], _xano_sdk.RefValue<"messages">, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1159
+ id: number;
1160
+ created_at: number;
1161
+ title: string;
1162
+ last_message_at: number | null;
1163
+ session_token?: unknown;
1164
+ user_id?: unknown;
1165
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
1166
+ id: number;
1167
+ created_at: number;
1168
+ conversation_id: number;
1169
+ role: "system" | "user" | "assistant";
1170
+ content: string;
1171
+ }, "id" | "created_at" | "conversation_id" | "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages", unknown>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1172
+ id: number;
1173
+ created_at: number;
1174
+ title: string;
1175
+ last_message_at: number | null;
1176
+ session_token?: unknown;
1177
+ user_id?: unknown;
1178
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
1179
+ id: number;
1180
+ created_at: number;
1181
+ conversation_id: number;
1182
+ role: "system" | "user" | "assistant";
1183
+ content: string;
1184
+ }, "id" | "created_at" | "conversation_id" | "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages", unknown>], `${string}/guest/conversations/{conversation_id}/messages`, "GET"> & {
1185
+ getPath: (opts: {
1186
+ canonical?: string;
1187
+ params: {
1188
+ conversation_id: string | number;
1189
+ };
1190
+ }) => string;
1191
+ toSearchParams: {
1192
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1193
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1194
+ };
1195
+ } & {
1196
+ auth?: unknown;
1197
+ };
1198
+ sendMessage: _xano_sdk.QueryDef<{
1199
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1200
+ readonly required: true;
1201
+ }, "int">;
1202
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1203
+ readonly required: true;
1204
+ }, "text">;
1205
+ readonly content: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1206
+ readonly required: false;
1207
+ readonly methods: readonly ["trim"];
1208
+ readonly description: "The user's message. Must be non-empty after trimming.";
1209
+ }, "text">;
1210
+ readonly message: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1211
+ readonly required: false;
1212
+ readonly methods: readonly ["trim"];
1213
+ readonly description: "Alias for `content`.";
1214
+ }, "text">;
1215
+ readonly prompt: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1216
+ readonly required: false;
1217
+ readonly methods: readonly ["trim"];
1218
+ readonly description: "Alias for `content`.";
1219
+ }, "text">;
1220
+ }, ChatReply, _xano_sdk.RefValue<"reply">, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1221
+ id: number;
1222
+ created_at: number;
1223
+ title: string;
1224
+ last_message_at: number | null;
1225
+ session_token?: unknown;
1226
+ user_id?: unknown;
1227
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1228
+ id: number;
1229
+ created_at: number;
1230
+ title: string;
1231
+ last_message_at: number | null;
1232
+ session_token?: unknown;
1233
+ user_id?: unknown;
1234
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1235
+ id: number;
1236
+ created_at: number;
1237
+ title: string;
1238
+ last_message_at: number | null;
1239
+ session_token?: unknown;
1240
+ user_id?: unknown;
1241
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1242
+ id: number;
1243
+ created_at: number;
1244
+ title: string;
1245
+ last_message_at: number | null;
1246
+ session_token?: unknown;
1247
+ user_id?: unknown;
1248
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>], `${string}/guest/conversations/{conversation_id}/send`, "POST"> & {
1249
+ getPath: (opts: {
1250
+ canonical?: string;
1251
+ params: {
1252
+ conversation_id: string | number;
1253
+ };
1254
+ }) => string;
1255
+ toSearchParams: {
1256
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1257
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1258
+ };
1259
+ } & {
1260
+ auth?: unknown;
1261
+ };
1262
+ deleteConversation: _xano_sdk.QueryDef<{
1263
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1264
+ readonly required: true;
1265
+ }, "int">;
1266
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1267
+ readonly required: true;
1268
+ }, "text">;
1269
+ }, never, _xano_sdk.ConstValue<null>, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1270
+ id: number;
1271
+ created_at: number;
1272
+ title: string;
1273
+ last_message_at: number | null;
1274
+ session_token?: unknown;
1275
+ user_id?: unknown;
1276
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, number>, _xano_sdk.Statement] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1277
+ id: number;
1278
+ created_at: number;
1279
+ title: string;
1280
+ last_message_at: number | null;
1281
+ session_token?: unknown;
1282
+ user_id?: unknown;
1283
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, number>, _xano_sdk.Statement], `${string}/guest/conversations/{conversation_id}/delete`, "POST"> & {
1284
+ getPath: (opts: {
1285
+ canonical?: string;
1286
+ params: {
1287
+ conversation_id: string | number;
1288
+ };
1289
+ }) => string;
1290
+ toSearchParams: {
1291
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1292
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1293
+ };
1294
+ } & {
1295
+ auth?: unknown;
1296
+ };
1297
+ all: ((_xano_sdk.QueryDef<{
1298
+ readonly title: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1299
+ readonly methods: readonly ["trim"];
1300
+ readonly description: "Optional thread title. Left blank, the first message's opening words become the title.";
1301
+ }, "text">;
1302
+ }, never, {
1303
+ id: _xano_sdk.RefValue<"conversation.id">;
1304
+ created_at: _xano_sdk.RefValue<"conversation.created_at">;
1305
+ title: _xano_sdk.RefValue<"conversation.title">;
1306
+ last_message_at: _xano_sdk.RefValue<"conversation.last_message_at">;
1307
+ session_token: _xano_sdk.RefValue<"session_token">;
1308
+ }, readonly [_xano_sdk.Statement & _xano_sdk.AsShapeBrand<"session_token", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1309
+ id: number;
1310
+ created_at: number;
1311
+ title: string;
1312
+ last_message_at: number | null;
1313
+ session_token?: unknown;
1314
+ user_id?: unknown;
1315
+ }, "id" | "title" | "last_message_at" | "created_at">>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"session_token", string>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1316
+ id: number;
1317
+ created_at: number;
1318
+ title: string;
1319
+ last_message_at: number | null;
1320
+ session_token?: unknown;
1321
+ user_id?: unknown;
1322
+ }, "id" | "title" | "last_message_at" | "created_at">>], `${string}/guest/conversations/create`, "POST"> & {
1323
+ getPath: (opts?: {
1324
+ canonical?: string;
1325
+ }) => string;
1326
+ toSearchParams: {
1327
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1328
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1329
+ };
1330
+ } & {
1331
+ auth?: unknown;
1332
+ }) | (_xano_sdk.QueryDef<{
1333
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1334
+ readonly required: true;
1335
+ }, "int">;
1336
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1337
+ readonly required: true;
1338
+ readonly description: "The token returned when the conversation was created.";
1339
+ }, "text">;
1340
+ }, PublicMessage[], _xano_sdk.RefValue<"messages">, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1341
+ id: number;
1342
+ created_at: number;
1343
+ title: string;
1344
+ last_message_at: number | null;
1345
+ session_token?: unknown;
1346
+ user_id?: unknown;
1347
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
1348
+ id: number;
1349
+ created_at: number;
1350
+ conversation_id: number;
1351
+ role: "system" | "user" | "assistant";
1352
+ content: string;
1353
+ }, "id" | "created_at" | "conversation_id" | "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages", unknown>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1354
+ id: number;
1355
+ created_at: number;
1356
+ title: string;
1357
+ last_message_at: number | null;
1358
+ session_token?: unknown;
1359
+ user_id?: unknown;
1360
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"recent", Pick<{
1361
+ id: number;
1362
+ created_at: number;
1363
+ conversation_id: number;
1364
+ role: "system" | "user" | "assistant";
1365
+ content: string;
1366
+ }, "id" | "created_at" | "conversation_id" | "role" | "content">[]>, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"messages", unknown>], `${string}/guest/conversations/{conversation_id}/messages`, "GET"> & {
1367
+ getPath: (opts: {
1368
+ canonical?: string;
1369
+ params: {
1370
+ conversation_id: string | number;
1371
+ };
1372
+ }) => string;
1373
+ toSearchParams: {
1374
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1375
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1376
+ };
1377
+ } & {
1378
+ auth?: unknown;
1379
+ }) | (_xano_sdk.QueryDef<{
1380
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1381
+ readonly required: true;
1382
+ }, "int">;
1383
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1384
+ readonly required: true;
1385
+ }, "text">;
1386
+ readonly content: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1387
+ readonly required: false;
1388
+ readonly methods: readonly ["trim"];
1389
+ readonly description: "The user's message. Must be non-empty after trimming.";
1390
+ }, "text">;
1391
+ readonly message: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1392
+ readonly required: false;
1393
+ readonly methods: readonly ["trim"];
1394
+ readonly description: "Alias for `content`.";
1395
+ }, "text">;
1396
+ readonly prompt: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1397
+ readonly required: false;
1398
+ readonly methods: readonly ["trim"];
1399
+ readonly description: "Alias for `content`.";
1400
+ }, "text">;
1401
+ }, ChatReply, _xano_sdk.RefValue<"reply">, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1402
+ id: number;
1403
+ created_at: number;
1404
+ title: string;
1405
+ last_message_at: number | null;
1406
+ session_token?: unknown;
1407
+ user_id?: unknown;
1408
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1409
+ id: number;
1410
+ created_at: number;
1411
+ title: string;
1412
+ last_message_at: number | null;
1413
+ session_token?: unknown;
1414
+ user_id?: unknown;
1415
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1416
+ id: number;
1417
+ created_at: number;
1418
+ title: string;
1419
+ last_message_at: number | null;
1420
+ session_token?: unknown;
1421
+ user_id?: unknown;
1422
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>] | readonly [_xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1423
+ id: number;
1424
+ created_at: number;
1425
+ title: string;
1426
+ last_message_at: number | null;
1427
+ session_token?: unknown;
1428
+ user_id?: unknown;
1429
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"resolved_turn_content", unknown>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"reply", ChatReply>], `${string}/guest/conversations/{conversation_id}/send`, "POST"> & {
1430
+ getPath: (opts: {
1431
+ canonical?: string;
1432
+ params: {
1433
+ conversation_id: string | number;
1434
+ };
1435
+ }) => string;
1436
+ toSearchParams: {
1437
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1438
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1439
+ };
1440
+ } & {
1441
+ auth?: unknown;
1442
+ }) | (_xano_sdk.QueryDef<{
1443
+ readonly conversation_id: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<number, {
1444
+ readonly required: true;
1445
+ }, "int">;
1446
+ readonly session_token: _xano_sdk.InputDescriptor & _xano_sdk.TypeBrand<string, {
1447
+ readonly required: true;
1448
+ }, "text">;
1449
+ }, never, _xano_sdk.ConstValue<null>, readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1450
+ id: number;
1451
+ created_at: number;
1452
+ title: string;
1453
+ last_message_at: number | null;
1454
+ session_token?: unknown;
1455
+ user_id?: unknown;
1456
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, number>, _xano_sdk.Statement] | readonly [_xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<"conversation", Pick<{
1457
+ id: number;
1458
+ created_at: number;
1459
+ title: string;
1460
+ last_message_at: number | null;
1461
+ session_token?: unknown;
1462
+ user_id?: unknown;
1463
+ }, "id" | "user_id" | "session_token"> | null>, _xano_sdk.Statement, _xano_sdk.Statement & _xano_sdk.AsShapeBrand<string, number>, _xano_sdk.Statement], `${string}/guest/conversations/{conversation_id}/delete`, "POST"> & {
1464
+ getPath: (opts: {
1465
+ canonical?: string;
1466
+ params: {
1467
+ conversation_id: string | number;
1468
+ };
1469
+ }) => string;
1470
+ toSearchParams: {
1471
+ (input: Record<string, _xano_sdk.SearchParamValue>): _xano_sdk.SearchParams;
1472
+ (input: Record<string, unknown>): _xano_sdk.SearchParams;
1473
+ };
1474
+ } & {
1475
+ auth?: unknown;
1476
+ }))[];
1477
+ };
1478
+
1479
+ /**
1480
+ * `createChatbot(opts)` — build every def for one configuration.
1481
+ * `registerChatbot(xano, opts)` — build them and register them in one call.
1482
+ *
1483
+ * There is **no cross-call agreement checking** here, unlike `@xano-sdk/auth`'s
1484
+ * `registerAuth`. Auth needs it because its `authenticationGroup` is a
1485
+ * process-wide module singleton: a second `registerAuth` could silently retarget
1486
+ * the first workspace's group, and omitting an option could make one workspace
1487
+ * inherit another's canonical. Every def here is minted fresh per
1488
+ * `createChatbot` call, so two calls simply produce two independent sets and
1489
+ * there is nothing to reconcile.
1490
+ *
1491
+ * There IS an idempotency guard, for a different reason. Core's own duplicate-def
1492
+ * guard compares def **identity**, and two `createChatbot` calls produce distinct
1493
+ * objects that merely share names — so a second `registerChatbot` on one instance
1494
+ * slips past it and fails much later at `export()` with
1495
+ *
1496
+ * Duplicate object guid (82dcb96…) shared by "dbo/conversation" and "dbo/conversation"
1497
+ *
1498
+ * which names one guid, the same label twice, and neither call. The WeakSet below
1499
+ * reports it at the call that made it.
1500
+ */
1501
+
1502
+ /** The token-authenticated endpoint family. */
1503
+ type AuthenticatedFamily = ReturnType<typeof authenticatedQueries>;
1504
+ /** The public guest endpoint family. */
1505
+ type GuestFamily = ReturnType<typeof guestQueries>;
1506
+ /**
1507
+ * Which families a given options object produces, decided at the type level.
1508
+ *
1509
+ * `authenticated` defaults to **true** and `guest` to **false**, so for the
1510
+ * overwhelmingly common call — `registerChatbot(xano, { authTable })` — these
1511
+ * resolve to a present `authenticated` and an absent `guest`, and a consumer
1512
+ * writes `bot.authenticated.sendMessage` with no `!`. Typing both as
1513
+ * `| undefined` unconditionally made every caller pay for a configuration
1514
+ * almost none of them use.
1515
+ *
1516
+ * A non-literal flag (`{ guest: someBoolean }`) is genuinely unknowable at
1517
+ * compile time, so it widens back to `… | undefined` — correct, and the only
1518
+ * case that still needs a check.
1519
+ *
1520
+ * ⚠ Written as structural `O extends { authenticated: … }` checks rather than the
1521
+ * shorter indexed access `O["authenticated"]`. When the key is ABSENT from `O`,
1522
+ * an indexed access falls back to the CONSTRAINT — `boolean | undefined` — so
1523
+ * every default install looked like a runtime boolean and stayed nullable, which
1524
+ * is the exact papercut this exists to remove. `extends` detects the missing key.
1525
+ */
1526
+ type AuthenticatedOf<O extends ChatbotOptions> = O extends {
1527
+ authenticated: false;
1528
+ } ? undefined : O extends {
1529
+ authenticated: true;
1530
+ } ? AuthenticatedFamily : O extends {
1531
+ authenticated: boolean;
1532
+ } ? AuthenticatedFamily | undefined : AuthenticatedFamily;
1533
+ /** @see {@link AuthenticatedOf} — the same rule, inverted (guest is off by default). */
1534
+ type GuestOf<O extends ChatbotOptions> = O extends {
1535
+ guest: true;
1536
+ } ? GuestFamily : O extends {
1537
+ guest: false;
1538
+ } ? undefined : O extends {
1539
+ guest: boolean;
1540
+ } ? GuestFamily | undefined : undefined;
1541
+ /**
1542
+ * Everything one `createChatbot` call produces.
1543
+ *
1544
+ * Parameterized by the options it was built from, so `authenticated` and `guest`
1545
+ * are present or absent according to those options rather than always nullable.
1546
+ * The bare `Chatbot` (no type argument) keeps both nullable — it describes *any*
1547
+ * configuration, which is what a variable annotated by hand should mean.
1548
+ */
1549
+ interface Chatbot<O extends ChatbotOptions = ChatbotOptions> {
1550
+ /** The resolved, fully-defaulted options these defs were built from. */
1551
+ options: ResolvedOptions;
1552
+ conversation: ReturnType<typeof conversationTable>;
1553
+ message: ReturnType<typeof messageTable>;
1554
+ agent: ReturnType<typeof chatAgent>;
1555
+ replyFn: ReturnType<typeof generateReplyFn>;
1556
+ group: ReturnType<typeof chatbotGroup>;
1557
+ /** The authenticated family. Absent only with `{ authenticated: false }`. */
1558
+ authenticated: AuthenticatedOf<O>;
1559
+ /** The guest family. Present only with `{ guest: true }`. */
1560
+ guest: GuestOf<O>;
1561
+ /** Every query def across both enabled families, ready for `registerQueries`. */
1562
+ queries: (AuthenticatedFamily["all"][number] | GuestFamily["all"][number])[];
1563
+ }
1564
+ /**
1565
+ * Build the full def set without registering anything.
1566
+ *
1567
+ * Reach for this over `registerChatbot` when you want to cherry-pick, reorder
1568
+ * registration around your own defs, or reference a def (the agent, the message
1569
+ * table) from a stack of your own. This is the cherry-pick path — a factory
1570
+ * package has no module-level def to import.
1571
+ *
1572
+ * ```ts
1573
+ * const bot = createChatbot({ authTable: userTable });
1574
+ * xano.registerTables([bot.conversation, bot.message]);
1575
+ * // …register only the endpoints you want
1576
+ * xano.registerQueries([bot.authenticated.sendMessage]);
1577
+ * ```
1578
+ *
1579
+ * Dependencies travel together: the queries need both tables, the reply function
1580
+ * and the agent; the reply function needs both tables and the agent. Registering
1581
+ * a query without them exports a reference to an object the workspace does not
1582
+ * hold, which fails the export.
1583
+ */
1584
+ declare function createChatbot<const O extends ChatbotOptions = Record<string, never>>(opts?: O): Chatbot<O>;
1585
+ /** What {@link registerChatbot} hands back: the def set, plus the instance it was registered on. */
1586
+ interface RegisteredChatbot<X extends Xano, O extends ChatbotOptions = ChatbotOptions> extends Chatbot<O> {
1587
+ /**
1588
+ * The instance the defs were registered on — the same object that was passed
1589
+ * in, for `export default`.
1590
+ */
1591
+ xano: X;
1592
+ }
1593
+ /**
1594
+ * Build and register the full set on the given instance.
1595
+ *
1596
+ * ```ts
1597
+ * import { workspace } from "@xano/sdk";
1598
+ * import { registerAuth, userTable } from "@xano-sdk/auth";
1599
+ * import { registerChatbot } from "@xano-sdk/chatbot";
1600
+ *
1601
+ * const xano = registerAuth(workspace("my-app"));
1602
+ * export const bot = registerChatbot(xano, { authTable: userTable });
1603
+ *
1604
+ * export default bot.xano; // the default export must be the Xano registry
1605
+ * ```
1606
+ *
1607
+ * **Why this returns the defs and not the instance.** The defs are factories, so
1608
+ * a consumer has no `import { sendMessage }` to point `InferInput<typeof …>` at —
1609
+ * the handle returned here is the only route to the real, registered defs.
1610
+ * Returning the bare instance made the turnkey path structurally un-typeable and
1611
+ * pushed frontends into calling {@link createChatbot} a second time at runtime,
1612
+ * which drags the whole statement graph into the browser bundle to obtain a type
1613
+ * that erases. Exporting `bot` and importing it with `import type` costs nothing:
1614
+ *
1615
+ * ```ts
1616
+ * // frontend — erases completely at build time
1617
+ * import type { bot } from "../xano/index.js";
1618
+ * type Send = typeof bot.authenticated.sendMessage;
1619
+ * ```
1620
+ *
1621
+ * For the common shapes there is no need to drill at all — `SendMessageBody`,
1622
+ * `ChatReply`, `ListConversationsResponse` and friends are exported directly.
1623
+ *
1624
+ * Note what the example does *not* do: this package never registers the auth
1625
+ * table. It only references it, and a reference resolves through the same
1626
+ * name-derived guid the table itself emits, so registration order does not matter
1627
+ * — and a consumer whose auth table is already registered by `registerAuth` (or by
1628
+ * hand) does not get a duplicate.
1629
+ *
1630
+ * Use {@link createChatbot} when you want the defs *without* registering them —
1631
+ * to cherry-pick a subset, or to reference one from a stack of your own.
1632
+ */
1633
+ declare function registerChatbot<X extends Xano, const O extends ChatbotOptions = Record<string, never>>(xano: X, opts?: O): RegisteredChatbot<X, O>;
1634
+
1635
+ /**
1636
+ * Request and response types for every endpoint — what a client sends and gets
1637
+ * back, and **where each input travels**.
1638
+ *
1639
+ * These exist because the defs are **factories** (see `register.ts`), so there is
1640
+ * no module-level `sendMessage` to write `InferInput<typeof sendMessage>`
1641
+ * against. Reaching the handles through the factory's return type is a type-level
1642
+ * operation — nothing is built, nothing is evaluated — so a browser importing
1643
+ * these pulls in no statement stack and no SDK runtime.
1644
+ *
1645
+ * ## The naming rule
1646
+ *
1647
+ * Every name is `<HandleName><Part>`, where the handle name is exactly the
1648
+ * property on `bot.authenticated` / `bot.guest` (`sendMessage` →
1649
+ * `SendMessage…`). One vocabulary for the def, the type, and the endpoint map.
1650
+ *
1651
+ * | part | is | goes |
1652
+ * |---|---|---|
1653
+ * | `…Params` | path parameters | interpolated into the URL |
1654
+ * | `…Query` | query-string parameters | `?a=b` |
1655
+ * | `…Body` | the JSON body | the request body |
1656
+ * | `…Input` | everything core derives — all three at once | — |
1657
+ * | `…Response` | what comes back | — |
1658
+ *
1659
+ * A part that an endpoint does not have is simply not exported for it, so the
1660
+ * presence of a name is itself the answer to "does this take a body?".
1661
+ *
1662
+ * **Why the split matters.** `…Input` alone is not enough to write a request:
1663
+ * `SendMessageInput` contains `conversation_id`, but that is read off the URL,
1664
+ * so `JSON.stringify(input)` sends a field the endpoint ignores while the type
1665
+ * still demands it. That forced `Partial<…>` on every call and threw away the
1666
+ * check on the field you *do* have to send. It is security-relevant on the guest
1667
+ * family too: `session_token` is a bearer credential, and whether it belongs in
1668
+ * the query string or the body is exactly the distinction
1669
+ * `GuestListMessagesQuery` vs `GuestSendMessageBody` encodes.
1670
+ */
1671
+
1672
+ /** The authenticated family's handles, as types. Builds nothing. */
1673
+ type Auth = ReturnType<typeof authenticatedQueries>;
1674
+ /** The guest family's handles, as types. Builds nothing. */
1675
+ type Guest = ReturnType<typeof guestQueries>;
1676
+ /** The path parameter every per-thread route carries. */
1677
+ type Thread = "conversation_id";
1678
+ /** `POST {prefix}/conversations/create` */
1679
+ type CreateConversationInput = InferInput<Auth["createConversation"]>;
1680
+ /** `POST {prefix}/conversations/create` — the JSON body (`{}` is valid). */
1681
+ type CreateConversationBody = CreateConversationInput;
1682
+ /** `POST {prefix}/conversations/create` */
1683
+ type CreateConversationResponse = InferResponse<Auth["createConversation"]>;
1684
+ /** `GET {prefix}/conversations` — takes nothing. */
1685
+ type ListConversationsResponse = InferResponse<Auth["listConversations"]>;
1686
+ /** `GET {prefix}/conversations/{conversation_id}/messages` */
1687
+ type ListMessagesInput = InferInput<Auth["listMessages"]>;
1688
+ /** `GET {prefix}/conversations/{conversation_id}/messages` — path parameters. */
1689
+ type ListMessagesParams = Pick<ListMessagesInput, Thread>;
1690
+ /** `GET {prefix}/conversations/{conversation_id}/messages` — oldest message first. */
1691
+ type ListMessagesResponse = InferResponse<Auth["listMessages"]>;
1692
+ /** `POST {prefix}/conversations/{conversation_id}/send` */
1693
+ type SendMessageInput = InferInput<Auth["sendMessage"]>;
1694
+ /** `POST {prefix}/conversations/{conversation_id}/send` — path parameters. */
1695
+ type SendMessageParams = Pick<SendMessageInput, Thread>;
1696
+ /** `POST {prefix}/conversations/{conversation_id}/send` — the JSON body. */
1697
+ type SendMessageBody = Omit<SendMessageInput, Thread>;
1698
+ /** `POST {prefix}/conversations/{conversation_id}/send` — this is `ChatReply`. */
1699
+ type SendMessageResponse = InferResponse<Auth["sendMessage"]>;
1700
+ /** `DELETE {prefix}/conversations/{conversation_id}` */
1701
+ type DeleteConversationInput = InferInput<Auth["deleteConversation"]>;
1702
+ /** `DELETE {prefix}/conversations/{conversation_id}` — path parameters. */
1703
+ type DeleteConversationParams = Pick<DeleteConversationInput, Thread>;
1704
+ /** `DELETE {prefix}/conversations/{conversation_id}` — returns `null`. */
1705
+ type DeleteConversationResponse = InferResponse<Auth["deleteConversation"]>;
1706
+ /** `POST {prefix}/conversations/{conversation_id}/claim` — only with `{ guest: true }`. */
1707
+ type ClaimConversationInput = InferInput<NonNullable<Auth["claimConversation"]>>;
1708
+ /** `POST {prefix}/conversations/{conversation_id}/claim` — path parameters. */
1709
+ type ClaimConversationParams = Pick<ClaimConversationInput, Thread>;
1710
+ /** `POST {prefix}/conversations/{conversation_id}/claim` — the JSON body (carries the guest token). */
1711
+ type ClaimConversationBody = Omit<ClaimConversationInput, Thread>;
1712
+ /** `POST {prefix}/conversations/{conversation_id}/claim` */
1713
+ type ClaimConversationResponse = InferResponse<NonNullable<Auth["claimConversation"]>>;
1714
+ /** `POST {prefix}/guest/conversations/create` */
1715
+ type GuestCreateConversationInput = InferInput<Guest["createConversation"]>;
1716
+ /** `POST {prefix}/guest/conversations/create` — the JSON body (`{}` is valid). */
1717
+ type GuestCreateConversationBody = GuestCreateConversationInput;
1718
+ /**
1719
+ * `POST {prefix}/guest/conversations/create`
1720
+ *
1721
+ * ⚠ The only response that ever carries `session_token`. Store it as a
1722
+ * credential; anyone holding it owns the thread until it is claimed.
1723
+ */
1724
+ type GuestCreateConversationResponse = InferResponse<Guest["createConversation"]>;
1725
+ /** `GET {prefix}/guest/conversations/{conversation_id}/messages` */
1726
+ type GuestListMessagesInput = InferInput<Guest["listMessages"]>;
1727
+ /** `GET {prefix}/guest/conversations/{conversation_id}/messages` — path parameters. */
1728
+ type GuestListMessagesParams = Pick<GuestListMessagesInput, Thread>;
1729
+ /**
1730
+ * `GET {prefix}/guest/conversations/{conversation_id}/messages` — query string.
1731
+ *
1732
+ * ⚠ A `GET` has no body, so the token rides in the URL here and will reach
1733
+ * access logs, proxies and `Referer` headers. That is why the *delete* endpoint
1734
+ * is a `POST` instead — see {@link GuestDeleteConversationBody}.
1735
+ */
1736
+ type GuestListMessagesQuery = Omit<GuestListMessagesInput, Thread>;
1737
+ /** `GET {prefix}/guest/conversations/{conversation_id}/messages` */
1738
+ type GuestListMessagesResponse = InferResponse<Guest["listMessages"]>;
1739
+ /** `POST {prefix}/guest/conversations/{conversation_id}/send` */
1740
+ type GuestSendMessageInput = InferInput<Guest["sendMessage"]>;
1741
+ /** `POST {prefix}/guest/conversations/{conversation_id}/send` — path parameters. */
1742
+ type GuestSendMessageParams = Pick<GuestSendMessageInput, Thread>;
1743
+ /** `POST {prefix}/guest/conversations/{conversation_id}/send` — the JSON body, token included. */
1744
+ type GuestSendMessageBody = Omit<GuestSendMessageInput, Thread>;
1745
+ /** `POST {prefix}/guest/conversations/{conversation_id}/send` */
1746
+ type GuestSendMessageResponse = InferResponse<Guest["sendMessage"]>;
1747
+ /** `POST {prefix}/guest/conversations/{conversation_id}/delete` */
1748
+ type GuestDeleteConversationInput = InferInput<Guest["deleteConversation"]>;
1749
+ /** `POST {prefix}/guest/conversations/{conversation_id}/delete` — path parameters. */
1750
+ type GuestDeleteConversationParams = Pick<GuestDeleteConversationInput, Thread>;
1751
+ /**
1752
+ * `POST {prefix}/guest/conversations/{conversation_id}/delete` — the JSON body.
1753
+ *
1754
+ * A `POST` rather than a `DELETE` on purpose: a `DELETE` would have to carry the
1755
+ * token in the query string, and a URL travels into access logs, proxies and
1756
+ * `Referer` headers. The body keeps the credential out of it.
1757
+ */
1758
+ type GuestDeleteConversationBody = Omit<GuestDeleteConversationInput, Thread>;
1759
+ /** `POST {prefix}/guest/conversations/{conversation_id}/delete` — returns `null`. */
1760
+ type GuestDeleteConversationResponse = InferResponse<Guest["deleteConversation"]>;
1761
+ /** One endpoint's complete wire contract. `never` marks a part it does not take. */
1762
+ interface ChatbotEndpoint<Verb extends string, Route extends string, Auth, Params, Query, Body, Response> {
1763
+ /** HTTP method. */
1764
+ verb: Verb;
1765
+ /** Route template, **relative to `routePrefix`** (default `"chat"`). */
1766
+ route: Route;
1767
+ /** `"token"` = `Authorization: Bearer` for `authTable`; `"session_token"` = the guest capability; `"none"` = public. */
1768
+ auth: Auth;
1769
+ /** Path parameters, interpolated into the URL. */
1770
+ params: Params;
1771
+ /** Query-string parameters. */
1772
+ query: Query;
1773
+ /** The JSON request body. */
1774
+ body: Body;
1775
+ /** The parsed JSON response. */
1776
+ response: Response;
1777
+ }
1778
+ /**
1779
+ * Every endpoint, keyed by the **same name as the def handle** — so
1780
+ * `bot.authenticated.sendMessage` and `ChatbotEndpoints["sendMessage"]` describe
1781
+ * one thing, and a client can be written or generated from this map alone.
1782
+ *
1783
+ * ```ts
1784
+ * type Send = ChatbotEndpoints["sendMessage"];
1785
+ * // Send["verb"] → "POST"
1786
+ * // Send["params"] → { conversation_id: number }
1787
+ * // Send["body"] → { content: string }
1788
+ * // Send["response"] → ChatReply
1789
+ * ```
1790
+ *
1791
+ * Routes are relative to `routePrefix`, and the public URL is
1792
+ * `/api:<canonical>/<routePrefix>/<route>`. Get the resolved path from
1793
+ * `xanosdk routes <entry> --emit xano/routes.gen.ts` rather than concatenating it
1794
+ * by hand.
1795
+ */
1796
+ interface ChatbotEndpoints {
1797
+ createConversation: ChatbotEndpoint<"POST", "conversations/create", "token", never, never, CreateConversationBody, CreateConversationResponse>;
1798
+ listConversations: ChatbotEndpoint<"GET", "conversations", "token", never, never, never, ListConversationsResponse>;
1799
+ listMessages: ChatbotEndpoint<"GET", "conversations/{conversation_id}/messages", "token", ListMessagesParams, never, never, ListMessagesResponse>;
1800
+ sendMessage: ChatbotEndpoint<"POST", "conversations/{conversation_id}/send", "token", SendMessageParams, never, SendMessageBody, SendMessageResponse>;
1801
+ deleteConversation: ChatbotEndpoint<"DELETE", "conversations/{conversation_id}", "token", DeleteConversationParams, never, never, DeleteConversationResponse>;
1802
+ claimConversation: ChatbotEndpoint<"POST", "conversations/{conversation_id}/claim", "token", ClaimConversationParams, never, ClaimConversationBody, ClaimConversationResponse>;
1803
+ guestCreateConversation: ChatbotEndpoint<"POST", "guest/conversations/create", "none", never, never, GuestCreateConversationBody, GuestCreateConversationResponse>;
1804
+ guestListMessages: ChatbotEndpoint<"GET", "guest/conversations/{conversation_id}/messages", "session_token", GuestListMessagesParams, GuestListMessagesQuery, never, GuestListMessagesResponse>;
1805
+ guestSendMessage: ChatbotEndpoint<"POST", "guest/conversations/{conversation_id}/send", "session_token", GuestSendMessageParams, never, GuestSendMessageBody, GuestSendMessageResponse>;
1806
+ guestDeleteConversation: ChatbotEndpoint<"POST", "guest/conversations/{conversation_id}/delete", "session_token", GuestDeleteConversationParams, never, GuestDeleteConversationBody, GuestDeleteConversationResponse>;
1807
+ }
1808
+ /** Every endpoint name in {@link ChatbotEndpoints}. */
1809
+ type ChatbotEndpointName = keyof ChatbotEndpoints;
1810
+
1811
+ export { type ChatAgent, type ChatReply, type Chatbot, type ChatbotAuthTable, type ChatbotEndpoint, type ChatbotEndpointName, type ChatbotEndpoints, type ChatbotGroup, type ChatbotLlmOptions, type ChatbotNames, type ChatbotOptions, type ClaimConversationBody, type ClaimConversationInput, type ClaimConversationParams, type ClaimConversationResponse, type Conversation, type ConversationTable, type CreateConversationBody, type CreateConversationInput, type CreateConversationResponse, DEFAULT_HISTORY_LIMIT, DEFAULT_LIST_LIMIT, DEFAULT_NAMES, DEFAULT_SYSTEM_PROMPT, DEFAULT_TRANSCRIPT_LIMIT, type DeleteConversationInput, type DeleteConversationParams, type DeleteConversationResponse, type GenerateReplyFn, type GuestCreateConversationBody, type GuestCreateConversationInput, type GuestCreateConversationResponse, type GuestDeleteConversationBody, type GuestDeleteConversationInput, type GuestDeleteConversationParams, type GuestDeleteConversationResponse, type GuestListMessagesInput, type GuestListMessagesParams, type GuestListMessagesQuery, type GuestListMessagesResponse, type GuestSendMessageBody, type GuestSendMessageInput, type GuestSendMessageParams, type GuestSendMessageResponse, type ListConversationsResponse, type ListMessagesInput, type ListMessagesParams, type ListMessagesResponse, MESSAGES_TEMPLATE, MESSAGE_ROLES, type Message, type MessageRole, type MessageTable, PUBLIC_CONVERSATION_FIELDS, PUBLIC_MESSAGE_FIELDS, type PublicConversation, type PublicMessage, type RegisteredChatbot, type ResolvedOptions, type SendMessageBody, type SendMessageInput, type SendMessageParams, type SendMessageResponse, TITLE_LENGTH, TOOLS_SYSTEM_PROMPT, authenticatedQueries, chatAgent, chatbotGroup, conversationTable, createChatbot, generateReplyFn, guestQueries, messageTable, registerChatbot, resolveOptions };