@vinaverse/client 0.1.0-alpha.3 → 0.1.0-alpha.5

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.
Files changed (42) hide show
  1. package/README.md +46 -0
  2. package/dist/agent/index.cjs +2852 -0
  3. package/dist/agent/index.cjs.map +1 -0
  4. package/dist/agent/index.d.cts +57 -0
  5. package/dist/agent/index.d.ts +57 -0
  6. package/dist/agent/index.js +99 -0
  7. package/dist/agent/index.js.map +1 -0
  8. package/dist/chunk-3WR2SUG2.js +416 -0
  9. package/dist/chunk-3WR2SUG2.js.map +1 -0
  10. package/dist/{chunk-AWHPWRGT.js → chunk-GWLLUOFY.js} +71 -15
  11. package/dist/chunk-GWLLUOFY.js.map +1 -0
  12. package/dist/chunk-VSJDVLCP.js +9 -0
  13. package/dist/chunk-VSJDVLCP.js.map +1 -0
  14. package/dist/chunk-ZWG2TMUL.js +975 -0
  15. package/dist/chunk-ZWG2TMUL.js.map +1 -0
  16. package/dist/contract-_NMdPjgN.d.cts +6 -0
  17. package/dist/contract-_NMdPjgN.d.ts +6 -0
  18. package/dist/conversation/index.cjs +198 -27
  19. package/dist/conversation/index.cjs.map +1 -1
  20. package/dist/conversation/index.d.cts +23 -343
  21. package/dist/conversation/index.d.ts +23 -343
  22. package/dist/conversation/index.js +36 -896
  23. package/dist/conversation/index.js.map +1 -1
  24. package/dist/index.cjs +70 -8
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +2 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.js +2 -1
  29. package/dist/runtime-B4nKwOTF.d.ts +232 -0
  30. package/dist/runtime-DDxwWBBr.d.cts +232 -0
  31. package/dist/{session--W6JXfwo.d.cts → session-8W3fRNeb.d.cts} +1635 -251
  32. package/dist/{session--W6JXfwo.d.ts → session-8W3fRNeb.d.ts} +1635 -251
  33. package/dist/store-C7FtS5AY.d.cts +384 -0
  34. package/dist/store-DFk0ayh8.d.ts +384 -0
  35. package/dist/testing/index.cjs +237 -0
  36. package/dist/testing/index.cjs.map +1 -0
  37. package/dist/testing/index.d.cts +49 -0
  38. package/dist/testing/index.d.ts +49 -0
  39. package/dist/testing/index.js +222 -0
  40. package/dist/testing/index.js.map +1 -0
  41. package/package.json +36 -4
  42. package/dist/chunk-AWHPWRGT.js.map +0 -1
@@ -0,0 +1,57 @@
1
+ import { S as Schemas, C as CardLink } from '../session-8W3fRNeb.cjs';
2
+ export { A as AgentBackend, a as AgentClock, b as AgentConversation, c as AgentConversationState, d as AgentEvent, e as AgentEventType, f as AgentFailure, g as AgentFailureReason, h as AgentInsecureAddresses, i as AgentKey, j as AgentPlace, k as AgentRating, l as AgentRefusal, m as AgentRetryPolicy, n as AgentRuntime, o as AgentRuntimeOptions, p as AgentSessionRequest, q as AgentStatus, r as AgentStatusRead, s as agentKey, t as createAgentRuntime } from '../runtime-DDxwWBBr.cjs';
3
+ import '../store-C7FtS5AY.cjs';
4
+
5
+ /** An amount in minor units with its ISO 4217 currency. */
6
+ interface AgentMoney {
7
+ readonly amount: number;
8
+ readonly currency: string;
9
+ }
10
+ interface AgentCardAction {
11
+ readonly action: string;
12
+ readonly label: string;
13
+ readonly deepLink: string | null;
14
+ }
15
+ /** What a card is about, as the tenant's tools name it: a UI routes a tap on the card here. */
16
+ interface AgentCardTarget {
17
+ readonly type: string;
18
+ readonly id: string;
19
+ }
20
+ interface ReadCard {
21
+ readonly id: string;
22
+ readonly kind: Schemas['Card']['kind'];
23
+ /** `professional` and `workspace`: drawn as a listing (photo, rating, price from, next open time). */
24
+ readonly listing: boolean;
25
+ readonly title: string;
26
+ readonly subtitle: string | null;
27
+ readonly body: string | null;
28
+ readonly badges: readonly string[];
29
+ readonly actions: readonly AgentCardAction[];
30
+ readonly target: AgentCardTarget | null;
31
+ /** The hero photo: the first https image, else `image_url`; `ratio` is width / height when both are known. */
32
+ readonly hero: {
33
+ readonly url: string;
34
+ readonly ratio: number | null;
35
+ } | null;
36
+ readonly rating: {
37
+ readonly stars: number;
38
+ readonly count: number;
39
+ } | null;
40
+ readonly priceFrom: AgentMoney | null;
41
+ readonly price: AgentMoney | null;
42
+ readonly nextAvailable: string | null;
43
+ readonly startsAt: string | null;
44
+ /** Cards one turn draws together; `carousel` draws them in a row, anything else a list. */
45
+ readonly group: {
46
+ readonly id: string;
47
+ readonly layout: 'list' | 'carousel';
48
+ } | null;
49
+ /** A `links` card's links, each with a label of at most 40 code points and a known purpose. */
50
+ readonly links: readonly CardLink[];
51
+ /** A `proposal` card's proposal id. */
52
+ readonly proposalId: string | null;
53
+ }
54
+ /** The contract's card (a `HeldCard`'s `card`, or a frame's), read for drawing; null for a kind this client skips. */
55
+ declare function readCard(value: unknown): ReadCard | null;
56
+
57
+ export { type AgentCardAction, type AgentCardTarget, type AgentMoney, type ReadCard, readCard };
@@ -0,0 +1,57 @@
1
+ import { S as Schemas, C as CardLink } from '../session-8W3fRNeb.js';
2
+ export { A as AgentBackend, a as AgentClock, b as AgentConversation, c as AgentConversationState, d as AgentEvent, e as AgentEventType, f as AgentFailure, g as AgentFailureReason, h as AgentInsecureAddresses, i as AgentKey, j as AgentPlace, k as AgentRating, l as AgentRefusal, m as AgentRetryPolicy, n as AgentRuntime, o as AgentRuntimeOptions, p as AgentSessionRequest, q as AgentStatus, r as AgentStatusRead, s as agentKey, t as createAgentRuntime } from '../runtime-B4nKwOTF.js';
3
+ import '../store-DFk0ayh8.js';
4
+
5
+ /** An amount in minor units with its ISO 4217 currency. */
6
+ interface AgentMoney {
7
+ readonly amount: number;
8
+ readonly currency: string;
9
+ }
10
+ interface AgentCardAction {
11
+ readonly action: string;
12
+ readonly label: string;
13
+ readonly deepLink: string | null;
14
+ }
15
+ /** What a card is about, as the tenant's tools name it: a UI routes a tap on the card here. */
16
+ interface AgentCardTarget {
17
+ readonly type: string;
18
+ readonly id: string;
19
+ }
20
+ interface ReadCard {
21
+ readonly id: string;
22
+ readonly kind: Schemas['Card']['kind'];
23
+ /** `professional` and `workspace`: drawn as a listing (photo, rating, price from, next open time). */
24
+ readonly listing: boolean;
25
+ readonly title: string;
26
+ readonly subtitle: string | null;
27
+ readonly body: string | null;
28
+ readonly badges: readonly string[];
29
+ readonly actions: readonly AgentCardAction[];
30
+ readonly target: AgentCardTarget | null;
31
+ /** The hero photo: the first https image, else `image_url`; `ratio` is width / height when both are known. */
32
+ readonly hero: {
33
+ readonly url: string;
34
+ readonly ratio: number | null;
35
+ } | null;
36
+ readonly rating: {
37
+ readonly stars: number;
38
+ readonly count: number;
39
+ } | null;
40
+ readonly priceFrom: AgentMoney | null;
41
+ readonly price: AgentMoney | null;
42
+ readonly nextAvailable: string | null;
43
+ readonly startsAt: string | null;
44
+ /** Cards one turn draws together; `carousel` draws them in a row, anything else a list. */
45
+ readonly group: {
46
+ readonly id: string;
47
+ readonly layout: 'list' | 'carousel';
48
+ } | null;
49
+ /** A `links` card's links, each with a label of at most 40 code points and a known purpose. */
50
+ readonly links: readonly CardLink[];
51
+ /** A `proposal` card's proposal id. */
52
+ readonly proposalId: string | null;
53
+ }
54
+ /** The contract's card (a `HeldCard`'s `card`, or a frame's), read for drawing; null for a kind this client skips. */
55
+ declare function readCard(value: unknown): ReadCard | null;
56
+
57
+ export { type AgentCardAction, type AgentCardTarget, type AgentMoney, type ReadCard, readCard };
@@ -0,0 +1,99 @@
1
+ export { AgentRefusal, agentKey, createAgentRuntime } from '../chunk-3WR2SUG2.js';
2
+ import '../chunk-ZWG2TMUL.js';
3
+ import { isKnownCard } from '../chunk-GWLLUOFY.js';
4
+
5
+ // src/agent/cards.ts
6
+ var LISTING = /* @__PURE__ */ new Set(["professional", "workspace"]);
7
+ var PURPOSES = /* @__PURE__ */ new Set(["help", "support", "policy", "contact", "feedback"]);
8
+ var GROUP_ID = /^[A-Za-z0-9_-]{1,64}$/;
9
+ var CURRENCY = /^[A-Z]{3}$/;
10
+ var isFields = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
11
+ var text = (v) => typeof v === "string" ? v : null;
12
+ var whole = (v) => typeof v === "number" && Number.isInteger(v) ? v : null;
13
+ var list = (v) => Array.isArray(v) ? v : [];
14
+ var https = (v) => {
15
+ const url = text(v);
16
+ return url !== null && /^https:\/\//i.test(url) ? url : null;
17
+ };
18
+ var instant = (v) => {
19
+ const at = text(v);
20
+ return at !== null && !Number.isNaN(Date.parse(at)) ? at : null;
21
+ };
22
+ function money(v) {
23
+ if (!isFields(v)) return null;
24
+ const amount = whole(v.amount);
25
+ const currency = text(v.currency);
26
+ return amount !== null && amount >= 0 && currency !== null && CURRENCY.test(currency) ? { amount, currency } : null;
27
+ }
28
+ function hero(card) {
29
+ for (const image of list(card.images)) {
30
+ if (!isFields(image)) continue;
31
+ const url = https(image.url);
32
+ if (url === null) continue;
33
+ const width = whole(image.width);
34
+ const height = whole(image.height);
35
+ return {
36
+ url,
37
+ ratio: width && height && width > 0 && height > 0 ? width / height : null
38
+ };
39
+ }
40
+ const legacy = https(card.image_url);
41
+ return legacy === null ? null : { url: legacy, ratio: null };
42
+ }
43
+ function readCard(value) {
44
+ if (!isFields(value)) return null;
45
+ const id = text(value.id);
46
+ const kind = text(value.kind);
47
+ const title = text(value.title);
48
+ if (id === null || kind === null || title === null) return null;
49
+ if (!isKnownCard({ kind })) return null;
50
+ const rating = isFields(value.rating) ? value.rating : null;
51
+ const ppm = whole(rating?.value_ppm);
52
+ const count = whole(rating?.count);
53
+ const group = isFields(value.group) ? value.group : null;
54
+ const groupId = text(group?.id);
55
+ const ref = isFields(value.ref) ? value.ref : null;
56
+ const refType = text(ref?.type);
57
+ const refId = text(ref?.id);
58
+ const proposal = isFields(value.proposal) ? value.proposal : null;
59
+ return {
60
+ id,
61
+ kind,
62
+ listing: LISTING.has(kind),
63
+ title,
64
+ subtitle: text(value.subtitle),
65
+ body: text(value.body),
66
+ badges: list(value.badges).filter(
67
+ (b) => typeof b === "string"
68
+ ),
69
+ actions: list(value.actions).flatMap((a) => {
70
+ if (!isFields(a)) return [];
71
+ const action = text(a.action);
72
+ const label = text(a.label);
73
+ return action === null || label === null ? [] : [{ action, label, deepLink: text(a.deep_link) }];
74
+ }),
75
+ target: refType !== null && refId !== null ? { type: refType, id: refId } : null,
76
+ hero: hero(value),
77
+ rating: ppm !== null && count !== null && ppm >= 0 && ppm <= 5e6 && count >= 0 ? { stars: ppm / 1e6, count } : null,
78
+ priceFrom: money(value.price_from),
79
+ price: money(value.price),
80
+ nextAvailable: instant(value.next_available),
81
+ startsAt: instant(value.starts_at),
82
+ group: groupId !== null && GROUP_ID.test(groupId) ? {
83
+ id: groupId,
84
+ layout: group?.layout === "carousel" ? "carousel" : "list"
85
+ } : null,
86
+ links: list(value.links).flatMap((l) => {
87
+ if (!isFields(l)) return [];
88
+ const label = text(l.label);
89
+ const url = text(l.url)?.trim() ?? "";
90
+ const purpose = text(l.purpose);
91
+ return label && [...label].length <= 40 && url && purpose && PURPOSES.has(purpose) ? [{ label, url, purpose }] : [];
92
+ }),
93
+ proposalId: kind === "proposal" ? text(proposal?.id) : null
94
+ };
95
+ }
96
+
97
+ export { readCard };
98
+ //# sourceMappingURL=index.js.map
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/agent/cards.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// A card as a UI draws it: the contract's card read once, every field checked, so a renderer never meets a bad value\n// (a photo that is not https, a rating out of range, a group id the contract would refuse). A kind this client does not\n// know is null: the UI skips it (§5).\nimport type { CardLink, Schemas } from '../events.js';\nimport { isKnownCard } from '../events.js';\n\ntype Fields = Readonly<Record<string, unknown>>;\n\n/** An amount in minor units with its ISO 4217 currency. */\nexport interface AgentMoney {\n readonly amount: number;\n readonly currency: string;\n}\n\nexport interface AgentCardAction {\n readonly action: string;\n readonly label: string;\n readonly deepLink: string | null;\n}\n\n/** What a card is about, as the tenant's tools name it: a UI routes a tap on the card here. */\nexport interface AgentCardTarget {\n readonly type: string;\n readonly id: string;\n}\n\nexport interface ReadCard {\n readonly id: string;\n readonly kind: Schemas['Card']['kind'];\n /** `professional` and `workspace`: drawn as a listing (photo, rating, price from, next open time). */\n readonly listing: boolean;\n readonly title: string;\n readonly subtitle: string | null;\n readonly body: string | null;\n readonly badges: readonly string[];\n readonly actions: readonly AgentCardAction[];\n readonly target: AgentCardTarget | null;\n /** The hero photo: the first https image, else `image_url`; `ratio` is width / height when both are known. */\n readonly hero: { readonly url: string; readonly ratio: number | null } | null;\n readonly rating: { readonly stars: number; readonly count: number } | null;\n readonly priceFrom: AgentMoney | null;\n readonly price: AgentMoney | null;\n readonly nextAvailable: string | null;\n readonly startsAt: string | null;\n /** Cards one turn draws together; `carousel` draws them in a row, anything else a list. */\n readonly group: {\n readonly id: string;\n readonly layout: 'list' | 'carousel';\n } | null;\n /** A `links` card's links, each with a label of at most 40 code points and a known purpose. */\n readonly links: readonly CardLink[];\n /** A `proposal` card's proposal id. */\n readonly proposalId: string | null;\n}\n\nconst LISTING = new Set(['professional', 'workspace']);\nconst PURPOSES = new Set(['help', 'support', 'policy', 'contact', 'feedback']);\nconst GROUP_ID = /^[A-Za-z0-9_-]{1,64}$/;\nconst CURRENCY = /^[A-Z]{3}$/;\n\nconst isFields = (v: unknown): v is Fields =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\nconst text = (v: unknown): string | null => (typeof v === 'string' ? v : null);\nconst whole = (v: unknown): number | null =>\n typeof v === 'number' && Number.isInteger(v) ? v : null;\nconst list = (v: unknown): readonly unknown[] => (Array.isArray(v) ? v : []);\nconst https = (v: unknown): string | null => {\n const url = text(v);\n return url !== null && /^https:\\/\\//i.test(url) ? url : null;\n};\nconst instant = (v: unknown): string | null => {\n const at = text(v);\n return at !== null && !Number.isNaN(Date.parse(at)) ? at : null;\n};\n\nfunction money(v: unknown): AgentMoney | null {\n if (!isFields(v)) return null;\n const amount = whole(v.amount);\n const currency = text(v.currency);\n return amount !== null &&\n amount >= 0 &&\n currency !== null &&\n CURRENCY.test(currency)\n ? { amount, currency }\n : null;\n}\n\nfunction hero(card: Fields): ReadCard['hero'] {\n for (const image of list(card.images)) {\n if (!isFields(image)) continue;\n const url = https(image.url);\n if (url === null) continue;\n const width = whole(image.width);\n const height = whole(image.height);\n return {\n url,\n ratio: width && height && width > 0 && height > 0 ? width / height : null,\n };\n }\n const legacy = https(card.image_url);\n return legacy === null ? null : { url: legacy, ratio: null };\n}\n\n/** The contract's card (a `HeldCard`'s `card`, or a frame's), read for drawing; null for a kind this client skips. */\nexport function readCard(value: unknown): ReadCard | null {\n if (!isFields(value)) return null;\n const id = text(value.id);\n const kind = text(value.kind);\n const title = text(value.title);\n if (id === null || kind === null || title === null) return null;\n if (!isKnownCard({ kind })) return null;\n const rating = isFields(value.rating) ? value.rating : null;\n const ppm = whole(rating?.value_ppm);\n const count = whole(rating?.count);\n const group = isFields(value.group) ? value.group : null;\n const groupId = text(group?.id);\n const ref = isFields(value.ref) ? value.ref : null;\n const refType = text(ref?.type);\n const refId = text(ref?.id);\n const proposal = isFields(value.proposal) ? value.proposal : null;\n return {\n id,\n kind: kind as ReadCard['kind'],\n listing: LISTING.has(kind),\n title,\n subtitle: text(value.subtitle),\n body: text(value.body),\n badges: list(value.badges).filter(\n (b): b is string => typeof b === 'string',\n ),\n actions: list(value.actions).flatMap((a) => {\n if (!isFields(a)) return [];\n const action = text(a.action);\n const label = text(a.label);\n return action === null || label === null\n ? []\n : [{ action, label, deepLink: text(a.deep_link) }];\n }),\n target:\n refType !== null && refId !== null ? { type: refType, id: refId } : null,\n hero: hero(value),\n rating:\n ppm !== null &&\n count !== null &&\n ppm >= 0 &&\n ppm <= 5_000_000 &&\n count >= 0\n ? { stars: ppm / 1_000_000, count }\n : null,\n priceFrom: money(value.price_from),\n price: money(value.price),\n nextAvailable: instant(value.next_available),\n startsAt: instant(value.starts_at),\n group:\n groupId !== null && GROUP_ID.test(groupId)\n ? {\n id: groupId,\n layout: group?.layout === 'carousel' ? 'carousel' : 'list',\n }\n : null,\n links: list(value.links).flatMap((l) => {\n if (!isFields(l)) return [];\n const label = text(l.label);\n const url = text(l.url)?.trim() ?? '';\n const purpose = text(l.purpose);\n return label &&\n [...label].length <= 40 &&\n url &&\n purpose &&\n PURPOSES.has(purpose)\n ? [{ label, url, purpose: purpose as CardLink['purpose'] }]\n : [];\n }),\n proposalId: kind === 'proposal' ? text(proposal?.id) : null,\n };\n}\n"]}
@@ -0,0 +1,416 @@
1
+ import { createConversation } from './chunk-ZWG2TMUL.js';
2
+
3
+ // src/agent/runtime.ts
4
+ var AgentRefusal = class extends Error {
5
+ constructor(kind, options = {}) {
6
+ super(
7
+ options.message ?? (kind === "ended" ? "The conversation is over." : "No agent now.")
8
+ );
9
+ this.kind = kind;
10
+ this.name = "AgentRefusal";
11
+ this.reason = options.reason ?? (kind === "ended" ? "ended" : "unknown");
12
+ this.code = options.code ?? null;
13
+ }
14
+ kind;
15
+ reason;
16
+ code;
17
+ };
18
+ var NOT_KEPT = /* @__PURE__ */ new Set(["starting", "unavailable", "unauthorized", "closed"]);
19
+ var NO_FEATURES = {
20
+ history: false,
21
+ memory: false,
22
+ businessAgent: false,
23
+ businessSetup: false
24
+ };
25
+ var SYSTEM_CLOCK = { now: () => Date.now() };
26
+ function agentKey(key) {
27
+ return `${key.subject ?? "guest"}|${key.mode}|${key.scope ?? "-"}|${key.thread ?? "chat"}`;
28
+ }
29
+ var samePlace = (a, b) => a?.screen === b?.screen && (a?.entity?.type ?? null) === (b?.entity?.type ?? null) && (a?.entity?.id ?? null) === (b?.entity?.id ?? null) && JSON.stringify(a?.filters ?? null) === JSON.stringify(b?.filters ?? null);
30
+ function usable(session, insecure) {
31
+ return typeof session.id === "string" && session.id !== "" && (insecure.realtime === true || /^wss:\/\//i.test(session.realtime_url ?? "")) && (insecure.turns === true || /^https:\/\//i.test(session.turns_url ?? "")) && Boolean(session.client_secret);
32
+ }
33
+ function warnInsecure(insecure) {
34
+ if (!(insecure.realtime || insecure.turns)) return;
35
+ if (globalThis.__DEV__ === true) return;
36
+ console.warn(
37
+ "@vinaverse/client/agent: insecureAddresses lets sessions use plaintext ws:// or http:// addresses. It is for mocks and local development only; remove it from release builds."
38
+ );
39
+ }
40
+ function createAgentRuntime(options) {
41
+ const { backend } = options;
42
+ const policy = {
43
+ delays: options.retry?.delays ?? [500, 1500, 3500],
44
+ isRetryable: options.retry?.isRetryable ?? retryable
45
+ };
46
+ const clock = options.clock ?? SYSTEM_CLOCK;
47
+ const keepAlive = options.keepAlive ?? "session";
48
+ const staleMs = options.statusStaleMs ?? 5 * 6e4;
49
+ const insecure = options.insecureAddresses ?? {};
50
+ warnInsecure(insecure);
51
+ const live = /* @__PURE__ */ new Map();
52
+ const current = /* @__PURE__ */ new Map();
53
+ const listeners = /* @__PURE__ */ new Set();
54
+ let status = null;
55
+ let reading = null;
56
+ let sessionName = null;
57
+ const emit = (event) => options.onEvent?.(event);
58
+ const changed = () => {
59
+ for (const l of [...listeners]) l();
60
+ };
61
+ const update = (entry, next) => {
62
+ entry.state = { ...entry.state, ...next };
63
+ for (const l of [...entry.listeners]) l();
64
+ };
65
+ const end = (k) => {
66
+ const entry = live.get(k);
67
+ if (!entry) return;
68
+ live.delete(k);
69
+ entry.store.dispose();
70
+ emit({ type: "conversation_ended", key: k });
71
+ changed();
72
+ };
73
+ const patiently = (run, signal, key) => retrying(
74
+ run,
75
+ policy,
76
+ signal,
77
+ (attempt) => emit({ type: "session_retried", key, attempt })
78
+ );
79
+ async function open(entry, key, request) {
80
+ if (live.get(entry.key) !== entry) throw new AgentRefusal("unavailable");
81
+ const told = entry.place;
82
+ const conversationId = request.conversationId ?? current.get(entry.key) ?? null;
83
+ let session;
84
+ try {
85
+ session = await patiently(
86
+ () => backend.openSession({
87
+ ...request,
88
+ conversationId,
89
+ key,
90
+ place: told,
91
+ entryPoint: entry.entryPoint
92
+ }),
93
+ request.signal,
94
+ entry.key
95
+ );
96
+ if (!usable(session, insecure))
97
+ throw new AgentRefusal("unavailable", {
98
+ reason: "invalid_session",
99
+ message: "The session is not usable (an id, a secret, a wss:// realtime_url and an https:// turns_url)."
100
+ });
101
+ } catch (error) {
102
+ if (live.get(entry.key) === entry) {
103
+ const failure = error instanceof AgentRefusal ? error.kind === "ended" && conversationId !== null ? "ended" : "unavailable" : policy.isRetryable(error) ? "unreachable" : "unavailable";
104
+ const reason = reasonOf(error, failure);
105
+ const code = error instanceof AgentRefusal ? error.code : codeOf(error);
106
+ update(entry, { failure, reason, code });
107
+ emit({ type: "session_failed", key: entry.key, failure, reason });
108
+ }
109
+ throw error;
110
+ }
111
+ if (live.get(entry.key) !== entry) throw new AgentRefusal("unavailable");
112
+ entry.told = told;
113
+ entry.expiresAt = session.expires_at ? Date.parse(session.expires_at) : null;
114
+ if (session.conversation_id)
115
+ current.set(entry.key, session.conversation_id);
116
+ const name = session.agent?.display_name?.trim();
117
+ if (name && name !== sessionName) {
118
+ sessionName = name;
119
+ changed();
120
+ }
121
+ update(entry, {
122
+ failure: null,
123
+ reason: null,
124
+ code: null,
125
+ sessionId: session.id,
126
+ moved: !samePlace(told, entry.place)
127
+ });
128
+ emit({
129
+ type: conversationId === null ? "session_opened" : "session_resumed",
130
+ key: entry.key,
131
+ sessionId: session.id,
132
+ ...entry.entryPoint ? { from: entry.entryPoint } : {}
133
+ });
134
+ return session;
135
+ }
136
+ const kept = (k) => `${options.conversation?.persistenceKey ?? "vinaverse.agent"}.${k}`;
137
+ function make(key) {
138
+ const k = agentKey(key);
139
+ const own = options.conversation ?? {};
140
+ const refresh = backend.refreshSecret?.bind(backend);
141
+ const entry = {
142
+ key: k,
143
+ store: createConversation({
144
+ ...own,
145
+ ...own.persistence ? {
146
+ persistenceKey: kept(k)
147
+ } : {},
148
+ getSession: (request) => open(entry, key, request),
149
+ ...refresh ? {
150
+ refreshSecret: (id) => patiently(() => refresh(id), void 0, k)
151
+ } : {},
152
+ clock,
153
+ onError: (error) => {
154
+ if (!(error instanceof AgentRefusal)) own.onError?.(error);
155
+ }
156
+ }),
157
+ listeners: /* @__PURE__ */ new Set(),
158
+ state: {
159
+ failure: null,
160
+ reason: null,
161
+ code: null,
162
+ moved: false,
163
+ ratings: /* @__PURE__ */ new Map(),
164
+ sessionId: null
165
+ },
166
+ place: null,
167
+ told: null,
168
+ revision: 0,
169
+ entryPoint: null,
170
+ expiresAt: null,
171
+ shown: 0,
172
+ started: false,
173
+ suspended: false,
174
+ sentOnce: /* @__PURE__ */ new Set()
175
+ };
176
+ return entry;
177
+ }
178
+ const over = (entry) => entry.expiresAt !== null && entry.expiresAt <= clock.now();
179
+ const tell = (entry, at) => {
180
+ entry.place = at.place ?? null;
181
+ entry.entryPoint = at.entryPoint ?? null;
182
+ const sessionId = entry.state.sessionId;
183
+ const moved = sessionId !== null && !samePlace(entry.told, entry.place);
184
+ update(entry, { moved });
185
+ const place = entry.place;
186
+ if (!moved || !place || !backend.updateContext || sessionId === null)
187
+ return;
188
+ const revision = ++entry.revision;
189
+ backend.updateContext(sessionId, place, revision).then(
190
+ () => {
191
+ if (live.get(entry.key) !== entry || entry.revision !== revision)
192
+ return;
193
+ entry.told = place;
194
+ update(entry, { moved: !samePlace(entry.told, entry.place) });
195
+ emit({ type: "context_updated", key: entry.key, sessionId });
196
+ },
197
+ () => void 0
198
+ // not served, or refused: the question about this place stays the way to say it
199
+ );
200
+ };
201
+ function handle(entry) {
202
+ return {
203
+ key: entry.key,
204
+ store: entry.store,
205
+ show(at = {}) {
206
+ if (live.get(entry.key) !== entry) return () => void 0;
207
+ if (entry.shown === 0 && over(entry)) {
208
+ end(entry.key);
209
+ return () => void 0;
210
+ }
211
+ entry.shown++;
212
+ if (entry.suspended) {
213
+ entry.suspended = false;
214
+ entry.store.setForeground(true);
215
+ }
216
+ tell(entry, at);
217
+ if (!entry.started) {
218
+ entry.started = true;
219
+ entry.store.start();
220
+ }
221
+ let released = false;
222
+ return () => {
223
+ if (released) return;
224
+ released = true;
225
+ entry.shown--;
226
+ if (entry.shown > 0 || live.get(entry.key) !== entry) return;
227
+ if (keepAlive === "view" || NOT_KEPT.has(entry.store.getSnapshot().status) || entry.expiresAt === null || over(entry)) {
228
+ end(entry.key);
229
+ return;
230
+ }
231
+ entry.suspended = true;
232
+ entry.store.setForeground(false);
233
+ };
234
+ },
235
+ tell: (at) => tell(entry, at),
236
+ getState: () => entry.state,
237
+ subscribe(listener) {
238
+ entry.listeners.add(listener);
239
+ return () => entry.listeners.delete(listener);
240
+ },
241
+ retry() {
242
+ update(entry, { failure: null, reason: null, code: null });
243
+ entry.store.start();
244
+ },
245
+ rate(turnId, rating) {
246
+ const sessionId = entry.state.sessionId;
247
+ if (sessionId === null || entry.state.ratings.get(turnId) === rating)
248
+ return;
249
+ update(entry, {
250
+ ratings: new Map(entry.state.ratings).set(turnId, rating)
251
+ });
252
+ emit({ type: "rated", key: entry.key, sessionId, turnId, rating });
253
+ void backend.sendFeedback?.({ sessionId, turnId, rating }).catch(() => void 0);
254
+ },
255
+ sendOnce(text) {
256
+ if (entry.sentOnce.has(text)) return;
257
+ entry.sentOnce.add(text);
258
+ entry.store.send(text);
259
+ }
260
+ };
261
+ }
262
+ const handles = /* @__PURE__ */ new WeakMap();
263
+ const lookup = (key) => {
264
+ const k = agentKey(key);
265
+ let entry = live.get(k);
266
+ if (!entry) {
267
+ entry = make(key);
268
+ live.set(k, entry);
269
+ }
270
+ let h = handles.get(entry);
271
+ if (!h) {
272
+ h = handle(entry);
273
+ handles.set(entry, h);
274
+ }
275
+ return h;
276
+ };
277
+ return {
278
+ conversation(key) {
279
+ const k = agentKey(key);
280
+ const entry = live.get(k);
281
+ if (entry && entry.shown === 0 && over(entry)) end(k);
282
+ return lookup(key);
283
+ },
284
+ peek: lookup,
285
+ startNew(key) {
286
+ const k = agentKey(key);
287
+ current.delete(k);
288
+ end(k);
289
+ },
290
+ dispose(key) {
291
+ end(agentKey(key));
292
+ },
293
+ continue(key, conversationId) {
294
+ const k = agentKey(key);
295
+ if (current.get(k) !== conversationId) {
296
+ current.set(k, conversationId);
297
+ const entry = live.get(k);
298
+ if (entry) {
299
+ entry.store.clear();
300
+ end(k);
301
+ } else {
302
+ try {
303
+ void Promise.resolve(
304
+ options.conversation?.persistence?.removeItem(kept(k))
305
+ ).catch(() => void 0);
306
+ } catch {
307
+ }
308
+ }
309
+ }
310
+ return lookup(key);
311
+ },
312
+ async signOut() {
313
+ for (const entry of live.values()) entry.store.clear();
314
+ live.clear();
315
+ current.clear();
316
+ sessionName = null;
317
+ changed();
318
+ await backend.endSessions?.().catch(() => void 0);
319
+ },
320
+ status() {
321
+ if (status && clock.now() - status.at < staleMs)
322
+ return Promise.resolve(status.value);
323
+ reading ??= readStatus(backend).then(
324
+ (value) => {
325
+ reading = null;
326
+ status = { value, at: clock.now() };
327
+ changed();
328
+ return value;
329
+ },
330
+ (error) => {
331
+ reading = null;
332
+ throw error;
333
+ }
334
+ );
335
+ return reading;
336
+ },
337
+ getStatus: () => status?.value ?? null,
338
+ getName: () => sessionName ?? status?.value.displayName ?? null,
339
+ subscribe(listener) {
340
+ listeners.add(listener);
341
+ return () => listeners.delete(listener);
342
+ },
343
+ emit
344
+ };
345
+ }
346
+ async function readStatus(backend) {
347
+ const read = backend.status ? await backend.status() : { available: true };
348
+ const available = read.available === true;
349
+ const features = read.features ?? NO_FEATURES;
350
+ return {
351
+ available,
352
+ launcher: available && read.launcher === true,
353
+ displayName: read.displayName?.trim() || null,
354
+ avatarUrl: read.avatarUrl?.startsWith("https://") ? read.avatarUrl : null,
355
+ features: {
356
+ history: available && features.history === true,
357
+ memory: available && features.memory === true,
358
+ businessAgent: available && features.businessAgent === true,
359
+ businessSetup: available && features.businessSetup === true
360
+ }
361
+ };
362
+ }
363
+ var field = (error, name) => typeof error === "object" && error !== null ? error[name] : void 0;
364
+ var retryable = (error) => field(error, "retryable") === true;
365
+ var REASONS = /* @__PURE__ */ new Set([
366
+ "ended",
367
+ "auth",
368
+ "off",
369
+ "rate_limited",
370
+ "network",
371
+ "server",
372
+ "invalid_session",
373
+ "unknown"
374
+ ]);
375
+ function reasonOf(error, failure) {
376
+ if (error instanceof AgentRefusal) return error.reason;
377
+ const given = field(error, "reason");
378
+ if (typeof given === "string" && REASONS.has(given))
379
+ return given;
380
+ const status = field(error, "status");
381
+ if (status === 401 || status === 403) return "auth";
382
+ if (status === 429) return "rate_limited";
383
+ if (typeof status === "number" && status >= 500) return "server";
384
+ return failure === "unreachable" ? "network" : "unknown";
385
+ }
386
+ function codeOf(error) {
387
+ const code = field(error, "code");
388
+ return typeof code === "string" ? code : null;
389
+ }
390
+ async function retrying(run, policy, signal, onRetry) {
391
+ for (let attempt = 0; ; attempt++) {
392
+ try {
393
+ return await run();
394
+ } catch (error) {
395
+ const wait = policy.delays[attempt];
396
+ if (wait === void 0 || !policy.isRetryable(error) || signal?.aborted)
397
+ throw error;
398
+ await new Promise((resolve, reject) => {
399
+ const timer = setTimeout(() => {
400
+ signal?.removeEventListener("abort", stop);
401
+ resolve();
402
+ }, wait);
403
+ function stop() {
404
+ clearTimeout(timer);
405
+ reject(error);
406
+ }
407
+ signal?.addEventListener("abort", stop, { once: true });
408
+ });
409
+ onRetry(attempt + 1);
410
+ }
411
+ }
412
+ }
413
+
414
+ export { AgentRefusal, agentKey, createAgentRuntime };
415
+ //# sourceMappingURL=chunk-3WR2SUG2.js.map
416
+ //# sourceMappingURL=chunk-3WR2SUG2.js.map