@happyvertical/smrt-chat 0.55.2 → 0.55.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.js CHANGED
@@ -1,12 +1,11 @@
1
1
  import { c as ChatThread, d as ChatParticipant, f as ChatMessage, i as clientRequestMessageId, l as ChatRoom, n as ChatService, o as VoiceSessionCollection, p as AgentSession, s as VoiceSession, t as ChatClientRequestConflictError, u as ChatReaction } from "./chunks/ChatService-C9UxuJaw.js";
2
- import { A as MAX_CLIENT_TOOLS, C as SESSION_CONTINUATIONS_FIELD, D as runAssistantTurn, E as createSessionContinuationStore, F as classifyToolError, I as invokeManifestTool, L as manifestToolToAITool, M as MAX_CLIENT_TOOL_SCHEMA_BYTES, N as appendClientToolResults, O as CLIENT_TOOL_RESULT_GUIDANCE, P as buildManifestToolCatalog, R as runToolLoop, S as DEFAULT_CONTINUATION_TTL_MS, T as createMemoryContinuationStore, _ as runPersonaConversationTurn, a as MAX_CHAT_STREAM_CONTENT_LENGTH, b as CONTINUATION_CLAIM_TTL_MS, c as encodeChatStreamEvent, d as conversationPersonaFromAgentPersona, f as conversationPersonaFromResolved, g as resolveConversationInstructions, h as recallPersonaMemory, i as DEFAULT_CHAT_STREAM_HEARTBEAT_MS, j as MAX_CLIENT_TOOL_RESULT_CHARS, k as DEFAULT_MAX_STEPS, l as runChatConversationStream, m as principalBindingFor, n as ChatStreamError, o as MAX_CHAT_STREAM_MESSAGES, p as formatRecalledMemory, r as ChatStreamUnauthorizedError, s as createChatStreamHandler, t as ChatStreamBadRequestError, u as bindPersonaToSession, v as ASSISTANT_TURN_GENERIC_ERROR, w as createAssistantTurnResponse, x as DEFAULT_ASSISTANT_TURN_HEARTBEAT_MS, y as AssistantTurnUserError, z as sanitizeClientToolDeclarations } from "./chunks/chat-stream-Bpx5qi-h.js";
2
+ import { A as MAX_CLIENT_TOOLS, C as SESSION_CONTINUATIONS_FIELD, D as runAssistantTurn, E as createSessionContinuationStore, F as classifyToolError, I as invokeManifestTool, L as manifestToolToAITool, M as MAX_CLIENT_TOOL_SCHEMA_BYTES, N as appendClientToolResults, O as CLIENT_TOOL_RESULT_GUIDANCE, P as buildManifestToolCatalog, R as runToolLoop, S as DEFAULT_CONTINUATION_TTL_MS, T as createMemoryContinuationStore, _ as runPersonaConversationTurn, a as MAX_CHAT_STREAM_CONTENT_LENGTH, b as CONTINUATION_CLAIM_TTL_MS, c as encodeChatStreamEvent, d as conversationPersonaFromAgentPersona, f as conversationPersonaFromResolved, g as resolveConversationInstructions, h as recallPersonaMemory, i as DEFAULT_CHAT_STREAM_HEARTBEAT_MS, j as MAX_CLIENT_TOOL_RESULT_CHARS, k as DEFAULT_MAX_STEPS, l as runChatConversationStream, m as principalBindingFor, n as ChatStreamError, o as MAX_CHAT_STREAM_MESSAGES, p as formatRecalledMemory, r as ChatStreamUnauthorizedError, s as createChatStreamHandler, t as ChatStreamBadRequestError, u as bindPersonaToSession, v as ASSISTANT_TURN_GENERIC_ERROR, w as createAssistantTurnResponse, x as DEFAULT_ASSISTANT_TURN_HEARTBEAT_MS, y as AssistantTurnUserError, z as sanitizeClientToolDeclarations } from "./chunks/chat-stream-cbCV0Q6C.js";
3
3
  import { i as matchesToolAllowList, n as encodeAssistantTurnEvent, r as readAssistantTurnStream, t as AssistantTurnStreamError } from "./chunks/assistant-turn-events-BbZUf-Ju.js";
4
4
  import { a as createServerDataSurfaceBridge, i as createDataSurfaceCommandBridge, n as DEFAULT_DATA_SURFACE_BRIDGE_TTL_MS, r as createDataSurfaceBridge, t as DATA_SURFACE_BRIDGE_VERSION } from "./chunks/data-surface-bridge-BJomMxjS.js";
5
5
  import { CHAT_MODULE_META, CHAT_UI_SLOTS } from "./ui.js";
6
- import { SmrtCollection, SmrtObject, ValidationError, field, foreignKey, smrt } from "@happyvertical/smrt-core";
6
+ import { SmrtCollection, SmrtObject, ValidationError, field, foreignKey, resolveDatabase, smrt } from "@happyvertical/smrt-core";
7
7
  import { DATA_DISCOVER_FUNCTION_NAME, DATA_DISCOVER_TOOL_SLUG, DATA_INSPECT_FUNCTION_NAME, DATA_INSPECT_TOOL_SLUG, DATA_QUERY_FUNCTION_NAME, DATA_QUERY_TOOL_SLUG, DEFAULT_DATA_SURFACE_DEADLINE_MS, DataSurfaceDeadlineError, DataSurfaceDeniedError, DataSurfaceQueryError, DataSurfaceRequestError, DataSurfaceResultOrderError, MAX_DATA_SURFACE_DEADLINE_MS, createDataSurfaceQueryFingerprint, createDataSurfaceTools } from "@happyvertical/smrt-agents";
8
8
  import { FeedbackCollection, feedbackSourceFor, personaLearningMemory, personaMemoryScope, reinforceFromFeedback } from "@happyvertical/smrt-personas";
9
- import { getDatabase } from "@happyvertical/sql";
10
9
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
11
10
  //#region src/chat-feedback.ts
12
11
  async function captureChatFeedback(options) {
@@ -33,7 +32,7 @@ async function captureChatFeedback(options) {
33
32
  let reinforced = null;
34
33
  if (options.reinforce !== false) {
35
34
  reinforced = await reinforceFromFeedback(personaLearningMemory({
36
- db: await getDatabase(options.db),
35
+ db: await resolveDatabase(options.db ?? {}),
37
36
  persona: options.persona,
38
37
  semanticSearch: options.semanticSearch
39
38
  }), feedback, { ratingNeutral: options.ratingNeutral });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/chat-feedback.ts","../src/models/VoiceGatewayTurn.ts","../src/collections/VoiceGatewayTurnCollection.ts","../src/voice.ts"],"sourcesContent":["/**\n * Chat feedback capture — turn an in-conversation judgement into a first-class\n * learning signal (L3 of the learning-agents epic, #1891).\n *\n * A tenant end-user accepting or rejecting an applied change, giving a\n * thumbs-up/down, or typing an inline correction produces a {@link Feedback}\n * row — carrying the conversation's **correlation-id** back to the turn it\n * judges — and (by default) immediately reinforces the persona's learning\n * memory. Because recall draws on that same memory next turn, captured feedback\n * *influences subsequent behaviour*: a rejected strategy decays below the reuse\n * floor and stops resurfacing; a correction supersedes it with the corrected\n * value.\n *\n * This is the human-signal half of the loop the personas package already models\n * ({@link reinforceFromFeedback}); the gated half — rewriting a persona's\n * instructions — stays in the directive-proposal flow.\n *\n * @module\n */\n\nimport type {\n LearningMemoryRecord,\n LearningSemanticSearch,\n SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport {\n type Feedback,\n FeedbackCollection,\n type FeedbackSignalType,\n feedbackSourceFor,\n personaLearningMemory,\n personaMemoryScope,\n reinforceFromFeedback,\n} from '@happyvertical/smrt-personas';\nimport { getDatabase } from '@happyvertical/sql';\n\n/** The minimal persona shape chat feedback needs to route the signal. */\nexport interface ChatFeedbackPersona {\n /** Persona id — required (a signal always judges a specific persona). */\n id?: string | null;\n /** Owning tenant. */\n tenantId?: string | null;\n /** Canonical agent class the persona configures (denormalised onto the row). */\n agentClass?: string;\n /** Learning memory partition key. */\n memoryScope?: string;\n}\n\n/**\n * Options for {@link captureChatFeedback}.\n */\nexport interface CaptureChatFeedbackOptions {\n /** Database handle. */\n db: SmrtClassOptions['db'];\n /** The persona the signal judges. */\n persona: ChatFeedbackPersona;\n /** The kind of signal. */\n signalType: FeedbackSignalType;\n /** Correlation-id of the conversation turn this signal judges. */\n correlationId: string;\n /** What {@link correlationId} names. Default `'chat_message'`. */\n correlationType?: string;\n /** Learning episode scope the signal reinforces (matches recall/capture). */\n scope: string;\n /** Learning episode key the signal reinforces. */\n key: string;\n /** The user id that authored the signal (null for autonomous). */\n actorId?: string | null;\n /** Numeric rating for a `rating` signal. */\n rating?: number | null;\n /** Corrected value for a `correction` signal. */\n correction?: string | null;\n /** Freeform note. */\n comment?: string | null;\n /** Structured metadata persisted on the row. */\n metadata?: Record<string, unknown>;\n /** Apply the signal to memory immediately. Default `true`. */\n reinforce?: boolean;\n /** Optional embedding search wired into the reinforced memory. */\n semanticSearch?: LearningSemanticSearch;\n /** Neutral point of a `rating` scale (see `FeedbackOutcomeOptions`). Default 0. */\n ratingNeutral?: number;\n}\n\n/** The outcome of capturing chat feedback. */\nexport interface ChatFeedbackResult {\n /** The persisted feedback row. */\n feedback: Feedback;\n /** The memory record the signal reinforced, or `null` when it carried none. */\n reinforced: LearningMemoryRecord | null;\n}\n\n/**\n * Capture one in-chat feedback signal as a {@link Feedback} row and (by default)\n * reinforce the persona's learning memory from it.\n *\n * @throws when the persona has no id (a signal must name a persisted persona).\n */\nexport async function captureChatFeedback(\n options: CaptureChatFeedbackOptions,\n): Promise<ChatFeedbackResult> {\n if (!options.persona.id) {\n throw new Error(\n 'captureChatFeedback requires a persisted persona (missing id)',\n );\n }\n const memoryScope = personaMemoryScope(options.persona);\n\n const feedbacks = await FeedbackCollection.create({ db: options.db });\n const feedback = await feedbacks.create({\n tenantId: options.persona.tenantId ?? null,\n personaId: options.persona.id,\n agentClass: options.persona.agentClass ?? '',\n memoryScope,\n scope: options.scope,\n key: options.key,\n signalType: options.signalType,\n source: feedbackSourceFor(options.signalType),\n correlationId: options.correlationId,\n correlationType: options.correlationType ?? 'chat_message',\n rating: options.rating ?? null,\n correction: options.correction ?? null,\n comment: options.comment ?? null,\n actorId: options.actorId ?? null,\n });\n if (options.metadata) {\n feedback.setMetadata(options.metadata);\n }\n await feedback.save();\n\n let reinforced: LearningMemoryRecord | null = null;\n if (options.reinforce !== false) {\n // LearningMemory operates on a resolved DB handle; `getDatabase` accepts a\n // config or a handle and returns a handle (idempotent for a handle).\n const memory = personaLearningMemory({\n db: await getDatabase(options.db as Parameters<typeof getDatabase>[0]),\n persona: options.persona,\n semanticSearch: options.semanticSearch,\n });\n reinforced = await reinforceFromFeedback(memory, feedback, {\n ratingNeutral: options.ratingNeutral,\n });\n // Gate exactly-once reinforcement so a later reflection pass never\n // re-applies this signal (mirrors the personas reflection runner).\n feedback.reinforcedAt = new Date();\n await feedback.save();\n }\n\n return { feedback, reinforced };\n}\n\n/** Shared options for the signal-typed convenience wrappers. */\nexport type ChatFeedbackBase = Omit<\n CaptureChatFeedbackOptions,\n 'signalType' | 'rating' | 'correction'\n>;\n\n/**\n * Accept an applied change — reinforces the judged strategy as a success.\n */\nexport function acceptAppliedChange(\n options: ChatFeedbackBase,\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'accept' });\n}\n\n/**\n * Reject an applied change — decays the judged strategy toward the failure floor\n * so it stops being recalled.\n */\nexport function rejectAppliedChange(\n options: ChatFeedbackBase & { comment?: string | null },\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'reject' });\n}\n\n/**\n * Record an inline correction — decays the wrong strategy AND supersedes its\n * stored value with the corrected one, so the next recall returns the fix.\n */\nexport function correctResponse(\n options: ChatFeedbackBase & { correction: string; comment?: string | null },\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({\n ...options,\n signalType: 'correction',\n correction: options.correction,\n });\n}\n\n/**\n * Record a numeric rating for a response (scale is caller-defined; pass\n * `ratingNeutral` for a mid-point).\n */\nexport function rateResponse(\n options: ChatFeedbackBase & { rating: number },\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({\n ...options,\n signalType: 'rating',\n rating: options.rating,\n });\n}\n\n/** Thumbs-up — a `+1` rating (reinforces as a success against neutral 0). */\nexport function thumbsUp(\n options: ChatFeedbackBase,\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'rating', rating: 1 });\n}\n\n/** Thumbs-down — a `-1` rating (decays as a failure against neutral 0). */\nexport function thumbsDown(\n options: ChatFeedbackBase,\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'rating', rating: -1 });\n}\n","import { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n VoiceGatewayTurnOptions,\n VoiceGatewayTurnStatus,\n} from '../types.js';\n\n/**\n * Durable reservation for a gateway turn. The natural key makes `turn_id`\n * replay checks concurrency-safe before transcript messages are written.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'voice_gateway_turns',\n conflictColumns: ['voice_session_id', 'gateway_turn_id'],\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class VoiceGatewayTurn extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-chat\";\n @tenantId()\n tenantId: string = '';\n\n @foreignKey('VoiceSession', { required: true })\n voiceSessionId: string = '';\n\n @field({ required: true })\n gatewaySessionId: string = '';\n\n @field({ required: true })\n gatewayTurnId: string = '';\n\n @field({ required: true })\n target: string = 'smrt:chat';\n\n @field({ required: true })\n status: VoiceGatewayTurnStatus = 'processing';\n\n @field()\n completedAt: Date | null = null;\n\n @field()\n failedAt: Date | null = null;\n\n constructor(options: VoiceGatewayTurnOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.voiceSessionId !== undefined)\n this.voiceSessionId = options.voiceSessionId;\n if (options.gatewaySessionId !== undefined)\n this.gatewaySessionId = options.gatewaySessionId;\n if (options.gatewayTurnId !== undefined)\n this.gatewayTurnId = options.gatewayTurnId;\n if (options.target !== undefined) this.target = options.target;\n if (options.status !== undefined) this.status = options.status;\n if (options.completedAt !== undefined)\n this.completedAt = options.completedAt;\n if (options.failedAt !== undefined) this.failedAt = options.failedAt;\n }\n\n async complete(now: Date = new Date()): Promise<void> {\n this.status = 'completed';\n this.completedAt = now;\n this.failedAt = null;\n await this.save();\n }\n\n async fail(now: Date = new Date()): Promise<void> {\n this.status = 'failed';\n this.failedAt = now;\n await this.save();\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { VoiceGatewayTurn } from '../models/VoiceGatewayTurn.js';\n\nexport class VoiceGatewayTurnCollection extends SmrtCollection<VoiceGatewayTurn> {\n static readonly _itemClass = VoiceGatewayTurn;\n\n async reserveTurn(input: {\n tenantId: string;\n voiceSessionId: string;\n gatewaySessionId: string;\n gatewayTurnId: string;\n target: string;\n }): Promise<VoiceGatewayTurn> {\n return this.create({\n ...input,\n status: 'processing',\n _insertOnly: true,\n });\n }\n}\n","import type { AIInterface, AIMessage } from '@happyvertical/ai';\nimport type { PrincipalAuditSink } from '@happyvertical/smrt-agents';\nimport {\n type SmrtClassOptions,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport { VoiceGatewayTurnCollection } from './collections/VoiceGatewayTurnCollection.js';\nimport { VoiceSessionCollection } from './collections/VoiceSessionCollection.js';\nimport type { ChatMessage } from './models/ChatMessage.js';\nimport type { VoiceGatewayTurn } from './models/VoiceGatewayTurn.js';\nimport type { VoiceSession } from './models/VoiceSession.js';\nimport {\n bindPersonaToSession,\n type ConversationPersona,\n type PersonaRecallOptions,\n runPersonaConversationTurn,\n} from './persona-conversation.js';\nimport type { ChatService } from './services/index.js';\n\nexport const SMRT_CHAT_VOICE_TARGET = 'smrt:chat';\nexport const MAX_VOICE_GATEWAY_TEXT_LENGTH = 12_000;\nconst DEFAULT_VOICE_SESSION_TTL_SECONDS = 10 * 60;\nconst DEFAULT_HISTORY_LIMIT = 24;\n\nexport interface VoiceGatewayTurnMetadata {\n tenantId?: string;\n actorProfileId?: string;\n chatRoomId?: string;\n threadId?: string;\n agentSessionId?: string;\n personaId?: string;\n voiceSessionId?: string;\n source?: string;\n [key: string]: unknown;\n}\n\nexport interface VoiceGatewayTurnPayload {\n session_id: string;\n turn_id: string;\n target: string;\n actor?: string;\n text: string;\n metadata?: VoiceGatewayTurnMetadata;\n}\n\nexport interface VoiceGatewayTurnResponseMetadata {\n tenantId: string;\n chatRoomId: string;\n threadId: string | null;\n agentSessionId: string;\n userMessageId: string;\n assistantMessageId: string | null;\n personaId: string;\n correlationId: string;\n voiceSessionId: string;\n source: string;\n}\n\nexport interface VoiceGatewayTurnResponse {\n session_id: string;\n turn_id: string;\n text: string;\n metadata: VoiceGatewayTurnResponseMetadata;\n}\n\nexport interface CreateVoiceChatSessionOptions {\n chatService: ChatService;\n db: SmrtClassOptions['db'];\n tenantId: string;\n actorProfileId: string;\n actorUserId?: string | null;\n persona: ConversationPersona;\n /** Existing agent session to bind voice to. Omit to create/reuse one. */\n agentSessionId?: string;\n /** Agent profile/session author id when creating a new agent session. */\n agentId?: string;\n /** Optional existing thread within the bound session room. */\n threadId?: string | null;\n /** Stable gateway-level `session_id`. Generated when omitted. */\n gatewaySessionId?: string;\n /** Subject key forwarded to ChatService.createAgentSession(). */\n sessionKey?: string | null;\n /** Voice binding TTL. Ignored when `expiresAt` is supplied. */\n ttlSeconds?: number;\n expiresAt?: Date;\n metadata?: Record<string, unknown>;\n target?: string;\n maxTokens?: number;\n maxMessages?: number;\n instructions?: string;\n}\n\nexport interface VoiceChatSessionCreationResult {\n voiceSession: VoiceSession;\n voiceSessionId: string;\n gatewaySessionId: string;\n expiresAt: Date;\n tenantId: string;\n actorProfileId: string;\n personaId: string;\n agentSessionId: string;\n chatRoomId: string;\n threadId: string | null;\n metadata: VoiceGatewayTurnMetadata;\n}\n\nexport interface HandleVoiceGatewayTurnOptions {\n chatService: ChatService;\n db: SmrtClassOptions['db'];\n ai: AIInterface;\n payload: VoiceGatewayTurnPayload;\n now?: Date;\n historyLimit?: number;\n recall?: PersonaRecallOptions | false;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n maxSteps?: number;\n postgresRls?: boolean;\n audit?: PrincipalAuditSink;\n}\n\nexport interface VoiceGatewayTurnHandlerOptions\n extends Omit<HandleVoiceGatewayTurnOptions, 'payload'> {\n gatewayToken: string | (() => string | Promise<string>);\n}\n\nexport class VoiceGatewayError extends Error {\n readonly status: number;\n readonly code: string;\n\n constructor(message: string, status: number, code: string) {\n super(message);\n this.name = 'VoiceGatewayError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class VoiceGatewayBadRequestError extends VoiceGatewayError {\n constructor(message: string) {\n super(message, 400, 'voice_gateway_bad_request');\n this.name = 'VoiceGatewayBadRequestError';\n }\n}\n\nexport class VoiceGatewayUnauthorizedError extends VoiceGatewayError {\n constructor(message = 'Voice gateway authorization failed') {\n super(message, 401, 'voice_gateway_unauthorized');\n this.name = 'VoiceGatewayUnauthorizedError';\n }\n}\n\nexport class VoiceSessionRejectedError extends VoiceGatewayError {\n constructor(message: string) {\n super(message, 403, 'voice_session_rejected');\n this.name = 'VoiceSessionRejectedError';\n }\n}\n\nexport class VoiceSessionExpiredError extends VoiceGatewayError {\n constructor(message = 'Voice session is expired') {\n super(message, 410, 'voice_session_expired');\n this.name = 'VoiceSessionExpiredError';\n }\n}\n\nexport class VoiceGatewayReplayError extends VoiceGatewayError {\n constructor(message = 'Voice gateway turn has already been processed') {\n super(message, 409, 'voice_gateway_replay');\n this.name = 'VoiceGatewayReplayError';\n }\n}\n\nexport async function createVoiceChatSession(\n options: CreateVoiceChatSessionOptions,\n): Promise<VoiceChatSessionCreationResult> {\n const target = options.target ?? SMRT_CHAT_VOICE_TARGET;\n const personaId = requireNonEmptyString(\n options.persona.id,\n 'createVoiceChatSession requires a persisted persona id',\n );\n if (\n options.persona.tenantId !== null &&\n options.persona.tenantId !== options.tenantId\n ) {\n throw new VoiceSessionRejectedError(\n 'Persona tenant does not match the voice session tenant',\n );\n }\n\n const persona: ConversationPersona = {\n ...options.persona,\n id: personaId,\n tenantId: options.tenantId,\n };\n\n let agentSession = options.agentSessionId\n ? await options.chatService.getAgentSession({\n agentSessionId: options.agentSessionId,\n tenantId: options.tenantId,\n })\n : null;\n\n if (options.agentSessionId) {\n if (!agentSession) {\n throw new VoiceSessionRejectedError('Agent session not found');\n }\n assertAgentSessionMatchesActor(agentSession, options.actorProfileId);\n assertActiveAgentSession(agentSession);\n } else {\n // `agentId` is the agent's logical identity and `agentProfileId` is the\n // Profile it AUTHORS as — two different things since #2995. The persona's\n // `actsAsProfileId` is the latter (a `crossPackageRef` to `Profile`), so it\n // is passed as the authoring profile rather than collapsed into `agentId`;\n // otherwise a synthetic `bot` profile would be minted for it and persona\n // replies would stop being attributed to the configured acting identity.\n const agentId =\n options.agentId ?? persona.id ?? persona.agentClass ?? undefined;\n if (!agentId) {\n throw new VoiceGatewayBadRequestError(\n 'createVoiceChatSession requires agentId when the persona has no id or agent class',\n );\n }\n const created = await options.chatService.createAgentSession({\n tenantId: options.tenantId,\n agentId,\n agentProfileId: persona.actsAsProfileId ?? null,\n actorProfileId: options.actorProfileId,\n allowedTools: persona.allowedTools,\n systemPrompt: options.instructions ?? persona.instructions,\n maxTokens: options.maxTokens,\n maxMessages: options.maxMessages,\n sessionKey: options.sessionKey,\n });\n agentSession = created.session;\n }\n\n const boundSession = await bindPersonaToSession({\n chatService: options.chatService,\n session: agentSession,\n actorProfileId: options.actorProfileId,\n tenantId: options.tenantId,\n persona,\n instructions: options.instructions,\n db: options.db,\n });\n assertActiveAgentSession(boundSession);\n\n const chatRoomId = requireNonEmptyString(\n boundSession.chatRoomId,\n 'Agent session has no chat room',\n );\n await options.chatService.getRoomForMember(\n chatRoomId,\n options.actorProfileId,\n options.tenantId,\n );\n\n const threadId = options.threadId ?? null;\n if (threadId) {\n const thread = await options.chatService.getThread({\n threadId,\n tenantId: options.tenantId,\n });\n if (!thread || thread.roomId !== chatRoomId) {\n throw new VoiceSessionRejectedError(\n 'threadId does not belong to the bound agent session room',\n );\n }\n }\n\n const voiceSessions = await VoiceSessionCollection.create({ db: options.db });\n const gatewaySessionId = options.gatewaySessionId ?? crypto.randomUUID();\n const expiresAt =\n options.expiresAt ??\n new Date(\n Date.now() +\n (options.ttlSeconds ?? DEFAULT_VOICE_SESSION_TTL_SECONDS) * 1000,\n );\n\n const voiceSession = await voiceSessions.create({\n tenantId: options.tenantId,\n gatewaySessionId,\n actorProfileId: options.actorProfileId,\n actorUserId: options.actorUserId ?? null,\n personaId,\n agentSessionId: boundSession.id as string,\n chatRoomId,\n threadId,\n target,\n status: 'active',\n expiresAt,\n personaSnapshot: JSON.stringify(persona),\n metadata: JSON.stringify(options.metadata ?? {}),\n });\n\n const voiceSessionId = voiceSession.id as string;\n return {\n voiceSession,\n voiceSessionId,\n gatewaySessionId,\n expiresAt,\n tenantId: options.tenantId,\n actorProfileId: options.actorProfileId,\n personaId,\n agentSessionId: boundSession.id as string,\n chatRoomId,\n threadId,\n metadata: {\n tenantId: options.tenantId,\n actorProfileId: options.actorProfileId,\n chatRoomId,\n threadId: threadId ?? undefined,\n agentSessionId: boundSession.id as string,\n personaId,\n voiceSessionId,\n source: 'smrt-chat',\n },\n };\n}\n\nexport async function handleVoiceGatewayTurn(\n options: HandleVoiceGatewayTurnOptions,\n): Promise<VoiceGatewayTurnResponse> {\n const payload = normalizeGatewayPayload(options.payload);\n const metadata = payload.metadata ?? {};\n const voiceSessionId = requireNonEmptyString(\n metadata.voiceSessionId,\n 'Voice gateway payload metadata.voiceSessionId is required',\n );\n\n const voiceSessions = await VoiceSessionCollection.create({ db: options.db });\n const voiceSession = await voiceSessions.get({\n id: voiceSessionId,\n target: payload.target,\n });\n if (!voiceSession) {\n throw new VoiceSessionRejectedError('Voice session not found');\n }\n if (voiceSession.isExpired(options.now)) {\n if (voiceSession.status === 'active') {\n await voiceSession.expire();\n }\n throw new VoiceSessionExpiredError();\n }\n if (!voiceSession.isActive(options.now)) {\n throw new VoiceSessionRejectedError('Voice session is not active');\n }\n if (voiceSession.hasProcessedTurn(payload.turn_id)) {\n throw new VoiceGatewayReplayError();\n }\n\n validateGatewayPayloadAgainstBinding(payload, voiceSession);\n const persona = requireVoiceSessionPersona(voiceSession);\n\n const agentSession = await options.chatService.getAgentSession({\n agentSessionId: voiceSession.agentSessionId,\n tenantId: voiceSession.tenantId,\n });\n if (!agentSession) {\n throw new VoiceSessionRejectedError('Bound agent session not found');\n }\n assertAgentSessionMatchesActor(agentSession, voiceSession.actorProfileId);\n assertActiveAgentSession(agentSession);\n if (agentSession.chatRoomId !== voiceSession.chatRoomId) {\n throw new VoiceSessionRejectedError(\n 'Bound agent session no longer belongs to the voice session room',\n );\n }\n\n if (voiceSession.threadId) {\n const thread = await options.chatService.getThread({\n threadId: voiceSession.threadId,\n tenantId: voiceSession.tenantId,\n });\n if (!thread || thread.roomId !== voiceSession.chatRoomId) {\n throw new VoiceSessionRejectedError(\n 'Bound thread no longer belongs to the voice session room',\n );\n }\n }\n\n const gatewayTurn = await reserveVoiceGatewayTurn(\n options.db,\n voiceSession,\n payload,\n );\n\n try {\n const history = await loadConversationHistory({\n chatService: options.chatService,\n tenantId: voiceSession.tenantId,\n actorProfileId: voiceSession.actorProfileId,\n roomId: voiceSession.chatRoomId,\n threadId: voiceSession.threadId,\n limit: options.historyLimit ?? DEFAULT_HISTORY_LIMIT,\n });\n const correlationId = crypto.randomUUID();\n const commonMetadata = {\n source: 'voice-gateway',\n target: payload.target,\n voiceSessionId,\n gatewaySessionId: payload.session_id,\n gatewayTurnId: payload.turn_id,\n correlationId,\n };\n\n const userMessage = await options.chatService.sendAgentUserMessage({\n tenantId: voiceSession.tenantId,\n agentSessionId: voiceSession.agentSessionId,\n actorProfileId: voiceSession.actorProfileId,\n content: payload.text,\n });\n await mergeAndSaveMetadata(userMessage, {\n ...commonMetadata,\n voiceRole: 'transcript',\n });\n\n const turn = await runPersonaConversationTurn({\n ai: options.ai,\n db: options.db,\n persona,\n tenantId: voiceSession.tenantId,\n userMessage: payload.text,\n history,\n chatService: options.chatService,\n session: agentSession,\n threadId: voiceSession.threadId,\n recall: options.recall,\n model: options.model,\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n maxSteps: options.maxSteps,\n postgresRls: options.postgresRls,\n audit: options.audit,\n onBehalfOfUserId: voiceSession.actorUserId ?? undefined,\n correlationId,\n });\n\n for (const toolMessage of turn.authoredMessages?.toolMessages ?? []) {\n await mergeAndSaveMetadata(toolMessage, {\n ...commonMetadata,\n voiceRole: 'tool',\n });\n }\n const assistantMessage = turn.authoredMessages?.assistantMessage ?? null;\n if (assistantMessage) {\n await mergeAndSaveMetadata(assistantMessage, {\n ...commonMetadata,\n voiceRole: 'assistant',\n });\n }\n\n voiceSession.recordGatewayTurn(payload.turn_id);\n await voiceSession.save();\n await gatewayTurn.complete();\n\n return {\n session_id: payload.session_id,\n turn_id: payload.turn_id,\n text: turn.result.content,\n metadata: {\n tenantId: voiceSession.tenantId,\n chatRoomId: voiceSession.chatRoomId,\n threadId: voiceSession.threadId,\n agentSessionId: voiceSession.agentSessionId,\n userMessageId: userMessage.id as string,\n assistantMessageId:\n (assistantMessage?.id as string | undefined) ?? null,\n personaId: voiceSession.personaId,\n correlationId: turn.correlationId,\n voiceSessionId,\n source: 'voice-gateway',\n },\n };\n } catch (error) {\n await markVoiceGatewayTurnFailed(gatewayTurn);\n throw error;\n }\n}\n\nexport function createVoiceGatewayTurnHandler(\n options: VoiceGatewayTurnHandlerOptions,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n if (request.method !== 'POST') {\n return jsonResponse({ error: 'Method not allowed' }, 405);\n }\n await assertVoiceGatewayBearer(\n request.headers,\n await resolveGatewayToken(options.gatewayToken),\n );\n const payload = normalizeGatewayPayload(await request.json());\n const response = await handleVoiceGatewayTurn({ ...options, payload });\n return jsonResponse(response, 200);\n } catch (error) {\n const status = error instanceof VoiceGatewayError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : 'Voice gateway turn failed';\n const code =\n error instanceof VoiceGatewayError ? error.code : 'voice_gateway_error';\n return jsonResponse({ error: message, code }, status);\n }\n };\n}\n\nexport async function assertVoiceGatewayBearer(\n headers: Headers,\n expectedToken: string,\n): Promise<void> {\n if (!expectedToken) {\n throw new VoiceGatewayUnauthorizedError(\n 'Voice gateway token is not configured',\n );\n }\n const authorization = headers.get('authorization') ?? '';\n const match = authorization.match(/^Bearer\\s+(.+)$/i);\n const actual = match?.[1] ?? '';\n if (!constantTimeEquals(actual, expectedToken)) {\n throw new VoiceGatewayUnauthorizedError();\n }\n}\n\nasync function resolveGatewayToken(\n token: string | (() => string | Promise<string>),\n): Promise<string> {\n return typeof token === 'function' ? token() : token;\n}\n\nfunction normalizeGatewayPayload(input: unknown): VoiceGatewayTurnPayload {\n if (!isRecord(input)) {\n throw new VoiceGatewayBadRequestError('Voice gateway payload must be JSON');\n }\n const sessionId = requireNonEmptyString(\n input.session_id,\n 'Voice gateway payload session_id is required',\n );\n const turnId = requireNonEmptyString(\n input.turn_id,\n 'Voice gateway payload turn_id is required',\n );\n const target = requireNonEmptyString(\n input.target,\n 'Voice gateway payload target is required',\n );\n if (target !== SMRT_CHAT_VOICE_TARGET) {\n throw new VoiceGatewayBadRequestError(\n `Unsupported voice gateway target '${target}'`,\n );\n }\n const text = requireNonEmptyString(\n input.text,\n 'Voice gateway payload text is required',\n );\n if (text.length > MAX_VOICE_GATEWAY_TEXT_LENGTH) {\n throw new VoiceGatewayBadRequestError(\n `Voice gateway payload text must be ${MAX_VOICE_GATEWAY_TEXT_LENGTH} characters or fewer`,\n );\n }\n const metadata = input.metadata;\n if (metadata !== undefined && !isRecord(metadata)) {\n throw new VoiceGatewayBadRequestError(\n 'Voice gateway payload metadata must be an object',\n );\n }\n\n return {\n session_id: sessionId,\n turn_id: turnId,\n target,\n actor:\n typeof input.actor === 'string' && input.actor.length > 0\n ? input.actor\n : undefined,\n text,\n metadata: metadata as VoiceGatewayTurnMetadata | undefined,\n };\n}\n\nfunction validateGatewayPayloadAgainstBinding(\n payload: VoiceGatewayTurnPayload,\n voiceSession: VoiceSession,\n): void {\n if (payload.session_id !== voiceSession.gatewaySessionId) {\n throw new VoiceSessionRejectedError(\n 'Gateway session_id does not match the voice session binding',\n );\n }\n const metadata = payload.metadata ?? {};\n assertMetadataMatches(\n metadata,\n 'tenantId',\n voiceSession.tenantId,\n 'tenantId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'actorProfileId',\n voiceSession.actorProfileId,\n 'actorProfileId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'chatRoomId',\n voiceSession.chatRoomId,\n 'chatRoomId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'threadId',\n voiceSession.threadId,\n 'threadId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'agentSessionId',\n voiceSession.agentSessionId,\n 'agentSessionId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'personaId',\n voiceSession.personaId,\n 'personaId does not match the voice session binding',\n );\n}\n\nfunction requireVoiceSessionPersona(\n voiceSession: VoiceSession,\n): ConversationPersona {\n const persona = voiceSession.getPersonaSnapshot();\n if (!hasNonEmptyString(persona.id)) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot has no persona id',\n );\n }\n if (persona.id !== voiceSession.personaId) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot does not match the voice session persona',\n );\n }\n if (persona.tenantId !== voiceSession.tenantId) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot tenant does not match the voice session tenant',\n );\n }\n if (!hasNonEmptyString(persona.runAsUserId)) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot has no runnable user',\n );\n }\n if (!Array.isArray(persona.allowedTools)) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot has an invalid tool allow-list',\n );\n }\n return persona;\n}\n\nasync function reserveVoiceGatewayTurn(\n db: SmrtClassOptions['db'],\n voiceSession: VoiceSession,\n payload: VoiceGatewayTurnPayload,\n): Promise<VoiceGatewayTurn> {\n const gatewayTurns = await VoiceGatewayTurnCollection.create({ db });\n try {\n return await gatewayTurns.reserveTurn({\n tenantId: voiceSession.tenantId,\n voiceSessionId: voiceSession.id as string,\n gatewaySessionId: payload.session_id,\n gatewayTurnId: payload.turn_id,\n target: payload.target,\n });\n } catch (error) {\n if (isUniqueConstraintError(error)) {\n throw new VoiceGatewayReplayError();\n }\n throw error;\n }\n}\n\nasync function markVoiceGatewayTurnFailed(\n gatewayTurn: VoiceGatewayTurn,\n): Promise<void> {\n try {\n await gatewayTurn.fail();\n } catch {\n // Preserve the original turn failure for the gateway response.\n }\n}\n\nfunction isUniqueConstraintError(error: unknown): boolean {\n return (\n error instanceof ValidationError &&\n error.code === 'VALIDATION_UNIQUE_CONSTRAINT'\n );\n}\n\nfunction assertMetadataMatches(\n metadata: VoiceGatewayTurnMetadata,\n key: keyof VoiceGatewayTurnMetadata,\n expected: string | null,\n message: string,\n): void {\n const actual = metadata[key];\n if (actual === undefined || actual === null || actual === '') {\n return;\n }\n if (typeof actual !== 'string' || actual !== expected) {\n throw new VoiceSessionRejectedError(message);\n }\n}\n\nfunction assertAgentSessionMatchesActor(\n session: { participantProfileId: string },\n actorProfileId: string,\n): void {\n if (session.participantProfileId !== actorProfileId) {\n throw new VoiceSessionRejectedError(\n 'Agent session participant does not match the voice session actor',\n );\n }\n}\n\nfunction assertActiveAgentSession(session: {\n isActive: () => boolean;\n chatRoomId: string | null;\n}): void {\n if (!session.isActive()) {\n throw new VoiceSessionRejectedError('Agent session is not active');\n }\n if (!session.chatRoomId) {\n throw new VoiceSessionRejectedError('Agent session has no chat room');\n }\n}\n\nasync function loadConversationHistory(input: {\n chatService: ChatService;\n tenantId: string;\n actorProfileId: string;\n roomId: string;\n threadId: string | null;\n limit: number;\n}): Promise<AIMessage[]> {\n const messages = input.threadId\n ? await input.chatService.getThreadMessages({\n threadId: input.threadId,\n actorProfileId: input.actorProfileId,\n tenantId: input.tenantId,\n limit: input.limit,\n })\n : (\n await input.chatService.getRoomMessages({\n roomId: input.roomId,\n actorProfileId: input.actorProfileId,\n tenantId: input.tenantId,\n limit: input.limit,\n })\n ).reverse();\n\n return messages\n .map(chatMessageToAIMessage)\n .filter((message): message is AIMessage => message !== null);\n}\n\nfunction chatMessageToAIMessage(message: ChatMessage): AIMessage | null {\n if (\n message.role !== 'user' &&\n message.role !== 'assistant' &&\n message.role !== 'system'\n ) {\n return null;\n }\n return { role: message.role, content: message.content } as AIMessage;\n}\n\nasync function mergeAndSaveMetadata(\n message: ChatMessage,\n metadata: Record<string, unknown>,\n): Promise<void> {\n message.setMetadata({ ...message.getMetadata(), ...metadata });\n await message.save();\n}\n\nfunction requireNonEmptyString(value: unknown, message: string): string {\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new VoiceGatewayBadRequestError(message);\n }\n return value;\n}\n\nfunction hasNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction constantTimeEquals(actual: string, expected: string): boolean {\n let diff = actual.length ^ expected.length;\n const length = Math.max(actual.length, expected.length);\n for (let index = 0; index < length; index++) {\n const actualCode = index < actual.length ? actual.charCodeAt(index) : 0;\n const expectedCode =\n index < expected.length ? expected.charCodeAt(index) : 0;\n diff |= actualCode ^ expectedCode;\n }\n return diff === 0;\n}\n\nfunction jsonResponse(body: unknown, status: number): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/chat-feedback.ts","../src/models/VoiceGatewayTurn.ts","../src/collections/VoiceGatewayTurnCollection.ts","../src/voice.ts"],"sourcesContent":["/**\n * Chat feedback capture — turn an in-conversation judgement into a first-class\n * learning signal (L3 of the learning-agents epic, #1891).\n *\n * A tenant end-user accepting or rejecting an applied change, giving a\n * thumbs-up/down, or typing an inline correction produces a {@link Feedback}\n * row — carrying the conversation's **correlation-id** back to the turn it\n * judges — and (by default) immediately reinforces the persona's learning\n * memory. Because recall draws on that same memory next turn, captured feedback\n * *influences subsequent behaviour*: a rejected strategy decays below the reuse\n * floor and stops resurfacing; a correction supersedes it with the corrected\n * value.\n *\n * This is the human-signal half of the loop the personas package already models\n * ({@link reinforceFromFeedback}); the gated half — rewriting a persona's\n * instructions — stays in the directive-proposal flow.\n *\n * @module\n */\n\nimport {\n type LearningMemoryRecord,\n type LearningSemanticSearch,\n resolveDatabase,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport {\n type Feedback,\n FeedbackCollection,\n type FeedbackSignalType,\n feedbackSourceFor,\n personaLearningMemory,\n personaMemoryScope,\n reinforceFromFeedback,\n} from '@happyvertical/smrt-personas';\n\n/** The minimal persona shape chat feedback needs to route the signal. */\nexport interface ChatFeedbackPersona {\n /** Persona id — required (a signal always judges a specific persona). */\n id?: string | null;\n /** Owning tenant. */\n tenantId?: string | null;\n /** Canonical agent class the persona configures (denormalised onto the row). */\n agentClass?: string;\n /** Learning memory partition key. */\n memoryScope?: string;\n}\n\n/**\n * Options for {@link captureChatFeedback}.\n */\nexport interface CaptureChatFeedbackOptions {\n /** Database handle. */\n db: SmrtClassOptions['db'];\n /** The persona the signal judges. */\n persona: ChatFeedbackPersona;\n /** The kind of signal. */\n signalType: FeedbackSignalType;\n /** Correlation-id of the conversation turn this signal judges. */\n correlationId: string;\n /** What {@link correlationId} names. Default `'chat_message'`. */\n correlationType?: string;\n /** Learning episode scope the signal reinforces (matches recall/capture). */\n scope: string;\n /** Learning episode key the signal reinforces. */\n key: string;\n /** The user id that authored the signal (null for autonomous). */\n actorId?: string | null;\n /** Numeric rating for a `rating` signal. */\n rating?: number | null;\n /** Corrected value for a `correction` signal. */\n correction?: string | null;\n /** Freeform note. */\n comment?: string | null;\n /** Structured metadata persisted on the row. */\n metadata?: Record<string, unknown>;\n /** Apply the signal to memory immediately. Default `true`. */\n reinforce?: boolean;\n /** Optional embedding search wired into the reinforced memory. */\n semanticSearch?: LearningSemanticSearch;\n /** Neutral point of a `rating` scale (see `FeedbackOutcomeOptions`). Default 0. */\n ratingNeutral?: number;\n}\n\n/** The outcome of capturing chat feedback. */\nexport interface ChatFeedbackResult {\n /** The persisted feedback row. */\n feedback: Feedback;\n /** The memory record the signal reinforced, or `null` when it carried none. */\n reinforced: LearningMemoryRecord | null;\n}\n\n/**\n * Capture one in-chat feedback signal as a {@link Feedback} row and (by default)\n * reinforce the persona's learning memory from it.\n *\n * @throws when the persona has no id (a signal must name a persisted persona).\n */\nexport async function captureChatFeedback(\n options: CaptureChatFeedbackOptions,\n): Promise<ChatFeedbackResult> {\n if (!options.persona.id) {\n throw new Error(\n 'captureChatFeedback requires a persisted persona (missing id)',\n );\n }\n const memoryScope = personaMemoryScope(options.persona);\n\n const feedbacks = await FeedbackCollection.create({ db: options.db });\n const feedback = await feedbacks.create({\n tenantId: options.persona.tenantId ?? null,\n personaId: options.persona.id,\n agentClass: options.persona.agentClass ?? '',\n memoryScope,\n scope: options.scope,\n key: options.key,\n signalType: options.signalType,\n source: feedbackSourceFor(options.signalType),\n correlationId: options.correlationId,\n correlationType: options.correlationType ?? 'chat_message',\n rating: options.rating ?? null,\n correction: options.correction ?? null,\n comment: options.comment ?? null,\n actorId: options.actorId ?? null,\n });\n if (options.metadata) {\n feedback.setMetadata(options.metadata);\n }\n await feedback.save();\n\n let reinforced: LearningMemoryRecord | null = null;\n if (options.reinforce !== false) {\n // LearningMemory operates on a resolved DB handle; core's `resolveDatabase`\n // accepts a config or a handle and returns a handle (identity for a handle).\n const memory = personaLearningMemory({\n db: await resolveDatabase(options.db ?? {}),\n persona: options.persona,\n semanticSearch: options.semanticSearch,\n });\n reinforced = await reinforceFromFeedback(memory, feedback, {\n ratingNeutral: options.ratingNeutral,\n });\n // Gate exactly-once reinforcement so a later reflection pass never\n // re-applies this signal (mirrors the personas reflection runner).\n feedback.reinforcedAt = new Date();\n await feedback.save();\n }\n\n return { feedback, reinforced };\n}\n\n/** Shared options for the signal-typed convenience wrappers. */\nexport type ChatFeedbackBase = Omit<\n CaptureChatFeedbackOptions,\n 'signalType' | 'rating' | 'correction'\n>;\n\n/**\n * Accept an applied change — reinforces the judged strategy as a success.\n */\nexport function acceptAppliedChange(\n options: ChatFeedbackBase,\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'accept' });\n}\n\n/**\n * Reject an applied change — decays the judged strategy toward the failure floor\n * so it stops being recalled.\n */\nexport function rejectAppliedChange(\n options: ChatFeedbackBase & { comment?: string | null },\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'reject' });\n}\n\n/**\n * Record an inline correction — decays the wrong strategy AND supersedes its\n * stored value with the corrected one, so the next recall returns the fix.\n */\nexport function correctResponse(\n options: ChatFeedbackBase & { correction: string; comment?: string | null },\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({\n ...options,\n signalType: 'correction',\n correction: options.correction,\n });\n}\n\n/**\n * Record a numeric rating for a response (scale is caller-defined; pass\n * `ratingNeutral` for a mid-point).\n */\nexport function rateResponse(\n options: ChatFeedbackBase & { rating: number },\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({\n ...options,\n signalType: 'rating',\n rating: options.rating,\n });\n}\n\n/** Thumbs-up — a `+1` rating (reinforces as a success against neutral 0). */\nexport function thumbsUp(\n options: ChatFeedbackBase,\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'rating', rating: 1 });\n}\n\n/** Thumbs-down — a `-1` rating (decays as a failure against neutral 0). */\nexport function thumbsDown(\n options: ChatFeedbackBase,\n): Promise<ChatFeedbackResult> {\n return captureChatFeedback({ ...options, signalType: 'rating', rating: -1 });\n}\n","import { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n VoiceGatewayTurnOptions,\n VoiceGatewayTurnStatus,\n} from '../types.js';\n\n/**\n * Durable reservation for a gateway turn. The natural key makes `turn_id`\n * replay checks concurrency-safe before transcript messages are written.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'voice_gateway_turns',\n conflictColumns: ['voice_session_id', 'gateway_turn_id'],\n api: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n})\nexport class VoiceGatewayTurn extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-chat\";\n @tenantId()\n tenantId: string = '';\n\n @foreignKey('VoiceSession', { required: true })\n voiceSessionId: string = '';\n\n @field({ required: true })\n gatewaySessionId: string = '';\n\n @field({ required: true })\n gatewayTurnId: string = '';\n\n @field({ required: true })\n target: string = 'smrt:chat';\n\n @field({ required: true })\n status: VoiceGatewayTurnStatus = 'processing';\n\n @field()\n completedAt: Date | null = null;\n\n @field()\n failedAt: Date | null = null;\n\n constructor(options: VoiceGatewayTurnOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.voiceSessionId !== undefined)\n this.voiceSessionId = options.voiceSessionId;\n if (options.gatewaySessionId !== undefined)\n this.gatewaySessionId = options.gatewaySessionId;\n if (options.gatewayTurnId !== undefined)\n this.gatewayTurnId = options.gatewayTurnId;\n if (options.target !== undefined) this.target = options.target;\n if (options.status !== undefined) this.status = options.status;\n if (options.completedAt !== undefined)\n this.completedAt = options.completedAt;\n if (options.failedAt !== undefined) this.failedAt = options.failedAt;\n }\n\n async complete(now: Date = new Date()): Promise<void> {\n this.status = 'completed';\n this.completedAt = now;\n this.failedAt = null;\n await this.save();\n }\n\n async fail(now: Date = new Date()): Promise<void> {\n this.status = 'failed';\n this.failedAt = now;\n await this.save();\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { VoiceGatewayTurn } from '../models/VoiceGatewayTurn.js';\n\nexport class VoiceGatewayTurnCollection extends SmrtCollection<VoiceGatewayTurn> {\n static readonly _itemClass = VoiceGatewayTurn;\n\n async reserveTurn(input: {\n tenantId: string;\n voiceSessionId: string;\n gatewaySessionId: string;\n gatewayTurnId: string;\n target: string;\n }): Promise<VoiceGatewayTurn> {\n return this.create({\n ...input,\n status: 'processing',\n _insertOnly: true,\n });\n }\n}\n","import type { AIInterface, AIMessage } from '@happyvertical/ai';\nimport type { PrincipalAuditSink } from '@happyvertical/smrt-agents';\nimport {\n type SmrtClassOptions,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport { VoiceGatewayTurnCollection } from './collections/VoiceGatewayTurnCollection.js';\nimport { VoiceSessionCollection } from './collections/VoiceSessionCollection.js';\nimport type { ChatMessage } from './models/ChatMessage.js';\nimport type { VoiceGatewayTurn } from './models/VoiceGatewayTurn.js';\nimport type { VoiceSession } from './models/VoiceSession.js';\nimport {\n bindPersonaToSession,\n type ConversationPersona,\n type PersonaRecallOptions,\n runPersonaConversationTurn,\n} from './persona-conversation.js';\nimport type { ChatService } from './services/index.js';\n\nexport const SMRT_CHAT_VOICE_TARGET = 'smrt:chat';\nexport const MAX_VOICE_GATEWAY_TEXT_LENGTH = 12_000;\nconst DEFAULT_VOICE_SESSION_TTL_SECONDS = 10 * 60;\nconst DEFAULT_HISTORY_LIMIT = 24;\n\nexport interface VoiceGatewayTurnMetadata {\n tenantId?: string;\n actorProfileId?: string;\n chatRoomId?: string;\n threadId?: string;\n agentSessionId?: string;\n personaId?: string;\n voiceSessionId?: string;\n source?: string;\n [key: string]: unknown;\n}\n\nexport interface VoiceGatewayTurnPayload {\n session_id: string;\n turn_id: string;\n target: string;\n actor?: string;\n text: string;\n metadata?: VoiceGatewayTurnMetadata;\n}\n\nexport interface VoiceGatewayTurnResponseMetadata {\n tenantId: string;\n chatRoomId: string;\n threadId: string | null;\n agentSessionId: string;\n userMessageId: string;\n assistantMessageId: string | null;\n personaId: string;\n correlationId: string;\n voiceSessionId: string;\n source: string;\n}\n\nexport interface VoiceGatewayTurnResponse {\n session_id: string;\n turn_id: string;\n text: string;\n metadata: VoiceGatewayTurnResponseMetadata;\n}\n\nexport interface CreateVoiceChatSessionOptions {\n chatService: ChatService;\n db: SmrtClassOptions['db'];\n tenantId: string;\n actorProfileId: string;\n actorUserId?: string | null;\n persona: ConversationPersona;\n /** Existing agent session to bind voice to. Omit to create/reuse one. */\n agentSessionId?: string;\n /** Agent profile/session author id when creating a new agent session. */\n agentId?: string;\n /** Optional existing thread within the bound session room. */\n threadId?: string | null;\n /** Stable gateway-level `session_id`. Generated when omitted. */\n gatewaySessionId?: string;\n /** Subject key forwarded to ChatService.createAgentSession(). */\n sessionKey?: string | null;\n /** Voice binding TTL. Ignored when `expiresAt` is supplied. */\n ttlSeconds?: number;\n expiresAt?: Date;\n metadata?: Record<string, unknown>;\n target?: string;\n maxTokens?: number;\n maxMessages?: number;\n instructions?: string;\n}\n\nexport interface VoiceChatSessionCreationResult {\n voiceSession: VoiceSession;\n voiceSessionId: string;\n gatewaySessionId: string;\n expiresAt: Date;\n tenantId: string;\n actorProfileId: string;\n personaId: string;\n agentSessionId: string;\n chatRoomId: string;\n threadId: string | null;\n metadata: VoiceGatewayTurnMetadata;\n}\n\nexport interface HandleVoiceGatewayTurnOptions {\n chatService: ChatService;\n db: SmrtClassOptions['db'];\n ai: AIInterface;\n payload: VoiceGatewayTurnPayload;\n now?: Date;\n historyLimit?: number;\n recall?: PersonaRecallOptions | false;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n maxSteps?: number;\n postgresRls?: boolean;\n audit?: PrincipalAuditSink;\n}\n\nexport interface VoiceGatewayTurnHandlerOptions\n extends Omit<HandleVoiceGatewayTurnOptions, 'payload'> {\n gatewayToken: string | (() => string | Promise<string>);\n}\n\nexport class VoiceGatewayError extends Error {\n readonly status: number;\n readonly code: string;\n\n constructor(message: string, status: number, code: string) {\n super(message);\n this.name = 'VoiceGatewayError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class VoiceGatewayBadRequestError extends VoiceGatewayError {\n constructor(message: string) {\n super(message, 400, 'voice_gateway_bad_request');\n this.name = 'VoiceGatewayBadRequestError';\n }\n}\n\nexport class VoiceGatewayUnauthorizedError extends VoiceGatewayError {\n constructor(message = 'Voice gateway authorization failed') {\n super(message, 401, 'voice_gateway_unauthorized');\n this.name = 'VoiceGatewayUnauthorizedError';\n }\n}\n\nexport class VoiceSessionRejectedError extends VoiceGatewayError {\n constructor(message: string) {\n super(message, 403, 'voice_session_rejected');\n this.name = 'VoiceSessionRejectedError';\n }\n}\n\nexport class VoiceSessionExpiredError extends VoiceGatewayError {\n constructor(message = 'Voice session is expired') {\n super(message, 410, 'voice_session_expired');\n this.name = 'VoiceSessionExpiredError';\n }\n}\n\nexport class VoiceGatewayReplayError extends VoiceGatewayError {\n constructor(message = 'Voice gateway turn has already been processed') {\n super(message, 409, 'voice_gateway_replay');\n this.name = 'VoiceGatewayReplayError';\n }\n}\n\nexport async function createVoiceChatSession(\n options: CreateVoiceChatSessionOptions,\n): Promise<VoiceChatSessionCreationResult> {\n const target = options.target ?? SMRT_CHAT_VOICE_TARGET;\n const personaId = requireNonEmptyString(\n options.persona.id,\n 'createVoiceChatSession requires a persisted persona id',\n );\n if (\n options.persona.tenantId !== null &&\n options.persona.tenantId !== options.tenantId\n ) {\n throw new VoiceSessionRejectedError(\n 'Persona tenant does not match the voice session tenant',\n );\n }\n\n const persona: ConversationPersona = {\n ...options.persona,\n id: personaId,\n tenantId: options.tenantId,\n };\n\n let agentSession = options.agentSessionId\n ? await options.chatService.getAgentSession({\n agentSessionId: options.agentSessionId,\n tenantId: options.tenantId,\n })\n : null;\n\n if (options.agentSessionId) {\n if (!agentSession) {\n throw new VoiceSessionRejectedError('Agent session not found');\n }\n assertAgentSessionMatchesActor(agentSession, options.actorProfileId);\n assertActiveAgentSession(agentSession);\n } else {\n // `agentId` is the agent's logical identity and `agentProfileId` is the\n // Profile it AUTHORS as — two different things since #2995. The persona's\n // `actsAsProfileId` is the latter (a `crossPackageRef` to `Profile`), so it\n // is passed as the authoring profile rather than collapsed into `agentId`;\n // otherwise a synthetic `bot` profile would be minted for it and persona\n // replies would stop being attributed to the configured acting identity.\n const agentId =\n options.agentId ?? persona.id ?? persona.agentClass ?? undefined;\n if (!agentId) {\n throw new VoiceGatewayBadRequestError(\n 'createVoiceChatSession requires agentId when the persona has no id or agent class',\n );\n }\n const created = await options.chatService.createAgentSession({\n tenantId: options.tenantId,\n agentId,\n agentProfileId: persona.actsAsProfileId ?? null,\n actorProfileId: options.actorProfileId,\n allowedTools: persona.allowedTools,\n systemPrompt: options.instructions ?? persona.instructions,\n maxTokens: options.maxTokens,\n maxMessages: options.maxMessages,\n sessionKey: options.sessionKey,\n });\n agentSession = created.session;\n }\n\n const boundSession = await bindPersonaToSession({\n chatService: options.chatService,\n session: agentSession,\n actorProfileId: options.actorProfileId,\n tenantId: options.tenantId,\n persona,\n instructions: options.instructions,\n db: options.db,\n });\n assertActiveAgentSession(boundSession);\n\n const chatRoomId = requireNonEmptyString(\n boundSession.chatRoomId,\n 'Agent session has no chat room',\n );\n await options.chatService.getRoomForMember(\n chatRoomId,\n options.actorProfileId,\n options.tenantId,\n );\n\n const threadId = options.threadId ?? null;\n if (threadId) {\n const thread = await options.chatService.getThread({\n threadId,\n tenantId: options.tenantId,\n });\n if (!thread || thread.roomId !== chatRoomId) {\n throw new VoiceSessionRejectedError(\n 'threadId does not belong to the bound agent session room',\n );\n }\n }\n\n const voiceSessions = await VoiceSessionCollection.create({ db: options.db });\n const gatewaySessionId = options.gatewaySessionId ?? crypto.randomUUID();\n const expiresAt =\n options.expiresAt ??\n new Date(\n Date.now() +\n (options.ttlSeconds ?? DEFAULT_VOICE_SESSION_TTL_SECONDS) * 1000,\n );\n\n const voiceSession = await voiceSessions.create({\n tenantId: options.tenantId,\n gatewaySessionId,\n actorProfileId: options.actorProfileId,\n actorUserId: options.actorUserId ?? null,\n personaId,\n agentSessionId: boundSession.id as string,\n chatRoomId,\n threadId,\n target,\n status: 'active',\n expiresAt,\n personaSnapshot: JSON.stringify(persona),\n metadata: JSON.stringify(options.metadata ?? {}),\n });\n\n const voiceSessionId = voiceSession.id as string;\n return {\n voiceSession,\n voiceSessionId,\n gatewaySessionId,\n expiresAt,\n tenantId: options.tenantId,\n actorProfileId: options.actorProfileId,\n personaId,\n agentSessionId: boundSession.id as string,\n chatRoomId,\n threadId,\n metadata: {\n tenantId: options.tenantId,\n actorProfileId: options.actorProfileId,\n chatRoomId,\n threadId: threadId ?? undefined,\n agentSessionId: boundSession.id as string,\n personaId,\n voiceSessionId,\n source: 'smrt-chat',\n },\n };\n}\n\nexport async function handleVoiceGatewayTurn(\n options: HandleVoiceGatewayTurnOptions,\n): Promise<VoiceGatewayTurnResponse> {\n const payload = normalizeGatewayPayload(options.payload);\n const metadata = payload.metadata ?? {};\n const voiceSessionId = requireNonEmptyString(\n metadata.voiceSessionId,\n 'Voice gateway payload metadata.voiceSessionId is required',\n );\n\n const voiceSessions = await VoiceSessionCollection.create({ db: options.db });\n const voiceSession = await voiceSessions.get({\n id: voiceSessionId,\n target: payload.target,\n });\n if (!voiceSession) {\n throw new VoiceSessionRejectedError('Voice session not found');\n }\n if (voiceSession.isExpired(options.now)) {\n if (voiceSession.status === 'active') {\n await voiceSession.expire();\n }\n throw new VoiceSessionExpiredError();\n }\n if (!voiceSession.isActive(options.now)) {\n throw new VoiceSessionRejectedError('Voice session is not active');\n }\n if (voiceSession.hasProcessedTurn(payload.turn_id)) {\n throw new VoiceGatewayReplayError();\n }\n\n validateGatewayPayloadAgainstBinding(payload, voiceSession);\n const persona = requireVoiceSessionPersona(voiceSession);\n\n const agentSession = await options.chatService.getAgentSession({\n agentSessionId: voiceSession.agentSessionId,\n tenantId: voiceSession.tenantId,\n });\n if (!agentSession) {\n throw new VoiceSessionRejectedError('Bound agent session not found');\n }\n assertAgentSessionMatchesActor(agentSession, voiceSession.actorProfileId);\n assertActiveAgentSession(agentSession);\n if (agentSession.chatRoomId !== voiceSession.chatRoomId) {\n throw new VoiceSessionRejectedError(\n 'Bound agent session no longer belongs to the voice session room',\n );\n }\n\n if (voiceSession.threadId) {\n const thread = await options.chatService.getThread({\n threadId: voiceSession.threadId,\n tenantId: voiceSession.tenantId,\n });\n if (!thread || thread.roomId !== voiceSession.chatRoomId) {\n throw new VoiceSessionRejectedError(\n 'Bound thread no longer belongs to the voice session room',\n );\n }\n }\n\n const gatewayTurn = await reserveVoiceGatewayTurn(\n options.db,\n voiceSession,\n payload,\n );\n\n try {\n const history = await loadConversationHistory({\n chatService: options.chatService,\n tenantId: voiceSession.tenantId,\n actorProfileId: voiceSession.actorProfileId,\n roomId: voiceSession.chatRoomId,\n threadId: voiceSession.threadId,\n limit: options.historyLimit ?? DEFAULT_HISTORY_LIMIT,\n });\n const correlationId = crypto.randomUUID();\n const commonMetadata = {\n source: 'voice-gateway',\n target: payload.target,\n voiceSessionId,\n gatewaySessionId: payload.session_id,\n gatewayTurnId: payload.turn_id,\n correlationId,\n };\n\n const userMessage = await options.chatService.sendAgentUserMessage({\n tenantId: voiceSession.tenantId,\n agentSessionId: voiceSession.agentSessionId,\n actorProfileId: voiceSession.actorProfileId,\n content: payload.text,\n });\n await mergeAndSaveMetadata(userMessage, {\n ...commonMetadata,\n voiceRole: 'transcript',\n });\n\n const turn = await runPersonaConversationTurn({\n ai: options.ai,\n db: options.db,\n persona,\n tenantId: voiceSession.tenantId,\n userMessage: payload.text,\n history,\n chatService: options.chatService,\n session: agentSession,\n threadId: voiceSession.threadId,\n recall: options.recall,\n model: options.model,\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n maxSteps: options.maxSteps,\n postgresRls: options.postgresRls,\n audit: options.audit,\n onBehalfOfUserId: voiceSession.actorUserId ?? undefined,\n correlationId,\n });\n\n for (const toolMessage of turn.authoredMessages?.toolMessages ?? []) {\n await mergeAndSaveMetadata(toolMessage, {\n ...commonMetadata,\n voiceRole: 'tool',\n });\n }\n const assistantMessage = turn.authoredMessages?.assistantMessage ?? null;\n if (assistantMessage) {\n await mergeAndSaveMetadata(assistantMessage, {\n ...commonMetadata,\n voiceRole: 'assistant',\n });\n }\n\n voiceSession.recordGatewayTurn(payload.turn_id);\n await voiceSession.save();\n await gatewayTurn.complete();\n\n return {\n session_id: payload.session_id,\n turn_id: payload.turn_id,\n text: turn.result.content,\n metadata: {\n tenantId: voiceSession.tenantId,\n chatRoomId: voiceSession.chatRoomId,\n threadId: voiceSession.threadId,\n agentSessionId: voiceSession.agentSessionId,\n userMessageId: userMessage.id as string,\n assistantMessageId:\n (assistantMessage?.id as string | undefined) ?? null,\n personaId: voiceSession.personaId,\n correlationId: turn.correlationId,\n voiceSessionId,\n source: 'voice-gateway',\n },\n };\n } catch (error) {\n await markVoiceGatewayTurnFailed(gatewayTurn);\n throw error;\n }\n}\n\nexport function createVoiceGatewayTurnHandler(\n options: VoiceGatewayTurnHandlerOptions,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n if (request.method !== 'POST') {\n return jsonResponse({ error: 'Method not allowed' }, 405);\n }\n await assertVoiceGatewayBearer(\n request.headers,\n await resolveGatewayToken(options.gatewayToken),\n );\n const payload = normalizeGatewayPayload(await request.json());\n const response = await handleVoiceGatewayTurn({ ...options, payload });\n return jsonResponse(response, 200);\n } catch (error) {\n const status = error instanceof VoiceGatewayError ? error.status : 500;\n const message =\n error instanceof Error ? error.message : 'Voice gateway turn failed';\n const code =\n error instanceof VoiceGatewayError ? error.code : 'voice_gateway_error';\n return jsonResponse({ error: message, code }, status);\n }\n };\n}\n\nexport async function assertVoiceGatewayBearer(\n headers: Headers,\n expectedToken: string,\n): Promise<void> {\n if (!expectedToken) {\n throw new VoiceGatewayUnauthorizedError(\n 'Voice gateway token is not configured',\n );\n }\n const authorization = headers.get('authorization') ?? '';\n const match = authorization.match(/^Bearer\\s+(.+)$/i);\n const actual = match?.[1] ?? '';\n if (!constantTimeEquals(actual, expectedToken)) {\n throw new VoiceGatewayUnauthorizedError();\n }\n}\n\nasync function resolveGatewayToken(\n token: string | (() => string | Promise<string>),\n): Promise<string> {\n return typeof token === 'function' ? token() : token;\n}\n\nfunction normalizeGatewayPayload(input: unknown): VoiceGatewayTurnPayload {\n if (!isRecord(input)) {\n throw new VoiceGatewayBadRequestError('Voice gateway payload must be JSON');\n }\n const sessionId = requireNonEmptyString(\n input.session_id,\n 'Voice gateway payload session_id is required',\n );\n const turnId = requireNonEmptyString(\n input.turn_id,\n 'Voice gateway payload turn_id is required',\n );\n const target = requireNonEmptyString(\n input.target,\n 'Voice gateway payload target is required',\n );\n if (target !== SMRT_CHAT_VOICE_TARGET) {\n throw new VoiceGatewayBadRequestError(\n `Unsupported voice gateway target '${target}'`,\n );\n }\n const text = requireNonEmptyString(\n input.text,\n 'Voice gateway payload text is required',\n );\n if (text.length > MAX_VOICE_GATEWAY_TEXT_LENGTH) {\n throw new VoiceGatewayBadRequestError(\n `Voice gateway payload text must be ${MAX_VOICE_GATEWAY_TEXT_LENGTH} characters or fewer`,\n );\n }\n const metadata = input.metadata;\n if (metadata !== undefined && !isRecord(metadata)) {\n throw new VoiceGatewayBadRequestError(\n 'Voice gateway payload metadata must be an object',\n );\n }\n\n return {\n session_id: sessionId,\n turn_id: turnId,\n target,\n actor:\n typeof input.actor === 'string' && input.actor.length > 0\n ? input.actor\n : undefined,\n text,\n metadata: metadata as VoiceGatewayTurnMetadata | undefined,\n };\n}\n\nfunction validateGatewayPayloadAgainstBinding(\n payload: VoiceGatewayTurnPayload,\n voiceSession: VoiceSession,\n): void {\n if (payload.session_id !== voiceSession.gatewaySessionId) {\n throw new VoiceSessionRejectedError(\n 'Gateway session_id does not match the voice session binding',\n );\n }\n const metadata = payload.metadata ?? {};\n assertMetadataMatches(\n metadata,\n 'tenantId',\n voiceSession.tenantId,\n 'tenantId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'actorProfileId',\n voiceSession.actorProfileId,\n 'actorProfileId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'chatRoomId',\n voiceSession.chatRoomId,\n 'chatRoomId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'threadId',\n voiceSession.threadId,\n 'threadId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'agentSessionId',\n voiceSession.agentSessionId,\n 'agentSessionId does not match the voice session binding',\n );\n assertMetadataMatches(\n metadata,\n 'personaId',\n voiceSession.personaId,\n 'personaId does not match the voice session binding',\n );\n}\n\nfunction requireVoiceSessionPersona(\n voiceSession: VoiceSession,\n): ConversationPersona {\n const persona = voiceSession.getPersonaSnapshot();\n if (!hasNonEmptyString(persona.id)) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot has no persona id',\n );\n }\n if (persona.id !== voiceSession.personaId) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot does not match the voice session persona',\n );\n }\n if (persona.tenantId !== voiceSession.tenantId) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot tenant does not match the voice session tenant',\n );\n }\n if (!hasNonEmptyString(persona.runAsUserId)) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot has no runnable user',\n );\n }\n if (!Array.isArray(persona.allowedTools)) {\n throw new VoiceSessionRejectedError(\n 'Voice session persona snapshot has an invalid tool allow-list',\n );\n }\n return persona;\n}\n\nasync function reserveVoiceGatewayTurn(\n db: SmrtClassOptions['db'],\n voiceSession: VoiceSession,\n payload: VoiceGatewayTurnPayload,\n): Promise<VoiceGatewayTurn> {\n const gatewayTurns = await VoiceGatewayTurnCollection.create({ db });\n try {\n return await gatewayTurns.reserveTurn({\n tenantId: voiceSession.tenantId,\n voiceSessionId: voiceSession.id as string,\n gatewaySessionId: payload.session_id,\n gatewayTurnId: payload.turn_id,\n target: payload.target,\n });\n } catch (error) {\n if (isUniqueConstraintError(error)) {\n throw new VoiceGatewayReplayError();\n }\n throw error;\n }\n}\n\nasync function markVoiceGatewayTurnFailed(\n gatewayTurn: VoiceGatewayTurn,\n): Promise<void> {\n try {\n await gatewayTurn.fail();\n } catch {\n // Preserve the original turn failure for the gateway response.\n }\n}\n\nfunction isUniqueConstraintError(error: unknown): boolean {\n return (\n error instanceof ValidationError &&\n error.code === 'VALIDATION_UNIQUE_CONSTRAINT'\n );\n}\n\nfunction assertMetadataMatches(\n metadata: VoiceGatewayTurnMetadata,\n key: keyof VoiceGatewayTurnMetadata,\n expected: string | null,\n message: string,\n): void {\n const actual = metadata[key];\n if (actual === undefined || actual === null || actual === '') {\n return;\n }\n if (typeof actual !== 'string' || actual !== expected) {\n throw new VoiceSessionRejectedError(message);\n }\n}\n\nfunction assertAgentSessionMatchesActor(\n session: { participantProfileId: string },\n actorProfileId: string,\n): void {\n if (session.participantProfileId !== actorProfileId) {\n throw new VoiceSessionRejectedError(\n 'Agent session participant does not match the voice session actor',\n );\n }\n}\n\nfunction assertActiveAgentSession(session: {\n isActive: () => boolean;\n chatRoomId: string | null;\n}): void {\n if (!session.isActive()) {\n throw new VoiceSessionRejectedError('Agent session is not active');\n }\n if (!session.chatRoomId) {\n throw new VoiceSessionRejectedError('Agent session has no chat room');\n }\n}\n\nasync function loadConversationHistory(input: {\n chatService: ChatService;\n tenantId: string;\n actorProfileId: string;\n roomId: string;\n threadId: string | null;\n limit: number;\n}): Promise<AIMessage[]> {\n const messages = input.threadId\n ? await input.chatService.getThreadMessages({\n threadId: input.threadId,\n actorProfileId: input.actorProfileId,\n tenantId: input.tenantId,\n limit: input.limit,\n })\n : (\n await input.chatService.getRoomMessages({\n roomId: input.roomId,\n actorProfileId: input.actorProfileId,\n tenantId: input.tenantId,\n limit: input.limit,\n })\n ).reverse();\n\n return messages\n .map(chatMessageToAIMessage)\n .filter((message): message is AIMessage => message !== null);\n}\n\nfunction chatMessageToAIMessage(message: ChatMessage): AIMessage | null {\n if (\n message.role !== 'user' &&\n message.role !== 'assistant' &&\n message.role !== 'system'\n ) {\n return null;\n }\n return { role: message.role, content: message.content } as AIMessage;\n}\n\nasync function mergeAndSaveMetadata(\n message: ChatMessage,\n metadata: Record<string, unknown>,\n): Promise<void> {\n message.setMetadata({ ...message.getMetadata(), ...metadata });\n await message.save();\n}\n\nfunction requireNonEmptyString(value: unknown, message: string): string {\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new VoiceGatewayBadRequestError(message);\n }\n return value;\n}\n\nfunction hasNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction constantTimeEquals(actual: string, expected: string): boolean {\n let diff = actual.length ^ expected.length;\n const length = Math.max(actual.length, expected.length);\n for (let index = 0; index < length; index++) {\n const actualCode = index < actual.length ? actual.charCodeAt(index) : 0;\n const expectedCode =\n index < expected.length ? expected.charCodeAt(index) : 0;\n diff |= actualCode ^ expectedCode;\n }\n return diff === 0;\n}\n\nfunction jsonResponse(body: unknown, status: number): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'content-type': 'application/json' },\n });\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-chat",
5
- "packageVersion": "0.55.2",
5
+ "packageVersion": "0.55.4",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-chat:AgentSessionCollection": {
8
8
  "name": "agentsessioncollection",
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import type { AIInterface, AIMessage } from '@happyvertical/ai';
21
21
  import type { PrincipalAuditSink, PrincipalBinding, PrincipalTool } from '@happyvertical/smrt-agents';
22
- import type { LearningMemoryRecord, LearningSemanticSearch, SmrtClassOptions } from '@happyvertical/smrt-core';
22
+ import { type LearningMemoryRecord, type LearningSemanticSearch, type SmrtClassOptions } from '@happyvertical/smrt-core';
23
23
  import type { AgentSession } from './models/AgentSession.js';
24
24
  import type { ChatMessage } from './models/ChatMessage.js';
25
25
  import { type ManifestTool, type ToolLoopResult } from './tool-loop.js';
@@ -1 +1 @@
1
- {"version":3,"file":"persona-conversation.d.ts","sourceRoot":"","sources":["../src/persona-conversation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACd,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAMlC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,qBAAqB;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,2EAA2E;IAC3E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qFAAqF;AACrF,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,mBAAmB,CAWtB;AAED,yEAAyE;AACzE,wBAAgB,mCAAmC,CAAC,OAAO,EAAE;IAC3D,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,MAAM,EAAE,CAAC;CACjC,GAAG,mBAAmB,CAWtB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,mBAAmB,GAC3B,gBAAgB,CAOlB;AAED,+EAA+E;AAC/E,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,sBAAsB,CAAC;CACzC;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAC1B,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAiBjC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAY5E;AAED;;;;;;;GAOG;AACH,wBAAsB,+BAA+B,CACnD,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAC1B,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,uDAAuD;AACvD,KAAK,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC;AAE5E,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB;IACvC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB;IACvB,EAAE,EAAE,WAAW,CAAC;IAChB,4DAA4D;IAC5D,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3B,gDAAgD;IAChD,OAAO,EAAE,mBAAmB,CAAC;IAC7B,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,mDAAmD;IACnD,WAAW,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC9C,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,oBAAoB,GAAG,KAAK,CAAC;IACtC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iFAAiF;IACjF,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,wDAAwD;AACxD,MAAM,WAAW,6BAA6B;IAC5C,kEAAkE;IAClE,MAAM,EAAE,cAAc,CAAC;IACvB,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,4BAA4B,CAAC;CACjD;AAED,oEAAoE;AACpE,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,gBAAgB,EAAE,WAAW,GAAG,IAAI,CAAC;CACtC;AAiBD;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,6BAA6B,CAAC,CA8ExC;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,WAAW,EAAE;QACX,wBAAwB,CAAC,MAAM,EAAE;YAC/B,cAAc,EAAE,MAAM,CAAC;YACvB,cAAc,EAAE,MAAM,CAAC;YACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;YACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;YACxB,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;KAC3B,CAAC;IACF,2BAA2B;IAC3B,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAClC,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,0CAA0C;IAC1C,OAAO,EAAE,mBAAmB,CAAC;IAC7B,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,EAAE,CAAC,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,YAAY,CAAC,CAavB"}
1
+ {"version":3,"file":"persona-conversation.d.ts","sourceRoot":"","sources":["../src/persona-conversation.ts"],"names":[],"mappings":"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"}
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-chat",
6
- "packageVersion": "0.55.2",
6
+ "packageVersion": "0.55.4",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "c75e87eccad2e9d1ee2d10133b30188cd05d29f4eef5c1f590b1363ab7590f6f",
11
- "packageJson": "91ae029d4ea508b0cf0c447263a3ea18b70c396546e1bd0eb0c7f312da0d4155",
10
+ "manifest": "bfbbfae2680e92a53811fc64f706491f702651482a1221d4e5097cdcf1fffd5d",
11
+ "packageJson": "9e9019303701881112d3cd90fcb194a3ff2fd5e6870adab107c028b61ba17d5b",
12
12
  "agents": "0d11ad3c134fc4de4c3fd61fb3a5e7d760ecf8ef6b2b16679b66358e6877dd74",
13
13
  "moduleDoc:agents/dev-workbench.md": "69b6f827d25c8aeb0e7516c90303af23948803213b5d34bc334c1e3376c83a16",
14
14
  "agentSurface:src/routes/chat-dev.intents.ts": "ff8f7c19c7eb6e841a08f03c97773c53092ed208004666bfed372bd1ad456b35"
package/dist/sveltekit.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { i as clientRequestMessageId, n as ChatService, t as ChatClientRequestConflictError } from "./chunks/ChatService-C9UxuJaw.js";
2
- import { D as runAssistantTurn, E as createSessionContinuationStore, P as buildManifestToolCatalog, j as MAX_CLIENT_TOOL_RESULT_CHARS, v as ASSISTANT_TURN_GENERIC_ERROR, w as createAssistantTurnResponse, z as sanitizeClientToolDeclarations } from "./chunks/chat-stream-Bpx5qi-h.js";
2
+ import { D as runAssistantTurn, E as createSessionContinuationStore, P as buildManifestToolCatalog, j as MAX_CLIENT_TOOL_RESULT_CHARS, v as ASSISTANT_TURN_GENERIC_ERROR, w as createAssistantTurnResponse, z as sanitizeClientToolDeclarations } from "./chunks/chat-stream-cbCV0Q6C.js";
3
3
  import { getCurrentSessionPermissionContext, getRequestScopedDatabase } from "@happyvertical/smrt-users";
4
4
  import { getConfig, loadConfig, resolveConfiguredAIProvider, toAIClientOptions } from "@happyvertical/smrt-config";
5
5
  //#region src/sveltekit.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-chat",
3
- "version": "0.55.2",
3
+ "version": "0.55.4",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Chat rooms, DMs, threads, and agent conversations for the SMRT framework",
6
6
  "type": "module",
@@ -78,17 +78,17 @@
78
78
  "access": "public"
79
79
  },
80
80
  "dependencies": {
81
- "@happyvertical/ai": "^0.102.2",
82
- "@happyvertical/smrt-agents": "0.55.2",
83
- "@happyvertical/smrt-config": "0.55.2",
84
- "@happyvertical/smrt-core": "0.55.2",
85
- "@happyvertical/smrt-personas": "0.55.2",
86
- "@happyvertical/smrt-profiles": "0.55.2",
87
- "@happyvertical/smrt-tenancy": "0.55.2",
88
- "@happyvertical/smrt-types": "0.55.2",
89
- "@happyvertical/smrt-ui": "0.55.2",
90
- "@happyvertical/smrt-users": "0.55.2",
91
- "@happyvertical/sql": "^0.102.2"
81
+ "@happyvertical/ai": "^0.102.3",
82
+ "@happyvertical/smrt-agents": "0.55.4",
83
+ "@happyvertical/smrt-config": "0.55.4",
84
+ "@happyvertical/smrt-core": "0.55.4",
85
+ "@happyvertical/smrt-personas": "0.55.4",
86
+ "@happyvertical/smrt-profiles": "0.55.4",
87
+ "@happyvertical/smrt-tenancy": "0.55.4",
88
+ "@happyvertical/smrt-types": "0.55.4",
89
+ "@happyvertical/smrt-ui": "0.55.4",
90
+ "@happyvertical/smrt-users": "0.55.4",
91
+ "@happyvertical/sql": "^0.102.3"
92
92
  },
93
93
  "peerDependencies": {
94
94
  "svelte": "^5.57.0"
@@ -99,9 +99,9 @@
99
99
  }
100
100
  },
101
101
  "devDependencies": {
102
- "@happyvertical/smrt-playground": "0.55.2",
103
- "@happyvertical/smrt-vitest": "0.55.2",
104
- "@happyvertical/smrt-web": "0.55.2",
102
+ "@happyvertical/smrt-playground": "0.55.4",
103
+ "@happyvertical/smrt-vitest": "0.55.4",
104
+ "@happyvertical/smrt-web": "0.55.4",
105
105
  "@mlc-ai/web-llm": "^0.2.85",
106
106
  "bitgpu": "0.19.1",
107
107
  "@sveltejs/kit": "2.69.1",