@aomi-labs/client 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sse.ts","../src/client.ts","../src/types.ts","../src/event-emitter.ts","../src/event-unwrap.ts","../src/wallet-utils.ts","../src/session.ts"],"sourcesContent":["import type { AomiSSEEvent, Logger } from \"./types\";\n\nexport type SseSubscriber = {\n subscribe: (\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ) => () => void;\n};\n\nexport type SseSubscriberOptions = {\n backendUrl: string;\n getHeaders: (sessionId: string) => HeadersInit;\n logger?: Logger;\n};\n\ntype SseSubscription = {\n abortController: AbortController | null;\n retries: number;\n retryTimer: ReturnType<typeof setTimeout> | null;\n stopped: boolean;\n listeners: Set<SseListener>;\n stop: (reason?: string) => void;\n};\n\ntype SseListener = {\n onUpdate: (event: AomiSSEEvent) => void;\n onError?: (error: unknown) => void;\n};\n\nfunction extractSseData(rawEvent: string): string | null {\n const dataLines = rawEvent\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart());\n if (!dataLines.length) return null;\n return dataLines.join(\"\\n\");\n}\n\nasync function readSseStream(\n stream: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n onMessage: (data: string) => void,\n): Promise<void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (!signal.aborted) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n buffer = buffer.replace(/\\r/g, \"\");\n\n let separatorIndex = buffer.indexOf(\"\\n\\n\");\n while (separatorIndex >= 0) {\n const rawEvent = buffer.slice(0, separatorIndex);\n buffer = buffer.slice(separatorIndex + 2);\n const data = extractSseData(rawEvent);\n if (data) {\n onMessage(data);\n }\n separatorIndex = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function createSseSubscriber({\n backendUrl,\n getHeaders,\n logger,\n}: SseSubscriberOptions): SseSubscriber {\n const subscriptions = new Map<string, SseSubscription>();\n\n const subscribe: SseSubscriber[\"subscribe\"] = (\n sessionId,\n onUpdate,\n onError,\n ) => {\n const existing = subscriptions.get(sessionId);\n const listener: SseListener = { onUpdate, onError };\n if (existing) {\n existing.listeners.add(listener);\n logger?.debug(\"[aomi][sse] listener added\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n return () => {\n existing.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n if (existing.listeners.size === 0) {\n existing.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === existing) {\n subscriptions.delete(sessionId);\n }\n }\n };\n }\n\n const subscription: SseSubscription = {\n abortController: null,\n retries: 0,\n retryTimer: null,\n stopped: false,\n listeners: new Set([listener]),\n stop: (reason?: string) => {\n subscription.stopped = true;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n subscription.abortController?.abort();\n subscription.abortController = null;\n logger?.debug(\"[aomi][sse] stop\", {\n sessionId,\n reason,\n retries: subscription.retries,\n });\n },\n };\n\n const scheduleRetry = () => {\n if (subscription.stopped) return;\n subscription.retries += 1;\n const delayMs = Math.min(500 * 2 ** (subscription.retries - 1), 10000);\n logger?.debug(\"[aomi][sse] retry scheduled\", {\n sessionId,\n delayMs,\n retries: subscription.retries,\n });\n subscription.retryTimer = setTimeout(() => {\n void open();\n }, delayMs);\n };\n\n const open = async () => {\n if (subscription.stopped) return;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n\n const controller = new AbortController();\n subscription.abortController = controller;\n const openedAt = Date.now();\n\n try {\n const response = await fetch(`${backendUrl}/api/updates`, {\n headers: getHeaders(sessionId),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(\n `SSE HTTP ${response.status}: ${response.statusText}`,\n );\n }\n\n if (!response.body) {\n throw new Error(\"SSE response missing body\");\n }\n\n subscription.retries = 0;\n\n await readSseStream(response.body, controller.signal, (data) => {\n let parsed: AomiSSEEvent;\n try {\n parsed = JSON.parse(data) as AomiSSEEvent;\n } catch (error) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n return;\n }\n\n for (const item of subscription.listeners) {\n try {\n item.onUpdate(parsed);\n } catch (error) {\n item.onError?.(error);\n }\n }\n });\n logger?.debug(\"[aomi][sse] stream ended\", {\n sessionId,\n aborted: controller.signal.aborted,\n stopped: subscription.stopped,\n durationMs: Date.now() - openedAt,\n });\n } catch (error) {\n if (!controller.signal.aborted && !subscription.stopped) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n }\n }\n\n if (!subscription.stopped) {\n scheduleRetry();\n }\n };\n\n subscriptions.set(sessionId, subscription);\n void open();\n\n return () => {\n subscription.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: subscription.listeners.size,\n });\n if (subscription.listeners.size === 0) {\n subscription.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === subscription) {\n subscriptions.delete(sessionId);\n }\n }\n };\n };\n\n return { subscribe };\n}\n","import type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiCreateThreadResponse,\n AomiInterruptResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n AomiSystemResponse,\n AomiThread,\n Logger,\n UserState,\n} from \"./types\";\nimport { createSseSubscriber, type SseSubscriber } from \"./sse\";\n\n// =============================================================================\n// Internal helpers\n// =============================================================================\n\nconst SESSION_ID_HEADER = \"X-Session-Id\";\nconst API_KEY_HEADER = \"X-API-Key\";\n\nfunction toQueryString(payload: Record<string, unknown>): string {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined || value === null) continue;\n params.set(key, String(value));\n }\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nfunction withSessionHeader(\n sessionId: string,\n init?: HeadersInit,\n): HeadersInit {\n const headers = new Headers(init);\n headers.set(SESSION_ID_HEADER, sessionId);\n return headers;\n}\n\nasync function postState<T>(\n baseUrl: string,\n path: string,\n payload: Record<string, unknown>,\n sessionId: string,\n apiKey?: string,\n): Promise<T> {\n const query = toQueryString(payload);\n const url = `${baseUrl}${path}${query}`;\n\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as T;\n}\n\n// =============================================================================\n// AomiClient\n// =============================================================================\n\nexport class AomiClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly logger?: Logger;\n private readonly sseSubscriber: SseSubscriber;\n\n constructor(options: AomiClientOptions) {\n // Strip trailing slash\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.logger = options.logger;\n\n this.sseSubscriber = createSseSubscriber({\n backendUrl: this.baseUrl,\n getHeaders: (sessionId) =>\n withSessionHeader(sessionId, { Accept: \"text/event-stream\" }),\n logger: this.logger,\n });\n }\n\n // ===========================================================================\n // Chat & State\n // ===========================================================================\n\n /**\n * Fetch current session state (messages, processing status, title).\n */\n async fetchState(\n sessionId: string,\n userState?: UserState,\n ): Promise<AomiStateResponse> {\n const url = new URL(\"/api/state\", this.baseUrl);\n if (userState) {\n url.searchParams.set(\"user_state\", JSON.stringify(userState));\n }\n\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiStateResponse;\n }\n\n /**\n * Send a chat message and return updated session state.\n */\n async sendMessage(\n sessionId: string,\n message: string,\n options?: {\n namespace?: string;\n publicKey?: string;\n apiKey?: string;\n userState?: UserState;\n },\n ): Promise<AomiChatResponse> {\n const namespace = options?.namespace ?? \"default\";\n const apiKey = options?.apiKey ?? this.apiKey;\n\n const payload: Record<string, unknown> = { message, namespace };\n if (options?.publicKey) {\n payload.public_key = options.publicKey;\n }\n if (options?.userState) {\n payload.user_state = JSON.stringify(options.userState);\n }\n\n return postState<AomiChatResponse>(\n this.baseUrl,\n \"/api/chat\",\n payload,\n sessionId,\n apiKey,\n );\n }\n\n /**\n * Send a system-level message (e.g. wallet state changes, context switches).\n */\n async sendSystemMessage(\n sessionId: string,\n message: string,\n ): Promise<AomiSystemResponse> {\n return postState<AomiSystemResponse>(\n this.baseUrl,\n \"/api/system\",\n { message },\n sessionId,\n );\n }\n\n /**\n * Interrupt the AI's current response.\n */\n async interrupt(sessionId: string): Promise<AomiInterruptResponse> {\n return postState<AomiInterruptResponse>(\n this.baseUrl,\n \"/api/interrupt\",\n {},\n sessionId,\n );\n }\n\n // ===========================================================================\n // SSE (Real-time Updates)\n // ===========================================================================\n\n /**\n * Subscribe to real-time SSE updates for a session.\n * Automatically reconnects with exponential backoff on disconnects.\n * Returns an unsubscribe function.\n */\n subscribeSSE(\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ): () => void {\n return this.sseSubscriber.subscribe(sessionId, onUpdate, onError);\n }\n\n // ===========================================================================\n // Thread / Session Management\n // ===========================================================================\n\n /**\n * List all threads for a wallet address.\n */\n async listThreads(publicKey: string): Promise<AomiThread[]> {\n const url = `${this.baseUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch threads: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiThread[];\n }\n\n /**\n * Get a single thread by ID.\n */\n async getThread(sessionId: string): Promise<AomiThread> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiThread;\n }\n\n /**\n * Create a new thread. The client generates the session ID.\n */\n async createThread(\n threadId: string,\n publicKey?: string,\n ): Promise<AomiCreateThreadResponse> {\n const body: Record<string, string> = {};\n if (publicKey) body.public_key = publicKey;\n\n const url = `${this.baseUrl}/api/sessions`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(threadId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create thread: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiCreateThreadResponse;\n }\n\n /**\n * Delete a thread by ID.\n */\n async deleteThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to delete thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Rename a thread.\n */\n async renameThread(sessionId: string, newTitle: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: withSessionHeader(sessionId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify({ title: newTitle }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to rename thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Archive a thread.\n */\n async archiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to archive thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Unarchive a thread.\n */\n async unarchiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to unarchive thread: HTTP ${response.status}`);\n }\n }\n\n // ===========================================================================\n // System Events\n // ===========================================================================\n\n /**\n * Get system events for a session.\n */\n async getSystemEvents(\n sessionId: string,\n count?: number,\n ): Promise<AomiSystemEvent[]> {\n const url = new URL(\"/api/events\", this.baseUrl);\n if (count !== undefined) {\n url.searchParams.set(\"count\", String(count));\n }\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n if (response.status === 404) return [];\n throw new Error(`Failed to get system events: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiSystemEvent[];\n }\n\n // ===========================================================================\n // Control API\n // ===========================================================================\n\n /**\n * Get available namespaces.\n */\n async getNamespaces(\n sessionId: string,\n options?: { publicKey?: string; apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/namespaces\", this.baseUrl);\n if (options?.publicKey) {\n url.searchParams.set(\"public_key\", options.publicKey);\n }\n\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to get namespaces: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Get available models.\n */\n async getModels(\n sessionId: string,\n options?: { apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/models\", this.baseUrl);\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), {\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get models: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Set the model for a session.\n */\n async setModel(\n sessionId: string,\n rig: string,\n options?: { namespace?: string; apiKey?: string },\n ): Promise<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }> {\n const apiKey = options?.apiKey ?? this.apiKey;\n const payload: Record<string, unknown> = { rig };\n if (options?.namespace) {\n payload.namespace = options.namespace;\n }\n\n return postState<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }>(this.baseUrl, \"/api/control/model\", payload, sessionId, apiKey);\n }\n}\n","// =============================================================================\n// User State\n// =============================================================================\n\n/**\n * Client-side user state synced with the backend.\n * Typically wallet connection info, but can be any key-value data.\n */\nexport type UserState = Record<string, unknown>;\n\n// =============================================================================\n// Logger\n// =============================================================================\n\n/**\n * Optional logger for debug output. Pass `console` or any compatible object.\n */\nexport type Logger = {\n debug: (...args: unknown[]) => void;\n};\n\n// =============================================================================\n// Client Options\n// =============================================================================\n\nexport type AomiClientOptions = {\n /** Base URL of the Aomi backend (e.g. \"https://aomi.dev\") */\n baseUrl: string;\n /** Default API key for non-default namespaces */\n apiKey?: string;\n /** Optional logger for debug output (default: silent) */\n logger?: Logger;\n};\n\n// =============================================================================\n// Base Types\n// =============================================================================\n\nexport interface AomiMessage {\n sender?: \"user\" | \"agent\" | \"system\" | string;\n content?: string;\n timestamp?: string;\n is_streaming?: boolean;\n tool_result?: [string, string] | null;\n}\n\n// =============================================================================\n// API Response Types\n// =============================================================================\n\n/**\n * GET /api/state\n * Fetches current session state including messages and processing status\n */\nexport interface AomiStateResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n}\n\n/**\n * POST /api/chat\n * Sends a chat message and returns updated session state\n */\nexport interface AomiChatResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n}\n\n/**\n * POST /api/system\n * Sends a system message and returns the response message\n */\nexport interface AomiSystemResponse {\n res?: AomiMessage | null;\n}\n\n/**\n * POST /api/interrupt\n * Interrupts current processing and returns updated session state\n */\nexport type AomiInterruptResponse = AomiChatResponse;\n\n/**\n * GET /api/sessions\n * Returns array of AomiThread\n */\nexport interface AomiThread {\n session_id: string;\n title: string;\n is_archived?: boolean;\n}\n\n/**\n * POST /api/sessions\n * Creates a new thread/session\n */\nexport interface AomiCreateThreadResponse {\n session_id: string;\n title?: string;\n}\n\n// =============================================================================\n// SSE Event Types (/api/updates)\n// =============================================================================\n\n/**\n * Base SSE event - all events have session_id and type\n */\nexport type AomiSSEEvent = {\n type:\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\"\n | string;\n session_id: string;\n new_title?: string;\n [key: string]: unknown;\n};\n\nexport type AomiSSEEventType =\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\";\n\n// =============================================================================\n// System Events (/api/events)\n// =============================================================================\n\n/**\n * Backend SystemEvent enum serializes as tagged JSON:\n * - InlineCall: {\"InlineCall\": {\"type\": \"wallet_tx_request\", \"payload\": {...}}}\n * - SystemNotice: {\"SystemNotice\": \"message\"}\n * - SystemError: {\"SystemError\": \"message\"}\n * - AsyncCallback: {\"AsyncCallback\": {...}} (not sent over HTTP)\n */\nexport type AomiSystemEvent =\n | { InlineCall: { type: string; payload?: unknown; [key: string]: unknown } }\n | { SystemNotice: string }\n | { SystemError: string }\n | { AsyncCallback: Record<string, unknown> };\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isInlineCall(\n event: AomiSystemEvent,\n): event is { InlineCall: { type: string; payload?: unknown } } {\n return \"InlineCall\" in event;\n}\n\nexport function isSystemNotice(\n event: AomiSystemEvent,\n): event is { SystemNotice: string } {\n return \"SystemNotice\" in event;\n}\n\nexport function isSystemError(\n event: AomiSystemEvent,\n): event is { SystemError: string } {\n return \"SystemError\" in event;\n}\n\nexport function isAsyncCallback(\n event: AomiSystemEvent,\n): event is { AsyncCallback: Record<string, unknown> } {\n return \"AsyncCallback\" in event;\n}\n","// =============================================================================\n// Typed EventEmitter (browser-safe, no Node.js deps)\n// =============================================================================\n\ntype Listener<T = unknown> = (payload: T) => void;\n\n/**\n * Minimal typed event emitter with wildcard support.\n *\n * ```ts\n * type Events = { message: string; error: { code: number } };\n * const ee = new TypedEventEmitter<Events>();\n * ee.on(\"message\", (msg) => console.log(msg));\n * ee.emit(\"message\", \"hello\");\n * ```\n */\nexport class TypedEventEmitter<\n EventMap extends Record<string, unknown> = Record<string, unknown>,\n> {\n private listeners = new Map<string, Set<Listener<never>>>();\n\n /**\n * Subscribe to an event type. Returns an unsubscribe function.\n */\n on<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(handler as Listener<never>);\n\n return () => {\n set!.delete(handler as Listener<never>);\n if (set!.size === 0) {\n this.listeners.delete(type);\n }\n };\n }\n\n /**\n * Subscribe to an event type for a single emission, then auto-unsubscribe.\n */\n once<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n const wrapper = ((payload: EventMap[K]) => {\n unsub();\n handler(payload);\n }) as Listener<EventMap[K]>;\n\n const unsub = this.on(type, wrapper);\n return unsub;\n }\n\n /**\n * Emit an event to all listeners of `type` and wildcard `\"*\"` listeners.\n */\n emit<K extends keyof EventMap & string>(\n type: K,\n payload: EventMap[K],\n ): void {\n // Type-specific listeners\n const typeSet = this.listeners.get(type);\n if (typeSet) {\n for (const handler of typeSet) {\n (handler as Listener<EventMap[K]>)(payload);\n }\n }\n\n // Wildcard listeners\n if (type !== \"*\") {\n const wildcardSet = this.listeners.get(\"*\");\n if (wildcardSet) {\n for (const handler of wildcardSet) {\n (handler as Listener<unknown>)({ type, payload });\n }\n }\n }\n }\n\n /**\n * Remove a specific handler from an event type.\n */\n off<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): void {\n const set = this.listeners.get(type);\n if (set) {\n set.delete(handler as Listener<never>);\n if (set.size === 0) {\n this.listeners.delete(type);\n }\n }\n }\n\n /**\n * Remove all listeners for all event types.\n */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","// =============================================================================\n// System Event Unwrap\n// =============================================================================\n//\n// Converts tagged-enum AomiSystemEvent into a flat { type, payload } object.\n// Ported from packages/react/src/contexts/event-context.tsx dispatchSystemEvents.\n\nimport type { AomiSystemEvent } from \"./types\";\nimport {\n isInlineCall,\n isSystemNotice,\n isSystemError,\n isAsyncCallback,\n} from \"./types\";\n\nexport type UnwrappedEvent = {\n type: string;\n payload: unknown;\n};\n\n/**\n * Unwrap a tagged-enum AomiSystemEvent from the backend into a flat event.\n *\n * ```ts\n * const event: AomiSystemEvent = { InlineCall: { type: \"wallet_tx_request\", payload: { to: \"0x...\" } } };\n * const unwrapped = unwrapSystemEvent(event);\n * // => { type: \"wallet_tx_request\", payload: { to: \"0x...\" } }\n * ```\n */\nexport function unwrapSystemEvent(\n event: AomiSystemEvent,\n): UnwrappedEvent | null {\n if (isInlineCall(event)) {\n return {\n type: event.InlineCall.type,\n payload: event.InlineCall.payload ?? event.InlineCall,\n };\n }\n\n if (isSystemNotice(event)) {\n return {\n type: \"system_notice\",\n payload: { message: event.SystemNotice },\n };\n }\n\n if (isSystemError(event)) {\n return {\n type: \"system_error\",\n payload: { message: event.SystemError },\n };\n }\n\n if (isAsyncCallback(event)) {\n return {\n type: \"async_callback\",\n payload: event.AsyncCallback,\n };\n }\n\n return null;\n}\n","// =============================================================================\n// Wallet Payload Normalization\n// =============================================================================\n//\n// Pure functions extracted from packages/react/src/handlers/wallet-handler.ts.\n// Normalizes the various payload shapes the backend can send for wallet\n// transaction and EIP-712 signing requests.\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletTxPayload = {\n to: string;\n value?: string;\n data?: string;\n chainId?: number;\n};\n\nexport type WalletEip712Payload = {\n typed_data?: {\n domain?: { chainId?: number | string };\n types?: Record<string, Array<{ name: string; type: string }>>;\n primaryType?: string;\n message?: Record<string, unknown>;\n };\n description?: string;\n};\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\ntype UnknownRecord = Record<string, unknown>;\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UnknownRecord;\n}\n\nfunction getToolArgs(payload: unknown): UnknownRecord {\n const root = asRecord(payload);\n const nestedArgs = asRecord(root?.args);\n return nestedArgs ?? root ?? {};\n}\n\nfunction parseChainId(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"string\") return undefined;\n\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n if (trimmed.startsWith(\"0x\")) {\n const parsedHex = Number.parseInt(trimmed.slice(2), 16);\n return Number.isFinite(parsedHex) ? parsedHex : undefined;\n }\n\n const parsed = Number.parseInt(trimmed, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\n// =============================================================================\n// Normalization\n// =============================================================================\n\n/**\n * Normalize a wallet_tx_request payload into a consistent shape.\n * Returns `null` if the payload is missing the required `to` field.\n */\nexport function normalizeTxPayload(payload: unknown): WalletTxPayload | null {\n const root = asRecord(payload);\n const args = getToolArgs(payload);\n const ctx = asRecord(root?.ctx);\n\n const to = typeof args.to === \"string\" ? args.to : undefined;\n if (!to) return null;\n\n const valueRaw = args.value;\n const value =\n typeof valueRaw === \"string\"\n ? valueRaw\n : typeof valueRaw === \"number\" && Number.isFinite(valueRaw)\n ? String(Math.trunc(valueRaw))\n : undefined;\n\n const data = typeof args.data === \"string\" ? args.data : undefined;\n const chainId =\n parseChainId(args.chainId) ??\n parseChainId(args.chain_id) ??\n parseChainId(ctx?.user_chain_id) ??\n parseChainId(ctx?.userChainId);\n\n return { to, value, data, chainId };\n}\n\n/**\n * Normalize an EIP-712 signing request payload.\n */\nexport function normalizeEip712Payload(\n payload: unknown,\n): WalletEip712Payload {\n const args = getToolArgs(payload);\n const typedDataRaw = args.typed_data ?? args.typedData;\n let typedData: WalletEip712Payload[\"typed_data\"] | undefined;\n\n if (typeof typedDataRaw === \"string\") {\n try {\n const parsed = JSON.parse(typedDataRaw) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n typedData = parsed as WalletEip712Payload[\"typed_data\"];\n }\n } catch {\n typedData = undefined;\n }\n } else if (\n typedDataRaw &&\n typeof typedDataRaw === \"object\" &&\n !Array.isArray(typedDataRaw)\n ) {\n typedData = typedDataRaw as WalletEip712Payload[\"typed_data\"];\n }\n\n const description =\n typeof args.description === \"string\" ? args.description : undefined;\n\n return { typed_data: typedData, description };\n}\n","// =============================================================================\n// Session — High-level orchestrated client\n// =============================================================================\n//\n// Wraps AomiClient with polling, event dispatch, and wallet request management.\n// Ported from the React runtime (polling-controller, event-context, wallet-handler).\n//\n// Usage:\n// const session = new Session({ baseUrl: \"https://api.aomi.dev\" });\n// session.on(\"wallet_tx_request\", async (req) => {\n// const signed = await signer.signTransaction(req.payload);\n// await session.resolve(req.id, { txHash: signed.hash });\n// });\n// const result = await session.send(\"swap 1 ETH for USDC\");\n// session.close();\n\nimport { AomiClient } from \"./client\";\nimport type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n UserState,\n} from \"./types\";\nimport { TypedEventEmitter } from \"./event-emitter\";\nimport { unwrapSystemEvent } from \"./event-unwrap\";\nimport {\n normalizeTxPayload,\n normalizeEip712Payload,\n type WalletTxPayload,\n type WalletEip712Payload,\n} from \"./wallet-utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletRequestKind = \"transaction\" | \"eip712_sign\";\n\nexport type WalletRequest = {\n id: string;\n kind: WalletRequestKind;\n payload: WalletTxPayload | WalletEip712Payload;\n timestamp: number;\n};\n\nexport type WalletRequestResult = {\n txHash?: string;\n signature?: string;\n amount?: string;\n};\n\nexport type SendResult = {\n messages: AomiMessage[];\n title?: string;\n};\n\nexport type SessionOptions = {\n /** Session ID. Auto-generated (crypto.randomUUID) if omitted. */\n sessionId?: string;\n /** Namespace for chat messages. Default: \"default\" */\n namespace?: string;\n /** User public key (wallet address). */\n publicKey?: string;\n /** API key override. */\n apiKey?: string;\n /** User state to send with requests (wallet connection info, etc). */\n userState?: UserState;\n /** Polling interval in ms. Default: 500 */\n pollIntervalMs?: number;\n /** Logger for debug output. Pass `console` for verbose logging. */\n logger?: { debug: (...args: unknown[]) => void };\n};\n\n/** Events emitted by Session. */\nexport type SessionEventMap = {\n /** A transaction signing request arrived from the backend. */\n wallet_tx_request: WalletRequest;\n /** An EIP-712 signing request arrived from the backend. */\n wallet_eip712_request: WalletRequest;\n /** A system notice from the backend. */\n system_notice: { message: string };\n /** A system error from the backend. */\n system_error: { message: string };\n /** An async callback event. */\n async_callback: Record<string, unknown>;\n /** SSE: tool execution in progress. */\n tool_update: AomiSSEEvent;\n /** SSE: tool execution completed. */\n tool_complete: AomiSSEEvent;\n /** Session title changed. */\n title_changed: { title: string };\n /** Messages updated (new messages from poll or send response). */\n messages: AomiMessage[];\n /** AI started processing. */\n processing_start: undefined;\n /** AI finished processing. */\n processing_end: undefined;\n /** An error occurred during polling or SSE. */\n error: { error: unknown };\n /** Wildcard: receives all events as { type, payload }. */\n \"*\": { type: string; payload: unknown };\n};\n\n// =============================================================================\n// Session Class\n// =============================================================================\n\nexport class Session extends TypedEventEmitter<SessionEventMap> {\n /** The underlying low-level client. */\n readonly client: AomiClient;\n /** The session (thread) ID. */\n readonly sessionId: string;\n\n private namespace: string;\n private publicKey?: string;\n private apiKey?: string;\n private userState?: UserState;\n private pollIntervalMs: number;\n private logger?: { debug: (...args: unknown[]) => void };\n\n // Internal state\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private unsubscribeSSE: (() => void) | null = null;\n private _isProcessing = false;\n private walletRequests: WalletRequest[] = [];\n private walletRequestNextId = 1;\n private _messages: AomiMessage[] = [];\n private _title?: string;\n private closed = false;\n\n // For send() blocking behavior\n private pendingResolve: ((result: SendResult) => void) | null = null;\n\n constructor(\n clientOrOptions: AomiClient | AomiClientOptions,\n sessionOptions?: SessionOptions,\n ) {\n super();\n\n this.client =\n clientOrOptions instanceof AomiClient\n ? clientOrOptions\n : new AomiClient(clientOrOptions);\n\n this.sessionId = sessionOptions?.sessionId ?? crypto.randomUUID();\n this.namespace = sessionOptions?.namespace ?? \"default\";\n this.publicKey = sessionOptions?.publicKey;\n this.apiKey = sessionOptions?.apiKey;\n this.userState = sessionOptions?.userState;\n this.pollIntervalMs = sessionOptions?.pollIntervalMs ?? 500;\n this.logger = sessionOptions?.logger;\n\n // Start SSE subscription\n this.unsubscribeSSE = this.client.subscribeSSE(\n this.sessionId,\n (event) => this.handleSSEEvent(event),\n (error) => this.emit(\"error\", { error }),\n );\n }\n\n // ===========================================================================\n // Public API — Chat\n // ===========================================================================\n\n /**\n * Send a message and wait for the AI to finish processing.\n *\n * The returned promise resolves when `is_processing` becomes `false` AND\n * there are no pending wallet requests. If a wallet request arrives\n * mid-processing, polling continues but the promise pauses until the\n * request is resolved or rejected via `resolve()` / `reject()`.\n */\n async send(message: string): Promise<SendResult> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n namespace: this.namespace,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.applyState(response);\n\n if (!response.is_processing && this.walletRequests.length === 0) {\n return { messages: this._messages, title: this._title };\n }\n\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n\n return new Promise<SendResult>((resolve) => {\n this.pendingResolve = resolve;\n this.startPolling();\n });\n }\n\n /**\n * Send a message without waiting for completion.\n * Polling starts in the background; listen to events for updates.\n */\n async sendAsync(message: string): Promise<AomiChatResponse> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n namespace: this.namespace,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.applyState(response);\n\n if (response.is_processing) {\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n this.startPolling();\n }\n\n return response;\n }\n\n // ===========================================================================\n // Public API — Wallet Request Resolution\n // ===========================================================================\n\n /**\n * Resolve a pending wallet request (transaction or EIP-712 signing).\n * Sends the result to the backend and resumes polling.\n */\n async resolve(requestId: string, result: WalletRequestResult): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: result.txHash ?? \"\",\n status: \"success\",\n amount: result.amount,\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"success\",\n signature: result.signature,\n description: eip712Payload.description,\n });\n }\n\n // Resume polling if still processing\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n /**\n * Reject a pending wallet request.\n * Sends an error to the backend and resumes polling.\n */\n async reject(requestId: string, reason?: string): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: \"\",\n status: \"failed\",\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"failed\",\n error: reason ?? \"Request rejected\",\n description: eip712Payload.description,\n });\n }\n\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n // ===========================================================================\n // Public API — Control\n // ===========================================================================\n\n /**\n * Cancel the AI's current response.\n */\n async interrupt(): Promise<void> {\n this.stopPolling();\n const response = await this.client.interrupt(this.sessionId);\n this.applyState(response);\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n\n /**\n * Close the session. Stops polling, unsubscribes SSE, removes all listeners.\n * The session cannot be used after closing.\n */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopPolling();\n this.unsubscribeSSE?.();\n this.unsubscribeSSE = null;\n this.resolvePending();\n this.removeAllListeners();\n }\n\n // ===========================================================================\n // Public API — Accessors\n // ===========================================================================\n\n /** Current messages in the session. */\n getMessages(): AomiMessage[] {\n return this._messages;\n }\n\n /** Current session title. */\n getTitle(): string | undefined {\n return this._title;\n }\n\n /** Pending wallet requests waiting for resolve/reject. */\n getPendingRequests(): WalletRequest[] {\n return [...this.walletRequests];\n }\n\n /** Whether the AI is currently processing. */\n getIsProcessing(): boolean {\n return this._isProcessing;\n }\n\n // ===========================================================================\n // Internal — Polling (ported from PollingController)\n // ===========================================================================\n\n private startPolling(): void {\n if (this.pollTimer || this.closed) return;\n\n this.logger?.debug(\"[session] polling started\", this.sessionId);\n this.pollTimer = setInterval(() => {\n void this.pollTick();\n }, this.pollIntervalMs);\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n this.logger?.debug(\"[session] polling stopped\", this.sessionId);\n }\n }\n\n private async pollTick(): Promise<void> {\n if (!this.pollTimer) return;\n\n try {\n const state = await this.client.fetchState(\n this.sessionId,\n this.userState,\n );\n\n // Guard: polling may have been stopped while awaiting fetch\n if (!this.pollTimer) return;\n\n this.applyState(state);\n\n if (!state.is_processing && this.walletRequests.length === 0) {\n this.stopPolling();\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n } catch (error) {\n this.logger?.debug(\"[session] poll error\", error);\n this.emit(\"error\", { error });\n }\n }\n\n // ===========================================================================\n // Internal — State Application\n // ===========================================================================\n\n private applyState(\n state: Pick<\n AomiStateResponse,\n \"messages\" | \"system_events\" | \"title\" | \"is_processing\"\n >,\n ): void {\n if (state.messages) {\n this._messages = state.messages;\n this.emit(\"messages\", this._messages);\n }\n\n if (state.title) {\n this._title = state.title;\n }\n\n if (state.system_events?.length) {\n this.dispatchSystemEvents(state.system_events);\n }\n }\n\n private dispatchSystemEvents(events: AomiSystemEvent[]): void {\n for (const event of events) {\n const unwrapped = unwrapSystemEvent(event);\n if (!unwrapped) continue;\n\n if (unwrapped.type === \"wallet_tx_request\") {\n const payload = normalizeTxPayload(unwrapped.payload);\n if (payload) {\n const req = this.enqueueWalletRequest(\"transaction\", payload);\n this.emit(\"wallet_tx_request\", req);\n }\n } else if (unwrapped.type === \"wallet_eip712_request\") {\n const payload = normalizeEip712Payload(unwrapped.payload ?? {});\n const req = this.enqueueWalletRequest(\"eip712_sign\", payload);\n this.emit(\"wallet_eip712_request\", req);\n } else if (\n unwrapped.type === \"system_notice\" ||\n unwrapped.type === \"system_error\" ||\n unwrapped.type === \"async_callback\"\n ) {\n // These match known event map keys — emit directly\n this.emit(\n unwrapped.type as keyof SessionEventMap,\n unwrapped.payload as never,\n );\n }\n }\n }\n\n // ===========================================================================\n // Internal — SSE Handling\n // ===========================================================================\n\n private handleSSEEvent(event: AomiSSEEvent): void {\n if (event.type === \"title_changed\" && event.new_title) {\n this._title = event.new_title;\n this.emit(\"title_changed\", { title: event.new_title });\n } else if (event.type === \"tool_update\") {\n this.emit(\"tool_update\", event);\n } else if (event.type === \"tool_complete\") {\n this.emit(\"tool_complete\", event);\n }\n }\n\n // ===========================================================================\n // Internal — Wallet Request Queue\n // ===========================================================================\n\n private enqueueWalletRequest(\n kind: WalletRequestKind,\n payload: WalletTxPayload | WalletEip712Payload,\n ): WalletRequest {\n const req: WalletRequest = {\n id: `wreq-${this.walletRequestNextId++}`,\n kind,\n payload,\n timestamp: Date.now(),\n };\n this.walletRequests.push(req);\n return req;\n }\n\n private removeWalletRequest(id: string): WalletRequest | null {\n const idx = this.walletRequests.findIndex((r) => r.id === id);\n if (idx === -1) return null;\n return this.walletRequests.splice(idx, 1)[0];\n }\n\n // ===========================================================================\n // Internal — Helpers\n // ===========================================================================\n\n private async sendSystemEvent(\n type: string,\n payload: unknown,\n ): Promise<void> {\n const message = JSON.stringify({ type, payload });\n await this.client.sendSystemMessage(this.sessionId, message);\n }\n\n private resolvePending(): void {\n if (this.pendingResolve) {\n const resolve = this.pendingResolve;\n this.pendingResolve = null;\n resolve({ messages: this._messages, title: this._title });\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"Session is closed\");\n }\n }\n}\n"],"mappings":"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","names":["_a"]}
1
+ {"version":3,"sources":["../src/sse.ts","../src/client.ts","../src/types.ts","../src/event-emitter.ts","../src/event-unwrap.ts","../src/wallet-utils.ts","../src/session.ts"],"sourcesContent":["import type { AomiSSEEvent, Logger } from \"./types\";\n\nexport type SseSubscriber = {\n subscribe: (\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ) => () => void;\n};\n\nexport type SseSubscriberOptions = {\n backendUrl: string;\n getHeaders: (sessionId: string) => HeadersInit;\n logger?: Logger;\n};\n\ntype SseSubscription = {\n abortController: AbortController | null;\n retries: number;\n retryTimer: ReturnType<typeof setTimeout> | null;\n stopped: boolean;\n listeners: Set<SseListener>;\n stop: (reason?: string) => void;\n};\n\ntype SseListener = {\n onUpdate: (event: AomiSSEEvent) => void;\n onError?: (error: unknown) => void;\n};\n\nfunction extractSseData(rawEvent: string): string | null {\n const dataLines = rawEvent\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart());\n if (!dataLines.length) return null;\n return dataLines.join(\"\\n\");\n}\n\nasync function readSseStream(\n stream: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n onMessage: (data: string) => void,\n): Promise<void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (!signal.aborted) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n buffer = buffer.replace(/\\r/g, \"\");\n\n let separatorIndex = buffer.indexOf(\"\\n\\n\");\n while (separatorIndex >= 0) {\n const rawEvent = buffer.slice(0, separatorIndex);\n buffer = buffer.slice(separatorIndex + 2);\n const data = extractSseData(rawEvent);\n if (data) {\n onMessage(data);\n }\n separatorIndex = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function createSseSubscriber({\n backendUrl,\n getHeaders,\n logger,\n}: SseSubscriberOptions): SseSubscriber {\n const subscriptions = new Map<string, SseSubscription>();\n\n const subscribe: SseSubscriber[\"subscribe\"] = (\n sessionId,\n onUpdate,\n onError,\n ) => {\n const existing = subscriptions.get(sessionId);\n const listener: SseListener = { onUpdate, onError };\n if (existing) {\n existing.listeners.add(listener);\n logger?.debug(\"[aomi][sse] listener added\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n return () => {\n existing.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n if (existing.listeners.size === 0) {\n existing.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === existing) {\n subscriptions.delete(sessionId);\n }\n }\n };\n }\n\n const subscription: SseSubscription = {\n abortController: null,\n retries: 0,\n retryTimer: null,\n stopped: false,\n listeners: new Set([listener]),\n stop: (reason?: string) => {\n subscription.stopped = true;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n subscription.abortController?.abort();\n subscription.abortController = null;\n logger?.debug(\"[aomi][sse] stop\", {\n sessionId,\n reason,\n retries: subscription.retries,\n });\n },\n };\n\n const scheduleRetry = () => {\n if (subscription.stopped) return;\n subscription.retries += 1;\n const delayMs = Math.min(500 * 2 ** (subscription.retries - 1), 10000);\n logger?.debug(\"[aomi][sse] retry scheduled\", {\n sessionId,\n delayMs,\n retries: subscription.retries,\n });\n subscription.retryTimer = setTimeout(() => {\n void open();\n }, delayMs);\n };\n\n const open = async () => {\n if (subscription.stopped) return;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n\n const controller = new AbortController();\n subscription.abortController = controller;\n const openedAt = Date.now();\n\n try {\n const response = await fetch(`${backendUrl}/api/updates`, {\n headers: getHeaders(sessionId),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(\n `SSE HTTP ${response.status}: ${response.statusText}`,\n );\n }\n\n if (!response.body) {\n throw new Error(\"SSE response missing body\");\n }\n\n subscription.retries = 0;\n\n await readSseStream(response.body, controller.signal, (data) => {\n let parsed: AomiSSEEvent;\n try {\n parsed = JSON.parse(data) as AomiSSEEvent;\n } catch (error) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n return;\n }\n\n for (const item of subscription.listeners) {\n try {\n item.onUpdate(parsed);\n } catch (error) {\n item.onError?.(error);\n }\n }\n });\n logger?.debug(\"[aomi][sse] stream ended\", {\n sessionId,\n aborted: controller.signal.aborted,\n stopped: subscription.stopped,\n durationMs: Date.now() - openedAt,\n });\n } catch (error) {\n if (!controller.signal.aborted && !subscription.stopped) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n }\n }\n\n if (!subscription.stopped) {\n scheduleRetry();\n }\n };\n\n subscriptions.set(sessionId, subscription);\n void open();\n\n return () => {\n subscription.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: subscription.listeners.size,\n });\n if (subscription.listeners.size === 0) {\n subscription.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === subscription) {\n subscriptions.delete(sessionId);\n }\n }\n };\n };\n\n return { subscribe };\n}\n","import type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiCreateThreadResponse,\n AomiInterruptResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n AomiSystemResponse,\n AomiThread,\n Logger,\n UserState,\n} from \"./types\";\nimport { createSseSubscriber, type SseSubscriber } from \"./sse\";\n\n// =============================================================================\n// Internal helpers\n// =============================================================================\n\nconst SESSION_ID_HEADER = \"X-Session-Id\";\nconst API_KEY_HEADER = \"X-API-Key\";\n\nfunction toQueryString(payload: Record<string, unknown>): string {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined || value === null) continue;\n params.set(key, String(value));\n }\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nfunction withSessionHeader(\n sessionId: string,\n init?: HeadersInit,\n): HeadersInit {\n const headers = new Headers(init);\n headers.set(SESSION_ID_HEADER, sessionId);\n return headers;\n}\n\nasync function postState<T>(\n baseUrl: string,\n path: string,\n payload: Record<string, unknown>,\n sessionId: string,\n apiKey?: string,\n): Promise<T> {\n const query = toQueryString(payload);\n const url = `${baseUrl}${path}${query}`;\n\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as T;\n}\n\n// =============================================================================\n// AomiClient\n// =============================================================================\n\nexport class AomiClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly logger?: Logger;\n private readonly sseSubscriber: SseSubscriber;\n\n constructor(options: AomiClientOptions) {\n // Strip trailing slash\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.logger = options.logger;\n\n this.sseSubscriber = createSseSubscriber({\n backendUrl: this.baseUrl,\n getHeaders: (sessionId) =>\n withSessionHeader(sessionId, { Accept: \"text/event-stream\" }),\n logger: this.logger,\n });\n }\n\n // ===========================================================================\n // Chat & State\n // ===========================================================================\n\n /**\n * Fetch current session state (messages, processing status, title).\n */\n async fetchState(\n sessionId: string,\n userState?: UserState,\n ): Promise<AomiStateResponse> {\n const url = new URL(\"/api/state\", this.baseUrl);\n if (userState) {\n url.searchParams.set(\"user_state\", JSON.stringify(userState));\n }\n\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiStateResponse;\n }\n\n /**\n * Send a chat message and return updated session state.\n */\n async sendMessage(\n sessionId: string,\n message: string,\n options?: {\n app?: string;\n publicKey?: string;\n apiKey?: string;\n userState?: UserState;\n },\n ): Promise<AomiChatResponse> {\n const app = options?.app ?? \"default\";\n const apiKey = options?.apiKey ?? this.apiKey;\n\n const payload: Record<string, unknown> = { message, app };\n if (options?.publicKey) {\n payload.public_key = options.publicKey;\n }\n if (options?.userState) {\n payload.user_state = JSON.stringify(options.userState);\n }\n\n return postState<AomiChatResponse>(\n this.baseUrl,\n \"/api/chat\",\n payload,\n sessionId,\n apiKey,\n );\n }\n\n /**\n * Send a system-level message (e.g. wallet state changes, context switches).\n */\n async sendSystemMessage(\n sessionId: string,\n message: string,\n ): Promise<AomiSystemResponse> {\n return postState<AomiSystemResponse>(\n this.baseUrl,\n \"/api/system\",\n { message },\n sessionId,\n );\n }\n\n /**\n * Interrupt the AI's current response.\n */\n async interrupt(sessionId: string): Promise<AomiInterruptResponse> {\n return postState<AomiInterruptResponse>(\n this.baseUrl,\n \"/api/interrupt\",\n {},\n sessionId,\n );\n }\n\n // ===========================================================================\n // SSE (Real-time Updates)\n // ===========================================================================\n\n /**\n * Subscribe to real-time SSE updates for a session.\n * Automatically reconnects with exponential backoff on disconnects.\n * Returns an unsubscribe function.\n */\n subscribeSSE(\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ): () => void {\n return this.sseSubscriber.subscribe(sessionId, onUpdate, onError);\n }\n\n // ===========================================================================\n // Thread / Session Management\n // ===========================================================================\n\n /**\n * List all threads for a wallet address.\n */\n async listThreads(publicKey: string): Promise<AomiThread[]> {\n const url = `${this.baseUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch threads: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiThread[];\n }\n\n /**\n * Get a single thread by ID.\n */\n async getThread(sessionId: string): Promise<AomiThread> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiThread;\n }\n\n /**\n * Create a new thread. The client generates the session ID.\n */\n async createThread(\n threadId: string,\n publicKey?: string,\n ): Promise<AomiCreateThreadResponse> {\n const body: Record<string, string> = {};\n if (publicKey) body.public_key = publicKey;\n\n const url = `${this.baseUrl}/api/sessions`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(threadId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create thread: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiCreateThreadResponse;\n }\n\n /**\n * Delete a thread by ID.\n */\n async deleteThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to delete thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Rename a thread.\n */\n async renameThread(sessionId: string, newTitle: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: withSessionHeader(sessionId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify({ title: newTitle }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to rename thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Archive a thread.\n */\n async archiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to archive thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Unarchive a thread.\n */\n async unarchiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to unarchive thread: HTTP ${response.status}`);\n }\n }\n\n // ===========================================================================\n // System Events\n // ===========================================================================\n\n /**\n * Get system events for a session.\n */\n async getSystemEvents(\n sessionId: string,\n count?: number,\n ): Promise<AomiSystemEvent[]> {\n const url = new URL(\"/api/events\", this.baseUrl);\n if (count !== undefined) {\n url.searchParams.set(\"count\", String(count));\n }\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n if (response.status === 404) return [];\n throw new Error(`Failed to get system events: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiSystemEvent[];\n }\n\n // ===========================================================================\n // Control API\n // ===========================================================================\n\n /**\n * Get available apps.\n */\n async getApps(\n sessionId: string,\n options?: { publicKey?: string; apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/apps\", this.baseUrl);\n if (options?.publicKey) {\n url.searchParams.set(\"public_key\", options.publicKey);\n }\n\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to get apps: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Get available models.\n */\n async getModels(\n sessionId: string,\n options?: { apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/models\", this.baseUrl);\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), {\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get models: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Set the model for a session.\n */\n async setModel(\n sessionId: string,\n rig: string,\n options?: { app?: string; apiKey?: string },\n ): Promise<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }> {\n const apiKey = options?.apiKey ?? this.apiKey;\n const payload: Record<string, unknown> = { rig };\n if (options?.app) {\n payload.app = options.app;\n }\n\n return postState<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }>(this.baseUrl, \"/api/control/model\", payload, sessionId, apiKey);\n }\n}\n","// =============================================================================\n// User State\n// =============================================================================\n\n/**\n * Client-side user state synced with the backend.\n * Typically wallet connection info, but can be any key-value data.\n */\nexport type UserState = Record<string, unknown>;\n\n// =============================================================================\n// Logger\n// =============================================================================\n\n/**\n * Optional logger for debug output. Pass `console` or any compatible object.\n */\nexport type Logger = {\n debug: (...args: unknown[]) => void;\n};\n\n// =============================================================================\n// Client Options\n// =============================================================================\n\nexport type AomiClientOptions = {\n /** Base URL of the Aomi backend (e.g. \"https://aomi.dev\") */\n baseUrl: string;\n /** Default API key for non-default apps */\n apiKey?: string;\n /** Optional logger for debug output (default: silent) */\n logger?: Logger;\n};\n\n// =============================================================================\n// Base Types\n// =============================================================================\n\nexport interface AomiMessage {\n sender?: \"user\" | \"agent\" | \"system\" | string;\n content?: string;\n timestamp?: string;\n is_streaming?: boolean;\n tool_result?: [string, string] | null;\n}\n\n// =============================================================================\n// API Response Types\n// =============================================================================\n\n/**\n * GET /api/state\n * Fetches current session state including messages and processing status\n */\nexport interface AomiStateResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n user_state?: UserState | null;\n}\n\n/**\n * POST /api/chat\n * Sends a chat message and returns updated session state\n */\nexport interface AomiChatResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n user_state?: UserState | null;\n}\n\n/**\n * POST /api/system\n * Sends a system message and returns the response message\n */\nexport interface AomiSystemResponse {\n res?: AomiMessage | null;\n}\n\n/**\n * POST /api/interrupt\n * Interrupts current processing and returns updated session state\n */\nexport type AomiInterruptResponse = AomiChatResponse;\n\n/**\n * GET /api/sessions\n * Returns array of AomiThread\n */\nexport interface AomiThread {\n session_id: string;\n title: string;\n is_archived?: boolean;\n}\n\n/**\n * POST /api/sessions\n * Creates a new thread/session\n */\nexport interface AomiCreateThreadResponse {\n session_id: string;\n title?: string;\n}\n\n// =============================================================================\n// SSE Event Types (/api/updates)\n// =============================================================================\n\n/**\n * Base SSE event - all events have session_id and type\n */\nexport type AomiSSEEvent = {\n type:\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\"\n | string;\n session_id: string;\n new_title?: string;\n [key: string]: unknown;\n};\n\nexport type AomiSSEEventType =\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\";\n\n// =============================================================================\n// System Events (/api/events)\n// =============================================================================\n\n/**\n * Backend SystemEvent enum serializes as tagged JSON:\n * - InlineCall: {\"InlineCall\": {\"type\": \"wallet_tx_request\", \"payload\": {...}}}\n * - SystemNotice: {\"SystemNotice\": \"message\"}\n * - SystemError: {\"SystemError\": \"message\"}\n * - AsyncCallback: {\"AsyncCallback\": {...}} (not sent over HTTP)\n */\nexport type AomiSystemEvent =\n | { InlineCall: { type: string; payload?: unknown; [key: string]: unknown } }\n | { SystemNotice: string }\n | { SystemError: string }\n | { AsyncCallback: Record<string, unknown> };\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isInlineCall(\n event: AomiSystemEvent,\n): event is { InlineCall: { type: string; payload?: unknown } } {\n return \"InlineCall\" in event;\n}\n\nexport function isSystemNotice(\n event: AomiSystemEvent,\n): event is { SystemNotice: string } {\n return \"SystemNotice\" in event;\n}\n\nexport function isSystemError(\n event: AomiSystemEvent,\n): event is { SystemError: string } {\n return \"SystemError\" in event;\n}\n\nexport function isAsyncCallback(\n event: AomiSystemEvent,\n): event is { AsyncCallback: Record<string, unknown> } {\n return \"AsyncCallback\" in event;\n}\n","// =============================================================================\n// Typed EventEmitter (browser-safe, no Node.js deps)\n// =============================================================================\n\ntype Listener<T = unknown> = (payload: T) => void;\n\n/**\n * Minimal typed event emitter with wildcard support.\n *\n * ```ts\n * type Events = { message: string; error: { code: number } };\n * const ee = new TypedEventEmitter<Events>();\n * ee.on(\"message\", (msg) => console.log(msg));\n * ee.emit(\"message\", \"hello\");\n * ```\n */\nexport class TypedEventEmitter<\n EventMap extends Record<string, unknown> = Record<string, unknown>,\n> {\n private listeners = new Map<string, Set<Listener<never>>>();\n\n /**\n * Subscribe to an event type. Returns an unsubscribe function.\n */\n on<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(handler as Listener<never>);\n\n return () => {\n set!.delete(handler as Listener<never>);\n if (set!.size === 0) {\n this.listeners.delete(type);\n }\n };\n }\n\n /**\n * Subscribe to an event type for a single emission, then auto-unsubscribe.\n */\n once<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n const wrapper = ((payload: EventMap[K]) => {\n unsub();\n handler(payload);\n }) as Listener<EventMap[K]>;\n\n const unsub = this.on(type, wrapper);\n return unsub;\n }\n\n /**\n * Emit an event to all listeners of `type` and wildcard `\"*\"` listeners.\n */\n emit<K extends keyof EventMap & string>(\n type: K,\n payload: EventMap[K],\n ): void {\n // Type-specific listeners\n const typeSet = this.listeners.get(type);\n if (typeSet) {\n for (const handler of typeSet) {\n (handler as Listener<EventMap[K]>)(payload);\n }\n }\n\n // Wildcard listeners\n if (type !== \"*\") {\n const wildcardSet = this.listeners.get(\"*\");\n if (wildcardSet) {\n for (const handler of wildcardSet) {\n (handler as Listener<unknown>)({ type, payload });\n }\n }\n }\n }\n\n /**\n * Remove a specific handler from an event type.\n */\n off<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): void {\n const set = this.listeners.get(type);\n if (set) {\n set.delete(handler as Listener<never>);\n if (set.size === 0) {\n this.listeners.delete(type);\n }\n }\n }\n\n /**\n * Remove all listeners for all event types.\n */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","// =============================================================================\n// System Event Unwrap\n// =============================================================================\n//\n// Converts tagged-enum AomiSystemEvent into a flat { type, payload } object.\n// Ported from packages/react/src/contexts/event-context.tsx dispatchSystemEvents.\n\nimport type { AomiSystemEvent } from \"./types\";\nimport {\n isInlineCall,\n isSystemNotice,\n isSystemError,\n isAsyncCallback,\n} from \"./types\";\n\nexport type UnwrappedEvent = {\n type: string;\n payload: unknown;\n};\n\n/**\n * Unwrap a tagged-enum AomiSystemEvent from the backend into a flat event.\n *\n * ```ts\n * const event: AomiSystemEvent = { InlineCall: { type: \"wallet_tx_request\", payload: { to: \"0x...\" } } };\n * const unwrapped = unwrapSystemEvent(event);\n * // => { type: \"wallet_tx_request\", payload: { to: \"0x...\" } }\n * ```\n */\nexport function unwrapSystemEvent(\n event: AomiSystemEvent,\n): UnwrappedEvent | null {\n if (isInlineCall(event)) {\n return {\n type: event.InlineCall.type,\n payload: event.InlineCall.payload ?? event.InlineCall,\n };\n }\n\n if (isSystemNotice(event)) {\n return {\n type: \"system_notice\",\n payload: { message: event.SystemNotice },\n };\n }\n\n if (isSystemError(event)) {\n return {\n type: \"system_error\",\n payload: { message: event.SystemError },\n };\n }\n\n if (isAsyncCallback(event)) {\n return {\n type: \"async_callback\",\n payload: event.AsyncCallback,\n };\n }\n\n return null;\n}\n","// =============================================================================\n// Wallet Payload Normalization\n// =============================================================================\n//\n// Pure functions extracted from packages/react/src/handlers/wallet-handler.ts.\n// Normalizes the various payload shapes the backend can send for wallet\n// transaction and EIP-712 signing requests.\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletTxPayload = {\n to: string;\n value?: string;\n data?: string;\n chainId?: number;\n};\n\nexport type WalletEip712Payload = {\n typed_data?: {\n domain?: { chainId?: number | string };\n types?: Record<string, Array<{ name: string; type: string }>>;\n primaryType?: string;\n message?: Record<string, unknown>;\n };\n description?: string;\n};\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\ntype UnknownRecord = Record<string, unknown>;\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UnknownRecord;\n}\n\nfunction getToolArgs(payload: unknown): UnknownRecord {\n const root = asRecord(payload);\n const nestedArgs = asRecord(root?.args);\n return nestedArgs ?? root ?? {};\n}\n\nfunction parseChainId(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"string\") return undefined;\n\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n if (trimmed.startsWith(\"0x\")) {\n const parsedHex = Number.parseInt(trimmed.slice(2), 16);\n return Number.isFinite(parsedHex) ? parsedHex : undefined;\n }\n\n const parsed = Number.parseInt(trimmed, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\n// =============================================================================\n// Normalization\n// =============================================================================\n\n/**\n * Normalize a wallet_tx_request payload into a consistent shape.\n * Returns `null` if the payload is missing the required `to` field.\n */\nexport function normalizeTxPayload(payload: unknown): WalletTxPayload | null {\n const root = asRecord(payload);\n const args = getToolArgs(payload);\n const ctx = asRecord(root?.ctx);\n\n const to = typeof args.to === \"string\" ? args.to : undefined;\n if (!to) return null;\n\n const valueRaw = args.value;\n const value =\n typeof valueRaw === \"string\"\n ? valueRaw\n : typeof valueRaw === \"number\" && Number.isFinite(valueRaw)\n ? String(Math.trunc(valueRaw))\n : undefined;\n\n const data = typeof args.data === \"string\" ? args.data : undefined;\n const chainId =\n parseChainId(args.chainId) ??\n parseChainId(args.chain_id) ??\n parseChainId(ctx?.user_chain_id) ??\n parseChainId(ctx?.userChainId);\n\n return { to, value, data, chainId };\n}\n\n/**\n * Normalize an EIP-712 signing request payload.\n */\nexport function normalizeEip712Payload(\n payload: unknown,\n): WalletEip712Payload {\n const args = getToolArgs(payload);\n const typedDataRaw = args.typed_data ?? args.typedData;\n let typedData: WalletEip712Payload[\"typed_data\"] | undefined;\n\n if (typeof typedDataRaw === \"string\") {\n try {\n const parsed = JSON.parse(typedDataRaw) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n typedData = parsed as WalletEip712Payload[\"typed_data\"];\n }\n } catch {\n typedData = undefined;\n }\n } else if (\n typedDataRaw &&\n typeof typedDataRaw === \"object\" &&\n !Array.isArray(typedDataRaw)\n ) {\n typedData = typedDataRaw as WalletEip712Payload[\"typed_data\"];\n }\n\n const description =\n typeof args.description === \"string\" ? args.description : undefined;\n\n return { typed_data: typedData, description };\n}\n","// =============================================================================\n// Session — High-level orchestrated client\n// =============================================================================\n//\n// Wraps AomiClient with polling, event dispatch, and wallet request management.\n// Ported from the React runtime (polling-controller, event-context, wallet-handler).\n//\n// Usage:\n// const session = new Session({ baseUrl: \"https://api.aomi.dev\" });\n// session.on(\"wallet_tx_request\", async (req) => {\n// const signed = await signer.signTransaction(req.payload);\n// await session.resolve(req.id, { txHash: signed.hash });\n// });\n// const result = await session.send(\"swap 1 ETH for USDC\");\n// session.close();\n\nimport { AomiClient } from \"./client\";\nimport type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n UserState,\n} from \"./types\";\nimport { TypedEventEmitter } from \"./event-emitter\";\nimport { unwrapSystemEvent } from \"./event-unwrap\";\nimport {\n normalizeTxPayload,\n normalizeEip712Payload,\n type WalletTxPayload,\n type WalletEip712Payload,\n} from \"./wallet-utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletRequestKind = \"transaction\" | \"eip712_sign\";\n\nexport type WalletRequest = {\n id: string;\n kind: WalletRequestKind;\n payload: WalletTxPayload | WalletEip712Payload;\n timestamp: number;\n};\n\nexport type WalletRequestResult = {\n txHash?: string;\n signature?: string;\n amount?: string;\n};\n\nexport type SendResult = {\n messages: AomiMessage[];\n title?: string;\n};\n\nfunction sortJson(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => sortJson(entry));\n }\n if (value && typeof value === \"object\") {\n return Object.keys(value as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, key) => {\n acc[key] = sortJson((value as Record<string, unknown>)[key]);\n return acc;\n }, {});\n }\n return value;\n}\n\nfunction isSubsetMatch(expected: unknown, actual: unknown): boolean {\n if (Array.isArray(expected)) {\n if (!Array.isArray(actual) || expected.length !== actual.length) {\n return false;\n }\n return expected.every((entry, index) =>\n isSubsetMatch(entry, actual[index]),\n );\n }\n\n if (expected && typeof expected === \"object\") {\n if (!actual || typeof actual !== \"object\" || Array.isArray(actual)) {\n return false;\n }\n\n return Object.entries(expected as Record<string, unknown>).every(\n ([key, value]) =>\n isSubsetMatch(value, (actual as Record<string, unknown>)[key]),\n );\n }\n\n return expected === actual;\n}\n\nexport type SessionOptions = {\n /** Session ID. Auto-generated (crypto.randomUUID) if omitted. */\n sessionId?: string;\n /** App for chat messages. Default: \"default\" */\n app?: string;\n /** User public key (wallet address). */\n publicKey?: string;\n /** API key override. */\n apiKey?: string;\n /** User state to send with requests (wallet connection info, etc). */\n userState?: UserState;\n /** Polling interval in ms. Default: 500 */\n pollIntervalMs?: number;\n /** Logger for debug output. Pass `console` for verbose logging. */\n logger?: { debug: (...args: unknown[]) => void };\n};\n\n/** Events emitted by Session. */\nexport type SessionEventMap = {\n /** A transaction signing request arrived from the backend. */\n wallet_tx_request: WalletRequest;\n /** An EIP-712 signing request arrived from the backend. */\n wallet_eip712_request: WalletRequest;\n /** A system notice from the backend. */\n system_notice: { message: string };\n /** A system error from the backend. */\n system_error: { message: string };\n /** An async callback event. */\n async_callback: Record<string, unknown>;\n /** SSE: tool execution in progress. */\n tool_update: AomiSSEEvent;\n /** SSE: tool execution completed. */\n tool_complete: AomiSSEEvent;\n /** Session title changed. */\n title_changed: { title: string };\n /** Messages updated (new messages from poll or send response). */\n messages: AomiMessage[];\n /** AI started processing. */\n processing_start: undefined;\n /** AI finished processing. */\n processing_end: undefined;\n /** An error occurred during polling or SSE. */\n error: { error: unknown };\n /** Wildcard: receives all events as { type, payload }. */\n \"*\": { type: string; payload: unknown };\n};\n\n// =============================================================================\n// Session Class\n// =============================================================================\n\nexport class ClientSession extends TypedEventEmitter<SessionEventMap> {\n /** The underlying low-level client. */\n readonly client: AomiClient;\n /** The session (thread) ID. */\n readonly sessionId: string;\n\n private app: string;\n private publicKey?: string;\n private apiKey?: string;\n private userState?: UserState;\n private pollIntervalMs: number;\n private logger?: { debug: (...args: unknown[]) => void };\n\n // Internal state\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private unsubscribeSSE: (() => void) | null = null;\n private _isProcessing = false;\n private walletRequests: WalletRequest[] = [];\n private walletRequestNextId = 1;\n private _messages: AomiMessage[] = [];\n private _title?: string;\n private closed = false;\n\n // For send() blocking behavior\n private pendingResolve: ((result: SendResult) => void) | null = null;\n\n constructor(\n clientOrOptions: AomiClient | AomiClientOptions,\n sessionOptions?: SessionOptions,\n ) {\n super();\n\n this.client =\n clientOrOptions instanceof AomiClient\n ? clientOrOptions\n : new AomiClient(clientOrOptions);\n\n this.sessionId = sessionOptions?.sessionId ?? crypto.randomUUID();\n this.app = sessionOptions?.app ?? \"default\";\n this.publicKey = sessionOptions?.publicKey;\n this.apiKey = sessionOptions?.apiKey;\n this.userState = sessionOptions?.userState;\n this.pollIntervalMs = sessionOptions?.pollIntervalMs ?? 500;\n this.logger = sessionOptions?.logger;\n\n // Start SSE subscription\n this.unsubscribeSSE = this.client.subscribeSSE(\n this.sessionId,\n (event) => this.handleSSEEvent(event),\n (error) => this.emit(\"error\", { error }),\n );\n }\n\n // ===========================================================================\n // Public API — Chat\n // ===========================================================================\n\n /**\n * Send a message and wait for the AI to finish processing.\n *\n * The returned promise resolves when `is_processing` becomes `false` AND\n * there are no pending wallet requests. If a wallet request arrives\n * mid-processing, polling continues but the promise pauses until the\n * request is resolved or rejected via `resolve()` / `reject()`.\n */\n async send(message: string): Promise<SendResult> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n app: this.app,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.assertUserStateAligned(response.user_state);\n this.applyState(response);\n\n if (!response.is_processing && this.walletRequests.length === 0) {\n return { messages: this._messages, title: this._title };\n }\n\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n\n return new Promise<SendResult>((resolve) => {\n this.pendingResolve = resolve;\n this.startPolling();\n });\n }\n\n /**\n * Send a message without waiting for completion.\n * Polling starts in the background; listen to events for updates.\n */\n async sendAsync(message: string): Promise<AomiChatResponse> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n app: this.app,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.assertUserStateAligned(response.user_state);\n this.applyState(response);\n\n if (response.is_processing) {\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n this.startPolling();\n }\n\n return response;\n }\n\n // ===========================================================================\n // Public API — Wallet Request Resolution\n // ===========================================================================\n\n /**\n * Resolve a pending wallet request (transaction or EIP-712 signing).\n * Sends the result to the backend and resumes polling.\n */\n async resolve(requestId: string, result: WalletRequestResult): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: result.txHash ?? \"\",\n status: \"success\",\n amount: result.amount,\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"success\",\n signature: result.signature,\n description: eip712Payload.description,\n });\n }\n\n // Resume polling if still processing\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n /**\n * Reject a pending wallet request.\n * Sends an error to the backend and resumes polling.\n */\n async reject(requestId: string, reason?: string): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: \"\",\n status: \"failed\",\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"failed\",\n error: reason ?? \"Request rejected\",\n description: eip712Payload.description,\n });\n }\n\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n // ===========================================================================\n // Public API — Control\n // ===========================================================================\n\n /**\n * Cancel the AI's current response.\n */\n async interrupt(): Promise<void> {\n this.stopPolling();\n const response = await this.client.interrupt(this.sessionId);\n this.applyState(response);\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n\n /**\n * Close the session. Stops polling, unsubscribes SSE, removes all listeners.\n * The session cannot be used after closing.\n */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopPolling();\n this.unsubscribeSSE?.();\n this.unsubscribeSSE = null;\n this.resolvePending();\n this.removeAllListeners();\n }\n\n // ===========================================================================\n // Public API — Accessors\n // ===========================================================================\n\n /** Current messages in the session. */\n getMessages(): AomiMessage[] {\n return this._messages;\n }\n\n /** Current session title. */\n getTitle(): string | undefined {\n return this._title;\n }\n\n /** Pending wallet requests waiting for resolve/reject. */\n getPendingRequests(): WalletRequest[] {\n return [...this.walletRequests];\n }\n\n /** Whether the AI is currently processing. */\n getIsProcessing(): boolean {\n return this._isProcessing;\n }\n\n resolveUserState(userState: UserState): void {\n this.userState = userState;\n\n const address = userState[\"address\"];\n if (typeof address === \"string\" && address.length > 0) {\n this.publicKey = address;\n }\n }\n\n resolveWallet(address: string, chainId?: number): void {\n this.resolveUserState({ address, chainId: chainId ?? 1, isConnected: true });\n }\n\n async syncUserState(): Promise<AomiStateResponse> {\n this.assertOpen();\n\n const state = await this.client.fetchState(this.sessionId, this.userState);\n this.assertUserStateAligned(state.user_state);\n this.applyState(state);\n return state;\n }\n\n // ===========================================================================\n // Internal — Polling (ported from PollingController)\n // ===========================================================================\n\n private startPolling(): void {\n if (this.pollTimer || this.closed) return;\n\n this.logger?.debug(\"[session] polling started\", this.sessionId);\n this.pollTimer = setInterval(() => {\n void this.pollTick();\n }, this.pollIntervalMs);\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n this.logger?.debug(\"[session] polling stopped\", this.sessionId);\n }\n }\n\n private async pollTick(): Promise<void> {\n if (!this.pollTimer) return;\n\n try {\n const state = await this.client.fetchState(\n this.sessionId,\n this.userState,\n );\n\n // Guard: polling may have been stopped while awaiting fetch\n if (!this.pollTimer) return;\n\n this.assertUserStateAligned(state.user_state);\n this.applyState(state);\n\n if (!state.is_processing && this.walletRequests.length === 0) {\n this.stopPolling();\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n } catch (error) {\n this.logger?.debug(\"[session] poll error\", error);\n this.emit(\"error\", { error });\n }\n }\n\n // ===========================================================================\n // Internal — State Application\n // ===========================================================================\n\n private applyState(\n state: Pick<\n AomiStateResponse,\n \"messages\" | \"system_events\" | \"title\" | \"is_processing\"\n >,\n ): void {\n if (state.messages) {\n this._messages = state.messages;\n this.emit(\"messages\", this._messages);\n }\n\n if (state.title) {\n this._title = state.title;\n }\n\n if (state.system_events?.length) {\n this.dispatchSystemEvents(state.system_events);\n }\n }\n\n private dispatchSystemEvents(events: AomiSystemEvent[]): void {\n for (const event of events) {\n const unwrapped = unwrapSystemEvent(event);\n if (!unwrapped) continue;\n\n if (unwrapped.type === \"wallet_tx_request\") {\n const payload = normalizeTxPayload(unwrapped.payload);\n if (payload) {\n const req = this.enqueueWalletRequest(\"transaction\", payload);\n this.emit(\"wallet_tx_request\", req);\n }\n } else if (unwrapped.type === \"wallet_eip712_request\") {\n const payload = normalizeEip712Payload(unwrapped.payload ?? {});\n const req = this.enqueueWalletRequest(\"eip712_sign\", payload);\n this.emit(\"wallet_eip712_request\", req);\n } else if (\n unwrapped.type === \"system_notice\" ||\n unwrapped.type === \"system_error\" ||\n unwrapped.type === \"async_callback\"\n ) {\n // These match known event map keys — emit directly\n this.emit(\n unwrapped.type as keyof SessionEventMap,\n unwrapped.payload as never,\n );\n }\n }\n }\n\n // ===========================================================================\n // Internal — SSE Handling\n // ===========================================================================\n\n private handleSSEEvent(event: AomiSSEEvent): void {\n if (event.type === \"title_changed\" && event.new_title) {\n this._title = event.new_title;\n this.emit(\"title_changed\", { title: event.new_title });\n } else if (event.type === \"tool_update\") {\n this.emit(\"tool_update\", event);\n } else if (event.type === \"tool_complete\") {\n this.emit(\"tool_complete\", event);\n }\n }\n\n // ===========================================================================\n // Internal — Wallet Request Queue\n // ===========================================================================\n\n private enqueueWalletRequest(\n kind: WalletRequestKind,\n payload: WalletTxPayload | WalletEip712Payload,\n ): WalletRequest {\n const req: WalletRequest = {\n id: `wreq-${this.walletRequestNextId++}`,\n kind,\n payload,\n timestamp: Date.now(),\n };\n this.walletRequests.push(req);\n return req;\n }\n\n private removeWalletRequest(id: string): WalletRequest | null {\n const idx = this.walletRequests.findIndex((r) => r.id === id);\n if (idx === -1) return null;\n return this.walletRequests.splice(idx, 1)[0];\n }\n\n // ===========================================================================\n // Internal — Helpers\n // ===========================================================================\n\n private async sendSystemEvent(\n type: string,\n payload: unknown,\n ): Promise<void> {\n const message = JSON.stringify({ type, payload });\n await this.client.sendSystemMessage(this.sessionId, message);\n }\n\n private resolvePending(): void {\n if (this.pendingResolve) {\n const resolve = this.pendingResolve;\n this.pendingResolve = null;\n resolve({ messages: this._messages, title: this._title });\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"Session is closed\");\n }\n }\n\n private assertUserStateAligned(actualUserState?: UserState | null): void {\n if (!this.userState) {\n return;\n }\n\n if (!actualUserState || !isSubsetMatch(this.userState, actualUserState)) {\n const expected = JSON.stringify(sortJson(this.userState));\n const actual = JSON.stringify(sortJson(actualUserState ?? null));\n throw new Error(\n `Backend user_state mismatch. expected subset=${expected} actual=${actual}`,\n );\n }\n }\n}\n"],"mappings":"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","names":["_a"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aomi-labs/client",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "description": "Platform-agnostic TypeScript client for the Aomi backend API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -7,7 +7,7 @@ description: >
7
7
  builds generic EVM transactions with speed and security natively on Ethereum
8
8
  light client. Handles multi-step workflows: chat with the agent, review pending
9
9
  transactions, sign and broadcast, then verify results.
10
- compatibility: "Requires @aomi-labs/client (`npm install -g @aomi-labs/client`). CLI executable is `aomi`. Set PRIVATE_KEY and CHAIN_RPC_URL for transaction signing."
10
+ compatibility: "Requires @aomi-labs/client (`npm install -g @aomi-labs/client`). CLI executable is `aomi`. Requires viem for signing (`npm install viem`). Set PRIVATE_KEY and CHAIN_RPC_URL env vars for transaction signing."
11
11
  license: MIT
12
12
  allowed-tools: Bash
13
13
  metadata:
@@ -19,14 +19,19 @@ metadata:
19
19
 
20
20
  Build and execute EVM transactions through a conversational AI agent.
21
21
 
22
- ## Setup
22
+ ## Preflight
23
23
 
24
- Before running any commands, verify the CLI is available:
24
+ On first use in a session, check the user's state:
25
25
 
26
26
  ```bash
27
- which aomi || npm install -g @aomi-labs/client
27
+ echo "PRIVATE_KEY=${PRIVATE_KEY:+set}${PRIVATE_KEY:-unset} CHAIN_RPC_URL=${CHAIN_RPC_URL:-unset}"; aomi status 2>/dev/null || echo "no session"
28
28
  ```
29
29
 
30
+ Key rules:
31
+ - If `PRIVATE_KEY` is set in env, do NOT also pass `--private-key` (flag overrides env → wrong wallet).
32
+ - `--public-key` must match the address derived from the signing key. Mismatch = agent builds txs for wrong wallet.
33
+ - Private keys must start with `0x`. Add the prefix if missing.
34
+
30
35
  ## Core Workflow
31
36
 
32
37
  The aomi CLI is **not** a long-running process. Each command starts, runs, and
@@ -68,7 +73,7 @@ Pass `--public-key` on the first chat so the agent knows the user's wallet
68
73
  address. It is persisted — subsequent commands in the same session don't need it.
69
74
 
70
75
  ```bash
71
- aomi chat "swap 1 ETH for USDC" --public-key 0xYourAddress
76
+ aomi chat "swap 1 ETH for USDC" --public-key 0xYourAddress --chain 1
72
77
  ```
73
78
 
74
79
  ### List transactions
@@ -118,6 +123,7 @@ All config can be passed as flags (priority) or env vars (fallback):
118
123
  | `--public-key` | `AOMI_PUBLIC_KEY` | — | Wallet address |
119
124
  | `--private-key` | `PRIVATE_KEY` | — | Hex private key (for `aomi sign`) |
120
125
  | `--rpc-url` | `CHAIN_RPC_URL` | — | RPC URL (for `aomi sign`) |
126
+ | `--chain` | `AOMI_CHAIN_ID` | `1` | Chain ID (1, 137, 42161, 8453, 10, 11155111) |
121
127
 
122
128
  ## Important Behavior
123
129
 
@@ -137,7 +143,8 @@ All config can be passed as flags (priority) or env vars (fallback):
137
143
  ```bash
138
144
  # 1. Start a session with wallet connected
139
145
  aomi chat "swap 1 ETH for USDC on Uniswap" \
140
- --public-key 0xYourAddress
146
+ --public-key 0xYourAddress \
147
+ --chain 1
141
148
 
142
149
  # 2. Agent builds the tx — check what's pending
143
150
  aomi tx