@vinaverse/client 0.1.0-alpha.6 → 0.1.0-alpha.7

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 (35) hide show
  1. package/README.md +66 -6
  2. package/dist/agent/index.cjs +523 -75
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +2 -2
  5. package/dist/agent/index.d.ts +2 -2
  6. package/dist/agent/index.js +2 -2
  7. package/dist/backend/index.cjs +268 -0
  8. package/dist/backend/index.cjs.map +1 -0
  9. package/dist/backend/index.d.cts +72 -0
  10. package/dist/backend/index.d.ts +72 -0
  11. package/dist/backend/index.js +250 -0
  12. package/dist/backend/index.js.map +1 -0
  13. package/dist/chunk-3BLRAWNC.js +840 -0
  14. package/dist/chunk-3BLRAWNC.js.map +1 -0
  15. package/dist/{chunk-ZWG2TMUL.js → chunk-46D3FSLU.js} +24 -2
  16. package/dist/chunk-46D3FSLU.js.map +1 -0
  17. package/dist/conversation/index.cjs +22 -0
  18. package/dist/conversation/index.cjs.map +1 -1
  19. package/dist/conversation/index.d.cts +2 -2
  20. package/dist/conversation/index.d.ts +2 -2
  21. package/dist/conversation/index.js +2 -2
  22. package/dist/{runtime-DLJbJkSr.d.ts → runtime-C3ZknHdG.d.cts} +137 -20
  23. package/dist/{runtime-CErMdYxJ.d.cts → runtime-CZ1hLvAl.d.ts} +137 -20
  24. package/dist/{store-C7FtS5AY.d.cts → store-7WU1kD9W.d.cts} +31 -1
  25. package/dist/{store-DFk0ayh8.d.ts → store-DrXSPHu6.d.ts} +31 -1
  26. package/dist/testing/index.cjs +38 -1
  27. package/dist/testing/index.cjs.map +1 -1
  28. package/dist/testing/index.d.cts +14 -3
  29. package/dist/testing/index.d.ts +14 -3
  30. package/dist/testing/index.js +40 -3
  31. package/dist/testing/index.js.map +1 -1
  32. package/package.json +21 -2
  33. package/dist/chunk-XPES5PZ3.js +0 -416
  34. package/dist/chunk-XPES5PZ3.js.map +0 -1
  35. package/dist/chunk-ZWG2TMUL.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// @vinaverse/client/testing: a scripted agent for an app's mock mode and tests, with no tenant and no network. It is an\n// `AgentBackend` (sessions, fresh secrets, status, feedback) and a WebSocket factory that speaks the realtime protocol:\n// session.ready (resumed with the conversation's transcript), replies streamed sentence by sentence, cards, a turn that\n// fails, refusals when opening (ended, unreachable, unavailable). The app scripts only its own answers.\nimport type {\n AgentBackend,\n AgentSessionRequest,\n AgentStatusRead,\n} from '../agent/runtime.js';\nimport { AgentRefusal } from '../agent/runtime.js';\nimport type { ConversationSession } from '../conversation/store.js';\nimport type { Card, Welcome } from '../events.js';\nimport type { WebSocketFactory, WebSocketLike } from '../session.js';\n\n/** One reply of the scripted agent. */\nexport interface MockReply {\n readonly text?: string;\n readonly cards?: readonly Card[];\n /** The turn fails before any text, with this code (`internal`, `timeout`, …). */\n readonly fail?: string;\n}\n\nexport interface MockAgentOptions {\n /** The agent's answer to the person's text. Default: an echo. */\n readonly reply?: (\n text: string,\n context: { readonly turn: number; readonly key: string },\n ) => MockReply | string;\n readonly agentName?: string;\n readonly disclosure?: string;\n readonly welcome?: Welcome;\n /** A refusal when opening a session (the scripted backend's answer), by request. */\n readonly refuse?: (\n request: AgentSessionRequest,\n attempt: number,\n ) => 'ended' | 'unreachable' | 'unavailable' | undefined;\n /** How long a session lives. Default 30 minutes. */\n readonly sessionMs?: number;\n readonly status?: AgentStatusRead;\n /** The clock sessions are dated by; default the device's. */\n readonly now?: () => number;\n}\n\nexport interface MockAgent {\n readonly backend: AgentBackend;\n /** The store's transport: `conversation.transport.webSocket`. */\n readonly webSocket: WebSocketFactory;\n /** What the app sent: feedback, sessions asked for, places told. */\n readonly log: {\n readonly sessions: AgentSessionRequest[];\n readonly feedback: unknown[];\n readonly contexts: unknown[];\n readonly ended: number;\n };\n}\n\ninterface Said {\n readonly role: 'person' | 'assistant';\n readonly text: string;\n readonly id: string;\n}\n\nconst sentences = (text: string) => text.match(/[^.!?]+[.!?]*\\s*/g) ?? [text];\n\nexport function createMockAgent(options: MockAgentOptions = {}): MockAgent {\n const now = options.now ?? (() => Date.now());\n const conversations = new Map<string, Said[]>();\n const sessions = new Map<string, { conversation: string; key: string }>();\n const log = {\n sessions: [] as AgentSessionRequest[],\n feedback: [] as unknown[],\n contexts: [] as unknown[],\n ended: 0,\n };\n let attempts = 0;\n let count = 0;\n\n const backend: AgentBackend = {\n async openSession(request) {\n log.sessions.push(request);\n attempts++;\n const refusal = options.refuse?.(request, attempts);\n if (refusal === 'unreachable')\n throw Object.assign(new Error('mock: unreachable'), {\n retryable: true,\n reason: 'network',\n });\n if (refusal) throw new AgentRefusal(refusal);\n if (\n request.conversationId !== null &&\n !conversations.has(request.conversationId)\n )\n throw new AgentRefusal('ended', { code: 'conversation_not_found' });\n count++;\n const conversation = request.conversationId ?? `cnv_MOCK${count}`;\n if (!conversations.has(conversation)) conversations.set(conversation, []);\n const id = `ses_MOCK${count}`;\n sessions.set(id, { conversation, key: `${request.key.mode}` });\n const session: ConversationSession = {\n id,\n realtime_url: `wss://mock.vinaverse.invalid/v1/sessions/${id}/realtime`,\n turns_url: `https://mock.vinaverse.invalid/v1/sessions/${id}/turns`,\n client_secret: `vv_cs_${'mock'.repeat(6)}`,\n conversation_id: conversation,\n expires_at: new Date(\n now() + (options.sessionMs ?? 30 * 60_000),\n ).toISOString(),\n ...(options.agentName\n ? { agent: { display_name: options.agentName } }\n : {}),\n ...(options.disclosure ? { disclosure: options.disclosure } : {}),\n ...(options.welcome ? { welcome: options.welcome } : {}),\n };\n return session;\n },\n async refreshSecret() {\n return `vv_cs_${'mock'.repeat(6)}`;\n },\n async updateContext(sessionId, place, revision) {\n log.contexts.push({ sessionId, place, revision });\n },\n async status() {\n return (\n options.status ?? {\n available: true,\n launcher: true,\n displayName: options.agentName ?? null,\n }\n );\n },\n async sendFeedback(feedback) {\n log.feedback.push(feedback);\n },\n async endSessions() {\n log.ended++;\n },\n };\n\n const webSocket: WebSocketFactory = (url) => {\n const sessionId = /sessions\\/([^/]+)\\/realtime/.exec(url)?.[1] ?? '';\n const held = sessions.get(sessionId);\n const said = held ? (conversations.get(held.conversation) ?? []) : [];\n let turn = said.filter((s) => s.role === 'person').length;\n let state = 0;\n const socket: WebSocketLike = {\n get readyState() {\n return state;\n },\n onopen: null,\n onmessage: null,\n onclose: null,\n onerror: null,\n send(data) {\n const frame = JSON.parse(data) as Record<string, unknown>;\n if (frame.type === 'ping') return deliver({ type: 'pong' });\n if (frame.type !== 'input.text') return;\n const id = String(frame.client_event_id ?? '');\n const text = String(frame.text ?? '');\n turn++;\n const turnId = `turn_MOCK${turn}`;\n said.push({ role: 'person', text, id });\n const answer =\n options.reply?.(text, { turn, key: held?.key ?? '' }) ??\n `You said: ${text}`;\n const reply: MockReply =\n typeof answer === 'string' ? { text: answer } : answer;\n deliver({ type: 'turn.started', turn_id: turnId, client_event_id: id });\n if (reply.fail) {\n deliver({\n type: 'turn.failed',\n turn_id: turnId,\n code: reply.fail,\n message: '',\n retryable: true,\n });\n return;\n }\n let so = '';\n for (const part of reply.text ? sentences(reply.text) : []) {\n so += part;\n deliver({ type: 'message.delta', turn_id: turnId, text: part });\n }\n if (reply.text) {\n deliver({\n type: 'message.completed',\n turn_id: turnId,\n text: so.trim(),\n });\n said.push({ role: 'assistant', text: so.trim(), id: turnId });\n }\n if (reply.cards?.length)\n deliver({ type: 'ui.cards', turn_id: turnId, cards: reply.cards });\n deliver({ type: 'turn.completed', turn_id: turnId });\n },\n close(code) {\n if (state === 3) return;\n state = 3;\n setTimeout(() => socket.onclose?.({ code: code ?? 1000 }), 0);\n },\n };\n function deliver(event: unknown) {\n setTimeout(() => {\n if (state === 1) socket.onmessage?.({ data: JSON.stringify(event) });\n }, 0);\n }\n setTimeout(() => {\n state = 1;\n socket.onopen?.({});\n const resumed = said.length > 0;\n socket.onmessage?.({\n data: JSON.stringify({\n type: 'session.ready',\n session: { id: sessionId, status: 'open' },\n resumed,\n limits: {},\n disclosure:\n options.disclosure ?? 'An AI agent. Powered by Vinaverse.',\n ...(resumed\n ? {\n transcript: said.map((s) => ({\n role: s.role,\n text: s.text,\n id: s.id,\n at: new Date(now()).toISOString(),\n })),\n }\n : {}),\n }),\n });\n }, 0);\n return socket;\n };\n\n return { backend, webSocket, log };\n}\n\n/** Cards as a tenant's tools would give them, for mock replies and tests. */\nexport const mockCards = {\n professional(id: string, extra: Partial<Card> = {}): Card {\n return {\n id,\n kind: 'professional',\n title: 'Riley Sample',\n subtitle: 'Barber · Los Angeles',\n ref: { type: 'professional', id },\n images: [\n {\n url: `https://images.example.test/${id}.webp`,\n width: 1600,\n height: 1000,\n },\n ],\n rating: { value_ppm: 4_800_000, count: 132 },\n price_from: { amount: 4500, currency: 'USD' },\n actions: [],\n source: { tool: 'search_professionals', call_id: 'call_MOCK' },\n ...extra,\n } as Card;\n },\n workspace(id: string, extra: Partial<Card> = {}): Card {\n return {\n id,\n kind: 'workspace',\n title: 'Suite 4',\n subtitle: 'Private suite · Atlanta',\n ref: { type: 'workspace', id },\n price_from: { amount: 6500, currency: 'USD' },\n actions: [],\n source: { tool: 'search_spaces', call_id: 'call_MOCK' },\n ...extra,\n } as Card;\n },\n links(id: string): Card {\n return {\n id,\n kind: 'links',\n title: 'Pages that can help',\n links: [\n {\n label: 'Help center',\n url: 'https://help.example.test/',\n purpose: 'help',\n },\n {\n label: 'Contact us',\n url: 'https://help.example.test/contact',\n purpose: 'contact',\n },\n ],\n actions: [],\n source: { tool: 'scope', call_id: 'turn_MOCK' },\n } as Card;\n },\n};\n"]}
1
+ {"version":3,"sources":["../../src/testing/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// @vinaverse/client/testing: a scripted agent for an app's mock mode and tests, with no tenant and no network. It is an\n// `AgentBackend` (sessions, fresh secrets, status, feedback) and a WebSocket factory that speaks the realtime protocol:\n// session.ready (resumed with the conversation's transcript), replies streamed sentence by sentence, cards, a turn that\n// fails, refusals when opening (ended, unreachable, unavailable). The app scripts only its own answers.\nimport type {\n AgentBackend,\n AgentSessionRequest,\n AgentStatusRead,\n} from '../agent/runtime.js';\nimport { AgentRefusal } from '../agent/runtime.js';\nimport type { ConversationSession } from '../conversation/store.js';\nimport type { Card, Welcome } from '../events.js';\nimport type { WebSocketFactory, WebSocketLike } from '../session.js';\n\n/** One reply of the scripted agent. */\nexport interface MockReply {\n readonly text?: string;\n readonly cards?: readonly Card[];\n /** The turn fails before any text, with this code (`internal`, `timeout`, …). */\n readonly fail?: string;\n}\n\nexport interface MockAgentOptions {\n /** Replies in order, one per turn (text, cards, a failure), after which `reply` (or the echo) answers. */\n readonly script?: readonly (MockReply | string)[];\n /** The agent's answer to the person's text. Default: the `script`, then an echo. */\n readonly reply?: (\n text: string,\n context: { readonly turn: number; readonly key: string },\n ) => MockReply | string;\n readonly agentName?: string;\n readonly disclosure?: string;\n readonly welcome?: Welcome;\n /** A refusal when opening a session (the scripted backend's answer), by request. */\n readonly refuse?: (\n request: AgentSessionRequest,\n attempt: number,\n ) => 'ended' | 'unreachable' | 'unavailable' | undefined;\n /** How long a session lives. Default 30 minutes. */\n readonly sessionMs?: number;\n readonly status?: AgentStatusRead;\n /** The clock sessions are dated by; default the device's. */\n readonly now?: () => number;\n}\n\nexport interface MockAgent {\n readonly backend: AgentBackend;\n /** The store's transport: `conversation.transport.webSocket`. */\n readonly webSocket: WebSocketFactory;\n /** What the app sent: feedback, sessions asked for, places told. */\n readonly log: {\n readonly sessions: AgentSessionRequest[];\n readonly feedback: unknown[];\n readonly contexts: unknown[];\n readonly ended: number;\n };\n}\n\ninterface Said {\n readonly role: 'person' | 'assistant';\n readonly text: string;\n readonly id: string;\n}\n\nconst sentences = (text: string) => text.match(/[^.!?]+[.!?]*\\s*/g) ?? [text];\n\nexport function createMockAgent(options: MockAgentOptions = {}): MockAgent {\n const now = options.now ?? (() => Date.now());\n const conversations = new Map<string, Said[]>();\n const sessions = new Map<string, { conversation: string; key: string }>();\n const log = {\n sessions: [] as AgentSessionRequest[],\n feedback: [] as unknown[],\n contexts: [] as unknown[],\n ended: 0,\n };\n let attempts = 0;\n let count = 0;\n\n const backend: AgentBackend = {\n async openSession(request) {\n log.sessions.push(request);\n attempts++;\n const refusal = options.refuse?.(request, attempts);\n if (refusal === 'unreachable')\n throw Object.assign(new Error('mock: unreachable'), {\n retryable: true,\n reason: 'network',\n });\n if (refusal) throw new AgentRefusal(refusal);\n if (\n request.conversationId !== null &&\n !conversations.has(request.conversationId)\n )\n throw new AgentRefusal('ended', { code: 'conversation_not_found' });\n count++;\n const conversation = request.conversationId ?? `cnv_MOCK${count}`;\n if (!conversations.has(conversation)) conversations.set(conversation, []);\n const id = `ses_MOCK${count}`;\n sessions.set(id, { conversation, key: `${request.key.mode}` });\n const session: ConversationSession = {\n id,\n realtime_url: `wss://mock.vinaverse.invalid/v1/sessions/${id}/realtime`,\n turns_url: `https://mock.vinaverse.invalid/v1/sessions/${id}/turns`,\n client_secret: `vv_cs_${'mock'.repeat(6)}`,\n conversation_id: conversation,\n expires_at: new Date(\n now() + (options.sessionMs ?? 30 * 60_000),\n ).toISOString(),\n ...(options.agentName\n ? { agent: { display_name: options.agentName } }\n : {}),\n ...(options.disclosure ? { disclosure: options.disclosure } : {}),\n ...(options.welcome ? { welcome: options.welcome } : {}),\n };\n return session;\n },\n async refreshSecret() {\n return `vv_cs_${'mock'.repeat(6)}`;\n },\n async updateContext(sessionId, place, revision) {\n log.contexts.push({ sessionId, place, revision });\n },\n async status() {\n return (\n options.status ?? {\n available: true,\n launcher: true,\n displayName: options.agentName ?? null,\n }\n );\n },\n async sendFeedback(feedback) {\n log.feedback.push(feedback);\n },\n async endSessions() {\n log.ended++;\n },\n };\n\n const webSocket: WebSocketFactory = (url) => {\n const sessionId = /sessions\\/([^/]+)\\/realtime/.exec(url)?.[1] ?? '';\n const held = sessions.get(sessionId);\n const said = held ? (conversations.get(held.conversation) ?? []) : [];\n let turn = said.filter((s) => s.role === 'person').length;\n let state = 0;\n const socket: WebSocketLike = {\n get readyState() {\n return state;\n },\n onopen: null,\n onmessage: null,\n onclose: null,\n onerror: null,\n send(data) {\n const frame = JSON.parse(data) as Record<string, unknown>;\n if (frame.type === 'ping') return deliver({ type: 'pong' });\n if (frame.type !== 'input.text') return;\n const id = String(frame.client_event_id ?? '');\n const text = String(frame.text ?? '');\n turn++;\n const turnId = `turn_MOCK${turn}`;\n said.push({ role: 'person', text, id });\n const answer =\n options.script?.[turn - 1] ??\n options.reply?.(text, { turn, key: held?.key ?? '' }) ??\n `You said: ${text}`;\n const reply: MockReply =\n typeof answer === 'string' ? { text: answer } : answer;\n deliver({ type: 'turn.started', turn_id: turnId, client_event_id: id });\n if (reply.fail) {\n deliver({\n type: 'turn.failed',\n turn_id: turnId,\n code: reply.fail,\n message: '',\n retryable: true,\n });\n return;\n }\n let so = '';\n for (const part of reply.text ? sentences(reply.text) : []) {\n so += part;\n deliver({ type: 'message.delta', turn_id: turnId, text: part });\n }\n if (reply.text) {\n deliver({\n type: 'message.completed',\n turn_id: turnId,\n text: so.trim(),\n });\n said.push({ role: 'assistant', text: so.trim(), id: turnId });\n }\n if (reply.cards?.length)\n deliver({ type: 'ui.cards', turn_id: turnId, cards: reply.cards });\n deliver({ type: 'turn.completed', turn_id: turnId });\n },\n close(code) {\n if (state === 3) return;\n state = 3;\n setTimeout(() => socket.onclose?.({ code: code ?? 1000 }), 0);\n },\n };\n function deliver(event: unknown) {\n setTimeout(() => {\n if (state === 1) socket.onmessage?.({ data: JSON.stringify(event) });\n }, 0);\n }\n setTimeout(() => {\n state = 1;\n socket.onopen?.({});\n const resumed = said.length > 0;\n socket.onmessage?.({\n data: JSON.stringify({\n type: 'session.ready',\n session: { id: sessionId, status: 'open' },\n resumed,\n limits: {},\n disclosure:\n options.disclosure ?? 'An AI agent. Powered by Vinaverse.',\n ...(resumed\n ? {\n transcript: said.map((s) => ({\n role: s.role,\n text: s.text,\n id: s.id,\n at: new Date(now()).toISOString(),\n })),\n }\n : {}),\n }),\n });\n }, 0);\n return socket;\n };\n\n return { backend, webSocket, log };\n}\n\n/** Cards as a tenant's tools would give them, for mock replies and tests. */\nexport const mockCards = {\n professional(id: string, extra: Partial<Card> = {}): Card {\n return {\n id,\n kind: 'professional',\n title: 'Riley Sample',\n subtitle: 'Barber · Los Angeles',\n ref: { type: 'professional', id },\n images: [\n {\n url: `https://images.example.test/${id}.webp`,\n width: 1600,\n height: 1000,\n },\n ],\n rating: { value_ppm: 4_800_000, count: 132 },\n price_from: { amount: 4500, currency: 'USD' },\n actions: [],\n source: { tool: 'search_professionals', call_id: 'call_MOCK' },\n ...extra,\n } as Card;\n },\n workspace(id: string, extra: Partial<Card> = {}): Card {\n return {\n id,\n kind: 'workspace',\n title: 'Suite 4',\n subtitle: 'Private suite · Atlanta',\n ref: { type: 'workspace', id },\n price_from: { amount: 6500, currency: 'USD' },\n actions: [],\n source: { tool: 'search_spaces', call_id: 'call_MOCK' },\n ...extra,\n } as Card;\n },\n /** A proposal the person confirms in the app (`confirm_mode: tenant_app`), pending for a day unless `expires_at`. */\n proposal(\n id: string,\n proposal: {\n readonly topic?: string;\n readonly title?: string;\n readonly summary?: string;\n readonly expires_at?: string;\n } = {},\n ): Card {\n const title = proposal.title ?? 'Silk press with Riley';\n return {\n id,\n kind: 'proposal',\n title,\n actions: [],\n source: { tool: 'create_proposal', call_id: 'call_MOCK' },\n proposal: {\n id: `prp_${id}`,\n status: 'pending',\n topic: proposal.topic ?? 'booking',\n title,\n summary: proposal.summary ?? 'Wednesday at 10:00 · $45',\n fields: [],\n expires_at:\n proposal.expires_at ??\n new Date(Date.now() + 24 * 3_600_000).toISOString(),\n confirm_mode: 'tenant_app',\n },\n } as Card;\n },\n /** Times to book, from `start` on the hour, one an hour. */\n timeSlots(id: string, start: string, count = 3): Card {\n const at = Date.parse(start);\n return {\n id,\n kind: 'time_slots',\n title: 'Open times',\n slots: Array.from({ length: count }, (_, i) => ({\n id: `slot_${i + 1}`,\n start: new Date(at + i * 3_600_000).toISOString(),\n end: new Date(at + (i + 1) * 3_600_000).toISOString(),\n })),\n actions: [],\n source: { tool: 'get_availability', call_id: 'call_MOCK' },\n } as Card;\n },\n links(id: string): Card {\n return {\n id,\n kind: 'links',\n title: 'Pages that can help',\n links: [\n {\n label: 'Help center',\n url: 'https://help.example.test/',\n purpose: 'help',\n },\n {\n label: 'Contact us',\n url: 'https://help.example.test/contact',\n purpose: 'contact',\n },\n ],\n actions: [],\n source: { tool: 'scope', call_id: 'turn_MOCK' },\n } as Card;\n },\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinaverse/client",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.7",
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.",
@@ -52,6 +52,16 @@
52
52
  "default": "./dist/agent/index.cjs"
53
53
  }
54
54
  },
55
+ "./backend": {
56
+ "import": {
57
+ "types": "./dist/backend/index.d.ts",
58
+ "default": "./dist/backend/index.js"
59
+ },
60
+ "require": {
61
+ "types": "./dist/backend/index.d.cts",
62
+ "default": "./dist/backend/index.cjs"
63
+ }
64
+ },
55
65
  "./testing": {
56
66
  "import": {
57
67
  "types": "./dist/testing/index.d.ts",
@@ -77,6 +87,9 @@
77
87
  ],
78
88
  "testing": [
79
89
  "./dist/testing/index.d.cts"
90
+ ],
91
+ "backend": [
92
+ "./dist/backend/index.d.cts"
80
93
  ]
81
94
  }
82
95
  },
@@ -104,7 +117,13 @@
104
117
  "name": "@vinaverse/client/agent (ESM, everything, the conversation store included; docs/architecture/agent-runtime.md)",
105
118
  "path": "dist/agent/index.js",
106
119
  "import": "*",
107
- "limit": "15 kB"
120
+ "limit": "17.5 kB"
121
+ },
122
+ {
123
+ "name": "@vinaverse/client/backend (ESM, everything: backendFromFetch and decodeBackendFailure)",
124
+ "path": "dist/backend/index.js",
125
+ "import": "*",
126
+ "limit": "2 kB"
108
127
  }
109
128
  ],
110
129
  "scripts": {
@@ -1,416 +0,0 @@
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, warn) {
34
- if (!(insecure.realtime || insecure.turns)) return;
35
- if (globalThis.__DEV__ === true) return;
36
- 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, options.onWarning ?? ((m) => console.warn(m)));
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-XPES5PZ3.js.map
416
- //# sourceMappingURL=chunk-XPES5PZ3.js.map