@mirasoth/soothe-client 0.1.0 → 0.2.1
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/chunk-AQZACDIC.js +1399 -0
- package/dist/chunk-AQZACDIC.js.map +1 -0
- package/dist/client-CB6WKQYW.js +7 -0
- package/dist/index.cjs +2383 -419
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1110 -280
- package/dist/index.d.ts +1110 -280
- package/dist/index.js +1265 -91
- package/dist/index.js.map +1 -1
- package/package.json +34 -8
- package/dist/chunk-OMAC7LA7.js +0 -647
- package/dist/chunk-OMAC7LA7.js.map +0 -1
- package/dist/client-QS23U6WX.js +0 -7
- /package/dist/{client-QS23U6WX.js.map → client-CB6WKQYW.js.map} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/verbosity.ts","../src/events.ts","../src/helpers.ts","../src/session.ts"],"sourcesContent":["/**\n * Custom error types for the Soothe client.\n */\n\n/** Represents a WebSocket connection failure. */\nexport class ConnectionError extends Error {\n readonly url: string;\n readonly attempt: number;\n readonly cause: Error;\n\n constructor(url: string, attempt: number, cause: Error) {\n super(`connection error to ${url} (attempt ${attempt}): ${cause.message}`);\n this.name = 'ConnectionError';\n this.url = url;\n this.attempt = attempt;\n this.cause = cause;\n }\n}\n\n/** Represents an error reported by the Soothe daemon. */\nexport class DaemonError extends Error {\n readonly code: string;\n /** The daemon's error message text. */\n readonly daemonMessage: string;\n\n constructor(code: string, message: string) {\n super(`daemon error [${code}]: ${message}`);\n this.name = 'DaemonError';\n this.code = code;\n this.daemonMessage = message;\n }\n}\n\n/** Represents a timeout waiting for a daemon response. */\nexport class TimeoutError extends Error {\n readonly operation: string;\n readonly duration: string;\n\n constructor(operation: string, duration: string) {\n super(`timeout after ${duration} waiting for ${operation}`);\n this.name = 'TimeoutError';\n this.operation = operation;\n this.duration = duration;\n }\n}\n","/**\n * Verbosity levels and tiers for event filtering.\n */\n\n/** User-configurable verbosity setting. */\nexport type VerbosityLevel = 'quiet' | 'normal' | 'debug';\n\n/** Minimum verbosity level at which content is visible. */\nexport enum VerbosityTier {\n /** Always visible (errors, assistant text, final reports) */\n Quiet = 0,\n /** Standard progress (plan updates, milestones, agentic loop) */\n Normal = 1,\n /** Detailed internals (protocol events, tool calls, subagent activity) */\n Detailed = 2,\n /** Everything including internals (thinking, heartbeats) */\n Debug = 3,\n /** Never shown at any level (implementation details) */\n Internal = 99,\n}\n\nconst verbosityLevelValues: Record<VerbosityLevel, number> = {\n quiet: 0,\n normal: 1,\n debug: 3,\n};\n\n/** Returns true if content at the given tier is visible at the given verbosity. */\nexport function shouldShow(tier: VerbosityTier, verbosity: VerbosityLevel): boolean {\n if (tier === VerbosityTier.Internal) {\n return false;\n }\n const level = verbosityLevelValues[verbosity] ?? 1; // default to normal\n return tier <= level;\n}\n\n/** Checks whether a string is a valid verbosity level. */\nexport function isValidVerbosityLevel(s: string): s is VerbosityLevel {\n return s in verbosityLevelValues;\n}\n","/**\n * Client-facing event namespace constants for the Soothe daemon wire protocol.\n *\n * Internal catalog types (`soothe.internal.*`) are server-only and are never\n * broadcast to WebSocket clients. Do not add them here.\n *\n * Format: soothe.<domain>.<component>.<action>\n */\n\nimport { VerbosityTier } from './verbosity.js';\n\n// Plan events (client UX)\nexport const EventPlanCreated = 'soothe.cognition.plan.created';\n\n// Explore subagent events (built-in wire, IG-339)\nexport const EventExploreStarted = 'soothe.subagent.explore.started';\nexport const EventExploreMilestone = 'soothe.subagent.explore.milestone';\nexport const EventExploreStepCompleted = 'soothe.subagent.explore.step.completed';\nexport const EventExploreCompleted = 'soothe.subagent.explore.completed';\n\n// Tacitus subagent events (built-in wire, IG-339)\nexport const EventTacitusStarted = 'soothe.subagent.tacitus.started';\nexport const EventTacitusGatherSummary = 'soothe.subagent.tacitus.gather.summary';\nexport const EventTacitusCompleted = 'soothe.subagent.tacitus.completed';\n\n// Control-plane wire envelopes (not soothe.* catalog events)\nexport const EventReplayComplete = 'replay_complete';\nexport const EventLoopReattachedWire = 'loop_reattached';\n\n// Tool events\nexport const EventToolStarted = 'soothe.tool.execution.started';\nexport const EventToolCompleted = 'soothe.tool.execution.completed';\nexport const EventToolError = 'soothe.tool.execution.error';\n\n// Stream tool call events (RFC-450, IG-416)\nexport const EventStreamToolCallUpdate = 'soothe.stream.tool_call.update';\nexport const EventToolCallUpdatesBatch = 'tool_call_updates_batch';\n\n// Agent loop events (cognition domain)\nexport const EventAgentLoopStarted = 'soothe.cognition.agent_loop.started';\nexport const EventAgentLoopIterated = 'soothe.cognition.agent_loop.iterated';\nexport const EventAgentLoopCompleted = 'soothe.cognition.agent_loop.completed';\nexport const EventAgentLoopReasoned = 'soothe.cognition.agent_loop.reasoned';\n\n// Message protocol events (client stream metadata)\nexport const EventMessageReceived = 'soothe.protocol.message.received';\nexport const EventMessageSent = 'soothe.protocol.message.sent';\n\n// Output events\nexport const EventFinalReport = 'soothe.output.autonomous.final_report.reported';\n\n// Error events\nexport const EventGeneralFailed = 'soothe.error.general.failed';\n\n// ---------------------------------------------------------------------------\n// Namespace parsing\n// ---------------------------------------------------------------------------\n\n/** Splits a 4-segment event namespace into domain, component, and action. */\nexport function parseNamespace(ns: string): { domain: string; component: string; action: string } | null {\n const parts = splitNamespace(ns);\n if (parts.length < 4 || parts[0] !== 'soothe') {\n return null;\n }\n if (parts[1] === 'internal') {\n return null;\n }\n return { domain: parts[1], component: parts[2], action: parts[3] };\n}\n\nfunction splitNamespace(ns: string): string[] {\n const parts: string[] = [];\n let start = 0;\n for (let i = 0; i < ns.length; i++) {\n if (ns[i] === '.') {\n parts.push(ns.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(ns.slice(start));\n return parts;\n}\n\n// ---------------------------------------------------------------------------\n// Classification\n// ---------------------------------------------------------------------------\n\n/** Returns the VerbosityTier for a given event type string. */\nexport function classifyEventVerbosity(eventTypeOrNamespace: string): VerbosityTier {\n const parsed = parseNamespace(eventTypeOrNamespace);\n if (!parsed) {\n return classifyByEventTypeString(eventTypeOrNamespace);\n }\n return classifyByDomainAndComponent(parsed.domain, parsed.component, eventTypeOrNamespace);\n}\n\nfunction classifyByDomainAndComponent(domain: string, _component: string, full: string): VerbosityTier {\n switch (domain) {\n case 'cognition':\n return VerbosityTier.Normal;\n case 'protocol':\n return VerbosityTier.Detailed;\n case 'tool':\n return VerbosityTier.Internal;\n case 'subagent':\n return classifySubagentEvent(full);\n case 'output':\n case 'error':\n return VerbosityTier.Quiet;\n default:\n return VerbosityTier.Normal;\n }\n}\n\nfunction classifySubagentEvent(full: string): VerbosityTier {\n const parsed = parseNamespace(full);\n if (!parsed) return VerbosityTier.Normal;\n switch (parsed.action) {\n case 'started':\n case 'completed':\n return VerbosityTier.Normal;\n default:\n return VerbosityTier.Detailed;\n }\n}\n\nfunction classifyByEventTypeString(eventType: string): VerbosityTier {\n if (eventType === EventFinalReport || eventType === EventGeneralFailed) {\n return VerbosityTier.Quiet;\n }\n if (eventType === EventToolStarted) {\n return VerbosityTier.Internal;\n }\n return VerbosityTier.Normal;\n}\n\n// ---------------------------------------------------------------------------\n// Event classification helpers\n// ---------------------------------------------------------------------------\n\n/** Event types that represent completion milestones. */\nexport function isCompletionEvent(eventType: string): boolean {\n return (\n eventType.endsWith('.completed') ||\n eventType.endsWith('.failed') ||\n eventType === EventGeneralFailed\n );\n}\n\n/** Lifecycle subagent events (started/completed) for progress UI. */\nexport function isSubagentProgressEvent(eventType: string): boolean {\n const parsed = parseNamespace(eventType);\n if (!parsed || parsed.domain !== 'subagent') {\n return false;\n }\n return parsed.action === 'started' || parsed.action === 'completed';\n}\n\n/** Essential progress event types for minimal UI surfaces. */\nexport const ESSENTIAL_EVENT_TYPES: ReadonlySet<string> = new Set([\n EventAgentLoopStarted,\n EventAgentLoopCompleted,\n EventAgentLoopReasoned,\n EventPlanCreated,\n EventExploreStarted,\n EventExploreCompleted,\n EventTacitusStarted,\n EventTacitusCompleted,\n EventGeneralFailed,\n]);\n","/**\n * Convenience RPC helper functions for the Soothe client.\n */\n\nimport type { Client } from './client.js';\nimport { defaultConfig } from './config.js';\n\n/** Checks daemon status via RPC. */\nexport async function checkDaemonStatus(client: Client, timeout?: number): Promise<Record<string, unknown>> {\n return client.requestResponse({ type: 'daemon_status' }, 'daemon_status_response', timeout ?? 5_000);\n}\n\n/** Performs a composite health check: connect + status RPC. */\nexport async function isDaemonLive(wsURL: string, timeout?: number): Promise<boolean> {\n const { Client } = await import('./client.js');\n const t = timeout ?? 5_000;\n const client = new Client(wsURL, defaultConfig());\n\n try {\n await client.connect();\n } catch {\n return false;\n }\n\n try {\n await checkDaemonStatus(client, t);\n return true;\n } catch {\n return false;\n } finally {\n client.close();\n }\n}\n\n/** Requests daemon shutdown via RPC. */\nexport async function requestDaemonShutdown(client: Client, timeout?: number): Promise<void> {\n const resp = await client.requestResponse({ type: 'daemon_shutdown' }, 'shutdown_ack', timeout ?? 10_000);\n if (resp.status !== 'acknowledged') {\n throw new Error(`shutdown not acknowledged: ${JSON.stringify(resp)}`);\n }\n}\n\n/** Fetches the skills catalog via RPC. */\nexport async function fetchSkillsCatalog(client: Client, timeout?: number): Promise<Record<string, unknown>[]> {\n const resp = await client.requestResponse({ type: 'skills_list' }, 'skills_list_response', timeout ?? 15_000);\n const skillsRaw = resp.skills;\n if (!skillsRaw || !Array.isArray(skillsRaw)) return [];\n return skillsRaw.filter((s): s is Record<string, unknown> => typeof s === 'object' && s !== null);\n}\n\n/** Fetches a daemon config section via RPC. */\nexport async function fetchConfigSection(client: Client, section: string, timeout?: number): Promise<Record<string, unknown>> {\n const resp = await client.requestResponse({ type: 'config_get', section }, 'config_get_response', timeout ?? 5_000);\n const sec = resp[section];\n if (sec && typeof sec === 'object') {\n return sec as Record<string, unknown>;\n }\n return resp;\n}\n","/**\n * Session bootstrap flows, wait helpers, and connect-with-retries.\n */\n\nimport type { Client } from './client.js';\nimport type { Config } from './config.js';\nimport { defaultConfig } from './config.js';\nimport type { DecodedMessage, LoopNewOptions, StatusResponse, ErrorResponse } from './protocol.js';\nimport { newLoopNewMessage } from './protocol.js';\n\n// ---------------------------------------------------------------------------\n// Bootstrap flows (loop-first, RFC-503)\n// ---------------------------------------------------------------------------\n\n/** Daemon ready → loop_new (or reuse id) → loop_subscribe; returns loop id. */\nexport async function bootstrapLoopSession(\n client: Client,\n resumeLoopId: string | null | undefined,\n config?: Config,\n loopNew?: LoopNewOptions,\n): Promise<string> {\n const cfg = config ?? defaultConfig();\n\n await client.sendMessage({ type: 'daemon_ready' });\n await waitDaemonReady(client, cfg.daemonReadyTimeout);\n\n let loopId = (resumeLoopId ?? '').trim();\n if (!loopId) {\n const newResp = await client.requestResponse(\n newLoopNewMessage(loopNew) as unknown as Record<string, unknown>,\n 'loop_new_response',\n cfg.loopStatusTimeout,\n );\n loopId = String(newResp.loop_id ?? '').trim();\n if (!loopId) {\n throw new Error('loop_new_response missing loop_id');\n }\n }\n\n const subResp = await client.requestResponse(\n { type: 'loop_subscribe', loop_id: loopId, verbosity: cfg.verbosityLevel },\n 'loop_subscribe_response',\n cfg.subscriptionTimeout,\n );\n if (subResp.success === false) {\n throw new Error(String(subResp.message ?? 'loop_subscribe failed'));\n }\n\n return loopId;\n}\n\n// ---------------------------------------------------------------------------\n// Wait helpers (use client's readEventWithTimeout internally)\n// ---------------------------------------------------------------------------\n\n/** Blocks until a daemon_ready message with state == \"ready\". */\nexport async function waitDaemonReady(\n client: Client,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n if (ev.type === 'daemon_ready') {\n if (ev.state === 'ready') return;\n throw new Error(\n `daemon not ready: state=${JSON.stringify(ev.state)} message=${JSON.stringify(ev.message ?? '')}`,\n );\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for daemon_ready (state=ready)`);\n}\n\n/** Waits for daemon_ready using messages from an ``AsyncIterable`` (e.g. ``receiveMessages()``). */\nexport async function waitDaemonReadyFromStream(\n eventStream: AsyncIterable<DecodedMessage>,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n for await (const msg of eventStream) {\n if (msg && typeof msg === 'object') {\n const m = msg as Record<string, unknown>;\n if (m.type === 'daemon_ready') {\n if (m.state === 'ready') return;\n throw new Error(\n `daemon not ready: state=${JSON.stringify(m.state)} message=${JSON.stringify(m.message ?? '')}`,\n );\n }\n }\n if (Date.now() >= deadline) break;\n }\n throw new Error(`timeout after ${timeout}ms waiting for daemon_ready (state=ready)`);\n}\n\n/** Waits for a status message with a non-empty ``loop_id``. */\nexport async function waitLoopStatusWithID(\n client: Client,\n timeout: number,\n): Promise<StatusResponse> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n\n if (ev.type === 'error') {\n const errResp = ev as unknown as ErrorResponse;\n throw new Error(`daemon error: ${errResp.code}: ${errResp.message}`);\n }\n\n if (ev.type === 'status') {\n const status = ev as unknown as StatusResponse;\n const lid = status.loop_id;\n if (lid && lid !== '') {\n return status;\n }\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for status with loop_id`);\n}\n\n/** Waits for subscription_confirmed or loop_subscribe_response matching loop id. */\nexport async function waitSubscriptionConfirmed(\n client: Client,\n wantLoopID: string,\n _wantVerbosity: string,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n if (ev.type === 'loop_subscribe_response' && ev.success === true) {\n if (String(ev.loop_id ?? '') === wantLoopID) return;\n }\n if (ev.type === 'subscription_confirmed') {\n const lid = String((ev as { loop_id?: string }).loop_id ?? '');\n if (lid === wantLoopID) return;\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for subscription_confirmed`);\n}\n\n// ---------------------------------------------------------------------------\n// Connect with retries\n// ---------------------------------------------------------------------------\n\n/** Attempts to connect to the Soothe daemon with bounded retries. */\nexport async function connectWithRetries(\n client: Client,\n maxRetries?: number,\n retryDelay?: number,\n): Promise<void> {\n const retries = maxRetries && maxRetries > 0 ? maxRetries : 40;\n const delay = retryDelay && retryDelay > 0 ? retryDelay : 250;\n\n let lastErr: Error | null = null;\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n await client.connect();\n return;\n } catch (err) {\n lastErr = err as Error;\n }\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n throw new Error(`failed to connect after ${retries} attempts: ${lastErr?.message ?? 'unknown error'}`);\n}"],"mappings":"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","names":["VerbosityTier","Client"]}
|
|
1
|
+
{"version":3,"sources":["../src/verbosity.ts","../src/events.ts","../src/helpers.ts","../src/session.ts","../src/appkit/broadcaster.ts","../src/appkit/thinking_step.ts","../src/appkit/classifier.ts","../src/appkit/query_gate.ts","../src/appkit/client.ts","../src/appkit/pool.ts","../src/appkit/turn_runner.ts"],"sourcesContent":["/**\n * Verbosity levels and tiers for event filtering.\n */\n\n/** User-configurable verbosity setting. */\nexport type VerbosityLevel = \"quiet\" | \"normal\" | \"debug\";\n\n/** Minimum verbosity level at which content is visible. */\nexport enum VerbosityTier {\n /** Always visible (errors, assistant text, final reports) */\n Quiet = 0,\n /** Standard progress (plan updates, milestones, agentic loop) */\n Normal = 1,\n /** Detailed internals (protocol events, tool calls, subagent activity) */\n Detailed = 2,\n /** Everything including internals (thinking, heartbeats) */\n Debug = 3,\n /** Never shown at any level (implementation details) */\n Internal = 99,\n}\n\nconst verbosityLevelValues: Record<VerbosityLevel, number> = {\n quiet: 0,\n normal: 1,\n debug: 3,\n};\n\n/** Returns true if content at the given tier is visible at the given verbosity. */\nexport function shouldShow(tier: VerbosityTier, verbosity: VerbosityLevel): boolean {\n if (tier === VerbosityTier.Internal) {\n return false;\n }\n const level = verbosityLevelValues[verbosity] ?? 1; // default to normal\n return tier <= level;\n}\n\n/** Checks whether a string is a valid verbosity level. */\nexport function isValidVerbosityLevel(s: string): s is VerbosityLevel {\n return s in verbosityLevelValues;\n}\n","/**\n * Client-facing event namespace constants for the Soothe daemon wire protocol.\n *\n * Internal catalog types (`soothe.internal.*`) are server-only and are never\n * broadcast to WebSocket clients. Do not add them here.\n *\n * Format: soothe.<domain>.<component>.<action>\n */\n\nimport { VerbosityTier } from \"./verbosity.js\";\n\n// Plan events (client UX)\nexport const EventPlanCreated = \"soothe.cognition.plan.created\";\n\n// Explore subagent events (built-in wire, IG-339)\nexport const EventExploreStarted = \"soothe.subagent.explore.started\";\nexport const EventExploreMilestone = \"soothe.subagent.explore.milestone\";\nexport const EventExploreStepCompleted = \"soothe.subagent.explore.step.completed\";\nexport const EventExploreCompleted = \"soothe.subagent.explore.completed\";\n\n// Tacitus subagent events (built-in wire, IG-339)\nexport const EventTacitusStarted = \"soothe.subagent.tacitus.started\";\nexport const EventTacitusGatherSummary = \"soothe.subagent.tacitus.gather.summary\";\nexport const EventTacitusCompleted = \"soothe.subagent.tacitus.completed\";\n\n// Control-plane wire envelopes (not soothe.* catalog events)\nexport const EventReplayComplete = \"replay_complete\";\nexport const EventLoopReattachedWire = \"loop_reattached\";\n\n// Card ledger replay frames (RFC-413, card_binder design)\nexport const EventCardReplayBegin = \"card.replay_begin\";\nexport const EventCardCreated = \"card.created\";\nexport const EventCardReplayEnd = \"card.replay_end\";\n\n// Tool events\nexport const EventToolStarted = \"soothe.tool.execution.started\";\nexport const EventToolCompleted = \"soothe.tool.execution.completed\";\nexport const EventToolError = \"soothe.tool.execution.error\";\n\n// Stream tool call events (RFC-450, IG-416)\nexport const EventStreamToolCallUpdate = \"soothe.stream.tool_call.update\";\nexport const EventToolCallUpdatesBatch = \"tool_call_updates_batch\";\n\n// StrangeLoop events (cognition domain)\nexport const EventStrangeLoopStarted = \"soothe.cognition.strange_loop.started\";\nexport const EventStrangeLoopCompleted = \"soothe.cognition.strange_loop.completed\";\nexport const EventStrangeLoopPlanDecision = \"soothe.cognition.strange_loop.plan.decision\";\nexport const EventStrangeLoopReasoned = \"soothe.cognition.strange_loop.reasoned\";\nexport const EventStrangeLoopStepStarted = \"soothe.cognition.strange_loop.step.started\";\nexport const EventStrangeLoopStepQueued = \"soothe.cognition.strange_loop.step.queued\";\nexport const EventStrangeLoopStepCompleted = \"soothe.cognition.strange_loop.step.completed\";\nexport const EventStrangeLoopContextCompacted = \"soothe.cognition.strange_loop.context.compacted\";\n\n// Message protocol events (client stream metadata)\nexport const EventMessageReceived = \"soothe.protocol.message.received\";\nexport const EventMessageSent = \"soothe.protocol.message.sent\";\n\n// Output events\nexport const EventFinalReport = \"soothe.output.autonomous.final_report.reported\";\n\n// Autopilot events (RFC-228)\nexport const EventAutopilotGoalStatus = \"soothe.autopilot.goal.status\";\nexport const EventAutopilotGoalProgress = \"soothe.autopilot.goal.progress\";\nexport const EventAutopilotGoalCreated = \"soothe.autopilot.goal.created\";\nexport const EventAutopilotGoalCompleted = \"soothe.autopilot.goal.completed\";\nexport const EventAutopilotWorkerAssigned = \"soothe.autopilot.worker.assigned\";\nexport const EventAutopilotWorkerUnassigned = \"soothe.autopilot.worker.unassigned\";\n\n// Error events\nexport const EventGeneralFailed = \"soothe.error.general.failed\";\n\n// ---------------------------------------------------------------------------\n// Namespace parsing\n// ---------------------------------------------------------------------------\n\n/** Splits a 4-segment event namespace into domain, component, and action. */\nexport function parseNamespace(\n ns: string,\n): { domain: string; component: string; action: string } | null {\n const parts = splitNamespace(ns);\n if (parts.length < 4 || parts[0] !== \"soothe\") {\n return null;\n }\n if (parts[1] === \"internal\") {\n return null;\n }\n return { domain: parts[1], component: parts[2], action: parts[3] };\n}\n\nfunction splitNamespace(ns: string): string[] {\n const parts: string[] = [];\n let start = 0;\n for (let i = 0; i < ns.length; i++) {\n if (ns[i] === \".\") {\n parts.push(ns.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(ns.slice(start));\n return parts;\n}\n\n// ---------------------------------------------------------------------------\n// Classification\n// ---------------------------------------------------------------------------\n\n/** Returns the VerbosityTier for a given event type string. */\nexport function classifyEventVerbosity(eventTypeOrNamespace: string): VerbosityTier {\n const parsed = parseNamespace(eventTypeOrNamespace);\n if (!parsed) {\n return classifyByEventTypeString(eventTypeOrNamespace);\n }\n return classifyByDomainAndComponent(parsed.domain, parsed.component, eventTypeOrNamespace);\n}\n\nfunction classifyByDomainAndComponent(\n domain: string,\n _component: string,\n full: string,\n): VerbosityTier {\n switch (domain) {\n case \"cognition\":\n return VerbosityTier.Normal;\n case \"protocol\":\n return VerbosityTier.Detailed;\n case \"tool\":\n return VerbosityTier.Internal;\n case \"subagent\":\n return classifySubagentEvent(full);\n case \"autopilot\":\n return VerbosityTier.Normal;\n case \"output\":\n case \"error\":\n return VerbosityTier.Quiet;\n default:\n return VerbosityTier.Normal;\n }\n}\n\nfunction classifySubagentEvent(full: string): VerbosityTier {\n const parsed = parseNamespace(full);\n if (!parsed) return VerbosityTier.Normal;\n switch (parsed.action) {\n case \"started\":\n case \"completed\":\n return VerbosityTier.Normal;\n default:\n return VerbosityTier.Detailed;\n }\n}\n\nfunction classifyByEventTypeString(eventType: string): VerbosityTier {\n if (eventType === EventFinalReport || eventType === EventGeneralFailed) {\n return VerbosityTier.Quiet;\n }\n if (eventType === EventToolStarted) {\n return VerbosityTier.Internal;\n }\n return VerbosityTier.Normal;\n}\n\n// ---------------------------------------------------------------------------\n// Event classification helpers\n// ---------------------------------------------------------------------------\n\n/** Event types that represent completion milestones. */\nexport function isCompletionEvent(eventType: string): boolean {\n return (\n eventType.endsWith(\".completed\") ||\n eventType.endsWith(\".failed\") ||\n eventType === EventGeneralFailed\n );\n}\n\n/** Lifecycle subagent events (started/completed) for progress UI. */\nexport function isSubagentProgressEvent(eventType: string): boolean {\n const parsed = parseNamespace(eventType);\n if (!parsed || parsed.domain !== \"subagent\") {\n return false;\n }\n return parsed.action === \"started\" || parsed.action === \"completed\";\n}\n","/**\n * Convenience RPC helper functions for the Soothe client (RFC-450 protocol-1).\n */\n\nimport type { Client } from \"./client.js\";\nimport { defaultConfig } from \"./config.js\";\n\n/** Checks daemon status via RPC. */\nexport async function checkDaemonStatus(\n client: Client,\n timeout?: number,\n): Promise<Record<string, unknown>> {\n return client.requestResponse(\"daemon_status\", {}, \"daemon_status\", timeout ?? 5_000);\n}\n\n/** Performs a composite health check: connect + handshake + status RPC. */\nexport async function isDaemonLive(wsURL: string, timeout?: number): Promise<boolean> {\n const { Client } = await import(\"./client.js\");\n const t = timeout ?? 5_000;\n const client = new Client(wsURL, defaultConfig());\n\n try {\n await client.connect();\n } catch {\n return false;\n }\n\n try {\n await checkDaemonStatus(client, t);\n return true;\n } catch {\n return false;\n } finally {\n client.close();\n }\n}\n\n/** Requests daemon shutdown via RPC. */\nexport async function requestDaemonShutdown(client: Client, timeout?: number): Promise<void> {\n const resp = await client.requestResponse(\n \"daemon_shutdown\",\n {},\n \"daemon_shutdown\",\n timeout ?? 10_000,\n );\n if (resp.status !== \"acknowledged\") {\n throw new Error(`shutdown not acknowledged: ${JSON.stringify(resp)}`);\n }\n}\n\n/** Fetches the skills catalog via RPC. */\nexport async function fetchSkillsCatalog(\n client: Client,\n timeout?: number,\n): Promise<Record<string, unknown>[]> {\n const resp = await client.requestResponse(\"skills_list\", {}, \"skills_list\", timeout ?? 15_000);\n const skillsRaw = resp.skills;\n if (!skillsRaw || !Array.isArray(skillsRaw)) return [];\n return skillsRaw.filter((s): s is Record<string, unknown> => typeof s === \"object\" && s !== null);\n}\n\n/** Fetches a daemon config section via RPC. */\nexport async function fetchConfigSection(\n client: Client,\n section: string,\n timeout?: number,\n): Promise<Record<string, unknown>> {\n const resp = await client.requestResponse(\n \"config_get\",\n { section },\n \"config_get\",\n timeout ?? 5_000,\n );\n const sec = resp[section];\n if (sec && typeof sec === \"object\") {\n return sec as Record<string, unknown>;\n }\n return resp;\n}\n\n/** Requests daemon config reload via RPC. */\nexport async function requestDaemonConfigReload(\n client: Client,\n timeout?: number,\n): Promise<Record<string, unknown>> {\n return client.requestResponse(\"config_reload\", {}, \"config_reload\", timeout ?? 15_000);\n}\n\n/** Requests loop history (RFC-631) and waits for the response. */\nexport async function fetchLoopHistory(\n client: Client,\n loopID: string,\n timeout?: number,\n): Promise<Record<string, unknown>> {\n return client.requestResponse(\n \"loop_history_fetch\",\n { loop_id: loopID },\n \"loop_history_fetch\",\n timeout ?? 15_000,\n );\n}\n\n/** Submits credentials for daemon-side authentication and waits for the response. */\nexport async function authenticate(\n client: Client,\n accessKey: string,\n secretKey: string,\n timeout?: number,\n): Promise<Record<string, unknown>> {\n return client.requestResponse(\n \"auth\",\n { access_key: accessKey, secret_key: secretKey },\n \"auth\",\n timeout ?? 15_000,\n );\n}\n\n/** Refreshes the daemon-side auth token and waits for the response. */\nexport async function refreshAuthToken(\n client: Client,\n refreshToken: string,\n timeout?: number,\n): Promise<Record<string, unknown>> {\n return client.requestResponse(\n \"auth_refresh\",\n { refresh_token: refreshToken },\n \"auth_refresh\",\n timeout ?? 15_000,\n );\n}\n","/**\n * Session bootstrap flows, wait helpers, and connect-with-retries.\n *\n * Under protocol-1 (RFC-450) the connection handshake (connection_init /\n * connection_ack) is performed by `client.connect()`. Bootstrap therefore\n * jumps straight to loop_new + subscribe(loop_events).\n */\n\nimport type { Client } from \"./client.js\";\nimport type { Config } from \"./config.js\";\nimport { defaultConfig } from \"./config.js\";\nimport { newLoopNewMessage } from \"./protocol.js\";\nimport { DaemonError } from \"./errors.js\";\n\n// ---------------------------------------------------------------------------\n// Bootstrap flows (loop-first, RFC-503)\n// ---------------------------------------------------------------------------\n\n/**\n * loop_new (or reuse id) → subscribe(loop_events); returns the loop id.\n * The protocol-1 handshake is assumed to have completed in `client.connect()`.\n */\nexport async function bootstrapLoopSession(\n client: Client,\n resumeLoopId: string | null | undefined,\n config?: Config,\n loopNew?: import(\"./protocol.js\").LoopNewOptions,\n): Promise<string> {\n const cfg = config ?? defaultConfig();\n\n let loopId = (resumeLoopId ?? \"\").trim();\n if (!loopId) {\n const env = newLoopNewMessage(loopNew);\n const newResp = await client.requestResponse(\n env.method,\n env.params ?? {},\n \"loop_new\",\n cfg.loopStatusTimeout,\n );\n loopId = String(newResp.loop_id ?? \"\").trim();\n if (!loopId) {\n throw new Error(\"loop_new response missing loop_id\");\n }\n }\n\n // Subscribe to the loop event stream. Confirmation arrives as a `next`\n // frame; client.subscribe() handles the initial ack/error window.\n await client.subscribe(\n \"loop_events\",\n { loop_id: loopId, verbosity: cfg.verbosityLevel },\n cfg.subscriptionTimeout,\n );\n\n return loopId;\n}\n\n// ---------------------------------------------------------------------------\n// Wait helpers (use client's readEventWithTimeout internally)\n// ---------------------------------------------------------------------------\n\n/**\n * Blocks until connection_ack reports readiness \"ready\". Resolves immediately\n * if the handshake already completed during connect().\n */\nexport async function waitDaemonReady(client: Client, timeout: number): Promise<void> {\n if (client.isConnected()) return;\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n if (ev.type === \"connection_ack\") {\n const result = (ev.result as Record<string, unknown> | undefined) ?? {};\n const state = result.readiness_state as string | undefined;\n if (state === \"ready\") return;\n throw new Error(`daemon not ready: state=${JSON.stringify(state ?? \"unknown\")}`);\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for connection_ack (ready)`);\n}\n\n/** Waits for a status message with a non-empty loop_id. */\nexport async function waitLoopStatusWithID(\n client: Client,\n timeout: number,\n): Promise<Record<string, unknown>> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n\n if (ev.type === \"error\") {\n const errObj = (ev.error as { code?: number; message?: string }) ?? {};\n throw new DaemonError(errObj.code ?? -32603, errObj.message ?? \"daemon error\");\n }\n\n if (ev.type === \"status\") {\n const lid = ev.loop_id as string | undefined;\n if (lid && lid !== \"\") {\n return ev;\n }\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for status with loop_id`);\n}\n\n/** Waits for a subscription confirmation `next` matching loop id. */\nexport async function waitSubscriptionConfirmed(\n client: Client,\n wantLoopID: string,\n _wantVerbosity: string,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n if (ev.type === \"next\") {\n const payload = (ev.payload as Record<string, unknown> | undefined) ?? {};\n const lid = String(payload.loop_id ?? \"\");\n if (lid === wantLoopID && payload.success === true) return;\n continue;\n }\n if (ev.type === \"error\") {\n const errObj = (ev.error as { message?: string }) ?? {};\n throw new Error(`daemon error: ${errObj.message ?? \"subscription failed\"}`);\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for subscription confirmation`);\n}\n\n// ---------------------------------------------------------------------------\n// Connect with retries\n// ---------------------------------------------------------------------------\n\n/** Attempts to connect to the Soothe daemon with bounded retries. */\nexport async function connectWithRetries(\n client: Client,\n maxRetries?: number,\n retryDelay?: number,\n): Promise<void> {\n const retries = maxRetries && maxRetries > 0 ? maxRetries : 40;\n const delay = retryDelay && retryDelay > 0 ? retryDelay : 250;\n\n let lastErr: Error | null = null;\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n await client.connect();\n return;\n } catch (err) {\n lastErr = err as Error;\n }\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n throw new Error(\n `failed to connect after ${retries} attempts: ${lastErr?.message ?? \"unknown error\"}`,\n );\n}\n","/**\n * SSE-style pub/sub fan-out for appkit (RFC-629 Layer 1).\n *\n * Generic, string-keyed pub/sub for SSE-style event delivery. The\n * application-agnostic successor to a domain-keyed broadcaster: applications\n * convert from their domain key type to `string` at their own boundary.\n *\n * Slow consumers do not stall the broadcaster: each subscriber has a bounded\n * queue and overflowing events are dropped (drop-on-full).\n */\n\n/** One Server-Sent Event payload. The Type vocabulary is app-defined. */\nexport interface SSEEvent {\n type: string;\n data: unknown;\n}\n\n/** Per-subscriber bounded queue. Events past the cap are dropped. */\nconst SUBSCRIBER_QUEUE_CAP = 100;\n\ninterface Subscriber {\n queue: SSEEvent[];\n /** Resolvers waiting for the next event. */\n waiters: Array<(ev: SSEEvent | null) => void>;\n closed: boolean;\n}\n\n/**\n * SSEBroadcaster fans events out to all subscribers for a session id.\n * Non-blocking: a full subscriber queue drops the event so one slow consumer\n * cannot block the others.\n */\nexport class SSEBroadcaster {\n private subscribers = new Map<string, Map<string, Subscriber>>();\n private nextSubID = 0;\n\n /** Creates an empty broadcaster. */\n constructor() {}\n\n /**\n * Registers a new subscriber channel for a session id. Returns an async\n * iterable the subscriber reads events from. Unsubscribe via\n * `unsubscribe()` or `close()`.\n */\n subscribe(sessionID: string): { iterable: AsyncIterable<SSEEvent>; id: string } {\n const subID = String(this.nextSubID++);\n const sub: Subscriber = { queue: [], waiters: [], closed: false };\n let subs = this.subscribers.get(sessionID);\n if (!subs) {\n subs = new Map();\n this.subscribers.set(sessionID, subs);\n }\n subs.set(subID, sub);\n\n const iterable: AsyncIterable<SSEEvent> = {\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<SSEEvent>> {\n if (sub.queue.length > 0) {\n return Promise.resolve({ value: sub.queue.shift()!, done: false });\n }\n if (sub.closed) {\n return Promise.resolve({ value: undefined as unknown as SSEEvent, done: true });\n }\n return new Promise<IteratorResult<SSEEvent>>(resolve => {\n sub.waiters.push(ev => {\n if (ev === null) {\n resolve({ value: undefined as unknown as SSEEvent, done: true });\n } else {\n resolve({ value: ev, done: false });\n }\n });\n });\n },\n };\n },\n };\n return { iterable, id: subID };\n }\n\n /** Removes a subscriber by id and closes its iterable. Safe if unknown. */\n unsubscribe(sessionID: string, subID: string): void {\n const subs = this.subscribers.get(sessionID);\n if (!subs) return;\n const sub = subs.get(subID);\n if (!sub) return;\n sub.closed = true;\n for (const w of sub.waiters) w(null);\n sub.waiters = [];\n subs.delete(subID);\n if (subs.size === 0) this.subscribers.delete(sessionID);\n }\n\n /**\n * Sends an event to all subscribers for a session id. Non-blocking: a full\n * subscriber queue is skipped (drop-on-full) so one slow consumer cannot\n * block the others.\n */\n broadcast(sessionID: string, event: SSEEvent): void {\n const subs = this.subscribers.get(sessionID);\n if (!subs) return;\n for (const sub of subs.values()) {\n if (sub.closed) continue;\n if (sub.waiters.length > 0) {\n const w = sub.waiters.shift()!;\n w(event);\n } else if (sub.queue.length < SUBSCRIBER_QUEUE_CAP) {\n sub.queue.push(event);\n }\n // else: drop-on-full.\n }\n }\n\n /** Closes all subscribers for a session id and removes the entry. */\n close(sessionID: string): void {\n const subs = this.subscribers.get(sessionID);\n if (!subs) return;\n for (const sub of subs.values()) {\n sub.closed = true;\n for (const w of sub.waiters) w(null);\n sub.waiters = [];\n }\n this.subscribers.delete(sessionID);\n }\n\n /** Closes every subscriber channel across all sessions. */\n closeAll(): void {\n for (const [sessionID, subs] of this.subscribers) {\n for (const sub of subs.values()) {\n sub.closed = true;\n for (const w of sub.waiters) w(null);\n sub.waiters = [];\n }\n this.subscribers.delete(sessionID);\n }\n }\n}\n","/**\n * Thinking-step extraction for appkit (RFC-629 Layer 1).\n *\n * Maps an allowlisted progress event to one structured UI line. Free-form\n * streams (tokens, reports, reasoning) are excluded. Ported from the Go\n * appkit's thinking_step with the allowlist made configurable.\n */\n\nconst MAX_THINKING_STEP_RUNES = 280;\n\n/** Default thinking-step event allowlist (triarch's set). */\nexport const DEFAULT_THINKING_STEP_EVENTS: ReadonlySet<string> = new Set([\n \"soothe.cognition.plan.step.started\",\n \"soothe.cognition.plan.step.completed\",\n \"soothe.cognition.plan.step.failed\",\n \"soothe.lifecycle.iteration.started\",\n \"soothe.agent.loop.step.started\",\n \"soothe.agent.loop.started\",\n \"soothe.cognition.plan.batch.started\",\n \"soothe.cognition.plan.created\",\n \"soothe.cognition.goal.created\",\n \"soothe.tool.execution.started\",\n]);\n\n/**\n * Maps an allowlisted progress event to one structured UI line. Returns\n * [line, true] for a recognized event; [\"\", false] otherwise. `allow` may be\n * omitted to use the default allowlist.\n */\nexport function extractThinkingStep(\n eventType: string,\n data: Record<string, unknown> | null,\n allow?: ReadonlySet<string>,\n): [string, boolean] {\n if (!eventType || !data) return [\"\", false];\n const et = eventType.trim();\n if (!et) return [\"\", false];\n\n const allowlist = allow ?? DEFAULT_THINKING_STEP_EVENTS;\n if (!allowlist.has(et)) return [\"\", false];\n\n let line = \"\";\n switch (et) {\n case \"soothe.cognition.plan.step.started\":\n line = formatPlanStepLine(data, \"\");\n break;\n case \"soothe.cognition.plan.step.completed\":\n line = formatPlanStepLine(data, \"done\");\n break;\n case \"soothe.cognition.plan.step.failed\": {\n const stepID = strField(data, \"step_id\");\n const errMsg = strField(data, \"error\");\n if (stepID && errMsg) line = `Step ${stepID} failed: ${errMsg}`;\n else if (stepID) line = `Step ${stepID} failed`;\n else if (errMsg) line = `Step failed: ${errMsg}`;\n break;\n }\n case \"soothe.agent.loop.step.started\":\n line = formatAgentStepLine(data, \"\");\n break;\n case \"soothe.cognition.plan.batch.started\": {\n const n = data[\"parallel_count\"];\n if (typeof n === \"number\" && n > 0) line = `Running ${Math.floor(n)} steps in parallel`;\n break;\n }\n case \"soothe.cognition.plan.created\":\n case \"soothe.agent.loop.started\": {\n const g = strField(data, \"goal\");\n if (g) line = \"Goal: \" + g;\n break;\n }\n case \"soothe.cognition.goal.created\": {\n const g = strField(data, \"friendly_message\", \"description\");\n if (g) line = \"Goal: \" + g;\n break;\n }\n case \"soothe.lifecycle.iteration.started\": {\n const g = strField(data, \"goal_description\");\n if (g) line = \"Iteration: \" + g;\n break;\n }\n case \"soothe.tool.execution.started\": {\n const name = strField(data, \"tool_name\", \"name\");\n if (name) line = \"Tool: \" + name;\n break;\n }\n default:\n return [\"\", false];\n }\n\n line = line.trim();\n if (!line) return [\"\", false];\n const runes = [...line];\n if (runes.length > MAX_THINKING_STEP_RUNES) {\n line = runes.slice(0, MAX_THINKING_STEP_RUNES).join(\"\") + \"…\";\n }\n return [line, true];\n}\n\nfunction formatPlanStepLine(data: Record<string, unknown>, suffix: string): string {\n const stepID = strField(data, \"step_id\");\n const desc = strField(data, \"description\");\n if (stepID && suffix) return `Step ${stepID}: ${suffix}`;\n if (stepID && desc) return `Step ${stepID}: ${desc}`;\n if (stepID) return `Step ${stepID}`;\n if (desc && suffix) return `Step: ${suffix}`;\n if (desc) return `Step: ${desc}`;\n if (suffix) return \"Step: \" + suffix;\n return \"\";\n}\n\nfunction formatAgentStepLine(data: Record<string, unknown>, suffix: string): string {\n const stepID = strField(data, \"step_id\");\n const desc = strField(data, \"description\");\n if (stepID && desc) return `Step ${stepID}: ${desc}`;\n if (desc) return suffix ? `Step: ${suffix}` : `Step: ${desc}`;\n if (stepID) return `Step ${stepID}`;\n return \"\";\n}\n\n/** Returns the first non-empty trimmed string field among `keys`. */\nfunction strField(data: Record<string, unknown>, ...keys: string[]): string {\n for (const key of keys) {\n const v = data[key];\n if (typeof v === \"string\") {\n const s = v.trim();\n if (s) return s;\n }\n }\n return \"\";\n}\n","/**\n * Event classifier for appkit (RFC-629 Layer 1).\n *\n * Maps a stream of decoded daemon events into deliverable/streaming/terminal\n * outcomes, keyed on (namespace, mode, phase) per RFC-614/RFC-403\n * (RFC-629 constraint #4). The app-agnostic successor to triarch's\n * ProcessChatEvent, with the deliverable phase set promoted from hardcoded\n * constants to configuration.\n *\n * Event shape: a protocol-1 `next` envelope carries\n * `{type:\"next\", payload:{namespace, mode, data, loop_id}}`. The daemon\n * wraps legacy free-form frames as `{payload:{namespace, mode:<orig type>,\n * data:<orig frame>}}` (RFC-450 §9.3). The classifier inspects the payload's\n * `mode`/`data`/`namespace` and the inner message's `phase`/`type`/`content`.\n */\n\nimport { DaemonError } from \"../errors.js\";\nimport { EventFinalReport } from \"../events.js\";\nimport { DEFAULT_THINKING_STEP_EVENTS, extractThinkingStep } from \"./thinking_step.js\";\n\n/** How a processed event should end the query loop. */\nexport enum ChatEventTerminal {\n /** Accumulate content; the query is still running. */\n Continue = 0,\n /** A user-visible final reply; persist it. */\n DeliverableComplete = 1,\n /** The query failed; persist an error. */\n FailedComplete = 2,\n}\n\n/** The structured outcome of classifying one daemon event. */\nexport interface ChatEventResult {\n content?: string;\n /** User-visible progress line (not a final reply). */\n thinkingStep?: string;\n terminal: ChatEventTerminal;\n /** soothe wire event type when terminal === DeliverableComplete. */\n completionEvent?: string;\n err?: Error;\n}\n\n/**\n * Product-specific decisions an EventClassifier needs. The DeliverablePhases\n * set is the key product knob: which message `phase` values count as\n * user-facing deliverables (triarch uses quiz, goal_completion, direct_model, and\n * direct intent_hint phases text_completion, image_to_text, ocr, embed;\n * other apps pass their own).\n */\nexport interface ClassifierConfig {\n /** Recognizes loop-tagged message phases that may end a query with\n * user-facing text. Required. */\n deliverablePhases: ReadonlySet<string>;\n /** Minimum trimmed rune count for a reply to be persisted as final\n * (avoids finishing on stub ACKs like \"...\"). Defaults to 8. */\n minDeliverableRunes?: number;\n /** Optional app override of the default thinking-step event allowlist. */\n thinkingStepEvents?: ReadonlySet<string>;\n}\n\n/** Event type of the daemon's replay completion signal (internal). */\nconst EVENT_LOOP_HISTORY_REPLAYED = \"soothe.lifecycle.loop.history.replayed\";\n\n/** Maps a stream of decoded daemon events into deliverable/streaming/terminal outcomes. */\nexport class EventClassifier {\n private deliverablePhases: ReadonlySet<string>;\n private minDeliverableRunes: number;\n private thinkingStepEvents?: ReadonlySet<string>;\n\n constructor(cfg: ClassifierConfig) {\n if (!cfg.deliverablePhases) {\n throw new Error(\"appkit: ClassifierConfig.deliverablePhases must not be nil\");\n }\n this.deliverablePhases = cfg.deliverablePhases;\n this.minDeliverableRunes =\n cfg.minDeliverableRunes && cfg.minDeliverableRunes > 0 ? cfg.minDeliverableRunes : 8;\n this.thinkingStepEvents = cfg.thinkingStepEvents;\n }\n\n /**\n * Inspects one decoded event and returns its outcome. `accumulated` is the\n * running assistant text so far, used to pick the final reply when a\n * deliverable event arrives.\n */\n classify(msg: unknown, accumulated: string): ChatEventResult {\n return this.processChatEvent(msg, accumulated);\n }\n\n /**\n * Reports whether a persisted completion_event is user-facing. Uses the\n * configured deliverable phase set; recognizes the protocol output namespace\n * and final_report component as deliverable.\n */\n isDeliverableCompletionEvent(eventType: string): boolean {\n if (!eventType) return false;\n if (eventType === EventFinalReport) return true;\n if (eventType.startsWith(\"soothe.protocol.message.\")) {\n const phase = eventType.slice(\"soothe.protocol.message.\".length);\n return this.isDeliverableLoopPhase(phase);\n }\n return eventType.includes(\"soothe.output\") && eventType.includes(\"responded\");\n }\n\n isDeliverableLoopPhase(phase: string): boolean {\n return this.deliverablePhases.has(phase);\n }\n\n private deliverableResult(content: string, completionEvent: string): ChatEventResult {\n return { content, terminal: ChatEventTerminal.DeliverableComplete, completionEvent };\n }\n\n private continueResult(content: string): ChatEventResult {\n return { content, terminal: ChatEventTerminal.Continue };\n }\n\n private failedResult(err: Error): ChatEventResult {\n return { terminal: ChatEventTerminal.FailedComplete, err };\n }\n\n /** Reports whether trimmed assistant text is long enough to persist as final. */\n isSubstantiveAssistantReply(content: string): boolean {\n return [...content.trim()].length >= this.minDeliverableRunes;\n }\n\n /**\n * Picks the user-visible reply for a completed query. Only a deliverable\n * terminal result with a recognized completion event yields a final reply.\n */\n resolveDeliverableFinalContent(\n eventResult: ChatEventResult,\n _accumulated: string,\n ): [string, boolean] {\n if (eventResult.terminal !== ChatEventTerminal.DeliverableComplete) return [\"\", false];\n if (!this.isDeliverableCompletionEvent(eventResult.completionEvent ?? \"\")) return [\"\", false];\n const final = (eventResult.content ?? \"\").trim();\n if (final) return [final, true];\n return [\"\", false];\n }\n\n /** The event→outcome mapper, ported from triarch's ProcessChatEvent. */\n private processChatEvent(msg: unknown, _accumulated: string): ChatEventResult {\n if (!msg || typeof msg !== \"object\") {\n return { terminal: ChatEventTerminal.Continue };\n }\n const m = msg as Record<string, unknown>;\n const typ = m.type as string | undefined;\n\n // Protocol-1 `next` envelope: the daemon wraps legacy frames in payload.\n if (typ === \"next\") {\n return this.classifyNextEnvelope(m);\n }\n\n // Protocol-1 RPC responses / subscription confirmations arrive as\n // response/next/complete envelopes. An `error` envelope is a daemon\n // failure; everything else is a protocol-level ack (not a deliverable).\n if (\n typ === \"response\" ||\n typ === \"complete\" ||\n typ === \"receipt_response\" ||\n typ === \"connection_ack\" ||\n typ === \"status\"\n ) {\n return { terminal: ChatEventTerminal.Continue };\n }\n if (typ === \"error\") {\n const errObj = (m.error as { code?: number; message?: string; data?: unknown }) ?? {};\n const code = typeof errObj.code === \"number\" ? errObj.code : -32603;\n return this.failedResult(\n new DaemonError(code, errObj.message ?? \"daemon error\", errObj.data),\n );\n }\n\n // Legacy flat-form `event` frame (mode/data at top level).\n if (typ === \"event\") {\n return this.classifyEventPayload(\n (m.namespace as unknown) ?? null,\n (m.mode as string) ?? \"\",\n m.data,\n );\n }\n\n return { terminal: ChatEventTerminal.Continue };\n }\n\n /** Classifies a `next` envelope by projecting its payload. */\n private classifyNextEnvelope(env: Record<string, unknown>): ChatEventResult {\n const payload = (env.payload as Record<string, unknown> | undefined) ?? {};\n // The inner event frame lives in payload.data, with its own mode/data.\n const innerData = payload.data as Record<string, unknown> | undefined;\n if (innerData && typeof innerData === \"object\") {\n const innerMode = (innerData.mode as string) ?? \"\";\n if (innerMode) {\n return this.classifyEventPayload(\n (innerData.namespace as unknown) ?? payload.namespace ?? null,\n innerMode,\n innerData.data,\n );\n }\n }\n // Fallback: payload itself carries mode/data directly.\n const mode = (payload.mode as string) ?? \"\";\n if (mode) {\n return this.classifyEventPayload((payload.namespace as unknown) ?? null, mode, payload.data);\n }\n return { terminal: ChatEventTerminal.Continue };\n }\n\n /**\n * Classifies an event payload by (namespace, mode, phase). `data` may be a\n * map or an array of messages (mode=\"messages\").\n */\n private classifyEventPayload(namespace: unknown, mode: string, data: unknown): ChatEventResult {\n // Normalize namespace to a string for matching.\n const ns = namespaceToString(namespace);\n\n // Normalize data to a map for thinking-step / output extraction.\n const dataMap = normalizeEventData(data);\n\n if (dataMap) {\n let dataType = ns;\n const dt = dataMap[\"type\"];\n if (typeof dt === \"string\" && dt) dataType = dt;\n if (dataType === EVENT_LOOP_HISTORY_REPLAYED) {\n return { terminal: ChatEventTerminal.Continue };\n }\n const [step, ok] = extractThinkingStep(dataType, dataMap, this.thinkingStepEvents);\n if (ok) {\n return { thinkingStep: step, terminal: ChatEventTerminal.Continue };\n }\n }\n\n // mode=\"messages\": assistant content (streaming chunks or deliverable).\n if (mode === \"messages\") {\n const result = this.classifyMessagesMode(data, ns);\n if (result) return result;\n }\n\n if (!dataMap) {\n return { terminal: ChatEventTerminal.Continue };\n }\n\n let dataType = ns;\n const dt = dataMap[\"type\"];\n if (typeof dt === \"string\" && dt) dataType = dt;\n let completionEvent = dataType;\n if (!completionEvent) completionEvent = ns;\n\n // soothe.output / responded namespaces.\n if (\n isNamespaceMatch(ns, dataType, \"soothe.output\") ||\n isNamespaceMatch(ns, dataType, \"responded\")\n ) {\n const [content, ok] = extractContentFromData(dataMap);\n if (ok) {\n if (this.isFinalOutputEvent(dataType, ns)) {\n return this.deliverableResult(content, completionEvent);\n }\n return this.continueResult(content);\n }\n }\n\n if (\n isNamespaceMatch(ns, dataType, \"agent_loop.completed\") ||\n isNamespaceMatch(ns, dataType, \"agent_loop.reasoned\") ||\n isNamespaceMatch(ns, dataType, \"loop.completed\")\n ) {\n const [content, ok] = extractContentFromData(dataMap);\n if (ok) return this.continueResult(content);\n }\n\n if (isNamespaceMatch(ns, dataType, \"final_report\")) {\n const [content, ok] = extractContentFromData(dataMap);\n if (ok) return this.deliverableResult(content, completionEvent);\n }\n\n if (dataType.includes(\"soothe.error.\") || ns.includes(\"soothe.error.\")) {\n const errType = dataType || ns;\n const msg = dataMap[\"message\"];\n if (typeof msg === \"string\" && msg) {\n return this.failedResult(new Error(`${errType}: ${msg}`));\n }\n const [content, ok] = extractContentFromData(dataMap);\n if (ok) return this.failedResult(new Error(`${errType}: ${content}`));\n return this.failedResult(new Error(errType));\n }\n\n if (\n isNamespaceMatch(ns, dataType, \"stream\") ||\n isNamespaceMatch(ns, dataType, \"progress\") ||\n isNamespaceMatch(ns, dataType, \"tool_call_updates_batch\") ||\n isNamespaceMatch(ns, dataType, \"soothe.stream.tool_call.update\")\n ) {\n const delta = dataMap[\"delta\"];\n if (typeof delta === \"string\") return this.continueResult(delta);\n }\n\n if (\n isNamespaceMatch(ns, dataType, \"heartbeat\") ||\n isNamespaceMatch(ns, dataType, \"system.daemon\") ||\n isNamespaceMatch(ns, dataType, \"agent_loop.started\") ||\n isNamespaceMatch(ns, dataType, \"intent.classified\")\n ) {\n return { terminal: ChatEventTerminal.Continue };\n }\n\n return { terminal: ChatEventTerminal.Continue };\n }\n\n /** Classifies a mode=\"messages\" payload (array of message objects). */\n private classifyMessagesMode(data: unknown, _ns: string): ChatEventResult | null {\n const items = Array.isArray(data) ? data : null;\n if (!items || items.length === 0) return null;\n const first = items[0];\n if (!first || typeof first !== \"object\") return null;\n\n const [msgType, rawContent, phase, hasPayload] = firstMessagePayload(data);\n if (hasPayload && rawContent && isStreamingMessageType(msgType)) {\n return this.continueResult(rawContent);\n }\n\n // Loop-tagged assistant message.\n const loopMsg = loopAIMessage(data);\n if (loopMsg) {\n const content = loopMsg.content;\n if (content) {\n if (isStreamingMessageType(loopMsg.type)) {\n return this.continueResult(content);\n }\n if (\n this.isDeliverableLoopPhase(loopMsg.phase) &&\n this.isSubstantiveAssistantReply(content)\n ) {\n return this.deliverableResult(content, \"soothe.protocol.message.\" + loopMsg.phase);\n }\n return this.continueResult(content);\n }\n }\n\n // Direct-LLM assistant content (mode=messages, terminal AIMessage, no phase).\n const [directContent, directOk] = this.messagesModeAssistantContent(data);\n if (directOk && this.isSubstantiveAssistantReply(directContent)) {\n return this.deliverableResult(directContent, \"soothe.protocol.message.direct_model\");\n }\n\n if (hasPayload && rawContent) {\n if (isTerminalMessageType(msgType) || msgType === \"\") {\n if (this.isDeliverableLoopPhase(phase) && this.isSubstantiveAssistantReply(rawContent)) {\n return this.deliverableResult(rawContent, \"soothe.protocol.message.\" + phase);\n }\n return this.continueResult(rawContent);\n }\n return this.continueResult(rawContent);\n }\n return null;\n }\n\n /**\n * Extracts plain assistant text from mode=\"messages\" events that carry a\n * terminal AIMessage without loop-tagged phase metadata (legacy direct_llm turns\n * before phase tagging; prefer deliverablePhases including text_completion).\n */\n private messagesModeAssistantContent(data: unknown): [string, boolean] {\n if (!Array.isArray(data) || data.length === 0) return [\"\", false];\n const msgMap = data[0] as Record<string, unknown>;\n if (!msgMap || typeof msgMap !== \"object\") return [\"\", false];\n const phase = typeof msgMap.phase === \"string\" ? msgMap.phase.trim() : \"\";\n if (phase) return [\"\", false];\n const msgType = typeof msgMap.type === \"string\" ? msgMap.type : \"\";\n if (msgType && !isTerminalMessageType(msgType)) return [\"\", false];\n const content = extractContentFromMessage(msgMap).trim();\n if (!content) return [\"\", false];\n return [content, true];\n }\n\n /** soothe output/responded events that carry user-facing final text. */\n private isFinalOutputEvent(dataType: string, ns: string): boolean {\n const combined = dataType + \" \" + ns;\n if (combined.includes(\"final_report\")) return true;\n for (const phase of this.deliverablePhases) {\n if (combined.includes(phase)) return true;\n }\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers (module-private)\n// ---------------------------------------------------------------------------\n\nfunction isStreamingMessageType(msgType: string): boolean {\n return msgType === \"AIMessageChunk\" || msgType === \"ai_chunk\" || msgType === \"message_chunk\";\n}\n\nfunction isTerminalMessageType(msgType: string): boolean {\n return msgType === \"AIMessage\" || msgType === \"ai\" || msgType === \"assistant\";\n}\n\n/** Extracts the first message's (type, content, phase, hasPayload). */\nfunction firstMessagePayload(data: unknown): [string, string, string, boolean] {\n if (!Array.isArray(data) || data.length === 0) return [\"\", \"\", \"\", false];\n const msgMap = data[0] as Record<string, unknown>;\n if (!msgMap || typeof msgMap !== \"object\") return [\"\", \"\", \"\", false];\n const msgType = typeof msgMap.type === \"string\" ? msgMap.type : \"\";\n const phase = typeof msgMap.phase === \"string\" ? msgMap.phase : \"\";\n const content = extractContentFromMessage(msgMap);\n return [msgType, content, phase, true];\n}\n\n/** Extracts a loop-tagged assistant message (type, content, phase). */\nfunction loopAIMessage(data: unknown): { type: string; content: string; phase: string } | null {\n if (!Array.isArray(data) || data.length === 0) return null;\n const msgMap = data[0] as Record<string, unknown>;\n if (!msgMap || typeof msgMap !== \"object\") return null;\n const phase = typeof msgMap.phase === \"string\" ? msgMap.phase.trim() : \"\";\n if (!phase) return null;\n const type = typeof msgMap.type === \"string\" ? msgMap.type : \"\";\n const content = extractContentFromMessage(msgMap);\n return { type, content, phase };\n}\n\nfunction extractContentFromMessage(msgMap: Record<string, unknown>): string {\n const c = msgMap.content;\n if (typeof c === \"string\" && c) return c;\n if (Array.isArray(c) && c.length > 0) {\n let b = \"\";\n for (const item of c) {\n if (typeof item === \"string\") {\n b += item;\n continue;\n }\n if (item && typeof item === \"object\") {\n const blk = item as Record<string, unknown>;\n const t = blk.text;\n if (typeof t === \"string\") b += t;\n }\n }\n return b;\n }\n const blocks = msgMap.content_blocks;\n if (Array.isArray(blocks) && blocks.length > 0) {\n let b = \"\";\n for (const blk of blocks) {\n if (blk && typeof blk === \"object\") {\n const m = blk as Record<string, unknown>;\n const t = m.text;\n if (typeof t === \"string\") b += t;\n }\n }\n return b;\n }\n return \"\";\n}\n\nfunction extractContentFromData(data: Record<string, unknown>): [string, boolean] {\n for (const key of [\n \"final_stdout_message\",\n \"completion_summary\",\n \"content\",\n \"text\",\n \"response\",\n \"output\",\n \"message\",\n \"report\",\n ]) {\n const val = data[key];\n if (typeof val === \"string\" && val) return [val, true];\n }\n const nested = data.data;\n if (nested && typeof nested === \"object\") {\n const nm = nested as Record<string, unknown>;\n for (const key of [\n \"final_stdout_message\",\n \"completion_summary\",\n \"content\",\n \"text\",\n \"response\",\n \"output\",\n \"message\",\n \"report\",\n ]) {\n const val = nm[key];\n if (typeof val === \"string\" && val) return [val, true];\n }\n }\n return [\"\", false];\n}\n\nfunction isNamespaceMatch(ns: string, dataType: string, pattern: string): boolean {\n return dataType.includes(pattern) || ns.includes(pattern);\n}\n\n/** Normalizes a namespace value (string or string[]) to a dotted string. */\nfunction namespaceToString(namespace: unknown): string {\n if (typeof namespace === \"string\") return namespace;\n if (Array.isArray(namespace)) return namespace.filter(s => typeof s === \"string\").join(\".\");\n return \"\";\n}\n\n/** Normalizes event data to a map. Strings are parsed as JSON. */\nfunction normalizeEventData(data: unknown): Record<string, unknown> | null {\n if (data == null) return null;\n if (typeof data === \"object\" && !Array.isArray(data)) {\n return data as Record<string, unknown>;\n }\n if (typeof data === \"string\") {\n try {\n const m = JSON.parse(data);\n if (m && typeof m === \"object\" && !Array.isArray(m)) return m;\n } catch {\n return null;\n }\n }\n return null;\n}\n\n// Re-export for callers that want the default allowlist.\nexport { DEFAULT_THINKING_STEP_EVENTS };\n","/**\n * Single-flight query gate for appkit (RFC-629 Layer 1).\n *\n * Enforces single-flight query execution per session id and the\n * cancel-before-context ordering: when a query is cancelled, the daemon is\n * told to stop (command_request{command:\"cancel\"}) BEFORE the local abort\n * signal is cancelled, on a detached timeout so the caller's cancellation\n * cannot block the wire send.\n *\n * The app-agnostic successor to triarch's AcquireQuery/CancelQuery/\n * sendLoopCancelCommand.\n */\n\n/** Returned when a session already has an in-flight query. */\nexport class ErrQueryBusy extends Error {\n constructor() {\n super(\"appkit: query already in progress for session\");\n this.name = \"ErrQueryBusy\";\n }\n}\n\ninterface QueryState {\n /** Local abort for the query's timeout context. */\n abort: AbortController;\n /** Daemon-cancel sender (sends command_request{cancel} for the loop). */\n sendCancel: ((signal: AbortSignal) => Promise<void>) | null;\n}\n\n/**\n * QueryGate enforces single-flight query execution per session id.\n */\nexport class QueryGate {\n private active = new Map<string, QueryState>();\n\n /** Constructs an empty gate. */\n constructor() {}\n\n /**\n * Reserves sessionID for one agent turn. Returns ErrQueryBusy if a query is\n * already in flight. `abort` is the AbortController for the query's timeout\n * context. `sendCancel` is the daemon-cancel sender; it is invoked from\n * `cancel()` on a detached 10s timeout.\n */\n acquire(\n sessionID: string,\n abort: AbortController,\n sendCancel: ((signal: AbortSignal) => Promise<void>) | null,\n ): void {\n if (this.active.has(sessionID)) {\n throw new ErrQueryBusy();\n }\n this.active.set(sessionID, { abort, sendCancel });\n }\n\n /**\n * Cooperatively stops a running query for sessionID. Sends the daemon cancel\n * (on a detached 10s-timeout abort so caller cancellation cannot block the\n * wire send) BEFORE aborting the local context. Returns silently if no query\n * is in flight (intent already satisfied).\n */\n async cancel(sessionID: string): Promise<void> {\n const state = this.active.get(sessionID);\n if (!state) return;\n this.active.delete(sessionID);\n\n if (state.sendCancel) {\n const detached = new AbortController();\n const timer = setTimeout(() => detached.abort(), 10_000);\n try {\n await state.sendCancel(detached.signal);\n } catch {\n // Log but proceed to local cancel; the query is still stopping locally.\n } finally {\n clearTimeout(timer);\n }\n }\n state.abort.abort();\n }\n\n /**\n * Clears the gate for sessionID without sending a daemon cancel. Call when a\n * query completes normally (success or local failure) so the next turn can\n * acquire.\n */\n release(sessionID: string): void {\n this.active.delete(sessionID);\n }\n\n /** Reports whether a query is in flight for sessionID. */\n isActive(sessionID: string): boolean {\n return this.active.has(sessionID);\n }\n}\n","/**\n * ManagedClient — the subset of the core Client that appkit's ConnectionPool\n * and TurnRunner depend on (RFC-629 Layer 1).\n *\n * The concrete `Client` satisfies it; tests supply a fake. Defining it as an\n * interface lets appkit be unit-tested without a live WebSocket daemon.\n */\n\nimport type { Client, InputOptions } from \"../client.js\";\nimport type { Config } from \"../config.js\";\nimport type { DecodedMessage } from \"../protocol.js\";\nimport type { DisconnectCause } from \"../errors.js\";\n\n/**\n * ManagedClient is the subset of the core Client that appkit depends on.\n * Methods are async (TS) rather than channel-based (Go).\n */\nexport interface ManagedClient {\n /** Dials and handshakes. */\n connect(): Promise<void>;\n /** Re-dials after a drop. */\n reconnect(): Promise<void>;\n /** Resumes a loop by id and probes liveness. */\n reattachAndProbe(loopID: string): Promise<void>;\n /** Sends a fire-and-forget notification (e.g. loop_input). */\n sendMessage(msg: unknown): Promise<void>;\n /** Sends user input to the daemon (loop_input notification). */\n sendInput(text: string, options?: InputOptions): Promise<void>;\n /** Starts the read loop, returning the event stream. */\n receiveMessages(signal?: AbortSignal): AsyncGenerator<DecodedMessage>;\n /** Returns whether the connection has dropped. */\n isDisconnected(): boolean;\n /** Returns the drop cause, or null if not dropped. */\n disconnectCause(): DisconnectCause | null;\n /** Reports connection liveness. */\n isConnected(): boolean;\n /** Tears down the connection. */\n close(): void;\n}\n\n/**\n * Builds a fresh ManagedClient for a daemon URL and config. ConnectionPool\n * calls it per pooled connection. Applications may supply a custom factory\n * (e.g. wrapping Client with logging/metrics).\n */\nexport type ClientFactory = (url: string, config?: Config) => ManagedClient;\n\nimport { defaultConfig } from \"../config.js\";\nimport { Client as CoreClient } from \"../client.js\";\n\n/** Returns a ClientFactory that builds a core Client. */\nexport function defaultClientFactory(): ClientFactory {\n return (url: string, config?: Config) => {\n return new CoreClient(url, config ?? defaultConfig()) as unknown as ManagedClient;\n };\n}\n\n/**\n * Creates a new loop (loop_new + subscribe) on a connected client and returns\n * the new loop id. The default implementation calls bootstrapLoopSession;\n * apps may override it.\n */\nexport type BootstrapFunc = (\n client: ManagedClient,\n workspaceID: string,\n userID: string,\n config?: Config,\n) => Promise<string>;\n\nimport { bootstrapLoopSession } from \"../session.js\";\nimport type { LoopNewOptions } from \"../protocol.js\";\n\n/** Default bootstrap: loop_new + subscribe(loop_events). */\nexport function defaultBootstrapFunc(): BootstrapFunc {\n return async (client: ManagedClient, workspaceID: string, userID: string, config?: Config) => {\n // bootstrapLoopSession expects a Client; cast through unknown.\n const c = client as unknown as Client;\n const opts: LoopNewOptions = {\n client_workspace: workspaceID,\n user_id: userID,\n client_workspace_id: workspaceID,\n };\n return bootstrapLoopSession(c, \"\", config, opts);\n };\n}\n","/**\n * Per-session connection pool for appkit (RFC-629 Layer 1).\n *\n * Manages a pool of daemon connections, one active per session. Reuses an\n * active connection when still live, otherwise bootstraps a fresh loop\n * (loop_new + subscribe) or reattaches an existing one (loop_reattach +\n * subscribe + reattachAndProbe). Persistence of session↔loop mappings is\n * abstracted behind SessionStore.\n *\n * The app-agnostic successor to triarch's SoothePoolManager connection\n * mechanics.\n */\n\nimport { StaleLoopError } from \"../errors.js\";\nimport type { Config } from \"../config.js\";\nimport { defaultConfig } from \"../config.js\";\nimport type { DecodedMessage } from \"../protocol.js\";\nimport type { SessionStore } from \"./session_store.js\";\nimport {\n type BootstrapFunc,\n type ClientFactory,\n type ManagedClient,\n defaultBootstrapFunc,\n defaultClientFactory,\n} from \"./client.js\";\n\n/** Returned when no free connection slot is available. */\nexport class ErrPoolExhausted extends Error {\n constructor() {\n super(\"appkit: connection pool exhausted\");\n this.name = \"ErrPoolExhausted\";\n }\n}\n\n/** Configures a ConnectionPool. Zero values use defaults. */\nexport interface PoolConfig {\n poolSize: number;\n queryTimeout: number; // ms\n connectionTimeout: number; // ms\n maxIdleTime: number; // ms\n healthCheckInterval: number; // ms\n}\n\n/** Returns env-overridable defaults (mirrors triarch). */\nexport function defaultPoolConfig(): PoolConfig {\n return {\n poolSize: 1000,\n queryTimeout: 30 * 60 * 1000,\n connectionTimeout: 30_000,\n maxIdleTime: 10 * 60 * 1000,\n healthCheckInterval: 30_000,\n };\n}\n\n/** One connection slot in the pool. */\nexport class PooledConn {\n slotID: number;\n client: ManagedClient;\n eventStream: AsyncGenerator<DecodedMessage> | null = null;\n streamController: AbortController | null = null;\n sessionID = \"\";\n loopID = \"\";\n workspaceID = \"\";\n lastUsed = 0;\n\n constructor(slotID: number, client: ManagedClient) {\n this.slotID = slotID;\n this.client = client;\n }\n\n /** Reports whether the underlying client signalled a drop. */\n isDisconnected(): boolean {\n return this.client.isDisconnected();\n }\n\n isConnected(): boolean {\n return this.client.isConnected() && !this.isDisconnected();\n }\n\n getLoopID(): string {\n return this.loopID;\n }\n}\n\n/**\n * ConnectionPool manages a pool of daemon connections, one active per session.\n */\nexport class ConnectionPool {\n private cfg: PoolConfig;\n private scfg: Config;\n private factory: ClientFactory;\n private bootstrap: BootstrapFunc;\n private store: SessionStore;\n private pool: PooledConn[] = [];\n private activeSlots = new Map<string, PooledConn>();\n private nextSlotID = 1;\n private url: string;\n\n /**\n * Constructs a pool. `url` is the daemon WebSocket URL. If cfg is null,\n * defaultPoolConfig is used; if scfg is null, defaultConfig is used; nil\n * factory/bootstrap fall back to the defaults.\n */\n constructor(\n url: string,\n store: SessionStore,\n cfg?: PoolConfig | null,\n scfg?: Config | null,\n factory?: ClientFactory | null,\n ) {\n this.cfg = cfg ?? defaultPoolConfig();\n this.scfg = scfg ?? defaultConfig();\n this.factory = factory ?? defaultClientFactory();\n this.bootstrap = defaultBootstrapFunc();\n this.store = store;\n this.url = url;\n // Pre-seed the pool with up to poolSize slots.\n for (let i = 0; i < this.cfg.poolSize; i++) {\n this.pool.push(new PooledConn(this.nextSlotID++, this.factory(url, this.scfg)));\n }\n }\n\n /** Overrides the loop bootstrap function (useful for test fakes). */\n withBootstrap(f: BootstrapFunc): ConnectionPool {\n if (f) this.bootstrap = f;\n return this;\n }\n\n /**\n * Returns a live connection for sessionID, reusing an active slot or\n * bootstrapping/reattaching as needed. The caller must call `release()`\n * when done with the connection (a turn completes or the session is reset).\n */\n async acquire(\n sessionID: string,\n workspaceID: string,\n userID: string,\n _signal?: AbortSignal,\n ): Promise<PooledConn> {\n // 1. Reuse active connection when still live.\n const existing = this.activeSlots.get(sessionID);\n if (existing) {\n if (existing.isDisconnected() || !existing.isConnected()) {\n await this.release(sessionID);\n } else {\n existing.lastUsed = Date.now();\n await this.store.updateLastUsed(sessionID).catch(() => {});\n return existing;\n }\n }\n\n // 2. Pull a slot from the pool.\n const conn = this.pool.pop();\n if (!conn) throw new ErrPoolExhausted();\n this.activeSlots.set(sessionID, conn);\n\n const { loopID, ok } = await this.store\n .getLoopIDForSession(sessionID)\n .catch(() => ({ loopID: \"\", ok: false }));\n let finalLoopID = \"\";\n try {\n if (!ok || !loopID) {\n // Fresh bootstrap.\n await conn.client.connect();\n finalLoopID = await this.bootstrapNew(conn, workspaceID, userID);\n await this.store.createSession(workspaceID, sessionID, finalLoopID, \"\").catch(() => {});\n } else {\n // Reattach.\n try {\n await this.resumeAndReattach(conn, loopID);\n finalLoopID = loopID;\n } catch {\n // Reattach failed (incl. StaleLoopError) → fresh bootstrap.\n await conn.client.connect();\n finalLoopID = await this.bootstrapNew(conn, workspaceID, userID);\n await this.store.createSession(workspaceID, sessionID, finalLoopID, \"\").catch(() => {});\n }\n }\n } catch (err) {\n await this.release(sessionID);\n throw err;\n }\n\n conn.sessionID = sessionID;\n conn.loopID = finalLoopID;\n conn.workspaceID = workspaceID;\n conn.lastUsed = Date.now();\n await this.store.updateLastUsed(sessionID).catch(() => {});\n return conn;\n }\n\n /** Tears down the connection for sessionID and returns the slot. */\n async release(sessionID: string): Promise<void> {\n const conn = this.activeSlots.get(sessionID);\n if (!conn) return;\n this.activeSlots.delete(sessionID);\n if (conn.streamController) {\n conn.streamController.abort();\n conn.streamController = null;\n }\n try {\n conn.client.close();\n } catch {\n // ignore\n }\n conn.sessionID = \"\";\n conn.loopID = \"\";\n conn.eventStream = null;\n // Return a fresh slot to the pool (the closed client is spent).\n this.pool.push(new PooledConn(this.nextSlotID++, this.factory(this.url, this.scfg)));\n }\n\n /**\n * Tears down the connection for sessionID so the next acquire bootstraps\n * fresh. The store should archive the loop id so getLoopIDForSession returns\n * false next time.\n */\n async resetSession(sessionID: string): Promise<void> {\n await this.release(sessionID);\n }\n\n /** Gracefully shuts down all active connections. */\n stop(): void {\n for (const [sid, conn] of this.activeSlots) {\n if (conn.streamController) conn.streamController.abort();\n try {\n conn.client.close();\n } catch {\n // ignore\n }\n this.activeSlots.delete(sid);\n }\n }\n\n /** Stats snapshot for observability. */\n stats(): { active: number; idle: number } {\n return { active: this.activeSlots.size, idle: this.pool.length };\n }\n\n /** Bootstrap a fresh loop and start the reader. */\n private async bootstrapNew(\n conn: PooledConn,\n workspaceID: string,\n userID: string,\n ): Promise<string> {\n const loopID = await this.bootstrap(conn.client, workspaceID, userID, this.scfg);\n this.startReader(conn);\n return loopID;\n }\n\n /** Reconnect + reattach an existing loop, then start the reader. */\n private async resumeAndReattach(conn: PooledConn, loopID: string): Promise<void> {\n await conn.client.connect();\n try {\n await conn.client.reattachAndProbe(loopID);\n } catch (err) {\n if (err instanceof StaleLoopError) throw err;\n throw err;\n }\n this.startReader(conn);\n }\n\n /** Starts a receiveMessages generator and stores the stream + controller. */\n private startReader(conn: PooledConn): void {\n const controller = new AbortController();\n conn.streamController = controller;\n conn.eventStream = conn.client.receiveMessages(controller.signal);\n }\n}\n","/**\n * Turn runner for appkit (RFC-629 Layer 1).\n *\n * Executes one query turn end-to-end: acquire a pooled connection, enforce\n * single-flight, send loop_input, consume the event stream, classify events,\n * resolve the deliverable, persist the reply, and broadcast completion.\n *\n * The app-agnostic successor to triarch's ExecuteQuery.\n */\n\nimport type { PooledConn } from \"./pool.js\";\nimport { type ConnectionPool } from \"./pool.js\";\nimport { type EventClassifier, ChatEventTerminal } from \"./classifier.js\";\nimport { type QueryGate } from \"./query_gate.js\";\nimport { type SSEBroadcaster, SSEEvent } from \"./broadcaster.js\";\nimport type { SessionStore, SessionMessage } from \"./session_store.js\";\nimport type { LoopInputIntentHint } from \"../intent_hints.js\";\nimport { validateLoopInputIntentHint } from \"../intent_hints.js\";\nimport type { DecodedMessage } from \"../protocol.js\";\n\n/** Returned when a turn exceeds the configured timeout. */\nexport class ErrQueryTimeout extends Error {\n constructor() {\n super(\"appkit: query timeout\");\n this.name = \"ErrQueryTimeout\";\n }\n}\n\n/** Configures a TurnRunner. */\nexport interface TurnConfig {\n /** Per-turn deadline in ms. Defaults to 30m. */\n queryTimeout: number;\n}\n\n/** Carries optional daemon hints on a loop_input payload. */\nexport interface InputOpts {\n intentHint?: LoopInputIntentHint;\n preferredSubagent?: string;\n responseSchema?: Record<string, unknown>;\n responseSchemaName?: string;\n responseSchemaStrict?: boolean;\n}\n\n/** Optional attachment shape (IG-327: {mime_type, data(base64)}). */\nexport type Attachment = Record<string, unknown>;\n\n/**\n * Builds a loop_input payload with optional attachments. Apps build this from\n * their product modes (e.g. triarch's ask/agent/deep-research).\n */\nexport function inputMessageForLoop(\n text: string,\n loopID: string,\n attachments?: Attachment[],\n opts?: InputOpts,\n): Record<string, unknown> {\n const msg: Record<string, unknown> = { type: \"loop_input\", content: text };\n if (loopID) msg.loop_id = loopID;\n if (attachments && attachments.length > 0) msg.attachments = attachments;\n if (opts) {\n if (opts.intentHint?.trim()) {\n const hintError = validateLoopInputIntentHint(opts.intentHint);\n if (hintError) {\n throw new Error(hintError);\n }\n msg.intent_hint = opts.intentHint.trim();\n }\n if (opts.preferredSubagent?.trim()) msg.preferred_subagent = opts.preferredSubagent.trim();\n if (opts.responseSchema && Object.keys(opts.responseSchema).length > 0) {\n msg.response_schema = opts.responseSchema;\n }\n if (opts.responseSchemaName?.trim()) msg.response_schema_name = opts.responseSchemaName.trim();\n if (opts.responseSchemaStrict !== undefined)\n msg.response_schema_strict = opts.responseSchemaStrict;\n }\n return msg;\n}\n\n/** Completion hook signature. */\nexport type OnComplete = (\n sessionID: string,\n loopID: string,\n content: string,\n completionEvent: string,\n elapsedMs: number,\n) => void;\n/** Error hook signature. */\nexport type OnError = (sessionID: string, loopID: string, err: Error) => void;\n\n/**\n * TurnRunner executes one query turn end-to-end.\n */\nexport class TurnRunner {\n private pool: ConnectionPool;\n private gate: QueryGate;\n private classifier: EventClassifier;\n private store: SessionStore;\n private broadcaster: SSEBroadcaster | null;\n private cfg: TurnConfig;\n private buildInput: typeof inputMessageForLoop = inputMessageForLoop;\n private onComplete: OnComplete | null = null;\n private onError: OnError | null = null;\n\n /**\n * Constructs a TurnRunner. pool, gate, classifier, and store are required;\n * broadcaster may be null.\n */\n constructor(\n pool: ConnectionPool,\n gate: QueryGate,\n classifier: EventClassifier,\n store: SessionStore,\n broadcaster: SSEBroadcaster | null,\n cfg: TurnConfig,\n ) {\n this.pool = pool;\n this.gate = gate;\n this.classifier = classifier;\n this.store = store;\n this.broadcaster = broadcaster;\n this.cfg = { queryTimeout: cfg.queryTimeout > 0 ? cfg.queryTimeout : 30 * 60 * 1000 };\n }\n\n /** Overrides the loop_input payload builder. */\n withInputBuilder(f: typeof inputMessageForLoop): TurnRunner {\n if (f) this.buildInput = f;\n return this;\n }\n\n /** Sets a completion hook (runs inline on success). */\n withOnComplete(f: OnComplete): TurnRunner {\n this.onComplete = f;\n return this;\n }\n\n /** Sets an error hook (runs inline on failure). */\n withOnError(f: OnError): TurnRunner {\n this.onError = f;\n return this;\n }\n\n /**\n * Runs one query turn. The response is broadcast via the SSE broadcaster and\n * persisted via the SessionStore; it is not returned to the caller (SSE\n * subscribers receive it). Resolves on success; rejects on failure\n * (ErrQueryTimeout, AbortError, or a daemon/processing error).\n */\n async execute(\n sessionID: string,\n message: string,\n userID: string,\n workspaceID: string,\n attachments: Attachment[] | null,\n opts: InputOpts | null,\n signal?: AbortSignal,\n ): Promise<void> {\n let conn: PooledConn;\n try {\n conn = await this.pool.acquire(sessionID, workspaceID, userID, signal);\n } catch (err) {\n await this.persistFailed(sessionID, \"\", err as Error);\n this.broadcastError(sessionID, err as Error);\n this.onError?.(sessionID, \"\", err as Error);\n throw err;\n }\n const loopID = conn.getLoopID();\n\n const timeoutController = new AbortController();\n const timeoutMs = this.cfg.queryTimeout;\n const timer = setTimeout(() => timeoutController.abort(), timeoutMs);\n\n // Build the daemon-cancel sender for this loop; register with the gate.\n const sendCancel = async (detachedSignal: AbortSignal) => {\n await this.sendLoopCancel(detachedSignal, conn, loopID);\n };\n try {\n this.gate.acquire(sessionID, timeoutController, sendCancel);\n } catch (err) {\n clearTimeout(timer);\n await this.pool.release(sessionID);\n await this.persistFailed(sessionID, loopID, err as Error);\n this.broadcastError(sessionID, err as Error);\n this.onError?.(sessionID, loopID, err as Error);\n throw err;\n }\n\n try {\n // Send loop_input.\n const inputMsg = this.buildInput(\n message,\n loopID,\n attachments ?? undefined,\n opts ?? undefined,\n );\n try {\n await conn.client.sendMessage(inputMsg);\n } catch (err) {\n await this.persistFailed(sessionID, loopID, err as Error);\n this.broadcastError(sessionID, err as Error);\n this.onError?.(sessionID, loopID, err as Error);\n throw err;\n }\n\n const eventStream = conn.eventStream;\n if (!eventStream) {\n const err = new Error(`missing event stream for session ${sessionID} (loop ${loopID})`);\n await this.persistFailed(sessionID, loopID, err);\n this.broadcastError(sessionID, err);\n this.onError?.(sessionID, loopID, err);\n throw err;\n }\n\n let assistantContent = \"\";\n const startedAt = Date.now();\n\n // A promise that resolves when the per-turn timeout OR the caller's\n // abort signal fires, so the stream-wait loop can race against it\n // instead of blocking forever on a stalled stream.\n const abortRace = new Promise<\"timeout\" | \"caller\">(resolve => {\n const onTimeout = () => resolve(\"timeout\");\n timeoutController.signal.addEventListener(\"abort\", onTimeout, { once: true });\n if (signal) {\n const onCaller = () => resolve(\"caller\");\n signal.addEventListener(\"abort\", onCaller, { once: true });\n }\n });\n\n const iterator = eventStream[Symbol.asyncIterator]();\n\n while (true) {\n const next = iterator.next();\n const raced = await Promise.race([\n next.then(res => ({ tag: \"msg\" as const, res })),\n abortRace.then(tag => ({ tag })),\n ]);\n\n if (\"tag\" in raced && raced.tag !== \"msg\") {\n if (raced.tag === \"caller\" || signal?.aborted) {\n const err = new Error(\"aborted\");\n await this.persistFailed(sessionID, loopID, err);\n this.broadcastError(sessionID, err);\n this.onError?.(sessionID, loopID, err);\n throw err;\n }\n // Timeout: tell the daemon to stop, then persist/broadcast.\n await this.sendLoopCancel(new AbortController().signal, conn, loopID).catch(() => {});\n await this.persistFailed(sessionID, loopID, new ErrQueryTimeout());\n this.broadcastError(sessionID, new ErrQueryTimeout());\n this.onError?.(sessionID, loopID, new ErrQueryTimeout());\n throw new ErrQueryTimeout();\n }\n\n const res = (raced as { tag: \"msg\"; res: IteratorResult<DecodedMessage> }).res;\n if (res.done) {\n // Stream ended without a deliverable — treat as failure.\n const err = new Error(\"event stream closed\");\n await this.persistFailed(sessionID, loopID, err);\n this.broadcastError(sessionID, err);\n this.onError?.(sessionID, loopID, err);\n throw err;\n }\n const msg = res.value;\n\n const eventResult = this.classifier.classify(msg, assistantContent);\n if (eventResult.err && eventResult.terminal === ChatEventTerminal.FailedComplete) {\n await this.persistFailed(sessionID, loopID, eventResult.err);\n this.broadcastError(sessionID, eventResult.err);\n this.onError?.(sessionID, loopID, eventResult.err);\n throw eventResult.err;\n }\n\n const step = (eventResult.thinkingStep ?? \"\").trim();\n if (step) this.broadcastThinkingStep(sessionID, step);\n\n if (eventResult.content) {\n if (eventResult.content.startsWith(assistantContent)) {\n assistantContent = eventResult.content;\n } else {\n assistantContent += eventResult.content;\n }\n }\n\n const [final, deliverable] = this.classifier.resolveDeliverableFinalContent(\n eventResult,\n assistantContent,\n );\n if (deliverable) {\n const elapsedMs = Date.now() - startedAt;\n await this.persistResponse(\n sessionID,\n loopID,\n final,\n startedAt,\n eventResult.completionEvent ?? \"\",\n );\n this.broadcastComplete(sessionID, final);\n this.onComplete?.(sessionID, loopID, final, eventResult.completionEvent ?? \"\", elapsedMs);\n return;\n }\n }\n } finally {\n clearTimeout(timer);\n this.gate.release(sessionID);\n }\n }\n\n /** Asks the daemon to cooperatively stop the loop runner on a detached signal. */\n private async sendLoopCancel(\n _signal: AbortSignal,\n conn: PooledConn,\n loopID: string,\n ): Promise<void> {\n const lid = (loopID ?? \"\").trim();\n if (!conn || !lid) return;\n const cancelMsg = { type: \"command_request\", command: \"cancel\", loop_id: lid };\n await conn.client.sendMessage(cancelMsg);\n }\n\n private async persistResponse(\n sessionID: string,\n loopID: string,\n content: string,\n startedAt: number,\n completionEvent: string,\n ): Promise<void> {\n const msg: SessionMessage = {\n role: \"assistant\",\n content,\n metadata: {\n started_at: startedAt,\n completed_at: Date.now(),\n duration_ms: Date.now() - startedAt,\n status: \"completed\",\n completion_event: completionEvent,\n deliverable: true,\n },\n };\n await this.store.appendMessage(sessionID, msg).catch(() => {});\n }\n\n private async persistFailed(sessionID: string, _loopID: string, err: Error): Promise<void> {\n const msg: SessionMessage = {\n role: \"error\",\n content: err.message,\n metadata: { status: \"failed\", error_message: err.message },\n };\n await this.store.appendMessage(sessionID, msg).catch(() => {});\n }\n\n private broadcastThinkingStep(sessionID: string, step: string): void {\n if (!this.broadcaster) return;\n this.broadcaster.broadcast(sessionID, { type: \"delta\", data: step + \"\\n\" } as SSEEvent);\n }\n\n private broadcastComplete(sessionID: string, content: string): void {\n this.broadcaster?.broadcast(sessionID, { type: \"complete\", data: content } as SSEEvent);\n }\n\n private broadcastError(sessionID: string, err: Error): void {\n this.broadcaster?.broadcast(sessionID, { type: \"query_error\", data: err.message } as SSEEvent);\n }\n}\n"],"mappings":"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","names":["VerbosityTier","Client","ChatEventTerminal","dataType","dt","res"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirasoth/soothe-client",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "WebSocket client in TypeScript for soothe-daemon",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -10,8 +10,14 @@
|
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
-
"import": {
|
|
14
|
-
|
|
13
|
+
"import": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"require": {
|
|
18
|
+
"types": "./dist/index.d.cts",
|
|
19
|
+
"default": "./dist/index.cjs"
|
|
20
|
+
}
|
|
15
21
|
}
|
|
16
22
|
},
|
|
17
23
|
"scripts": {
|
|
@@ -20,26 +26,46 @@
|
|
|
20
26
|
"test": "vitest run",
|
|
21
27
|
"test:watch": "vitest",
|
|
22
28
|
"test:integration": "SOOTHE_INTEGRATION=1 vitest run test/integration.test.ts",
|
|
23
|
-
"typecheck": "tsc --noEmit"
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"*.ts\"",
|
|
31
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" \"*.ts\"",
|
|
32
|
+
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\" \"*.ts\"",
|
|
33
|
+
"lint:fix": "eslint --fix \"src/**/*.ts\" \"test/**/*.ts\" \"*.ts\" && npm run format"
|
|
24
34
|
},
|
|
25
35
|
"repository": {
|
|
26
36
|
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/
|
|
37
|
+
"url": "git+https://github.com/mirasoth/soothe-client-typescript.git"
|
|
28
38
|
},
|
|
29
|
-
"keywords": [
|
|
39
|
+
"keywords": [
|
|
40
|
+
"soothe",
|
|
41
|
+
"websocket",
|
|
42
|
+
"client",
|
|
43
|
+
"daemon",
|
|
44
|
+
"typescript"
|
|
45
|
+
],
|
|
30
46
|
"author": "OpenSoothe",
|
|
31
47
|
"license": "MIT",
|
|
32
48
|
"type": "module",
|
|
33
|
-
"files": [
|
|
34
|
-
|
|
49
|
+
"files": [
|
|
50
|
+
"dist/**/*",
|
|
51
|
+
"README.md",
|
|
52
|
+
"LICENSE"
|
|
53
|
+
],
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=19.0.0"
|
|
56
|
+
},
|
|
35
57
|
"dependencies": {
|
|
36
58
|
"ws": "^8.20.0"
|
|
37
59
|
},
|
|
38
60
|
"devDependencies": {
|
|
61
|
+
"@eslint/js": "^9.39.0",
|
|
39
62
|
"@types/node": "^22.0.0",
|
|
40
63
|
"@types/ws": "^8.18.1",
|
|
64
|
+
"eslint": "^9.39.0",
|
|
65
|
+
"prettier": "^3.6.0",
|
|
41
66
|
"tsup": "^8.0.0",
|
|
42
67
|
"typescript": "^5.7.0",
|
|
68
|
+
"typescript-eslint": "^8.46.0",
|
|
43
69
|
"vitest": "^3.0.0"
|
|
44
70
|
}
|
|
45
71
|
}
|