@vinaverse/client 0.1.0-alpha.2 → 0.1.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AnswerInput, h as AuthMode, b as CONTRACT, c as Card, d as CardKind, e as ClientErrorCode, j as ClientEvent, C as ClientSecret, k as Connection, l as ConversationEngine, m as ConversationState, F as FetchLike, n as Frame, H as HeldCard, f as HeldQuestion, M as Message, g as Proposal, P as ProposalOutcome, Q as Question, R as Reconnect, o as ServerEvent, p as ServerEventOf, q as ServerEventType, r as SessionEvents, S as SessionInfo, a as SessionOptions, s as SessionStatus, t as SseTarget, T as ToolLine, u as TranscriptItem, v as TurnInput, V as VinaverseClientError, w as VinaverseSession, W as WebSocketFactory, x as WebSocketLike, y as cardActionSse, i as isKnownCard, z as sseFrames, B as turnSse } from './session--W6JXfwo.cjs';
1
+ export { A as AnswerInput, l as AuthMode, b as CONTRACT, c as Card, f as CardKind, h as ClientErrorCode, m as ClientEvent, C as ClientSecret, n as Connection, o as ConversationEngine, p as ConversationState, F as FetchLike, q as Frame, H as HeldCard, i as HeldQuestion, M as Message, j as Proposal, P as ProposalOutcome, Q as Question, R as Reconnect, r as ServerEvent, s as ServerEventOf, t as ServerEventType, u as SessionEvents, S as SessionInfo, a as SessionOptions, v as SessionStatus, w as SseTarget, T as ToolLine, x as TranscriptItem, y as TurnInput, V as VinaverseClientError, z as VinaverseSession, B as WebSocketFactory, D as WebSocketLike, E as cardActionSse, k as isKnownCard, G as sseFrames, I as turnSse } from './session-C3qZwGPG.cjs';
2
2
 
3
3
  /**
4
4
  * The client secret, checked: an app holds only the session's `vv_cs_` secret, which the tenant's backend got from
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AnswerInput, h as AuthMode, b as CONTRACT, c as Card, d as CardKind, e as ClientErrorCode, j as ClientEvent, C as ClientSecret, k as Connection, l as ConversationEngine, m as ConversationState, F as FetchLike, n as Frame, H as HeldCard, f as HeldQuestion, M as Message, g as Proposal, P as ProposalOutcome, Q as Question, R as Reconnect, o as ServerEvent, p as ServerEventOf, q as ServerEventType, r as SessionEvents, S as SessionInfo, a as SessionOptions, s as SessionStatus, t as SseTarget, T as ToolLine, u as TranscriptItem, v as TurnInput, V as VinaverseClientError, w as VinaverseSession, W as WebSocketFactory, x as WebSocketLike, y as cardActionSse, i as isKnownCard, z as sseFrames, B as turnSse } from './session--W6JXfwo.js';
1
+ export { A as AnswerInput, l as AuthMode, b as CONTRACT, c as Card, f as CardKind, h as ClientErrorCode, m as ClientEvent, C as ClientSecret, n as Connection, o as ConversationEngine, p as ConversationState, F as FetchLike, q as Frame, H as HeldCard, i as HeldQuestion, M as Message, j as Proposal, P as ProposalOutcome, Q as Question, R as Reconnect, r as ServerEvent, s as ServerEventOf, t as ServerEventType, u as SessionEvents, S as SessionInfo, a as SessionOptions, v as SessionStatus, w as SseTarget, T as ToolLine, x as TranscriptItem, y as TurnInput, V as VinaverseClientError, z as VinaverseSession, B as WebSocketFactory, D as WebSocketLike, E as cardActionSse, k as isKnownCard, G as sseFrames, I as turnSse } from './session-C3qZwGPG.js';
2
2
 
3
3
  /**
4
4
  * The client secret, checked: an app holds only the session's `vv_cs_` secret, which the tenant's backend got from
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { CONTRACT, ConversationEngine, VinaverseClientError, VinaverseSession, cardActionSse, clientSecret, isKnownCard, sseFrames, turnSse } from './chunk-AWHPWRGT.js';
1
+ export { CONTRACT, ConversationEngine, VinaverseClientError, VinaverseSession, cardActionSse, clientSecret, isKnownCard, sseFrames, turnSse } from './chunk-MKUNSAMT.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  declare const CONTRACT: {
2
- readonly api: "v1-draft.17";
3
- readonly commit: "fe4fb7d2945e1ced2bce7d44e85a4b28005e46df";
2
+ readonly api: "v1-draft.20";
3
+ readonly commit: "5f6f41bdbfbdd6eadf21180eed1ffddfa5310355";
4
4
  };
5
5
 
6
6
  /** A frame as received or sent: its `type`, and whatever else the contract gives it. */
@@ -187,6 +187,12 @@ declare class ConversationEngine {
187
187
  sent(event: Frame): void;
188
188
  received(event: Frame): void;
189
189
  private ready;
190
+ /**
191
+ * A transcript merged by key: an item the app holds keeps its place, with the text the server recorded; one it does
192
+ * not hold goes just after the nearest earlier item it does (just before the first later one when none came before,
193
+ * at the end when it holds none of them). Nothing the app holds is dropped.
194
+ */
195
+ private mergeTranscript;
190
196
  private hold;
191
197
  private recorded;
192
198
  private rejected;
@@ -411,6 +417,56 @@ interface components {
411
417
  conversation_key?: string;
412
418
  /** @description Optional. Resumes the conversation with this id (`Session.conversation_id`, `ConversationState`), as an alternative to `conversation_key` or together with it; `createSession` describes resuming and the order of its checks. */
413
419
  conversation_id?: components["schemas"]["ConversationId"];
420
+ experience_mode?: components["schemas"]["ExperienceMode"];
421
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
422
+ screen_context?: components["schemas"]["ScreenContext"];
423
+ };
424
+ /**
425
+ * @description v1-draft.20, optional on `createSession`: the side of the tenant's app the person is on. `customer` for the customer agent (a `client` or `guest`), `business` for a business agent (a `professional`, `host` or `staff`). Left out, it follows the agent's template; `createSession` describes the binding.
426
+ * @enum {string}
427
+ */
428
+ ExperienceMode: "customer" | "business";
429
+ /** @description v1-draft.20, optional, with `experience_mode: business` only: the business the person acts for, as the tenant's backend knows it (a professional's business, a host's place). Opaque to Vinaverse; it binds the conversation, so a person acting for two businesses keeps two conversations. It never reaches a model prompt. */
430
+ BusinessScopeId: string;
431
+ /** @description v1-draft.20, optional on `createSession`: where the person is in the tenant's app when the session opens, as the tenant's backend vouches for it (it checked that the person may see the entity). It grants nothing: no tool, capability or record. The agent reads it as data in its working notes (never in the cached system prompt, never as something the person said), as a hint: before it states anything about the entity it reads it with a tool, and a tool that refuses means the agent says it cannot see it. A screen change while the chat is open does not open a new session; live updates are a later addition. Never arbitrary page text, URLs, names, amounts or instructions: only these fields, from this vocabulary. */
432
+ ScreenContext: {
433
+ /**
434
+ * @description A coarse screen from a fixed vocabulary; the tenant maps its own screens onto it. `other` when none fits. Customer side: `home`, `explore`, `search_results`, `professional`, `workspace`, `service`, `class`, `checkout`, `booking`, `bookings`, `inbox`, `profile`. Business side: `business_hub`, `setup`, `services`, `hours`, `location`, `gallery`, `spaces`, `space_manage`, `renters`, `payouts`, `plans`, `team`.
435
+ * @enum {string}
436
+ */
437
+ screen: "home" | "explore" | "search_results" | "professional" | "workspace" | "service" | "class" | "checkout" | "booking" | "bookings" | "inbox" | "profile" | "business_hub" | "setup" | "services" | "hours" | "location" | "gallery" | "spaces" | "space_manage" | "renters" | "payouts" | "plans" | "team" | "other";
438
+ /** @description the object on the screen, as the tenant's read tools name it; `id` is a tool id (letters, digits and `_`, `.`, `:`, `-`), since it reaches the agent's working notes */
439
+ entity?: {
440
+ /** @enum {string} */
441
+ type: "professional" | "workspace" | "service" | "class" | "booking" | "location";
442
+ id: string;
443
+ };
444
+ /** @description the filters the screen shows, typed; free text never */
445
+ filters?: {
446
+ service_ids?: string[];
447
+ category_ids?: string[];
448
+ area_id?: string;
449
+ /** Format: date */
450
+ date_from?: string;
451
+ /** Format: date */
452
+ date_to?: string;
453
+ price_max?: components["schemas"]["Money"];
454
+ };
455
+ /** @description the tenant's counter for this person's screen state; a later update never goes back to a lower one */
456
+ revision: number;
457
+ };
458
+ /** @description v1-draft.20: a tap target the app draws under the welcome. Tapping it sends `message` as the person's own text (an `input.text`, or `createTurnSse`), exactly as if they typed it; it starts nothing else. */
459
+ Chip: {
460
+ /** @description in Unicode code points */
461
+ label: string;
462
+ /** @description in Unicode code points */
463
+ message: string;
464
+ };
465
+ /** @description v1-draft.20: the tenant's greeting for the session's mode, with the chips of the session's screen when its manifest has some for it (else the mode's own), from the connector manifest (admin-v1 `Connector.welcome`), checked when the manifest loads. The app shows it the moment the session is ready: it costs no model call and is not a turn. The agent knows it was shown and does not greet again. */
466
+ Welcome: {
467
+ /** @description in Unicode code points */
468
+ text: string;
469
+ chips: components["schemas"]["Chip"][];
414
470
  };
415
471
  ClientSecret: {
416
472
  /** @description `vv_cs_` and base64url characters, so the secret is a valid WebSocket subprotocol token in `bearer.<secret>`. */
@@ -429,6 +485,11 @@ interface components {
429
485
  id: string;
430
486
  version: string;
431
487
  display_name: string;
488
+ /**
489
+ * Format: uri
490
+ * @description v1-draft.19, optional: the agent's avatar (`getAgentAvatarImage`), a square 512 px WebP with no metadata, re-encoded by Vinaverse from the tenant's upload and passed by its image screen. The URL is immutable (it changes when the image does), so an app may cache the image for as long as it likes; it needs no credential. Absent: no avatar yet, so draw the name's monogram.
491
+ */
492
+ avatar_url?: string;
432
493
  };
433
494
  client_secret: components["schemas"]["ClientSecret"];
434
495
  /** Format: uri */
@@ -443,6 +504,14 @@ interface components {
443
504
  disclosure: string;
444
505
  /** @description The conversation this session belongs to, the same for every session of it, however it was resumed (by `conversation_key` or `conversation_id`). Present whenever the session belongs to a conversation: when the request named one, and for every guided-flow session. It is absent only for a session with no conversation, and optional in the schema so clients built on earlier drafts keep working. */
445
506
  conversation_id?: components["schemas"]["ConversationId"];
507
+ /** @description v1-draft.20, the session's mode, as given or as the agent's template sets it */
508
+ experience_mode?: components["schemas"]["ExperienceMode"];
509
+ /** @description v1-draft.20, present when the session acts for a business */
510
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
511
+ /** @description v1-draft.20, the screen context the session accepted, when `createSession` gave one */
512
+ screen_context?: components["schemas"]["ScreenContext"];
513
+ /** @description v1-draft.20, absent when the tenant's manifest has no welcome for the session's mode */
514
+ welcome?: components["schemas"]["Welcome"];
446
515
  };
447
516
  SessionStatus: {
448
517
  id: string;
@@ -505,6 +574,35 @@ interface components {
505
574
  label: string;
506
575
  deep_link?: string;
507
576
  };
577
+ /** @description v1-draft.20: one photo of a `professional` or `workspace` card. Https only, from a prefix the tenant registered (admin-v1 `Connector.image_url_prefixes`), compared after the URL is parsed and normalized (no user info, backslash, fragment or dot segment): an image that fails is dropped, never the card. The tenant serves only photos its own moderation approved, at URLs that stay valid as long as the transcript (a card in history draws them again). An image that fails to load draws the name's monogram; the card stays. */
578
+ CardImage: {
579
+ /** Format: uri */
580
+ url: string;
581
+ width?: number;
582
+ height?: number;
583
+ };
584
+ /** @description v1-draft.20: the cards one turn draws together carry the same `id`. `layout` is a hint: `carousel` draws them in one horizontal row, `list` one under another. A client that does not know `group`, or a `layout` value, draws a list, as before. */
585
+ CardGroup: {
586
+ id: string;
587
+ /** @enum {string} */
588
+ layout: "list" | "carousel";
589
+ };
590
+ /** @description v1-draft.20, one link of a `links` card: one of the tenant's own destinations from its connector manifest (admin-v1 `Connector.help_links`), never a link the model wrote. */
591
+ CardLink: {
592
+ /** @description in Unicode code points */
593
+ label: string;
594
+ /** @description an https page of the tenant's, or a deep link that passes the deep-link rule (`next_step`) */
595
+ url: string;
596
+ /** @enum {string} */
597
+ purpose: "help" | "support" | "policy" | "contact" | "feedback";
598
+ };
599
+ /** @description v1-draft.20, on a `links` card: the tenant's scope policy, at the version in force, that kept the agent from answering, and why. */
600
+ ScopeProvenance: {
601
+ policy_id: string;
602
+ version: string;
603
+ /** @enum {string} */
604
+ reason: "off_scope" | "competitor" | "blocked_topic";
605
+ };
508
606
  /**
509
607
  * @description `ref` is present on every customer-agent card (professional … handoff); copilot cards (metric_chart … document) may omit it, since a metric, cluster or claim is not a tenant object. A `question` card (guided flows) carries `question`, has no `actions` (the person answers with `ui.answer`), uses `title` as a short label for the question, and its `source` names the tool call that fetched the flow's definition.
510
608
  * A `next_step` card is a step the person finishes on the tenant's own screen (payouts, a plan purchase, photos). It has a `title` (at most 80 code points), a `body` (at most 300) and exactly one action: `action: open`, with a `label` (at most 40) and a `deep_link`. It may omit `ref`, and its `source` names the tool call the step came from. - **Nothing is written.** Tapping the action opens `deep_link` in the tenant's app. The app sends no
@@ -524,14 +622,17 @@ interface components {
524
622
  * know.
525
623
  * - **It is not restored.** A `next_step` card is in neither `pending_cards` nor `transcript`; after a
526
624
  * reconnect the agent shows the step again once it reads the tenant's state.
625
+ *
626
+ * **Listing cards** (v1-draft.20). A `professional` or `workspace` card may carry `images` (up to five, the first the hero; `image_url`, when present, is the first one's URL, for clients that predate `images`), `next_available` (the earliest open time the tenant's tool returned; a hint, so a tap on its time reads availability again), `price_from` and a `group`. An app draws one hero image first and the rest on a swipe.
627
+ * **A `links` card** (v1-draft.20) answers what the tenant's scope keeps the agent from answering: a question off its scope, a comparison with a competitor, a blocked topic. Its `links` are the tenant's own help, support, policy, contact or feedback destinations (`CardLink`), its `provenance` names the scope policy and the reason, and it has no `actions`: each link opens the tenant's page. It belongs to a recorded turn, with the agent's one line around it, never to `input.rejected`. Its `source.tool` is `scope` and its `source.call_id` the turn's id: no tool call made it. An earlier client skips the unknown kind, as it skips any.
527
628
  */
528
629
  Card: {
529
630
  id: string;
530
631
  /**
531
- * @description customer-agent kinds, then business-copilot kinds (Studio), then `question` (guided flows), then `proposal` (a change the person confirms or declines in the tenant's app), then `next_step` (a step the person finishes on the tenant's own screen)
632
+ * @description customer-agent kinds, then business-copilot kinds (Studio), then `question` (guided flows), then `proposal` (a change the person confirms or declines in the tenant's app), then `next_step` (a step the person finishes on the tenant's own screen), then `links` (v1-draft.20: the tenant's own pages, when its scope keeps the agent from answering)
532
633
  * @enum {string}
533
634
  */
534
- kind: "professional" | "workspace" | "service" | "time_slots" | "booking" | "quote" | "policy" | "handoff" | "metric_chart" | "metric_table" | "gap_list" | "cluster" | "claim" | "document" | "question" | "proposal" | "next_step";
635
+ kind: "professional" | "workspace" | "service" | "time_slots" | "booking" | "quote" | "policy" | "handoff" | "metric_chart" | "metric_table" | "gap_list" | "cluster" | "claim" | "document" | "question" | "proposal" | "next_step" | "links";
535
636
  question?: components["schemas"]["Question"];
536
637
  proposal?: components["schemas"]["Proposal"];
537
638
  ref?: components["schemas"]["CardRef"];
@@ -539,6 +640,17 @@ interface components {
539
640
  subtitle?: string;
540
641
  /** Format: uri */
541
642
  image_url?: string;
643
+ /** @description v1-draft.20, a `professional` or `workspace` card's photos, the first the hero */
644
+ images?: components["schemas"]["CardImage"][];
645
+ /**
646
+ * Format: date-time
647
+ * @description v1-draft.20, a `professional` or `workspace` card's earliest open time, as the tenant's tool returned it
648
+ */
649
+ next_available?: string;
650
+ group?: components["schemas"]["CardGroup"];
651
+ /** @description v1-draft.20, a `links` card's links */
652
+ links?: components["schemas"]["CardLink"][];
653
+ provenance?: components["schemas"]["ScopeProvenance"];
542
654
  rating?: {
543
655
  value_ppm: number;
544
656
  count: number;
@@ -582,7 +694,7 @@ interface components {
582
694
  points: {
583
695
  /** Format: date */
584
696
  t: string;
585
- /** @description null when suppressed by the k-anonymity floor */
697
+ /** @description null when suppressed by the k-anonymity floor; on a metric without k_floor, nothing to measure */
586
698
  value: number | null;
587
699
  suppressed?: boolean;
588
700
  }[];
@@ -600,6 +712,7 @@ interface components {
600
712
  dims: {
601
713
  [key: string]: string;
602
714
  };
715
+ /** @description null when suppressed by the metric's k_floor; on a metric without k_floor, nothing to measure */
603
716
  values: {
604
717
  [key: string]: number | null;
605
718
  };
@@ -644,7 +757,7 @@ interface components {
644
757
  snippet?: string;
645
758
  /** Format: date-time */
646
759
  updated_at?: string;
647
- } & (unknown & unknown & unknown);
760
+ } & (unknown & unknown & unknown & unknown);
648
761
  /** @enum {string} */
649
762
  ValueUnit: "count" | "ppm" | "micros_usd" | "ms";
650
763
  MetricRef: {
@@ -652,6 +765,7 @@ interface components {
652
765
  label: string;
653
766
  unit: components["schemas"]["ValueUnit"];
654
767
  definition: string;
768
+ /** @description The privacy floor: a value built from fewer than this many distinct people is suppressed (`null`). Absent when no floor applies, as on a business's own operational data (Studio's pages, read by the business copilot); a `null` value there means there was nothing to measure, never a hidden count. */
655
769
  k_floor?: number;
656
770
  };
657
771
  /** @description Links a span of the reply text to the card or tool call it came from. Offsets are in Unicode code points (not bytes, not UTF-16 units), start inclusive, end exclusive. */
@@ -1064,6 +1178,10 @@ interface components {
1064
1178
  };
1065
1179
  disclosure: string;
1066
1180
  resumed: boolean;
1181
+ /** @description v1-draft.20, the session's mode (`Session.experience_mode`), so the app keeps one store per mode */
1182
+ experience_mode?: components["schemas"]["ExperienceMode"];
1183
+ /** @description v1-draft.20, present when the session acts for a business */
1184
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
1067
1185
  /**
1068
1186
  * @description Optional. The last messages of the conversation, oldest first, text only, so the app can redraw it after a kill or a reconnect. Older context is not sent.
1069
1187
  * A guided flow's resumed `session.ready` always carries it. Any other session's (a chat; v1-draft.17) carries it when `resumed` is true and there is something to restore, whether the app reconnects to the same session or the backend created a new session of the conversation: - the conversation's messages across its sessions (the session's own when it has no conversation):
@@ -1785,6 +1903,11 @@ type Proposal = Schemas['Proposal'];
1785
1903
  type TranscriptItem = Schemas['TranscriptItem'];
1786
1904
  type ClientSecret = Schemas['ClientSecret'];
1787
1905
  type TurnInput = Schemas['TurnInput'];
1906
+ /** v1-draft.20: the tenant's greeting for the session's mode, and the chips that send a message as the person's own. */
1907
+ type Welcome = Schemas['Welcome'];
1908
+ type CardImage = Schemas['CardImage'];
1909
+ type CardGroup = Schemas['CardGroup'];
1910
+ type CardLink = Schemas['CardLink'];
1788
1911
  /** The session as createSession returns it to the tenant's backend, which passes this part to the app. */
1789
1912
  type SessionInfo = Pick<Schemas['Session'], 'id' | 'realtime_url' | 'turns_url' | 'conversation_id'> & {
1790
1913
  client_secret: ClientSecret | string;
@@ -2025,4 +2148,4 @@ declare class VinaverseSession {
2025
2148
  private emit;
2026
2149
  }
2027
2150
 
2028
- export { type AnswerInput as A, turnSse as B, type ClientSecret as C, type FetchLike as F, type HeldCard as H, type Message as M, type ProposalOutcome as P, type Question as Q, type Reconnect as R, type SessionInfo as S, type ToolLine as T, VinaverseClientError as V, type WebSocketFactory as W, type SessionOptions as a, CONTRACT as b, type Card as c, type CardKind as d, type ClientErrorCode as e, type HeldQuestion as f, type Proposal as g, type AuthMode as h, isKnownCard as i, type ClientEvent as j, type Connection as k, ConversationEngine as l, type ConversationState as m, type Frame as n, type ServerEvent as o, type ServerEventOf as p, type ServerEventType as q, type SessionEvents as r, type SessionStatus as s, type SseTarget as t, type TranscriptItem as u, type TurnInput as v, VinaverseSession as w, type WebSocketLike as x, cardActionSse as y, sseFrames as z };
2151
+ export { type AnswerInput as A, type WebSocketFactory as B, type ClientSecret as C, type WebSocketLike as D, cardActionSse as E, type FetchLike as F, sseFrames as G, type HeldCard as H, turnSse as I, type Message as M, type ProposalOutcome as P, type Question as Q, type Reconnect as R, type SessionInfo as S, type ToolLine as T, VinaverseClientError as V, type Welcome as W, type SessionOptions as a, CONTRACT as b, type Card as c, type CardGroup as d, type CardImage as e, type CardKind as f, type CardLink as g, type ClientErrorCode as h, type HeldQuestion as i, type Proposal as j, isKnownCard as k, type AuthMode as l, type ClientEvent as m, type Connection as n, ConversationEngine as o, type ConversationState as p, type Frame as q, type ServerEvent as r, type ServerEventOf as s, type ServerEventType as t, type SessionEvents as u, type SessionStatus as v, type SseTarget as w, type TranscriptItem as x, type TurnInput as y, VinaverseSession as z };
@@ -1,6 +1,6 @@
1
1
  declare const CONTRACT: {
2
- readonly api: "v1-draft.17";
3
- readonly commit: "fe4fb7d2945e1ced2bce7d44e85a4b28005e46df";
2
+ readonly api: "v1-draft.20";
3
+ readonly commit: "5f6f41bdbfbdd6eadf21180eed1ffddfa5310355";
4
4
  };
5
5
 
6
6
  /** A frame as received or sent: its `type`, and whatever else the contract gives it. */
@@ -187,6 +187,12 @@ declare class ConversationEngine {
187
187
  sent(event: Frame): void;
188
188
  received(event: Frame): void;
189
189
  private ready;
190
+ /**
191
+ * A transcript merged by key: an item the app holds keeps its place, with the text the server recorded; one it does
192
+ * not hold goes just after the nearest earlier item it does (just before the first later one when none came before,
193
+ * at the end when it holds none of them). Nothing the app holds is dropped.
194
+ */
195
+ private mergeTranscript;
190
196
  private hold;
191
197
  private recorded;
192
198
  private rejected;
@@ -411,6 +417,56 @@ interface components {
411
417
  conversation_key?: string;
412
418
  /** @description Optional. Resumes the conversation with this id (`Session.conversation_id`, `ConversationState`), as an alternative to `conversation_key` or together with it; `createSession` describes resuming and the order of its checks. */
413
419
  conversation_id?: components["schemas"]["ConversationId"];
420
+ experience_mode?: components["schemas"]["ExperienceMode"];
421
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
422
+ screen_context?: components["schemas"]["ScreenContext"];
423
+ };
424
+ /**
425
+ * @description v1-draft.20, optional on `createSession`: the side of the tenant's app the person is on. `customer` for the customer agent (a `client` or `guest`), `business` for a business agent (a `professional`, `host` or `staff`). Left out, it follows the agent's template; `createSession` describes the binding.
426
+ * @enum {string}
427
+ */
428
+ ExperienceMode: "customer" | "business";
429
+ /** @description v1-draft.20, optional, with `experience_mode: business` only: the business the person acts for, as the tenant's backend knows it (a professional's business, a host's place). Opaque to Vinaverse; it binds the conversation, so a person acting for two businesses keeps two conversations. It never reaches a model prompt. */
430
+ BusinessScopeId: string;
431
+ /** @description v1-draft.20, optional on `createSession`: where the person is in the tenant's app when the session opens, as the tenant's backend vouches for it (it checked that the person may see the entity). It grants nothing: no tool, capability or record. The agent reads it as data in its working notes (never in the cached system prompt, never as something the person said), as a hint: before it states anything about the entity it reads it with a tool, and a tool that refuses means the agent says it cannot see it. A screen change while the chat is open does not open a new session; live updates are a later addition. Never arbitrary page text, URLs, names, amounts or instructions: only these fields, from this vocabulary. */
432
+ ScreenContext: {
433
+ /**
434
+ * @description A coarse screen from a fixed vocabulary; the tenant maps its own screens onto it. `other` when none fits. Customer side: `home`, `explore`, `search_results`, `professional`, `workspace`, `service`, `class`, `checkout`, `booking`, `bookings`, `inbox`, `profile`. Business side: `business_hub`, `setup`, `services`, `hours`, `location`, `gallery`, `spaces`, `space_manage`, `renters`, `payouts`, `plans`, `team`.
435
+ * @enum {string}
436
+ */
437
+ screen: "home" | "explore" | "search_results" | "professional" | "workspace" | "service" | "class" | "checkout" | "booking" | "bookings" | "inbox" | "profile" | "business_hub" | "setup" | "services" | "hours" | "location" | "gallery" | "spaces" | "space_manage" | "renters" | "payouts" | "plans" | "team" | "other";
438
+ /** @description the object on the screen, as the tenant's read tools name it; `id` is a tool id (letters, digits and `_`, `.`, `:`, `-`), since it reaches the agent's working notes */
439
+ entity?: {
440
+ /** @enum {string} */
441
+ type: "professional" | "workspace" | "service" | "class" | "booking" | "location";
442
+ id: string;
443
+ };
444
+ /** @description the filters the screen shows, typed; free text never */
445
+ filters?: {
446
+ service_ids?: string[];
447
+ category_ids?: string[];
448
+ area_id?: string;
449
+ /** Format: date */
450
+ date_from?: string;
451
+ /** Format: date */
452
+ date_to?: string;
453
+ price_max?: components["schemas"]["Money"];
454
+ };
455
+ /** @description the tenant's counter for this person's screen state; a later update never goes back to a lower one */
456
+ revision: number;
457
+ };
458
+ /** @description v1-draft.20: a tap target the app draws under the welcome. Tapping it sends `message` as the person's own text (an `input.text`, or `createTurnSse`), exactly as if they typed it; it starts nothing else. */
459
+ Chip: {
460
+ /** @description in Unicode code points */
461
+ label: string;
462
+ /** @description in Unicode code points */
463
+ message: string;
464
+ };
465
+ /** @description v1-draft.20: the tenant's greeting for the session's mode, with the chips of the session's screen when its manifest has some for it (else the mode's own), from the connector manifest (admin-v1 `Connector.welcome`), checked when the manifest loads. The app shows it the moment the session is ready: it costs no model call and is not a turn. The agent knows it was shown and does not greet again. */
466
+ Welcome: {
467
+ /** @description in Unicode code points */
468
+ text: string;
469
+ chips: components["schemas"]["Chip"][];
414
470
  };
415
471
  ClientSecret: {
416
472
  /** @description `vv_cs_` and base64url characters, so the secret is a valid WebSocket subprotocol token in `bearer.<secret>`. */
@@ -429,6 +485,11 @@ interface components {
429
485
  id: string;
430
486
  version: string;
431
487
  display_name: string;
488
+ /**
489
+ * Format: uri
490
+ * @description v1-draft.19, optional: the agent's avatar (`getAgentAvatarImage`), a square 512 px WebP with no metadata, re-encoded by Vinaverse from the tenant's upload and passed by its image screen. The URL is immutable (it changes when the image does), so an app may cache the image for as long as it likes; it needs no credential. Absent: no avatar yet, so draw the name's monogram.
491
+ */
492
+ avatar_url?: string;
432
493
  };
433
494
  client_secret: components["schemas"]["ClientSecret"];
434
495
  /** Format: uri */
@@ -443,6 +504,14 @@ interface components {
443
504
  disclosure: string;
444
505
  /** @description The conversation this session belongs to, the same for every session of it, however it was resumed (by `conversation_key` or `conversation_id`). Present whenever the session belongs to a conversation: when the request named one, and for every guided-flow session. It is absent only for a session with no conversation, and optional in the schema so clients built on earlier drafts keep working. */
445
506
  conversation_id?: components["schemas"]["ConversationId"];
507
+ /** @description v1-draft.20, the session's mode, as given or as the agent's template sets it */
508
+ experience_mode?: components["schemas"]["ExperienceMode"];
509
+ /** @description v1-draft.20, present when the session acts for a business */
510
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
511
+ /** @description v1-draft.20, the screen context the session accepted, when `createSession` gave one */
512
+ screen_context?: components["schemas"]["ScreenContext"];
513
+ /** @description v1-draft.20, absent when the tenant's manifest has no welcome for the session's mode */
514
+ welcome?: components["schemas"]["Welcome"];
446
515
  };
447
516
  SessionStatus: {
448
517
  id: string;
@@ -505,6 +574,35 @@ interface components {
505
574
  label: string;
506
575
  deep_link?: string;
507
576
  };
577
+ /** @description v1-draft.20: one photo of a `professional` or `workspace` card. Https only, from a prefix the tenant registered (admin-v1 `Connector.image_url_prefixes`), compared after the URL is parsed and normalized (no user info, backslash, fragment or dot segment): an image that fails is dropped, never the card. The tenant serves only photos its own moderation approved, at URLs that stay valid as long as the transcript (a card in history draws them again). An image that fails to load draws the name's monogram; the card stays. */
578
+ CardImage: {
579
+ /** Format: uri */
580
+ url: string;
581
+ width?: number;
582
+ height?: number;
583
+ };
584
+ /** @description v1-draft.20: the cards one turn draws together carry the same `id`. `layout` is a hint: `carousel` draws them in one horizontal row, `list` one under another. A client that does not know `group`, or a `layout` value, draws a list, as before. */
585
+ CardGroup: {
586
+ id: string;
587
+ /** @enum {string} */
588
+ layout: "list" | "carousel";
589
+ };
590
+ /** @description v1-draft.20, one link of a `links` card: one of the tenant's own destinations from its connector manifest (admin-v1 `Connector.help_links`), never a link the model wrote. */
591
+ CardLink: {
592
+ /** @description in Unicode code points */
593
+ label: string;
594
+ /** @description an https page of the tenant's, or a deep link that passes the deep-link rule (`next_step`) */
595
+ url: string;
596
+ /** @enum {string} */
597
+ purpose: "help" | "support" | "policy" | "contact" | "feedback";
598
+ };
599
+ /** @description v1-draft.20, on a `links` card: the tenant's scope policy, at the version in force, that kept the agent from answering, and why. */
600
+ ScopeProvenance: {
601
+ policy_id: string;
602
+ version: string;
603
+ /** @enum {string} */
604
+ reason: "off_scope" | "competitor" | "blocked_topic";
605
+ };
508
606
  /**
509
607
  * @description `ref` is present on every customer-agent card (professional … handoff); copilot cards (metric_chart … document) may omit it, since a metric, cluster or claim is not a tenant object. A `question` card (guided flows) carries `question`, has no `actions` (the person answers with `ui.answer`), uses `title` as a short label for the question, and its `source` names the tool call that fetched the flow's definition.
510
608
  * A `next_step` card is a step the person finishes on the tenant's own screen (payouts, a plan purchase, photos). It has a `title` (at most 80 code points), a `body` (at most 300) and exactly one action: `action: open`, with a `label` (at most 40) and a `deep_link`. It may omit `ref`, and its `source` names the tool call the step came from. - **Nothing is written.** Tapping the action opens `deep_link` in the tenant's app. The app sends no
@@ -524,14 +622,17 @@ interface components {
524
622
  * know.
525
623
  * - **It is not restored.** A `next_step` card is in neither `pending_cards` nor `transcript`; after a
526
624
  * reconnect the agent shows the step again once it reads the tenant's state.
625
+ *
626
+ * **Listing cards** (v1-draft.20). A `professional` or `workspace` card may carry `images` (up to five, the first the hero; `image_url`, when present, is the first one's URL, for clients that predate `images`), `next_available` (the earliest open time the tenant's tool returned; a hint, so a tap on its time reads availability again), `price_from` and a `group`. An app draws one hero image first and the rest on a swipe.
627
+ * **A `links` card** (v1-draft.20) answers what the tenant's scope keeps the agent from answering: a question off its scope, a comparison with a competitor, a blocked topic. Its `links` are the tenant's own help, support, policy, contact or feedback destinations (`CardLink`), its `provenance` names the scope policy and the reason, and it has no `actions`: each link opens the tenant's page. It belongs to a recorded turn, with the agent's one line around it, never to `input.rejected`. Its `source.tool` is `scope` and its `source.call_id` the turn's id: no tool call made it. An earlier client skips the unknown kind, as it skips any.
527
628
  */
528
629
  Card: {
529
630
  id: string;
530
631
  /**
531
- * @description customer-agent kinds, then business-copilot kinds (Studio), then `question` (guided flows), then `proposal` (a change the person confirms or declines in the tenant's app), then `next_step` (a step the person finishes on the tenant's own screen)
632
+ * @description customer-agent kinds, then business-copilot kinds (Studio), then `question` (guided flows), then `proposal` (a change the person confirms or declines in the tenant's app), then `next_step` (a step the person finishes on the tenant's own screen), then `links` (v1-draft.20: the tenant's own pages, when its scope keeps the agent from answering)
532
633
  * @enum {string}
533
634
  */
534
- kind: "professional" | "workspace" | "service" | "time_slots" | "booking" | "quote" | "policy" | "handoff" | "metric_chart" | "metric_table" | "gap_list" | "cluster" | "claim" | "document" | "question" | "proposal" | "next_step";
635
+ kind: "professional" | "workspace" | "service" | "time_slots" | "booking" | "quote" | "policy" | "handoff" | "metric_chart" | "metric_table" | "gap_list" | "cluster" | "claim" | "document" | "question" | "proposal" | "next_step" | "links";
535
636
  question?: components["schemas"]["Question"];
536
637
  proposal?: components["schemas"]["Proposal"];
537
638
  ref?: components["schemas"]["CardRef"];
@@ -539,6 +640,17 @@ interface components {
539
640
  subtitle?: string;
540
641
  /** Format: uri */
541
642
  image_url?: string;
643
+ /** @description v1-draft.20, a `professional` or `workspace` card's photos, the first the hero */
644
+ images?: components["schemas"]["CardImage"][];
645
+ /**
646
+ * Format: date-time
647
+ * @description v1-draft.20, a `professional` or `workspace` card's earliest open time, as the tenant's tool returned it
648
+ */
649
+ next_available?: string;
650
+ group?: components["schemas"]["CardGroup"];
651
+ /** @description v1-draft.20, a `links` card's links */
652
+ links?: components["schemas"]["CardLink"][];
653
+ provenance?: components["schemas"]["ScopeProvenance"];
542
654
  rating?: {
543
655
  value_ppm: number;
544
656
  count: number;
@@ -582,7 +694,7 @@ interface components {
582
694
  points: {
583
695
  /** Format: date */
584
696
  t: string;
585
- /** @description null when suppressed by the k-anonymity floor */
697
+ /** @description null when suppressed by the k-anonymity floor; on a metric without k_floor, nothing to measure */
586
698
  value: number | null;
587
699
  suppressed?: boolean;
588
700
  }[];
@@ -600,6 +712,7 @@ interface components {
600
712
  dims: {
601
713
  [key: string]: string;
602
714
  };
715
+ /** @description null when suppressed by the metric's k_floor; on a metric without k_floor, nothing to measure */
603
716
  values: {
604
717
  [key: string]: number | null;
605
718
  };
@@ -644,7 +757,7 @@ interface components {
644
757
  snippet?: string;
645
758
  /** Format: date-time */
646
759
  updated_at?: string;
647
- } & (unknown & unknown & unknown);
760
+ } & (unknown & unknown & unknown & unknown);
648
761
  /** @enum {string} */
649
762
  ValueUnit: "count" | "ppm" | "micros_usd" | "ms";
650
763
  MetricRef: {
@@ -652,6 +765,7 @@ interface components {
652
765
  label: string;
653
766
  unit: components["schemas"]["ValueUnit"];
654
767
  definition: string;
768
+ /** @description The privacy floor: a value built from fewer than this many distinct people is suppressed (`null`). Absent when no floor applies, as on a business's own operational data (Studio's pages, read by the business copilot); a `null` value there means there was nothing to measure, never a hidden count. */
655
769
  k_floor?: number;
656
770
  };
657
771
  /** @description Links a span of the reply text to the card or tool call it came from. Offsets are in Unicode code points (not bytes, not UTF-16 units), start inclusive, end exclusive. */
@@ -1064,6 +1178,10 @@ interface components {
1064
1178
  };
1065
1179
  disclosure: string;
1066
1180
  resumed: boolean;
1181
+ /** @description v1-draft.20, the session's mode (`Session.experience_mode`), so the app keeps one store per mode */
1182
+ experience_mode?: components["schemas"]["ExperienceMode"];
1183
+ /** @description v1-draft.20, present when the session acts for a business */
1184
+ business_scope_id?: components["schemas"]["BusinessScopeId"];
1067
1185
  /**
1068
1186
  * @description Optional. The last messages of the conversation, oldest first, text only, so the app can redraw it after a kill or a reconnect. Older context is not sent.
1069
1187
  * A guided flow's resumed `session.ready` always carries it. Any other session's (a chat; v1-draft.17) carries it when `resumed` is true and there is something to restore, whether the app reconnects to the same session or the backend created a new session of the conversation: - the conversation's messages across its sessions (the session's own when it has no conversation):
@@ -1785,6 +1903,11 @@ type Proposal = Schemas['Proposal'];
1785
1903
  type TranscriptItem = Schemas['TranscriptItem'];
1786
1904
  type ClientSecret = Schemas['ClientSecret'];
1787
1905
  type TurnInput = Schemas['TurnInput'];
1906
+ /** v1-draft.20: the tenant's greeting for the session's mode, and the chips that send a message as the person's own. */
1907
+ type Welcome = Schemas['Welcome'];
1908
+ type CardImage = Schemas['CardImage'];
1909
+ type CardGroup = Schemas['CardGroup'];
1910
+ type CardLink = Schemas['CardLink'];
1788
1911
  /** The session as createSession returns it to the tenant's backend, which passes this part to the app. */
1789
1912
  type SessionInfo = Pick<Schemas['Session'], 'id' | 'realtime_url' | 'turns_url' | 'conversation_id'> & {
1790
1913
  client_secret: ClientSecret | string;
@@ -2025,4 +2148,4 @@ declare class VinaverseSession {
2025
2148
  private emit;
2026
2149
  }
2027
2150
 
2028
- export { type AnswerInput as A, turnSse as B, type ClientSecret as C, type FetchLike as F, type HeldCard as H, type Message as M, type ProposalOutcome as P, type Question as Q, type Reconnect as R, type SessionInfo as S, type ToolLine as T, VinaverseClientError as V, type WebSocketFactory as W, type SessionOptions as a, CONTRACT as b, type Card as c, type CardKind as d, type ClientErrorCode as e, type HeldQuestion as f, type Proposal as g, type AuthMode as h, isKnownCard as i, type ClientEvent as j, type Connection as k, ConversationEngine as l, type ConversationState as m, type Frame as n, type ServerEvent as o, type ServerEventOf as p, type ServerEventType as q, type SessionEvents as r, type SessionStatus as s, type SseTarget as t, type TranscriptItem as u, type TurnInput as v, VinaverseSession as w, type WebSocketLike as x, cardActionSse as y, sseFrames as z };
2151
+ export { type AnswerInput as A, type WebSocketFactory as B, type ClientSecret as C, type WebSocketLike as D, cardActionSse as E, type FetchLike as F, sseFrames as G, type HeldCard as H, turnSse as I, type Message as M, type ProposalOutcome as P, type Question as Q, type Reconnect as R, type SessionInfo as S, type ToolLine as T, VinaverseClientError as V, type Welcome as W, type SessionOptions as a, CONTRACT as b, type Card as c, type CardGroup as d, type CardImage as e, type CardKind as f, type CardLink as g, type ClientErrorCode as h, type HeldQuestion as i, type Proposal as j, isKnownCard as k, type AuthMode as l, type ClientEvent as m, type Connection as n, ConversationEngine as o, type ConversationState as p, type Frame as q, type ServerEvent as r, type ServerEventOf as s, type ServerEventType as t, type SessionEvents as u, type SessionStatus as v, type SseTarget as w, type TranscriptItem as x, type TurnInput as y, VinaverseSession as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinaverse/client",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "Vinaverse for apps: the realtime session client (WebSocket with SSE fallback, resume, typed events and cards). No UI.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Vinaverse, Inc.",
@@ -63,16 +63,16 @@
63
63
  },
64
64
  "size-limit": [
65
65
  {
66
- "name": "@vinaverse/client (ESM, everything; why 6.7 kB: docs/architecture/client.md, Size budget)",
66
+ "name": "@vinaverse/client (ESM, everything; why 7 kB: docs/architecture/client.md, Size budget)",
67
67
  "path": "dist/index.js",
68
68
  "import": "*",
69
- "limit": "6.7 kB"
69
+ "limit": "7 kB"
70
70
  },
71
71
  {
72
72
  "name": "@vinaverse/client/conversation (ESM, everything, the session included; docs/architecture/conversation.md, Size budget)",
73
73
  "path": "dist/conversation/index.js",
74
74
  "import": "*",
75
- "limit": "12 kB"
75
+ "limit": "13 kB"
76
76
  }
77
77
  ],
78
78
  "scripts": {