agentxjs 2.9.0-dev-20260317030407 → 2.9.0-dev-20260317033749

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -802,6 +802,7 @@ var Presentation = class {
802
802
  async send(content) {
803
803
  this.state = addUserConversation(this.state, content);
804
804
  this.notify();
805
+ await new Promise((resolve) => setTimeout(resolve, 0));
805
806
  try {
806
807
  await this.agentx.runtime.session.send(this.instanceId, content);
807
808
  } catch (error) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/LocalClient.ts","../src/AgentHandle.ts","../src/namespaces/images.ts","../src/namespaces/llm.ts","../src/presentation/types.ts","../src/presentation/reducer.ts","../src/presentation/Presentation.ts","../src/namespaces/presentations.ts","../src/namespaces/sessions.ts","../src/RemoteClient.ts"],"sourcesContent":["/**\n * agentxjs - AgentX Client SDK\n *\n * Fluent API supporting local, remote, and server modes.\n *\n * @example Local mode\n * ```typescript\n * import { createAgentX } from \"agentxjs\";\n * import { nodePlatform } from \"@agentxjs/node-platform\";\n *\n * const ax = createAgentX(nodePlatform({ createDriver }));\n * const agent = await ax.chat.create({ name: \"Aristotle\", model: \"claude-sonnet-4-6\" });\n * await agent.send(\"Hello!\");\n * ```\n *\n * @example Remote mode\n * ```typescript\n * const ax = createAgentX();\n * const client = await ax.connect(\"ws://localhost:5200\");\n * ```\n *\n * @example Server mode\n * ```typescript\n * const ax = createAgentX(nodePlatform({ createDriver }));\n * const server = await ax.serve({ port: 5200 });\n * ```\n */\n\nimport type { CreateDriver } from \"@agentxjs/core/driver\";\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport { createAgentXRuntime } from \"@agentxjs/core/runtime\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { LocalClient } from \"./LocalClient\";\nimport { RemoteClient } from \"./RemoteClient\";\nimport type { AgentX, AgentXBuilder, AgentXServer, ConnectOptions, ServeConfig } from \"./types\";\n\nconst poolLogger = createLogger(\"agentx/connection-pool\");\n\n// ============================================================================\n// Connection Pool — module-level singleton for WebSocket connection reuse\n//\n// Solves React 18+ Strict Mode double-mount:\n// mount → connect (refCount=1) → unmount → dispose (refCount=0, deferred)\n// → re-mount → connect (reuse, refCount=1)\n// ============================================================================\n\ninterface PoolEntry {\n client: RemoteClient;\n refCount: number;\n}\n\nconst connectionPool = new Map<string, PoolEntry>();\n\nfunction pooledConnect(serverUrl: string, factory: () => Promise<RemoteClient>): Promise<AgentX> {\n const existing = connectionPool.get(serverUrl);\n if (existing && existing.client.connected) {\n existing.refCount++;\n poolLogger.debug(\"Connection reused\", { serverUrl, refCount: existing.refCount });\n return Promise.resolve(wrapWithRefCount(serverUrl, existing));\n }\n\n return factory().then((client) => {\n const entry: PoolEntry = { client, refCount: 1 };\n connectionPool.set(serverUrl, entry);\n poolLogger.debug(\"Connection created\", { serverUrl });\n return wrapWithRefCount(serverUrl, entry);\n });\n}\n\nfunction wrapWithRefCount(serverUrl: string, entry: PoolEntry): AgentX {\n const client = entry.client;\n const originalDispose = client.dispose.bind(client);\n const originalDisconnect = client.disconnect.bind(client);\n\n // Override dispose — only truly dispose when refCount reaches 0\n client.dispose = async () => {\n entry.refCount--;\n poolLogger.debug(\"Connection released\", { serverUrl, refCount: entry.refCount });\n if (entry.refCount <= 0) {\n connectionPool.delete(serverUrl);\n await originalDispose();\n }\n };\n\n // disconnect follows same refCount logic\n client.disconnect = async () => {\n entry.refCount--;\n if (entry.refCount <= 0) {\n connectionPool.delete(serverUrl);\n await originalDisconnect();\n }\n };\n\n return client;\n}\n\n/**\n * Platform configuration for createAgentX\n */\nexport interface PlatformConfig {\n platform: AgentXPlatform;\n createDriver: CreateDriver;\n}\n\n/**\n * Create an AgentX builder\n *\n * @param config - Platform configuration (optional). Without it, only connect() is available.\n * @returns AgentXBuilder — local AgentX + connect() + serve()\n */\nexport function createAgentX(config?: PlatformConfig): AgentXBuilder {\n let localClient: LocalClient | null = null;\n\n function getLocalClient(): LocalClient {\n if (localClient) return localClient;\n if (!config) {\n throw new Error(\n \"Local mode requires a platform. Pass a PlatformConfig to createAgentX(), or use connect() for remote mode.\"\n );\n }\n const runtime = createAgentXRuntime(config.platform, config.createDriver);\n localClient = new LocalClient(runtime);\n return localClient;\n }\n\n if (config) {\n getLocalClient();\n }\n\n return {\n get connected() {\n return localClient?.connected ?? false;\n },\n\n get events() {\n return getLocalClient().events;\n },\n\n get runtime() {\n return getLocalClient().runtime;\n },\n\n get provider() {\n return getLocalClient().provider;\n },\n\n get chat() {\n return getLocalClient().chat;\n },\n\n on(type, handler) {\n return getLocalClient().on(type, handler);\n },\n\n onAny(handler) {\n return getLocalClient().onAny(handler);\n },\n\n onError(handler) {\n return getLocalClient().onError(handler);\n },\n\n async disconnect() {\n await localClient?.disconnect();\n },\n\n async dispose() {\n await localClient?.dispose();\n localClient = null;\n },\n\n async connect(serverUrl: string, options?: ConnectOptions): Promise<AgentX> {\n return pooledConnect(serverUrl, async () => {\n const remoteClient = new RemoteClient({\n serverUrl,\n headers: options?.headers as Record<string, string> | undefined,\n context: options?.context,\n timeout: options?.timeout,\n autoReconnect: options?.autoReconnect,\n customPlatform: config?.platform,\n });\n await remoteClient.connect();\n return remoteClient;\n });\n },\n\n async serve(serveConfig?: ServeConfig): Promise<AgentXServer> {\n if (!config) {\n throw new Error(\"serve() requires a platform. Pass a PlatformConfig to createAgentX().\");\n }\n if (!config.platform.channelServer) {\n throw new Error(\n \"serve() requires platform.channelServer. Ensure your platform supports server mode.\"\n );\n }\n\n const { createServer } = await import(\"./server\");\n return createServer({\n platform: config.platform,\n createDriver: config.createDriver,\n port: serveConfig?.port,\n host: serveConfig?.host,\n server: serveConfig?.server as any,\n wsPath: serveConfig?.wsPath,\n });\n },\n\n async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {\n return getLocalClient().rpc<T>(method, params);\n },\n };\n}\n\n// Re-export context interfaces\nexport type { Capability, Context, ContextProvider } from \"@agentxjs/core/context\";\n// Re-export error types\nexport type { AgentXErrorCategory, AgentXErrorContext } from \"@agentxjs/core/error\";\nexport { AgentXError, AgentXErrorCode } from \"@agentxjs/core/error\";\n// Re-export Presentation\nexport type {\n AssistantConversation,\n Block,\n Conversation,\n ErrorConversation,\n FileBlock,\n ImageBlock,\n PresentationErrorHandler,\n PresentationMetrics,\n PresentationOptions,\n PresentationState,\n PresentationUpdateHandler,\n TextBlock,\n ThinkingBlock,\n ToolBlock,\n UserConversation,\n} from \"./presentation\";\nexport {\n addUserConversation,\n createInitialState,\n initialMetrics,\n initialPresentationState,\n messagesToConversations,\n Presentation,\n presentationReducer,\n} from \"./presentation\";\n// Re-export types\nexport type {\n AgentConfig,\n AgentHandle,\n AgentX,\n AgentXBuilder,\n AgentXServer,\n BaseResponse,\n ChatNamespace,\n ConnectOptions,\n ImageCreateResponse,\n ImageGetResponse,\n ImageListResponse,\n ImageNamespace,\n ImageRecord,\n ImageUpdateResponse,\n InstanceCreateResponse,\n InstanceGetResponse,\n InstanceInfo,\n InstanceListResponse,\n LLMNamespace,\n LLMProviderCreateResponse,\n LLMProviderDefaultResponse,\n LLMProviderGetResponse,\n LLMProviderListResponse,\n LLMProviderUpdateResponse,\n MaybeAsync,\n MessageSendResponse,\n PresentationNamespace,\n RuntimeNamespace,\n ServeConfig,\n SessionNamespace,\n} from \"./types\";\n","/**\n * LocalClient - AgentX client for local mode\n *\n * Runs an embedded Runtime + Driver directly, without WebSocket.\n * Implements the same AgentX interface as RemoteClient.\n */\n\nimport type { AgentXError } from \"@agentxjs/core/error\";\nimport type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from \"@agentxjs/core/event\";\n\nimport type { AgentXRuntime } from \"@agentxjs/core/runtime\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { AgentHandleImpl } from \"./AgentHandle\";\nimport { registerAll } from \"./handlers\";\nimport { createLocalImages } from \"./namespaces/images\";\nimport { createLocalLLM } from \"./namespaces/llm\";\nimport { createPresentations } from \"./namespaces/presentations\";\nimport { createLocalSessions } from \"./namespaces/sessions\";\nimport { RpcHandlerRegistry } from \"./RpcHandlerRegistry\";\nimport type { AgentX, ChatNamespace, LLMNamespace, RuntimeNamespace } from \"./types\";\n\nconst logger = createLogger(\"agentx/LocalClient\");\n\n/**\n * LocalClient - Embedded runtime implementation\n */\nexport class LocalClient implements AgentX {\n private readonly _runtime: AgentXRuntime;\n private registry: RpcHandlerRegistry | null = null;\n private isDisposed = false;\n\n readonly chat: ChatNamespace;\n readonly runtime: RuntimeNamespace;\n readonly provider: LLMNamespace;\n\n constructor(agentxRuntime: AgentXRuntime) {\n this._runtime = agentxRuntime;\n const platform = agentxRuntime.platform;\n\n const image = createLocalImages(platform, agentxRuntime);\n const session = createLocalSessions(agentxRuntime);\n const llm = createLocalLLM(platform);\n // Workspace resolver: imageId → PresentationWorkspace\n const workspaceResolver = async (imageId: string) => {\n const wp = platform.workspaceProvider;\n if (!wp) return null;\n const img = await platform.imageRepository.findImageById(imageId);\n if (!img?.workspaceId) return null;\n const ws = await wp.create(img.workspaceId);\n return {\n read: (path: string) => ws.read(path),\n write: (path: string, content: string) => ws.write(path, content),\n list: async (path?: string) => {\n const entries = await ws.list(path);\n return entries.map((e) => ({ name: e.name, path: e.path, type: e.type }));\n },\n };\n };\n const present = createPresentations(this, session, workspaceResolver);\n\n this.runtime = { image, session, present, llm };\n this.provider = llm;\n this.chat = this.createChatNamespace();\n\n logger.info(\"LocalClient initialized\");\n }\n\n // ==================== Properties ====================\n\n get connected(): boolean {\n return !this.isDisposed;\n }\n\n get events(): EventBus {\n return this._runtime.platform.eventBus;\n }\n\n // ==================== Event Subscription ====================\n\n on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {\n return this._runtime.platform.eventBus.on(type, handler);\n }\n\n onAny(handler: BusEventHandler): Unsubscribe {\n return this._runtime.platform.eventBus.onAny(handler);\n }\n\n // ==================== Error Handling ====================\n\n onError(handler: (error: AgentXError) => void): Unsubscribe {\n return this._runtime.platform.eventBus.on(\"agentx_error\", (event) => {\n handler(event.data as AgentXError);\n });\n }\n\n // ==================== RPC ====================\n\n async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {\n if (!this.registry) {\n this.registry = new RpcHandlerRegistry();\n registerAll(this.registry);\n }\n const result = await this.registry.handle(this._runtime, method, params);\n if (result.success) {\n return result.data as T;\n }\n throw new Error(result.message);\n }\n\n // ==================== Private ====================\n\n private createChatNamespace(): ChatNamespace {\n const rt = this.runtime;\n return {\n async create(params) {\n const imgRes = await rt.image.create(params);\n const runRes = await rt.image.run(imgRes.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n async list() {\n return rt.image.list();\n },\n async get(id) {\n const res = await rt.image.get(id);\n if (!res.record) return null;\n const runRes = await rt.image.run(res.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n };\n }\n\n // ==================== Lifecycle ====================\n\n async disconnect(): Promise<void> {\n // No-op for local mode\n }\n\n async dispose(): Promise<void> {\n if (this.isDisposed) return;\n await this._runtime.shutdown();\n this.isDisposed = true;\n logger.info(\"LocalClient disposed\");\n }\n}\n","/**\n * AgentHandle — live reference to a created agent.\n *\n * Wraps identity (IDs) + delegates operations to instance namespaces.\n */\n\nimport type { Message } from \"@agentxjs/core/agent\";\nimport type { Presentation, PresentationOptions } from \"./presentation\";\nimport type {\n AgentConfig,\n AgentHandle,\n BaseResponse,\n MessageSendResponse,\n RuntimeNamespace,\n} from \"./types\";\n\nexport class AgentHandleImpl implements AgentHandle {\n readonly instanceId: string;\n readonly imageId: string;\n readonly containerId: string;\n readonly sessionId: string;\n\n private readonly ns: RuntimeNamespace;\n\n constructor(\n ids: { instanceId: string; imageId: string; containerId: string; sessionId: string },\n ns: RuntimeNamespace\n ) {\n this.instanceId = ids.instanceId;\n this.imageId = ids.imageId;\n this.containerId = ids.containerId;\n this.sessionId = ids.sessionId;\n this.ns = ns;\n }\n\n async send(content: string | unknown[]): Promise<MessageSendResponse> {\n return this.ns.session.send(this.instanceId, content);\n }\n\n async interrupt(): Promise<BaseResponse> {\n return this.ns.session.interrupt(this.instanceId);\n }\n\n async history(): Promise<Message[]> {\n return this.ns.image.getMessages(this.imageId);\n }\n\n async present(options?: PresentationOptions): Promise<Presentation> {\n return this.ns.present.create(this.instanceId, options);\n }\n\n async update(\n updates: Partial<\n Pick<\n AgentConfig,\n \"name\" | \"description\" | \"model\" | \"systemPrompt\" | \"mcpServers\" | \"customData\"\n >\n >\n ): Promise<void> {\n await this.ns.image.update(this.imageId, updates);\n }\n\n async delete(): Promise<void> {\n await this.ns.image.stop(this.imageId);\n await this.ns.image.delete(this.imageId);\n }\n}\n","/**\n * Image namespace factories\n */\n\nimport type { Message } from \"@agentxjs/core/agent\";\nimport { DEFAULT_CONTAINER_ID } from \"@agentxjs/core/container\";\nimport type { RpcClient } from \"@agentxjs/core/network\";\nimport type { AgentXPlatform, AgentXRuntime } from \"@agentxjs/core/runtime\";\nimport type {\n AgentConfig,\n BaseResponse,\n ImageCreateResponse,\n ImageGetResponse,\n ImageListResponse,\n ImageNamespace,\n ImageUpdateResponse,\n InstanceCreateResponse,\n} from \"../types\";\n\n/**\n * Create local image namespace backed by embedded runtime\n */\nexport function createLocalImages(\n platform: AgentXPlatform,\n runtime?: AgentXRuntime\n): ImageNamespace {\n return {\n async create(params: AgentConfig): Promise<ImageCreateResponse> {\n const { imageRepository, sessionRepository } = platform;\n const { createImage } = await import(\"@agentxjs/core/image\");\n\n const { model, systemPrompt, mcpServers, ...rest } = params;\n const embody =\n model || systemPrompt || mcpServers\n ? { model, systemPrompt, mcpServers: mcpServers as any }\n : undefined;\n\n const image = await createImage(\n {\n containerId: DEFAULT_CONTAINER_ID,\n ...rest,\n embody,\n },\n { imageRepository, sessionRepository }\n );\n\n return {\n record: image.toRecord(),\n requestId: \"\",\n };\n },\n\n async get(imageId: string): Promise<ImageGetResponse> {\n const record = await platform.imageRepository.findImageById(imageId);\n return {\n record,\n requestId: \"\",\n };\n },\n\n async list(): Promise<ImageListResponse> {\n const records = await platform.imageRepository.findAllImages();\n\n return {\n records,\n requestId: \"\",\n };\n },\n\n async update(\n imageId: string,\n updates: {\n name?: string;\n description?: string;\n customData?: Record<string, unknown>;\n }\n ): Promise<ImageUpdateResponse> {\n const { loadImage } = await import(\"@agentxjs/core/image\");\n const { imageRepository, sessionRepository } = platform;\n\n const image = await loadImage(imageId, { imageRepository, sessionRepository });\n if (!image) {\n throw new Error(`Image not found: ${imageId}`);\n }\n\n const updated = await image.update(updates);\n return { record: updated.toRecord(), requestId: \"\" };\n },\n\n async delete(imageId: string): Promise<BaseResponse> {\n const { loadImage } = await import(\"@agentxjs/core/image\");\n const { imageRepository, sessionRepository } = platform;\n\n const image = await loadImage(imageId, { imageRepository, sessionRepository });\n if (image) {\n await image.delete();\n }\n\n return { requestId: \"\" };\n },\n\n async getMessages(imageId: string): Promise<Message[]> {\n const imageRecord = await platform.imageRepository.findImageById(imageId);\n if (!imageRecord) return [];\n return platform.sessionRepository.getMessages(imageRecord.sessionId);\n },\n\n async run(imageId: string): Promise<InstanceCreateResponse> {\n if (!runtime) throw new Error(\"Runtime not available\");\n const existing = runtime\n .getAgents()\n .find((a) => a.imageId === imageId && a.lifecycle === \"running\");\n if (existing) {\n return {\n instanceId: existing.instanceId,\n imageId: existing.imageId,\n containerId: existing.containerId,\n sessionId: existing.sessionId,\n requestId: \"\",\n };\n }\n const agent = await runtime.createAgent({ imageId });\n return {\n instanceId: agent.instanceId,\n imageId: agent.imageId,\n containerId: agent.containerId,\n sessionId: agent.sessionId,\n requestId: \"\",\n };\n },\n\n async stop(imageId: string): Promise<BaseResponse> {\n if (!runtime) throw new Error(\"Runtime not available\");\n const agent = runtime\n .getAgents()\n .find((a) => a.imageId === imageId && a.lifecycle === \"running\");\n if (agent) await runtime.stopAgent(agent.instanceId);\n return { requestId: \"\" };\n },\n };\n}\n\n/**\n * Create remote image namespace backed by RPC client\n */\nexport function createRemoteImages(rpcClient: RpcClient): ImageNamespace {\n return {\n async create(params: AgentConfig): Promise<ImageCreateResponse> {\n const result = await rpcClient.call<ImageCreateResponse>(\"image.create\", {\n ...params,\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n\n async get(imageId: string): Promise<ImageGetResponse> {\n const result = await rpcClient.call<ImageGetResponse>(\"image.get\", { imageId });\n return { ...result, requestId: \"\" };\n },\n\n async list(): Promise<ImageListResponse> {\n const result = await rpcClient.call<ImageListResponse>(\"image.list\", {});\n return { ...result, requestId: \"\" };\n },\n\n async update(\n imageId: string,\n updates: {\n name?: string;\n description?: string;\n customData?: Record<string, unknown>;\n }\n ): Promise<ImageUpdateResponse> {\n const result = await rpcClient.call<ImageUpdateResponse>(\"image.update\", {\n imageId,\n updates,\n });\n return { ...result, requestId: \"\" };\n },\n\n async delete(imageId: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"image.delete\", { imageId });\n return { ...result, requestId: \"\" };\n },\n\n async getMessages(imageId: string): Promise<Message[]> {\n const result = await rpcClient.call<{ messages: Message[] }>(\"image.messages\", { imageId });\n return result.messages ?? [];\n },\n\n async run(imageId: string): Promise<InstanceCreateResponse> {\n const result = await rpcClient.call<InstanceCreateResponse>(\"image.run\", { imageId });\n return { ...result, requestId: \"\" };\n },\n\n async stop(imageId: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"image.stop\", { imageId });\n return { ...result, requestId: \"\" };\n },\n };\n}\n","/**\n * LLM Provider namespace factories\n */\n\nimport { DEFAULT_CONTAINER_ID } from \"@agentxjs/core/container\";\nimport type { RpcClient } from \"@agentxjs/core/network\";\nimport type { LLMProviderRecord } from \"@agentxjs/core/persistence\";\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport { generateId } from \"@deepracticex/id\";\nimport type {\n BaseResponse,\n LLMNamespace,\n LLMProviderCreateResponse,\n LLMProviderDefaultResponse,\n LLMProviderGetResponse,\n LLMProviderListResponse,\n LLMProviderUpdateResponse,\n} from \"../types\";\n\n/**\n * Create local LLM namespace backed by platform repository\n */\nexport function createLocalLLM(platform: AgentXPlatform): LLMNamespace {\n const repo = platform.llmProviderRepository;\n if (!repo) {\n throw new Error(\"LLM provider repository not available on this platform\");\n }\n\n return {\n async create(params): Promise<LLMProviderCreateResponse> {\n const now = Date.now();\n const record: LLMProviderRecord = {\n id: generateId(\"llm\"),\n containerId: DEFAULT_CONTAINER_ID,\n name: params.name,\n vendor: params.vendor,\n protocol: params.protocol,\n apiKey: params.apiKey,\n baseUrl: params.baseUrl,\n model: params.model,\n isDefault: false,\n createdAt: now,\n updatedAt: now,\n };\n\n await repo.saveLLMProvider(record);\n return { record, requestId: \"\" };\n },\n\n async get(id: string): Promise<LLMProviderGetResponse> {\n const record = await repo.findLLMProviderById(id);\n return { record, requestId: \"\" };\n },\n\n async list(): Promise<LLMProviderListResponse> {\n const records = await repo.findLLMProvidersByContainerId(DEFAULT_CONTAINER_ID);\n return { records, requestId: \"\" };\n },\n\n async update(id, updates): Promise<LLMProviderUpdateResponse> {\n const existing = await repo.findLLMProviderById(id);\n if (!existing) {\n throw new Error(`LLM provider not found: ${id}`);\n }\n\n const updated: LLMProviderRecord = {\n ...existing,\n ...updates,\n id: existing.id,\n containerId: existing.containerId,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n\n await repo.saveLLMProvider(updated);\n return { record: updated, requestId: \"\" };\n },\n\n async delete(id: string): Promise<BaseResponse> {\n await repo.deleteLLMProvider(id);\n return { requestId: \"\" };\n },\n\n async setDefault(id: string): Promise<BaseResponse> {\n await repo.setDefaultLLMProvider(id);\n return { requestId: \"\" };\n },\n\n async getDefault(): Promise<LLMProviderDefaultResponse> {\n const record = await repo.findDefaultLLMProvider(DEFAULT_CONTAINER_ID);\n return { record, requestId: \"\" };\n },\n };\n}\n\n/**\n * Create remote LLM namespace backed by RPC client\n */\nexport function createRemoteLLM(rpcClient: RpcClient): LLMNamespace {\n return {\n async create(params): Promise<LLMProviderCreateResponse> {\n const result = await rpcClient.call<LLMProviderCreateResponse>(\"llm.create\", {\n ...params,\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n\n async get(id: string): Promise<LLMProviderGetResponse> {\n const result = await rpcClient.call<LLMProviderGetResponse>(\"llm.get\", { id });\n return { ...result, requestId: \"\" };\n },\n\n async list(): Promise<LLMProviderListResponse> {\n const result = await rpcClient.call<LLMProviderListResponse>(\"llm.list\", {\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n\n async update(id, updates): Promise<LLMProviderUpdateResponse> {\n const result = await rpcClient.call<LLMProviderUpdateResponse>(\"llm.update\", {\n id,\n updates,\n });\n return { ...result, requestId: \"\" };\n },\n\n async delete(id: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"llm.delete\", { id });\n return { ...result, requestId: \"\" };\n },\n\n async setDefault(id: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"llm.default\", { id });\n return { ...result, requestId: \"\" };\n },\n\n async getDefault(): Promise<LLMProviderDefaultResponse> {\n const result = await rpcClient.call<LLMProviderDefaultResponse>(\"llm.default\", {\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n };\n}\n","/**\n * Presentation Types\n *\n * UI-friendly data model aggregated from stream events.\n * This implements the Presentation Model pattern.\n */\n\n// ============================================================================\n// Block Types - Basic content units\n// ============================================================================\n\n/**\n * Text block\n */\nexport interface TextBlock {\n type: \"text\";\n content: string;\n}\n\n/**\n * Tool block - represents a tool call and its result\n */\nexport interface ToolBlock {\n type: \"tool\";\n toolUseId: string;\n toolName: string;\n toolInput: Record<string, unknown>;\n toolResult?: string;\n /** Partial JSON input being streamed (visible during input-streaming phase) */\n partialInput?: string;\n status: \"pending\" | \"running\" | \"completed\" | \"error\" | \"interrupted\";\n}\n\n/**\n * Image block\n */\nexport interface ImageBlock {\n type: \"image\";\n url: string;\n alt?: string;\n}\n\n/**\n * File block\n */\nexport interface FileBlock {\n type: \"file\";\n filename: string;\n mediaType: string;\n}\n\n/**\n * Thinking/reasoning block — AI's internal reasoning process\n */\nexport interface ThinkingBlock {\n type: \"thinking\";\n content: string;\n}\n\n/**\n * All block types\n */\nexport type Block = TextBlock | ToolBlock | ImageBlock | FileBlock | ThinkingBlock;\n\n// ============================================================================\n// Conversation Types - A single turn in the conversation\n// ============================================================================\n\n/**\n * User conversation\n */\nexport interface UserConversation {\n role: \"user\";\n blocks: Block[];\n}\n\n/**\n * Token usage for a message (one LLM call / step)\n */\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Assistant conversation\n */\nexport interface AssistantConversation {\n role: \"assistant\";\n blocks: Block[];\n isStreaming: boolean;\n /** Accumulated token usage across all steps in this conversation */\n usage?: TokenUsage;\n}\n\n/**\n * Error conversation\n */\nexport interface ErrorConversation {\n role: \"error\";\n message: string;\n}\n\n/**\n * All conversation types\n */\nexport type Conversation = UserConversation | AssistantConversation | ErrorConversation;\n\n// ============================================================================\n// Presentation Metrics\n// ============================================================================\n\n/**\n * Turn-level metrics.\n * Reset at the start of each turn, preserved after turn ends.\n */\nexport interface TurnMetrics {\n /** Timestamp when the current turn started (null when idle before first turn) */\n turnStartedAt: number | null;\n /** Input tokens consumed in the current turn */\n inputTokens: number;\n /** Output tokens generated in the current turn */\n outputTokens: number;\n}\n\n/**\n * Session-level context metrics.\n * Tracks the overall context window usage across the entire session.\n */\nexport interface SessionMetrics {\n /** Current context size in tokens (last inputTokens from LLM — includes full history) */\n contextTokens: number;\n /** Model's context window limit (0 = unknown) */\n contextLimit: number;\n /** Context usage ratio 0-1 (0 when limit unknown) */\n contextUsage: number;\n}\n\n/**\n * Combined presentation metrics — turn + session level.\n */\nexport interface PresentationMetrics extends TurnMetrics {\n /** Session-level context window metrics */\n session: SessionMetrics;\n}\n\n// ============================================================================\n// Workspace State\n// ============================================================================\n\n/**\n * File tree entry — recursive structure for rendering directory tree\n */\nexport interface FileTreeEntry {\n /** File or directory name */\n name: string;\n /** Path relative to workspace root */\n path: string;\n /** File or directory */\n type: \"file\" | \"directory\";\n /** Children (only for directories) */\n children?: FileTreeEntry[];\n}\n\n/**\n * Workspace state — real-time workspace view\n */\nexport interface WorkspaceState {\n /**\n * Current file tree (recursive).\n * Frontend just renders this tree directly.\n */\n files: FileTreeEntry[];\n}\n\n// ============================================================================\n// Presentation Workspace Operations\n// ============================================================================\n\n/**\n * PresentationWorkspace — file operations exposed to the consumer.\n * Wraps the underlying Workspace with a simple API.\n */\nexport interface PresentationWorkspace {\n /** Read file content */\n read(path: string): Promise<string>;\n /** Write content to a file */\n write(path: string, content: string): Promise<void>;\n /** List directory entries */\n list(path?: string): Promise<FileTreeEntry[]>;\n}\n\n// ============================================================================\n// Presentation State\n// ============================================================================\n\n/**\n * Connection state\n */\nexport type ConnectionState = \"connected\" | \"connecting\" | \"disconnected\";\n\n/**\n * Presentation state - the complete UI state\n */\nexport interface PresentationState {\n /**\n * All conversations including the currently streaming one.\n * The streaming conversation is the last item with `isStreaming: true`.\n * Frontend just does `conversations.map(...)` — no merging needed.\n */\n conversations: Conversation[];\n\n /**\n * Current agent status\n *\n * - idle: No active request\n * - submitted: Message sent, waiting for first token\n * - thinking: LLM outputting thinking/reasoning content\n * - responding: LLM outputting text content\n * - executing: Tool call in progress\n */\n status: \"idle\" | \"submitted\" | \"thinking\" | \"responding\" | \"executing\";\n\n /**\n * WebSocket connection state\n */\n connection: ConnectionState;\n\n /**\n * Real-time metrics for the current turn\n */\n metrics: PresentationMetrics;\n\n /**\n * Workspace state — real-time file tree.\n * null when agent has no workspace.\n */\n workspace: WorkspaceState | null;\n}\n\n/**\n * Initial presentation metrics\n */\nexport const initialSessionMetrics: SessionMetrics = {\n contextTokens: 0,\n contextLimit: 0,\n contextUsage: 0,\n};\n\nexport const initialMetrics: PresentationMetrics = {\n turnStartedAt: null,\n inputTokens: 0,\n outputTokens: 0,\n session: initialSessionMetrics,\n};\n\n/**\n * Initial presentation state\n */\nexport const initialPresentationState: PresentationState = {\n conversations: [],\n status: \"idle\",\n connection: \"connected\",\n metrics: initialMetrics,\n workspace: null,\n};\n","/**\n * Presentation Reducer\n *\n * Aggregates events into PresentationState.\n * Pure function: (state, event) => newState\n *\n * Event consumption strategy:\n * - Stream layer: message_start, text_delta, tool_use_start, tool_use_stop, message_stop\n * (for real-time streaming display)\n * - Message layer: tool_result_message\n * (for tool execution results — arrives after message_stop)\n *\n * Tool calls are stream-level blocks within the assistant turn,\n * matching the mainstream API pattern (Anthropic, OpenAI).\n */\n\nimport type {\n AssistantMessage,\n ErrorMessage,\n Message,\n ToolCallPart,\n ToolResultMessage,\n ToolResultOutput,\n UserContentPart,\n UserMessage,\n} from \"@agentxjs/core/agent\";\nimport type { BusEvent } from \"@agentxjs/core/event\";\nimport type {\n AssistantConversation,\n Block,\n ConnectionState,\n Conversation,\n FileTreeEntry,\n PresentationState,\n TextBlock,\n TokenUsage,\n ToolBlock,\n} from \"./types\";\nimport { initialMetrics, initialPresentationState } from \"./types\";\n\n// ============================================================================\n// Event Data Types\n// ============================================================================\n\ninterface MessageStartData {\n messageId?: string;\n model?: string;\n}\n\ninterface TextDeltaData {\n text: string;\n}\n\ninterface ToolUseStartData {\n toolCallId: string;\n toolName: string;\n}\n\ninterface ToolUseStopData {\n toolCallId: string;\n toolName: string;\n input: Record<string, unknown>;\n}\n\ninterface MessageDeltaData {\n usage?: {\n inputTokens: number;\n outputTokens: number;\n };\n}\n\ninterface MessageStopData {\n stopReason?: string;\n}\n\ninterface ErrorData {\n message: string;\n code?: string;\n}\n\n// ============================================================================\n// Reducer\n// ============================================================================\n\n/**\n * Reduce an event into presentation state.\n *\n * Consumes:\n * - Stream events: message_start, text_delta, tool_use_start, tool_use_stop, message_stop\n * - Message events: tool_result_message\n * - Error events: error\n */\nexport function presentationReducer(state: PresentationState, event: BusEvent): PresentationState {\n switch (event.type) {\n // Stream layer — real-time display\n case \"message_start\":\n return handleMessageStart(state, event.data as MessageStartData);\n\n case \"thinking_delta\":\n return handleThinkingDelta(state, event.data as TextDeltaData);\n\n case \"text_delta\":\n return handleTextDelta(state, event.data as TextDeltaData);\n\n case \"tool_use_start\":\n return handleToolUseStart(state, event.data as ToolUseStartData);\n\n case \"tool_use_stop\":\n return handleToolUseStop(state, event.data as ToolUseStopData);\n\n case \"input_json_delta\":\n return handleInputJsonDelta(state, event.data as { partialJson: string });\n\n case \"message_delta\":\n return handleMessageDelta(state, event.data as MessageDeltaData);\n\n case \"message_stop\":\n return handleMessageStop(state, event.data as MessageStopData);\n\n // Message layer — tool results from Engine\n case \"tool_result_message\":\n return handleToolResultMessage(state, event.data as ToolResultMessage);\n\n case \"tool_result\":\n return handleToolResult(\n state,\n event.data as { toolCallId: string; result: unknown; isError: boolean }\n );\n\n case \"error\":\n return handleError(state, event.data as ErrorData);\n\n case \"interrupted\":\n return handleInterrupted(state);\n\n // Connection state\n case \"connection_state\":\n return handleConnectionState(state, event.data as { state: string });\n\n // Workspace file tree\n case \"workspace_tree\":\n return handleWorkspaceTree(state, event.data as { files: FileTreeEntry[] });\n\n // Rewind — runtime-level operation\n case \"rewind\":\n return handleRewind(state, event.data as { truncatedCount: number });\n\n default:\n return state;\n }\n}\n\n// ============================================================================\n// Helpers — operate on the last assistant conversation in conversations[]\n// ============================================================================\n\n/**\n * Get the last conversation if it's a streaming assistant conversation.\n */\nfunction getStreamingConv(state: PresentationState): AssistantConversation | null {\n const last = state.conversations[state.conversations.length - 1];\n if (last?.role === \"assistant\" && (last as AssistantConversation).isStreaming) {\n return last as AssistantConversation;\n }\n return null;\n}\n\n/**\n * Update the last conversation in the array (must be streaming assistant).\n */\nfunction updateLastConv(\n state: PresentationState,\n updater: (conv: AssistantConversation) => AssistantConversation,\n extraState?: Partial<PresentationState>\n): PresentationState {\n const conv = getStreamingConv(state);\n if (!conv) return state;\n\n const updated = updater(conv);\n const conversations = [...state.conversations];\n conversations[conversations.length - 1] = updated;\n\n return { ...state, conversations, ...extraState };\n}\n\ninterface InputJsonDeltaData {\n partialJson: string;\n}\n\n// ============================================================================\n// Handlers — all operate on conversations[]\n// ============================================================================\n\nfunction handleMessageStart(state: PresentationState, _data: MessageStartData): PresentationState {\n const newConv: AssistantConversation = {\n role: \"assistant\",\n blocks: [],\n isStreaming: true,\n };\n\n // Only reset metrics at the start of a new turn (idle/submitted → submitted).\n // Mid-turn message_start (after tool_use) should keep accumulating.\n const isNewTurn = state.status === \"idle\" || state.status === \"submitted\";\n const metrics = isNewTurn ? { ...initialMetrics, turnStartedAt: Date.now() } : state.metrics;\n\n return {\n ...state,\n conversations: [...state.conversations, newConv],\n status: \"submitted\",\n metrics,\n };\n}\n\nfunction handleThinkingDelta(state: PresentationState, data: TextDeltaData): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = [...conv.blocks];\n const lastBlock = blocks[blocks.length - 1];\n\n if (lastBlock && lastBlock.type === \"thinking\") {\n blocks[blocks.length - 1] = {\n ...lastBlock,\n content: (lastBlock as any).content + data.text,\n };\n } else {\n blocks.push({ type: \"thinking\", content: data.text } as Block);\n }\n\n return { ...conv, blocks };\n },\n { status: \"thinking\" }\n );\n}\n\nfunction handleTextDelta(state: PresentationState, data: TextDeltaData): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = [...conv.blocks];\n const lastBlock = blocks[blocks.length - 1];\n\n if (lastBlock && lastBlock.type === \"text\") {\n blocks[blocks.length - 1] = {\n ...lastBlock,\n content: lastBlock.content + data.text,\n };\n } else {\n blocks.push({ type: \"text\", content: data.text } as TextBlock);\n }\n\n return { ...conv, blocks };\n },\n { status: \"responding\" }\n );\n}\n\nfunction handleToolUseStart(state: PresentationState, data: ToolUseStartData): PresentationState {\n const toolBlock: ToolBlock = {\n type: \"tool\",\n toolUseId: data.toolCallId,\n toolName: data.toolName,\n toolInput: {},\n status: \"pending\",\n };\n\n return updateLastConv(state, (conv) => ({ ...conv, blocks: [...conv.blocks, toolBlock] }), {\n status: \"executing\",\n });\n}\n\nfunction handleInputJsonDelta(\n state: PresentationState,\n data: InputJsonDeltaData\n): PresentationState {\n return updateLastConv(state, (conv) => {\n const blocks = conv.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.status === \"pending\") {\n return {\n ...block,\n partialInput: ((block as any).partialInput || \"\") + data.partialJson,\n } as ToolBlock;\n }\n return block;\n });\n return { ...conv, blocks };\n });\n}\n\nfunction handleToolUseStop(state: PresentationState, data: ToolUseStopData): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = conv.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.toolUseId === data.toolCallId) {\n return { ...block, toolInput: data.input, status: \"running\" };\n }\n return block;\n });\n return { ...conv, blocks };\n },\n { status: \"executing\" }\n );\n}\n\nfunction handleMessageDelta(state: PresentationState, data: MessageDeltaData): PresentationState {\n if (!data.usage) return state;\n\n const newState = updateLastConv(state, (conv) => {\n const prev = conv.usage;\n const usage: TokenUsage = {\n inputTokens: (prev?.inputTokens ?? 0) + data.usage!.inputTokens,\n outputTokens: (prev?.outputTokens ?? 0) + data.usage!.outputTokens,\n };\n return { ...conv, usage };\n });\n\n // inputTokens from LLM = current context size (full history sent each call)\n const contextTokens = data.usage.inputTokens;\n const contextLimit = newState.metrics.session.contextLimit;\n const contextUsage = contextLimit > 0 ? contextTokens / contextLimit : 0;\n\n return {\n ...newState,\n metrics: {\n ...newState.metrics,\n inputTokens: newState.metrics.inputTokens + data.usage.inputTokens,\n outputTokens: newState.metrics.outputTokens + data.usage.outputTokens,\n session: {\n contextTokens,\n contextLimit,\n contextUsage,\n },\n },\n };\n}\n\nfunction handleMessageStop(state: PresentationState, data: MessageStopData): PresentationState {\n // tool_use stop → keep streaming, tool results are still incoming\n if (data.stopReason === \"tool_use\") {\n return { ...state, status: \"executing\" };\n }\n\n // end_turn / max_tokens → mark completed, clear turnStartedAt\n return updateLastConv(state, (conv) => ({ ...conv, isStreaming: false }), {\n status: \"idle\",\n metrics: { ...state.metrics, turnStartedAt: null },\n });\n}\n\nfunction handleToolResultMessage(\n state: PresentationState,\n data: ToolResultMessage\n): PresentationState {\n const toolCallId = data.toolCallId;\n\n // Find tool block in any conversation (could be in last streaming or already completed)\n const conversations = state.conversations.map((conv): Conversation => {\n if (conv.role !== \"assistant\") return conv;\n const ac = conv as AssistantConversation;\n const hasMatch = ac.blocks.some((b) => b.type === \"tool\" && b.toolUseId === toolCallId);\n if (!hasMatch) return conv;\n\n const blocks = ac.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.toolUseId === toolCallId) {\n return {\n ...block,\n toolResult: formatToolResultOutput(data.toolResult.output),\n status:\n data.toolResult.output.type === \"error-text\" ||\n data.toolResult.output.type === \"error-json\" ||\n data.toolResult.output.type === \"execution-denied\"\n ? \"error\"\n : \"completed\",\n };\n }\n return block;\n });\n return { ...ac, blocks };\n });\n\n return { ...state, conversations, status: \"responding\" };\n}\n\n/**\n * Handle tool_result from stream layer (raw driver event).\n */\nfunction handleToolResult(\n state: PresentationState,\n data: { toolCallId: string; result: unknown; isError: boolean }\n): PresentationState {\n const { toolCallId, result, isError } = data;\n const resultStr =\n typeof result === \"string\"\n ? result\n : result instanceof Error\n ? result.message\n : JSON.stringify(result);\n\n const conversations = state.conversations.map((conv): Conversation => {\n if (conv.role !== \"assistant\") return conv;\n const ac = conv as AssistantConversation;\n const hasMatch = ac.blocks.some((b) => b.type === \"tool\" && b.toolUseId === toolCallId);\n if (!hasMatch) return conv;\n\n const blocks = ac.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.toolUseId === toolCallId) {\n return { ...block, toolResult: resultStr, status: isError ? \"error\" : \"completed\" };\n }\n return block;\n });\n return { ...ac, blocks };\n });\n\n return { ...state, conversations, status: \"responding\" };\n}\n\nfunction handleError(state: PresentationState, data: ErrorData): PresentationState {\n // If there's a streaming conversation with content, keep it\n const conv = getStreamingConv(state);\n let conversations = state.conversations;\n if (conv && conv.blocks.length > 0) {\n // Mark streaming conv as completed before adding error\n conversations = [...state.conversations];\n conversations[conversations.length - 1] = { ...conv, isStreaming: false };\n }\n\n return {\n ...state,\n conversations: [...conversations, { role: \"error\", message: data.message }],\n status: \"idle\",\n };\n}\n\n/**\n * Interrupt handlers per block type.\n * Each handler receives a block and returns the interrupted version.\n * New block types register here — handleInterrupted stays fixed.\n */\nconst interruptHandlers: Partial<Record<Block[\"type\"], (block: Block) => Block>> = {\n tool: (block) => {\n const tb = block as ToolBlock;\n if (tb.status === \"pending\" || tb.status === \"running\") {\n return { ...tb, status: \"interrupted\", toolResult: \"Interrupted\" };\n }\n return block;\n },\n};\n\nfunction handleInterrupted(state: PresentationState): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = conv.blocks.map((block): Block => {\n const handler = interruptHandlers[block.type];\n return handler ? handler(block) : block;\n });\n return { ...conv, blocks, isStreaming: false };\n },\n { status: \"idle\" }\n );\n}\n\nfunction handleConnectionState(\n state: PresentationState,\n data: { state: string }\n): PresentationState {\n const connection = data.state as ConnectionState;\n if (connection === state.connection) return state;\n return { ...state, connection };\n}\n\nfunction handleRewind(\n state: PresentationState,\n data: { truncatedCount: number }\n): PresentationState {\n // Remove the last N conversations (truncatedCount maps roughly to messages, not conversations)\n // Simplest: re-derive from the event — just drop conversations from the end\n const toRemove = Math.max(1, Math.ceil(data.truncatedCount / 2));\n const conversations = state.conversations.slice(\n 0,\n Math.max(0, state.conversations.length - toRemove)\n );\n return { ...state, conversations, status: \"idle\" };\n}\n\nfunction handleWorkspaceTree(\n state: PresentationState,\n data: { files: FileTreeEntry[] }\n): PresentationState {\n return {\n ...state,\n workspace: { files: data.files },\n };\n}\n\n// ============================================================================\n// Helper: Add user conversation\n// ============================================================================\n\nexport function addUserConversation(\n state: PresentationState,\n content: string | UserContentPart[]\n): PresentationState {\n const blocks: Block[] =\n typeof content === \"string\"\n ? [{ type: \"text\", content }]\n : content.map((part) => {\n switch (part.type) {\n case \"text\":\n return { type: \"text\" as const, content: part.text };\n case \"image\":\n return {\n type: \"image\" as const,\n url: `data:${part.mediaType};base64,${part.data}`,\n alt: part.name,\n };\n case \"file\":\n return {\n type: \"file\" as const,\n filename: part.filename ?? \"file\",\n mediaType: part.mediaType,\n };\n default:\n return { type: \"text\" as const, content: String(part) };\n }\n });\n\n return {\n ...state,\n conversations: [...state.conversations, { role: \"user\", blocks }],\n status: \"submitted\",\n };\n}\n\nexport function createInitialState(): PresentationState {\n return { ...initialPresentationState };\n}\n\n// ============================================================================\n// Helper: Format tool result output\n// ============================================================================\n\nfunction formatToolResultOutput(output: ToolResultOutput): string {\n switch (output.type) {\n case \"text\":\n case \"error-text\":\n return output.value;\n case \"json\":\n case \"error-json\":\n return JSON.stringify(output.value);\n case \"execution-denied\":\n return output.reason ?? \"Execution denied\";\n case \"content\":\n return output.value\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text)\n .join(\"\");\n }\n}\n\n// ============================================================================\n// Message → Conversation Converter\n// ============================================================================\n\n/**\n * Convert persisted Messages to Presentation Conversations.\n *\n * Groups consecutive assistant + tool-result messages\n * into a single AssistantConversation.\n *\n * Tool calls are now part of AssistantMessage.content (as ToolCallPart),\n * so we extract them directly from the assistant message.\n */\nexport function messagesToConversations(messages: Message[]): Conversation[] {\n const conversations: Conversation[] = [];\n let currentAssistant: AssistantConversation | null = null;\n\n function flushAssistant() {\n if (currentAssistant && currentAssistant.blocks.length > 0) {\n conversations.push(currentAssistant);\n }\n currentAssistant = null;\n }\n\n for (const msg of messages) {\n switch (msg.subtype) {\n case \"user\": {\n flushAssistant();\n const m = msg as UserMessage;\n const blocks: Block[] =\n typeof m.content === \"string\"\n ? [{ type: \"text\", content: m.content }]\n : m.content.map((part): Block => {\n switch (part.type) {\n case \"text\":\n return { type: \"text\", content: part.text };\n case \"image\":\n return {\n type: \"image\",\n url: `data:${part.mediaType};base64,${part.data}`,\n alt: part.name,\n };\n case \"file\":\n return {\n type: \"file\",\n filename: part.filename ?? \"file\",\n mediaType: part.mediaType,\n };\n default:\n return { type: \"text\", content: String(part) };\n }\n });\n conversations.push({ role: \"user\", blocks });\n break;\n }\n\n case \"assistant\": {\n if (!currentAssistant) {\n currentAssistant = { role: \"assistant\", blocks: [], isStreaming: false };\n }\n const m = msg as AssistantMessage;\n if (typeof m.content === \"string\") {\n if (m.content) {\n currentAssistant.blocks.push({ type: \"text\", content: m.content } as TextBlock);\n }\n } else {\n // Extract all content parts — must match what real-time streaming produces\n for (const part of m.content) {\n if (part.type === \"text\") {\n if (part.text) {\n currentAssistant.blocks.push({ type: \"text\", content: part.text } as TextBlock);\n }\n } else if (part.type === \"thinking\") {\n if (part.reasoning) {\n currentAssistant.blocks.push({\n type: \"thinking\",\n content: part.reasoning,\n } as Block);\n }\n } else if (part.type === \"tool-call\") {\n const tc = part as ToolCallPart;\n currentAssistant.blocks.push({\n type: \"tool\",\n toolUseId: tc.id,\n toolName: tc.name,\n toolInput: tc.input,\n status: \"completed\",\n } as ToolBlock);\n } else if (part.type === \"file\") {\n currentAssistant.blocks.push({\n type: \"file\",\n filename: (part as any).filename ?? \"file\",\n mediaType: (part as any).mediaType ?? \"application/octet-stream\",\n } as Block);\n }\n }\n }\n break;\n }\n\n case \"tool-result\": {\n const m = msg as ToolResultMessage;\n if (currentAssistant) {\n for (const block of currentAssistant.blocks) {\n if (block.type === \"tool\" && block.toolUseId === m.toolResult.id) {\n block.toolResult = formatToolResultOutput(m.toolResult.output);\n block.status =\n m.toolResult.output.type === \"error-text\" ||\n m.toolResult.output.type === \"error-json\" ||\n m.toolResult.output.type === \"execution-denied\"\n ? \"error\"\n : \"completed\";\n break;\n }\n }\n }\n break;\n }\n\n case \"error\": {\n flushAssistant();\n const m = msg as ErrorMessage;\n conversations.push({\n role: \"error\",\n message: m.content,\n });\n break;\n }\n }\n }\n\n flushAssistant();\n return conversations;\n}\n","/**\n * Presentation Class\n *\n * High-level API for UI integration.\n * Wraps AgentX client and provides presentation state management.\n */\n\nimport type { UserContentPart } from \"@agentxjs/core/agent\";\nimport type { BusEvent, Unsubscribe } from \"@agentxjs/core/event\";\nimport type { AgentX } from \"../types\";\nimport { addUserConversation, createInitialState, presentationReducer } from \"./reducer\";\nimport type { Conversation, PresentationState, PresentationWorkspace } from \"./types\";\nimport { initialPresentationState } from \"./types\";\n\n/**\n * Presentation update handler\n */\nexport type PresentationUpdateHandler = (state: PresentationState) => void;\n\n/**\n * Presentation error handler\n */\nexport type PresentationErrorHandler = (error: Error) => void;\n\n/**\n * Presentation options\n */\nexport interface PresentationOptions {\n /**\n * Called on every state update\n */\n onUpdate?: PresentationUpdateHandler;\n\n /**\n * Called on errors\n */\n onError?: PresentationErrorHandler;\n}\n\n/**\n * Presentation - UI-friendly wrapper for AgentX\n */\nexport class Presentation {\n private agentx: AgentX;\n private instanceId: string;\n private state: PresentationState;\n private updateHandlers: Set<PresentationUpdateHandler> = new Set();\n private errorHandlers: Set<PresentationErrorHandler> = new Set();\n private eventUnsubscribe: Unsubscribe | null = null;\n\n /**\n * Workspace operations — read, write, list files in the agent's workspace.\n * null when the agent has no workspace.\n */\n readonly workspace: PresentationWorkspace | null;\n\n constructor(\n agentx: AgentX,\n instanceId: string,\n options?: PresentationOptions,\n initialConversations?: Conversation[],\n workspace?: PresentationWorkspace | null\n ) {\n this.agentx = agentx;\n this.instanceId = instanceId;\n this.workspace = workspace ?? null;\n this.state = initialConversations?.length\n ? { ...initialPresentationState, conversations: initialConversations }\n : createInitialState();\n\n // Register initial handlers\n if (options?.onUpdate) {\n this.updateHandlers.add(options.onUpdate);\n }\n if (options?.onError) {\n this.errorHandlers.add(options.onError);\n }\n\n // Subscribe to all events\n this.subscribeToEvents();\n\n // Load initial workspace file tree\n if (this.workspace) {\n this.workspace.list(\".\").then((files) => {\n this.state = { ...this.state, workspace: { files } };\n this.notify();\n });\n }\n }\n\n /**\n * Get current state\n */\n getState(): PresentationState {\n return this.state;\n }\n\n /**\n * Subscribe to state updates\n */\n onUpdate(handler: PresentationUpdateHandler): Unsubscribe {\n this.updateHandlers.add(handler);\n // Immediately call with current state\n handler(this.state);\n return () => {\n this.updateHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to errors\n */\n onError(handler: PresentationErrorHandler): Unsubscribe {\n this.errorHandlers.add(handler);\n return () => {\n this.errorHandlers.delete(handler);\n };\n }\n\n /**\n * Send a message (text or content parts with files/images)\n */\n async send(content: string | UserContentPart[]): Promise<void> {\n // Add user conversation\n this.state = addUserConversation(this.state, content);\n this.notify();\n\n try {\n // Send message via agentx\n await this.agentx.runtime.session.send(this.instanceId, content);\n } catch (error) {\n this.notifyError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Interrupt current response\n */\n async interrupt(): Promise<void> {\n try {\n await this.agentx.runtime.session.interrupt(this.instanceId);\n } catch (error) {\n this.notifyError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Rewind conversation to a specific index.\n *\n * Calls runtime.rewind — a system-level operation that:\n * 1. Truncates session messages\n * 2. Resets circuit breaker\n * 3. Emits rewind event → reducer updates state\n *\n * @param index - conversation index to rewind to (0-based, removes this index and after)\n */\n async rewind(index: number): Promise<void> {\n const conversations = this.state.conversations;\n if (index < 0 || index >= conversations.length) return;\n\n try {\n // Map conversation index to message ID\n const messages = await this.agentx.runtime.session.getMessages(this.instanceId);\n if (messages.length === 0) return;\n\n if (index === 0) {\n // Rewind to beginning — use first message\n await this.agentx.rpc(\"runtime.rewind\", {\n imageId: this.instanceId,\n messageId: messages[0].id,\n });\n } else {\n // Find the message that corresponds to the conversation before rewind point\n let msgIndex = -1;\n let convCount = 0;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].subtype === \"user\" || messages[i].subtype === \"assistant\") {\n convCount++;\n }\n if (convCount >= index) {\n msgIndex = i;\n break;\n }\n }\n if (msgIndex >= 0 && msgIndex < messages.length) {\n await this.agentx.rpc(\"runtime.rewind\", {\n imageId: this.instanceId,\n messageId: messages[msgIndex].id,\n });\n }\n }\n } catch (error) {\n this.notifyError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Edit a user message and resend.\n * Rewinds to the message, replaces it, and sends the new content.\n *\n * @param index - conversation index of the user message to edit (0-based)\n * @param content - new content to send\n */\n async editAndResend(index: number, content: string | UserContentPart[]): Promise<void> {\n // Rewind to before this message\n await this.rewind(index);\n\n // Send the new content\n await this.send(content);\n }\n\n /**\n * Reset state\n */\n reset(): void {\n this.state = createInitialState();\n this.notify();\n }\n\n /**\n * Dispose and cleanup\n */\n dispose(): void {\n if (this.eventUnsubscribe) {\n this.eventUnsubscribe();\n this.eventUnsubscribe = null;\n }\n this.updateHandlers.clear();\n this.errorHandlers.clear();\n }\n\n // ==================== Private ====================\n\n private subscribeToEvents(): void {\n // Subscribe to all events and filter by instanceId\n this.eventUnsubscribe = this.agentx.onAny((event: BusEvent) => {\n // Filter events for this agent (if context is available)\n // Note: Events from server may or may not include context with instanceId\n const eventWithContext = event as BusEvent & { context?: { instanceId?: string } };\n const eventAgentId = eventWithContext.context?.instanceId;\n\n // Only filter if event has context and neither instanceId nor imageId matches\n if (eventAgentId && eventAgentId !== this.instanceId) {\n // Also check imageId in context\n const eventImageId = (eventWithContext.context as any)?.imageId;\n if (!eventImageId || eventImageId !== this.instanceId) {\n return;\n }\n }\n\n // Reduce event into state\n const newState = presentationReducer(this.state, event);\n if (newState !== this.state) {\n this.state = newState;\n this.notify();\n }\n });\n }\n\n private notify(): void {\n for (const handler of this.updateHandlers) {\n try {\n handler(this.state);\n } catch (error) {\n console.error(\"Presentation update handler error:\", error);\n }\n }\n }\n\n private notifyError(error: Error): void {\n for (const handler of this.errorHandlers) {\n try {\n handler(error);\n } catch (e) {\n console.error(\"Presentation error handler error:\", e);\n }\n }\n }\n}\n","/**\n * Presentation namespace factory\n *\n * Singleton per imageId — same imageId always returns the same Presentation.\n * First call creates from history, subsequent calls return existing instance.\n * Options (onUpdate, onError) are additive — new handlers are merged in.\n */\n\nimport { messagesToConversations, Presentation, type PresentationOptions } from \"../presentation\";\nimport type { PresentationWorkspace } from \"../presentation/types\";\nimport type { AgentX, PresentationNamespace, SessionNamespace } from \"../types\";\n\n/**\n * Workspace resolver — given an imageId, returns a PresentationWorkspace or null.\n * Provided by the client (local or remote) to decouple from runtime internals.\n */\nexport type WorkspaceResolver = (imageId: string) => Promise<PresentationWorkspace | null>;\n\nexport function createPresentations(\n agentx: AgentX,\n sessionNs: SessionNamespace,\n workspaceResolver?: WorkspaceResolver\n): PresentationNamespace {\n const instances = new Map<string, Presentation>();\n\n return {\n async create(imageId: string, options?: PresentationOptions): Promise<Presentation> {\n // Return existing singleton\n const existing = instances.get(imageId);\n if (existing) {\n // Merge new handlers if provided\n if (options?.onUpdate) existing.onUpdate(options.onUpdate);\n if (options?.onError) existing.onError(options.onError);\n return existing;\n }\n\n // Resolve workspace for this image\n const workspace = workspaceResolver ? await workspaceResolver(imageId) : null;\n\n // Create new from history\n const messages = await sessionNs.getMessages(imageId);\n const conversations = messagesToConversations(messages);\n const presentation = new Presentation(agentx, imageId, options, conversations, workspace);\n\n instances.set(imageId, presentation);\n\n // Clean up on dispose\n const originalDispose = presentation.dispose.bind(presentation);\n presentation.dispose = () => {\n instances.delete(imageId);\n originalDispose();\n };\n\n return presentation;\n },\n };\n}\n","/**\n * Session namespace factories (messaging)\n */\n\nimport type { Message, UserContentPart } from \"@agentxjs/core/agent\";\nimport type { RpcClient } from \"@agentxjs/core/network\";\nimport type { AgentXRuntime } from \"@agentxjs/core/runtime\";\nimport type { BaseResponse, InstanceInfo, MessageSendResponse, SessionNamespace } from \"../types\";\n\n/**\n * Create local session namespace backed by embedded runtime\n */\n/**\n * Resolve an imageId or instanceId to a running agent instanceId.\n * If no agent exists for this imageId, auto-creates one.\n */\nasync function resolveLocal(runtime: AgentXRuntime, id: string): Promise<string> {\n // Direct instanceId\n if (id.startsWith(\"inst_\")) {\n const agent = runtime.getAgent(id);\n if (agent) return id;\n }\n\n // imageId — find existing or auto-create\n const imageId = id.startsWith(\"img_\") ? id : id;\n const existing = runtime\n .getAgents()\n .find((a) => a.imageId === imageId && a.lifecycle === \"running\");\n if (existing) return existing.instanceId;\n\n const agent = await runtime.createAgent({ imageId });\n return agent.instanceId;\n}\n\nexport function createLocalSessions(runtime: AgentXRuntime): SessionNamespace {\n return {\n async send(id: string, content: string | unknown[]): Promise<MessageSendResponse> {\n const instanceId = await resolveLocal(runtime, id);\n await runtime.receive(instanceId, content as string | UserContentPart[]);\n return { instanceId, requestId: \"\" };\n },\n\n async interrupt(id: string): Promise<BaseResponse> {\n const instanceId = await resolveLocal(runtime, id);\n runtime.interrupt(instanceId);\n return { requestId: \"\" };\n },\n\n async getMessages(id: string): Promise<Message[]> {\n // For imageId, get messages directly from session\n if (id.startsWith(\"img_\")) {\n const image = await runtime.platform.imageRepository.findImageById(id);\n if (!image) return [];\n return runtime.platform.sessionRepository.getMessages(image.sessionId);\n }\n const agent = runtime.getAgent(id);\n if (!agent) return [];\n return runtime.platform.sessionRepository.getMessages(agent.sessionId);\n },\n };\n}\n\n/**\n * Create remote session namespace backed by RPC client\n */\n/**\n * Detect whether an ID is an imageId or instanceId based on prefix.\n * imageId starts with \"img_\", instanceId starts with \"inst_\".\n */\nfunction resolveId(id: string): { imageId?: string; instanceId?: string } {\n if (id.startsWith(\"inst_\")) return { instanceId: id };\n return { imageId: id };\n}\n\nexport function createRemoteSessions(rpcClient: RpcClient): SessionNamespace {\n return {\n async send(id: string, content: string | unknown[]): Promise<MessageSendResponse> {\n const result = await rpcClient.call<MessageSendResponse>(\"message.send\", {\n ...resolveId(id),\n content,\n });\n return { ...result, requestId: \"\" };\n },\n\n async interrupt(id: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"instance.interrupt\", {\n ...resolveId(id),\n });\n return { ...result, requestId: \"\" };\n },\n\n async getMessages(id: string): Promise<Message[]> {\n // For instanceId, resolve to imageId first\n if (id.startsWith(\"inst_\")) {\n const agentRes = await rpcClient.call<{ agent: { imageId: string } | null }>(\n \"instance.get\",\n { instanceId: id }\n );\n if (!agentRes.agent) return [];\n id = agentRes.agent.imageId;\n }\n const msgRes = await rpcClient.call<{ messages: Message[] }>(\"image.messages\", {\n imageId: id,\n });\n return msgRes.messages ?? [];\n },\n };\n}\n","/**\n * RemoteClient - AgentX client for remote server\n *\n * Uses RpcClient from @agentxjs/core/network for JSON-RPC communication.\n * This class focuses on business logic, not protocol details.\n */\n\nimport type { AgentXError } from \"@agentxjs/core/error\";\nimport type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from \"@agentxjs/core/event\";\nimport { EventBusImpl } from \"@agentxjs/core/event\";\nimport { RpcClient } from \"@agentxjs/core/network\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { AgentHandleImpl } from \"./AgentHandle\";\nimport { createRemoteImages } from \"./namespaces/images\";\nimport { createRemoteLLM } from \"./namespaces/llm\";\nimport { createPresentations } from \"./namespaces/presentations\";\nimport { createRemoteSessions } from \"./namespaces/sessions\";\nimport type {\n AgentX,\n ChatNamespace,\n LLMNamespace,\n RemoteClientConfig,\n RuntimeNamespace,\n} from \"./types\";\n\nconst logger = createLogger(\"agentx/RemoteClient\");\n\n/**\n * RemoteClient implementation using JSON-RPC 2.0\n */\nexport class RemoteClient implements AgentX {\n private readonly config: RemoteClientConfig;\n private readonly eventBus: EventBus;\n private readonly rpcClient: RpcClient;\n\n readonly chat: ChatNamespace;\n readonly runtime: RuntimeNamespace;\n readonly provider: LLMNamespace;\n\n constructor(config: RemoteClientConfig) {\n this.config = config;\n this.eventBus = new EventBusImpl();\n\n // Create RPC client (WebSocket factory from platform if available)\n this.rpcClient = new RpcClient({\n url: config.serverUrl,\n createWebSocket: config.customPlatform?.channelClient,\n timeout: config.timeout ?? 30000,\n autoReconnect: config.autoReconnect ?? true,\n headers: config.headers as Record<string, string> | undefined,\n debug: false,\n });\n\n // Forward stream events to internal event bus\n this.rpcClient.onStreamEvent((topic, event) => {\n logger.debug(\"Received stream event\", { topic, type: event.type });\n this.eventBus.emit(event as BusEvent);\n });\n\n // Forward connection state changes to event bus\n this.rpcClient.onStateChange((state) => {\n this.eventBus.emit({\n type: \"connection_state\",\n timestamp: Date.now(),\n data: { state },\n } as BusEvent);\n });\n\n // Assemble namespaces\n const image = createRemoteImages(this.rpcClient);\n const session = createRemoteSessions(this.rpcClient);\n const llm = createRemoteLLM(this.rpcClient);\n // Workspace resolver via RPC — server handles workspace access\n const workspaceResolver = async (imageId: string) => {\n const rpc = this.rpcClient;\n return {\n read: async (path: string) => {\n const res = await rpc.call<{ content: string }>(\"workspace.read\", { imageId, path });\n return res.content;\n },\n write: async (path: string, content: string) => {\n await rpc.call(\"workspace.write\", { imageId, path, content });\n },\n list: async (path?: string) => {\n const res = await rpc.call<{\n files: Array<{ name: string; path: string; type: \"file\" | \"directory\" }>;\n }>(\"workspace.list\", { imageId, path });\n return res.files;\n },\n };\n };\n const present = createPresentations(this, session, workspaceResolver);\n\n this.runtime = { image, session, present, llm };\n this.provider = llm;\n this.chat = this.createChatNamespace();\n }\n\n // ==================== Properties ====================\n\n get connected(): boolean {\n return this.rpcClient.connected;\n }\n\n get events(): EventBus {\n return this.eventBus;\n }\n\n // ==================== Connection ====================\n\n async connect(): Promise<void> {\n await this.rpcClient.connect();\n logger.info(\"Connected to server\", { url: this.config.serverUrl });\n }\n\n async disconnect(): Promise<void> {\n this.rpcClient.disconnect();\n logger.info(\"Disconnected from server\");\n }\n\n async dispose(): Promise<void> {\n this.rpcClient.dispose();\n this.eventBus.destroy();\n logger.info(\"RemoteClient disposed\");\n }\n\n // ==================== Event Subscription ====================\n\n on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {\n return this.eventBus.on(type, handler);\n }\n\n onAny(handler: BusEventHandler): Unsubscribe {\n return this.eventBus.onAny(handler);\n }\n\n // ==================== Error Handling ====================\n\n onError(handler: (error: AgentXError) => void): Unsubscribe {\n return this.eventBus.on(\"agentx_error\", (event) => {\n handler(event.data as AgentXError);\n });\n }\n\n // ==================== RPC ====================\n\n async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {\n return this.rpcClient.call<T>(method, params);\n }\n\n // ==================== Private ====================\n\n private createChatNamespace(): ChatNamespace {\n const rt = this.runtime;\n return {\n async create(params) {\n const imgRes = await rt.image.create(params);\n const runRes = await rt.image.run(imgRes.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n async list() {\n return rt.image.list();\n },\n async get(id) {\n const res = await rt.image.get(id);\n if (!res.record) return null;\n const runRes = await rt.image.run(res.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n };\n }\n}\n"],"mappings":"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","names":["createLogger","DEFAULT_CONTAINER_ID","agent","createLogger","logger","createLogger","createLogger"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/LocalClient.ts","../src/AgentHandle.ts","../src/namespaces/images.ts","../src/namespaces/llm.ts","../src/presentation/types.ts","../src/presentation/reducer.ts","../src/presentation/Presentation.ts","../src/namespaces/presentations.ts","../src/namespaces/sessions.ts","../src/RemoteClient.ts"],"sourcesContent":["/**\n * agentxjs - AgentX Client SDK\n *\n * Fluent API supporting local, remote, and server modes.\n *\n * @example Local mode\n * ```typescript\n * import { createAgentX } from \"agentxjs\";\n * import { nodePlatform } from \"@agentxjs/node-platform\";\n *\n * const ax = createAgentX(nodePlatform({ createDriver }));\n * const agent = await ax.chat.create({ name: \"Aristotle\", model: \"claude-sonnet-4-6\" });\n * await agent.send(\"Hello!\");\n * ```\n *\n * @example Remote mode\n * ```typescript\n * const ax = createAgentX();\n * const client = await ax.connect(\"ws://localhost:5200\");\n * ```\n *\n * @example Server mode\n * ```typescript\n * const ax = createAgentX(nodePlatform({ createDriver }));\n * const server = await ax.serve({ port: 5200 });\n * ```\n */\n\nimport type { CreateDriver } from \"@agentxjs/core/driver\";\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport { createAgentXRuntime } from \"@agentxjs/core/runtime\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { LocalClient } from \"./LocalClient\";\nimport { RemoteClient } from \"./RemoteClient\";\nimport type { AgentX, AgentXBuilder, AgentXServer, ConnectOptions, ServeConfig } from \"./types\";\n\nconst poolLogger = createLogger(\"agentx/connection-pool\");\n\n// ============================================================================\n// Connection Pool — module-level singleton for WebSocket connection reuse\n//\n// Solves React 18+ Strict Mode double-mount:\n// mount → connect (refCount=1) → unmount → dispose (refCount=0, deferred)\n// → re-mount → connect (reuse, refCount=1)\n// ============================================================================\n\ninterface PoolEntry {\n client: RemoteClient;\n refCount: number;\n}\n\nconst connectionPool = new Map<string, PoolEntry>();\n\nfunction pooledConnect(serverUrl: string, factory: () => Promise<RemoteClient>): Promise<AgentX> {\n const existing = connectionPool.get(serverUrl);\n if (existing && existing.client.connected) {\n existing.refCount++;\n poolLogger.debug(\"Connection reused\", { serverUrl, refCount: existing.refCount });\n return Promise.resolve(wrapWithRefCount(serverUrl, existing));\n }\n\n return factory().then((client) => {\n const entry: PoolEntry = { client, refCount: 1 };\n connectionPool.set(serverUrl, entry);\n poolLogger.debug(\"Connection created\", { serverUrl });\n return wrapWithRefCount(serverUrl, entry);\n });\n}\n\nfunction wrapWithRefCount(serverUrl: string, entry: PoolEntry): AgentX {\n const client = entry.client;\n const originalDispose = client.dispose.bind(client);\n const originalDisconnect = client.disconnect.bind(client);\n\n // Override dispose — only truly dispose when refCount reaches 0\n client.dispose = async () => {\n entry.refCount--;\n poolLogger.debug(\"Connection released\", { serverUrl, refCount: entry.refCount });\n if (entry.refCount <= 0) {\n connectionPool.delete(serverUrl);\n await originalDispose();\n }\n };\n\n // disconnect follows same refCount logic\n client.disconnect = async () => {\n entry.refCount--;\n if (entry.refCount <= 0) {\n connectionPool.delete(serverUrl);\n await originalDisconnect();\n }\n };\n\n return client;\n}\n\n/**\n * Platform configuration for createAgentX\n */\nexport interface PlatformConfig {\n platform: AgentXPlatform;\n createDriver: CreateDriver;\n}\n\n/**\n * Create an AgentX builder\n *\n * @param config - Platform configuration (optional). Without it, only connect() is available.\n * @returns AgentXBuilder — local AgentX + connect() + serve()\n */\nexport function createAgentX(config?: PlatformConfig): AgentXBuilder {\n let localClient: LocalClient | null = null;\n\n function getLocalClient(): LocalClient {\n if (localClient) return localClient;\n if (!config) {\n throw new Error(\n \"Local mode requires a platform. Pass a PlatformConfig to createAgentX(), or use connect() for remote mode.\"\n );\n }\n const runtime = createAgentXRuntime(config.platform, config.createDriver);\n localClient = new LocalClient(runtime);\n return localClient;\n }\n\n if (config) {\n getLocalClient();\n }\n\n return {\n get connected() {\n return localClient?.connected ?? false;\n },\n\n get events() {\n return getLocalClient().events;\n },\n\n get runtime() {\n return getLocalClient().runtime;\n },\n\n get provider() {\n return getLocalClient().provider;\n },\n\n get chat() {\n return getLocalClient().chat;\n },\n\n on(type, handler) {\n return getLocalClient().on(type, handler);\n },\n\n onAny(handler) {\n return getLocalClient().onAny(handler);\n },\n\n onError(handler) {\n return getLocalClient().onError(handler);\n },\n\n async disconnect() {\n await localClient?.disconnect();\n },\n\n async dispose() {\n await localClient?.dispose();\n localClient = null;\n },\n\n async connect(serverUrl: string, options?: ConnectOptions): Promise<AgentX> {\n return pooledConnect(serverUrl, async () => {\n const remoteClient = new RemoteClient({\n serverUrl,\n headers: options?.headers as Record<string, string> | undefined,\n context: options?.context,\n timeout: options?.timeout,\n autoReconnect: options?.autoReconnect,\n customPlatform: config?.platform,\n });\n await remoteClient.connect();\n return remoteClient;\n });\n },\n\n async serve(serveConfig?: ServeConfig): Promise<AgentXServer> {\n if (!config) {\n throw new Error(\"serve() requires a platform. Pass a PlatformConfig to createAgentX().\");\n }\n if (!config.platform.channelServer) {\n throw new Error(\n \"serve() requires platform.channelServer. Ensure your platform supports server mode.\"\n );\n }\n\n const { createServer } = await import(\"./server\");\n return createServer({\n platform: config.platform,\n createDriver: config.createDriver,\n port: serveConfig?.port,\n host: serveConfig?.host,\n server: serveConfig?.server as any,\n wsPath: serveConfig?.wsPath,\n });\n },\n\n async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {\n return getLocalClient().rpc<T>(method, params);\n },\n };\n}\n\n// Re-export context interfaces\nexport type { Capability, Context, ContextProvider } from \"@agentxjs/core/context\";\n// Re-export error types\nexport type { AgentXErrorCategory, AgentXErrorContext } from \"@agentxjs/core/error\";\nexport { AgentXError, AgentXErrorCode } from \"@agentxjs/core/error\";\n// Re-export Presentation\nexport type {\n AssistantConversation,\n Block,\n Conversation,\n ErrorConversation,\n FileBlock,\n ImageBlock,\n PresentationErrorHandler,\n PresentationMetrics,\n PresentationOptions,\n PresentationState,\n PresentationUpdateHandler,\n TextBlock,\n ThinkingBlock,\n ToolBlock,\n UserConversation,\n} from \"./presentation\";\nexport {\n addUserConversation,\n createInitialState,\n initialMetrics,\n initialPresentationState,\n messagesToConversations,\n Presentation,\n presentationReducer,\n} from \"./presentation\";\n// Re-export types\nexport type {\n AgentConfig,\n AgentHandle,\n AgentX,\n AgentXBuilder,\n AgentXServer,\n BaseResponse,\n ChatNamespace,\n ConnectOptions,\n ImageCreateResponse,\n ImageGetResponse,\n ImageListResponse,\n ImageNamespace,\n ImageRecord,\n ImageUpdateResponse,\n InstanceCreateResponse,\n InstanceGetResponse,\n InstanceInfo,\n InstanceListResponse,\n LLMNamespace,\n LLMProviderCreateResponse,\n LLMProviderDefaultResponse,\n LLMProviderGetResponse,\n LLMProviderListResponse,\n LLMProviderUpdateResponse,\n MaybeAsync,\n MessageSendResponse,\n PresentationNamespace,\n RuntimeNamespace,\n ServeConfig,\n SessionNamespace,\n} from \"./types\";\n","/**\n * LocalClient - AgentX client for local mode\n *\n * Runs an embedded Runtime + Driver directly, without WebSocket.\n * Implements the same AgentX interface as RemoteClient.\n */\n\nimport type { AgentXError } from \"@agentxjs/core/error\";\nimport type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from \"@agentxjs/core/event\";\n\nimport type { AgentXRuntime } from \"@agentxjs/core/runtime\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { AgentHandleImpl } from \"./AgentHandle\";\nimport { registerAll } from \"./handlers\";\nimport { createLocalImages } from \"./namespaces/images\";\nimport { createLocalLLM } from \"./namespaces/llm\";\nimport { createPresentations } from \"./namespaces/presentations\";\nimport { createLocalSessions } from \"./namespaces/sessions\";\nimport { RpcHandlerRegistry } from \"./RpcHandlerRegistry\";\nimport type { AgentX, ChatNamespace, LLMNamespace, RuntimeNamespace } from \"./types\";\n\nconst logger = createLogger(\"agentx/LocalClient\");\n\n/**\n * LocalClient - Embedded runtime implementation\n */\nexport class LocalClient implements AgentX {\n private readonly _runtime: AgentXRuntime;\n private registry: RpcHandlerRegistry | null = null;\n private isDisposed = false;\n\n readonly chat: ChatNamespace;\n readonly runtime: RuntimeNamespace;\n readonly provider: LLMNamespace;\n\n constructor(agentxRuntime: AgentXRuntime) {\n this._runtime = agentxRuntime;\n const platform = agentxRuntime.platform;\n\n const image = createLocalImages(platform, agentxRuntime);\n const session = createLocalSessions(agentxRuntime);\n const llm = createLocalLLM(platform);\n // Workspace resolver: imageId → PresentationWorkspace\n const workspaceResolver = async (imageId: string) => {\n const wp = platform.workspaceProvider;\n if (!wp) return null;\n const img = await platform.imageRepository.findImageById(imageId);\n if (!img?.workspaceId) return null;\n const ws = await wp.create(img.workspaceId);\n return {\n read: (path: string) => ws.read(path),\n write: (path: string, content: string) => ws.write(path, content),\n list: async (path?: string) => {\n const entries = await ws.list(path);\n return entries.map((e) => ({ name: e.name, path: e.path, type: e.type }));\n },\n };\n };\n const present = createPresentations(this, session, workspaceResolver);\n\n this.runtime = { image, session, present, llm };\n this.provider = llm;\n this.chat = this.createChatNamespace();\n\n logger.info(\"LocalClient initialized\");\n }\n\n // ==================== Properties ====================\n\n get connected(): boolean {\n return !this.isDisposed;\n }\n\n get events(): EventBus {\n return this._runtime.platform.eventBus;\n }\n\n // ==================== Event Subscription ====================\n\n on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {\n return this._runtime.platform.eventBus.on(type, handler);\n }\n\n onAny(handler: BusEventHandler): Unsubscribe {\n return this._runtime.platform.eventBus.onAny(handler);\n }\n\n // ==================== Error Handling ====================\n\n onError(handler: (error: AgentXError) => void): Unsubscribe {\n return this._runtime.platform.eventBus.on(\"agentx_error\", (event) => {\n handler(event.data as AgentXError);\n });\n }\n\n // ==================== RPC ====================\n\n async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {\n if (!this.registry) {\n this.registry = new RpcHandlerRegistry();\n registerAll(this.registry);\n }\n const result = await this.registry.handle(this._runtime, method, params);\n if (result.success) {\n return result.data as T;\n }\n throw new Error(result.message);\n }\n\n // ==================== Private ====================\n\n private createChatNamespace(): ChatNamespace {\n const rt = this.runtime;\n return {\n async create(params) {\n const imgRes = await rt.image.create(params);\n const runRes = await rt.image.run(imgRes.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n async list() {\n return rt.image.list();\n },\n async get(id) {\n const res = await rt.image.get(id);\n if (!res.record) return null;\n const runRes = await rt.image.run(res.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n };\n }\n\n // ==================== Lifecycle ====================\n\n async disconnect(): Promise<void> {\n // No-op for local mode\n }\n\n async dispose(): Promise<void> {\n if (this.isDisposed) return;\n await this._runtime.shutdown();\n this.isDisposed = true;\n logger.info(\"LocalClient disposed\");\n }\n}\n","/**\n * AgentHandle — live reference to a created agent.\n *\n * Wraps identity (IDs) + delegates operations to instance namespaces.\n */\n\nimport type { Message } from \"@agentxjs/core/agent\";\nimport type { Presentation, PresentationOptions } from \"./presentation\";\nimport type {\n AgentConfig,\n AgentHandle,\n BaseResponse,\n MessageSendResponse,\n RuntimeNamespace,\n} from \"./types\";\n\nexport class AgentHandleImpl implements AgentHandle {\n readonly instanceId: string;\n readonly imageId: string;\n readonly containerId: string;\n readonly sessionId: string;\n\n private readonly ns: RuntimeNamespace;\n\n constructor(\n ids: { instanceId: string; imageId: string; containerId: string; sessionId: string },\n ns: RuntimeNamespace\n ) {\n this.instanceId = ids.instanceId;\n this.imageId = ids.imageId;\n this.containerId = ids.containerId;\n this.sessionId = ids.sessionId;\n this.ns = ns;\n }\n\n async send(content: string | unknown[]): Promise<MessageSendResponse> {\n return this.ns.session.send(this.instanceId, content);\n }\n\n async interrupt(): Promise<BaseResponse> {\n return this.ns.session.interrupt(this.instanceId);\n }\n\n async history(): Promise<Message[]> {\n return this.ns.image.getMessages(this.imageId);\n }\n\n async present(options?: PresentationOptions): Promise<Presentation> {\n return this.ns.present.create(this.instanceId, options);\n }\n\n async update(\n updates: Partial<\n Pick<\n AgentConfig,\n \"name\" | \"description\" | \"model\" | \"systemPrompt\" | \"mcpServers\" | \"customData\"\n >\n >\n ): Promise<void> {\n await this.ns.image.update(this.imageId, updates);\n }\n\n async delete(): Promise<void> {\n await this.ns.image.stop(this.imageId);\n await this.ns.image.delete(this.imageId);\n }\n}\n","/**\n * Image namespace factories\n */\n\nimport type { Message } from \"@agentxjs/core/agent\";\nimport { DEFAULT_CONTAINER_ID } from \"@agentxjs/core/container\";\nimport type { RpcClient } from \"@agentxjs/core/network\";\nimport type { AgentXPlatform, AgentXRuntime } from \"@agentxjs/core/runtime\";\nimport type {\n AgentConfig,\n BaseResponse,\n ImageCreateResponse,\n ImageGetResponse,\n ImageListResponse,\n ImageNamespace,\n ImageUpdateResponse,\n InstanceCreateResponse,\n} from \"../types\";\n\n/**\n * Create local image namespace backed by embedded runtime\n */\nexport function createLocalImages(\n platform: AgentXPlatform,\n runtime?: AgentXRuntime\n): ImageNamespace {\n return {\n async create(params: AgentConfig): Promise<ImageCreateResponse> {\n const { imageRepository, sessionRepository } = platform;\n const { createImage } = await import(\"@agentxjs/core/image\");\n\n const { model, systemPrompt, mcpServers, ...rest } = params;\n const embody =\n model || systemPrompt || mcpServers\n ? { model, systemPrompt, mcpServers: mcpServers as any }\n : undefined;\n\n const image = await createImage(\n {\n containerId: DEFAULT_CONTAINER_ID,\n ...rest,\n embody,\n },\n { imageRepository, sessionRepository }\n );\n\n return {\n record: image.toRecord(),\n requestId: \"\",\n };\n },\n\n async get(imageId: string): Promise<ImageGetResponse> {\n const record = await platform.imageRepository.findImageById(imageId);\n return {\n record,\n requestId: \"\",\n };\n },\n\n async list(): Promise<ImageListResponse> {\n const records = await platform.imageRepository.findAllImages();\n\n return {\n records,\n requestId: \"\",\n };\n },\n\n async update(\n imageId: string,\n updates: {\n name?: string;\n description?: string;\n customData?: Record<string, unknown>;\n }\n ): Promise<ImageUpdateResponse> {\n const { loadImage } = await import(\"@agentxjs/core/image\");\n const { imageRepository, sessionRepository } = platform;\n\n const image = await loadImage(imageId, { imageRepository, sessionRepository });\n if (!image) {\n throw new Error(`Image not found: ${imageId}`);\n }\n\n const updated = await image.update(updates);\n return { record: updated.toRecord(), requestId: \"\" };\n },\n\n async delete(imageId: string): Promise<BaseResponse> {\n const { loadImage } = await import(\"@agentxjs/core/image\");\n const { imageRepository, sessionRepository } = platform;\n\n const image = await loadImage(imageId, { imageRepository, sessionRepository });\n if (image) {\n await image.delete();\n }\n\n return { requestId: \"\" };\n },\n\n async getMessages(imageId: string): Promise<Message[]> {\n const imageRecord = await platform.imageRepository.findImageById(imageId);\n if (!imageRecord) return [];\n return platform.sessionRepository.getMessages(imageRecord.sessionId);\n },\n\n async run(imageId: string): Promise<InstanceCreateResponse> {\n if (!runtime) throw new Error(\"Runtime not available\");\n const existing = runtime\n .getAgents()\n .find((a) => a.imageId === imageId && a.lifecycle === \"running\");\n if (existing) {\n return {\n instanceId: existing.instanceId,\n imageId: existing.imageId,\n containerId: existing.containerId,\n sessionId: existing.sessionId,\n requestId: \"\",\n };\n }\n const agent = await runtime.createAgent({ imageId });\n return {\n instanceId: agent.instanceId,\n imageId: agent.imageId,\n containerId: agent.containerId,\n sessionId: agent.sessionId,\n requestId: \"\",\n };\n },\n\n async stop(imageId: string): Promise<BaseResponse> {\n if (!runtime) throw new Error(\"Runtime not available\");\n const agent = runtime\n .getAgents()\n .find((a) => a.imageId === imageId && a.lifecycle === \"running\");\n if (agent) await runtime.stopAgent(agent.instanceId);\n return { requestId: \"\" };\n },\n };\n}\n\n/**\n * Create remote image namespace backed by RPC client\n */\nexport function createRemoteImages(rpcClient: RpcClient): ImageNamespace {\n return {\n async create(params: AgentConfig): Promise<ImageCreateResponse> {\n const result = await rpcClient.call<ImageCreateResponse>(\"image.create\", {\n ...params,\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n\n async get(imageId: string): Promise<ImageGetResponse> {\n const result = await rpcClient.call<ImageGetResponse>(\"image.get\", { imageId });\n return { ...result, requestId: \"\" };\n },\n\n async list(): Promise<ImageListResponse> {\n const result = await rpcClient.call<ImageListResponse>(\"image.list\", {});\n return { ...result, requestId: \"\" };\n },\n\n async update(\n imageId: string,\n updates: {\n name?: string;\n description?: string;\n customData?: Record<string, unknown>;\n }\n ): Promise<ImageUpdateResponse> {\n const result = await rpcClient.call<ImageUpdateResponse>(\"image.update\", {\n imageId,\n updates,\n });\n return { ...result, requestId: \"\" };\n },\n\n async delete(imageId: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"image.delete\", { imageId });\n return { ...result, requestId: \"\" };\n },\n\n async getMessages(imageId: string): Promise<Message[]> {\n const result = await rpcClient.call<{ messages: Message[] }>(\"image.messages\", { imageId });\n return result.messages ?? [];\n },\n\n async run(imageId: string): Promise<InstanceCreateResponse> {\n const result = await rpcClient.call<InstanceCreateResponse>(\"image.run\", { imageId });\n return { ...result, requestId: \"\" };\n },\n\n async stop(imageId: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"image.stop\", { imageId });\n return { ...result, requestId: \"\" };\n },\n };\n}\n","/**\n * LLM Provider namespace factories\n */\n\nimport { DEFAULT_CONTAINER_ID } from \"@agentxjs/core/container\";\nimport type { RpcClient } from \"@agentxjs/core/network\";\nimport type { LLMProviderRecord } from \"@agentxjs/core/persistence\";\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport { generateId } from \"@deepracticex/id\";\nimport type {\n BaseResponse,\n LLMNamespace,\n LLMProviderCreateResponse,\n LLMProviderDefaultResponse,\n LLMProviderGetResponse,\n LLMProviderListResponse,\n LLMProviderUpdateResponse,\n} from \"../types\";\n\n/**\n * Create local LLM namespace backed by platform repository\n */\nexport function createLocalLLM(platform: AgentXPlatform): LLMNamespace {\n const repo = platform.llmProviderRepository;\n if (!repo) {\n throw new Error(\"LLM provider repository not available on this platform\");\n }\n\n return {\n async create(params): Promise<LLMProviderCreateResponse> {\n const now = Date.now();\n const record: LLMProviderRecord = {\n id: generateId(\"llm\"),\n containerId: DEFAULT_CONTAINER_ID,\n name: params.name,\n vendor: params.vendor,\n protocol: params.protocol,\n apiKey: params.apiKey,\n baseUrl: params.baseUrl,\n model: params.model,\n isDefault: false,\n createdAt: now,\n updatedAt: now,\n };\n\n await repo.saveLLMProvider(record);\n return { record, requestId: \"\" };\n },\n\n async get(id: string): Promise<LLMProviderGetResponse> {\n const record = await repo.findLLMProviderById(id);\n return { record, requestId: \"\" };\n },\n\n async list(): Promise<LLMProviderListResponse> {\n const records = await repo.findLLMProvidersByContainerId(DEFAULT_CONTAINER_ID);\n return { records, requestId: \"\" };\n },\n\n async update(id, updates): Promise<LLMProviderUpdateResponse> {\n const existing = await repo.findLLMProviderById(id);\n if (!existing) {\n throw new Error(`LLM provider not found: ${id}`);\n }\n\n const updated: LLMProviderRecord = {\n ...existing,\n ...updates,\n id: existing.id,\n containerId: existing.containerId,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n\n await repo.saveLLMProvider(updated);\n return { record: updated, requestId: \"\" };\n },\n\n async delete(id: string): Promise<BaseResponse> {\n await repo.deleteLLMProvider(id);\n return { requestId: \"\" };\n },\n\n async setDefault(id: string): Promise<BaseResponse> {\n await repo.setDefaultLLMProvider(id);\n return { requestId: \"\" };\n },\n\n async getDefault(): Promise<LLMProviderDefaultResponse> {\n const record = await repo.findDefaultLLMProvider(DEFAULT_CONTAINER_ID);\n return { record, requestId: \"\" };\n },\n };\n}\n\n/**\n * Create remote LLM namespace backed by RPC client\n */\nexport function createRemoteLLM(rpcClient: RpcClient): LLMNamespace {\n return {\n async create(params): Promise<LLMProviderCreateResponse> {\n const result = await rpcClient.call<LLMProviderCreateResponse>(\"llm.create\", {\n ...params,\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n\n async get(id: string): Promise<LLMProviderGetResponse> {\n const result = await rpcClient.call<LLMProviderGetResponse>(\"llm.get\", { id });\n return { ...result, requestId: \"\" };\n },\n\n async list(): Promise<LLMProviderListResponse> {\n const result = await rpcClient.call<LLMProviderListResponse>(\"llm.list\", {\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n\n async update(id, updates): Promise<LLMProviderUpdateResponse> {\n const result = await rpcClient.call<LLMProviderUpdateResponse>(\"llm.update\", {\n id,\n updates,\n });\n return { ...result, requestId: \"\" };\n },\n\n async delete(id: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"llm.delete\", { id });\n return { ...result, requestId: \"\" };\n },\n\n async setDefault(id: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"llm.default\", { id });\n return { ...result, requestId: \"\" };\n },\n\n async getDefault(): Promise<LLMProviderDefaultResponse> {\n const result = await rpcClient.call<LLMProviderDefaultResponse>(\"llm.default\", {\n containerId: DEFAULT_CONTAINER_ID,\n });\n return { ...result, requestId: \"\" };\n },\n };\n}\n","/**\n * Presentation Types\n *\n * UI-friendly data model aggregated from stream events.\n * This implements the Presentation Model pattern.\n */\n\n// ============================================================================\n// Block Types - Basic content units\n// ============================================================================\n\n/**\n * Text block\n */\nexport interface TextBlock {\n type: \"text\";\n content: string;\n}\n\n/**\n * Tool block - represents a tool call and its result\n */\nexport interface ToolBlock {\n type: \"tool\";\n toolUseId: string;\n toolName: string;\n toolInput: Record<string, unknown>;\n toolResult?: string;\n /** Partial JSON input being streamed (visible during input-streaming phase) */\n partialInput?: string;\n status: \"pending\" | \"running\" | \"completed\" | \"error\" | \"interrupted\";\n}\n\n/**\n * Image block\n */\nexport interface ImageBlock {\n type: \"image\";\n url: string;\n alt?: string;\n}\n\n/**\n * File block\n */\nexport interface FileBlock {\n type: \"file\";\n filename: string;\n mediaType: string;\n}\n\n/**\n * Thinking/reasoning block — AI's internal reasoning process\n */\nexport interface ThinkingBlock {\n type: \"thinking\";\n content: string;\n}\n\n/**\n * All block types\n */\nexport type Block = TextBlock | ToolBlock | ImageBlock | FileBlock | ThinkingBlock;\n\n// ============================================================================\n// Conversation Types - A single turn in the conversation\n// ============================================================================\n\n/**\n * User conversation\n */\nexport interface UserConversation {\n role: \"user\";\n blocks: Block[];\n}\n\n/**\n * Token usage for a message (one LLM call / step)\n */\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Assistant conversation\n */\nexport interface AssistantConversation {\n role: \"assistant\";\n blocks: Block[];\n isStreaming: boolean;\n /** Accumulated token usage across all steps in this conversation */\n usage?: TokenUsage;\n}\n\n/**\n * Error conversation\n */\nexport interface ErrorConversation {\n role: \"error\";\n message: string;\n}\n\n/**\n * All conversation types\n */\nexport type Conversation = UserConversation | AssistantConversation | ErrorConversation;\n\n// ============================================================================\n// Presentation Metrics\n// ============================================================================\n\n/**\n * Turn-level metrics.\n * Reset at the start of each turn, preserved after turn ends.\n */\nexport interface TurnMetrics {\n /** Timestamp when the current turn started (null when idle before first turn) */\n turnStartedAt: number | null;\n /** Input tokens consumed in the current turn */\n inputTokens: number;\n /** Output tokens generated in the current turn */\n outputTokens: number;\n}\n\n/**\n * Session-level context metrics.\n * Tracks the overall context window usage across the entire session.\n */\nexport interface SessionMetrics {\n /** Current context size in tokens (last inputTokens from LLM — includes full history) */\n contextTokens: number;\n /** Model's context window limit (0 = unknown) */\n contextLimit: number;\n /** Context usage ratio 0-1 (0 when limit unknown) */\n contextUsage: number;\n}\n\n/**\n * Combined presentation metrics — turn + session level.\n */\nexport interface PresentationMetrics extends TurnMetrics {\n /** Session-level context window metrics */\n session: SessionMetrics;\n}\n\n// ============================================================================\n// Workspace State\n// ============================================================================\n\n/**\n * File tree entry — recursive structure for rendering directory tree\n */\nexport interface FileTreeEntry {\n /** File or directory name */\n name: string;\n /** Path relative to workspace root */\n path: string;\n /** File or directory */\n type: \"file\" | \"directory\";\n /** Children (only for directories) */\n children?: FileTreeEntry[];\n}\n\n/**\n * Workspace state — real-time workspace view\n */\nexport interface WorkspaceState {\n /**\n * Current file tree (recursive).\n * Frontend just renders this tree directly.\n */\n files: FileTreeEntry[];\n}\n\n// ============================================================================\n// Presentation Workspace Operations\n// ============================================================================\n\n/**\n * PresentationWorkspace — file operations exposed to the consumer.\n * Wraps the underlying Workspace with a simple API.\n */\nexport interface PresentationWorkspace {\n /** Read file content */\n read(path: string): Promise<string>;\n /** Write content to a file */\n write(path: string, content: string): Promise<void>;\n /** List directory entries */\n list(path?: string): Promise<FileTreeEntry[]>;\n}\n\n// ============================================================================\n// Presentation State\n// ============================================================================\n\n/**\n * Connection state\n */\nexport type ConnectionState = \"connected\" | \"connecting\" | \"disconnected\";\n\n/**\n * Presentation state - the complete UI state\n */\nexport interface PresentationState {\n /**\n * All conversations including the currently streaming one.\n * The streaming conversation is the last item with `isStreaming: true`.\n * Frontend just does `conversations.map(...)` — no merging needed.\n */\n conversations: Conversation[];\n\n /**\n * Current agent status\n *\n * - idle: No active request\n * - submitted: Message sent, waiting for first token\n * - thinking: LLM outputting thinking/reasoning content\n * - responding: LLM outputting text content\n * - executing: Tool call in progress\n */\n status: \"idle\" | \"submitted\" | \"thinking\" | \"responding\" | \"executing\";\n\n /**\n * WebSocket connection state\n */\n connection: ConnectionState;\n\n /**\n * Real-time metrics for the current turn\n */\n metrics: PresentationMetrics;\n\n /**\n * Workspace state — real-time file tree.\n * null when agent has no workspace.\n */\n workspace: WorkspaceState | null;\n}\n\n/**\n * Initial presentation metrics\n */\nexport const initialSessionMetrics: SessionMetrics = {\n contextTokens: 0,\n contextLimit: 0,\n contextUsage: 0,\n};\n\nexport const initialMetrics: PresentationMetrics = {\n turnStartedAt: null,\n inputTokens: 0,\n outputTokens: 0,\n session: initialSessionMetrics,\n};\n\n/**\n * Initial presentation state\n */\nexport const initialPresentationState: PresentationState = {\n conversations: [],\n status: \"idle\",\n connection: \"connected\",\n metrics: initialMetrics,\n workspace: null,\n};\n","/**\n * Presentation Reducer\n *\n * Aggregates events into PresentationState.\n * Pure function: (state, event) => newState\n *\n * Event consumption strategy:\n * - Stream layer: message_start, text_delta, tool_use_start, tool_use_stop, message_stop\n * (for real-time streaming display)\n * - Message layer: tool_result_message\n * (for tool execution results — arrives after message_stop)\n *\n * Tool calls are stream-level blocks within the assistant turn,\n * matching the mainstream API pattern (Anthropic, OpenAI).\n */\n\nimport type {\n AssistantMessage,\n ErrorMessage,\n Message,\n ToolCallPart,\n ToolResultMessage,\n ToolResultOutput,\n UserContentPart,\n UserMessage,\n} from \"@agentxjs/core/agent\";\nimport type { BusEvent } from \"@agentxjs/core/event\";\nimport type {\n AssistantConversation,\n Block,\n ConnectionState,\n Conversation,\n FileTreeEntry,\n PresentationState,\n TextBlock,\n TokenUsage,\n ToolBlock,\n} from \"./types\";\nimport { initialMetrics, initialPresentationState } from \"./types\";\n\n// ============================================================================\n// Event Data Types\n// ============================================================================\n\ninterface MessageStartData {\n messageId?: string;\n model?: string;\n}\n\ninterface TextDeltaData {\n text: string;\n}\n\ninterface ToolUseStartData {\n toolCallId: string;\n toolName: string;\n}\n\ninterface ToolUseStopData {\n toolCallId: string;\n toolName: string;\n input: Record<string, unknown>;\n}\n\ninterface MessageDeltaData {\n usage?: {\n inputTokens: number;\n outputTokens: number;\n };\n}\n\ninterface MessageStopData {\n stopReason?: string;\n}\n\ninterface ErrorData {\n message: string;\n code?: string;\n}\n\n// ============================================================================\n// Reducer\n// ============================================================================\n\n/**\n * Reduce an event into presentation state.\n *\n * Consumes:\n * - Stream events: message_start, text_delta, tool_use_start, tool_use_stop, message_stop\n * - Message events: tool_result_message\n * - Error events: error\n */\nexport function presentationReducer(state: PresentationState, event: BusEvent): PresentationState {\n switch (event.type) {\n // Stream layer — real-time display\n case \"message_start\":\n return handleMessageStart(state, event.data as MessageStartData);\n\n case \"thinking_delta\":\n return handleThinkingDelta(state, event.data as TextDeltaData);\n\n case \"text_delta\":\n return handleTextDelta(state, event.data as TextDeltaData);\n\n case \"tool_use_start\":\n return handleToolUseStart(state, event.data as ToolUseStartData);\n\n case \"tool_use_stop\":\n return handleToolUseStop(state, event.data as ToolUseStopData);\n\n case \"input_json_delta\":\n return handleInputJsonDelta(state, event.data as { partialJson: string });\n\n case \"message_delta\":\n return handleMessageDelta(state, event.data as MessageDeltaData);\n\n case \"message_stop\":\n return handleMessageStop(state, event.data as MessageStopData);\n\n // Message layer — tool results from Engine\n case \"tool_result_message\":\n return handleToolResultMessage(state, event.data as ToolResultMessage);\n\n case \"tool_result\":\n return handleToolResult(\n state,\n event.data as { toolCallId: string; result: unknown; isError: boolean }\n );\n\n case \"error\":\n return handleError(state, event.data as ErrorData);\n\n case \"interrupted\":\n return handleInterrupted(state);\n\n // Connection state\n case \"connection_state\":\n return handleConnectionState(state, event.data as { state: string });\n\n // Workspace file tree\n case \"workspace_tree\":\n return handleWorkspaceTree(state, event.data as { files: FileTreeEntry[] });\n\n // Rewind — runtime-level operation\n case \"rewind\":\n return handleRewind(state, event.data as { truncatedCount: number });\n\n default:\n return state;\n }\n}\n\n// ============================================================================\n// Helpers — operate on the last assistant conversation in conversations[]\n// ============================================================================\n\n/**\n * Get the last conversation if it's a streaming assistant conversation.\n */\nfunction getStreamingConv(state: PresentationState): AssistantConversation | null {\n const last = state.conversations[state.conversations.length - 1];\n if (last?.role === \"assistant\" && (last as AssistantConversation).isStreaming) {\n return last as AssistantConversation;\n }\n return null;\n}\n\n/**\n * Update the last conversation in the array (must be streaming assistant).\n */\nfunction updateLastConv(\n state: PresentationState,\n updater: (conv: AssistantConversation) => AssistantConversation,\n extraState?: Partial<PresentationState>\n): PresentationState {\n const conv = getStreamingConv(state);\n if (!conv) return state;\n\n const updated = updater(conv);\n const conversations = [...state.conversations];\n conversations[conversations.length - 1] = updated;\n\n return { ...state, conversations, ...extraState };\n}\n\ninterface InputJsonDeltaData {\n partialJson: string;\n}\n\n// ============================================================================\n// Handlers — all operate on conversations[]\n// ============================================================================\n\nfunction handleMessageStart(state: PresentationState, _data: MessageStartData): PresentationState {\n const newConv: AssistantConversation = {\n role: \"assistant\",\n blocks: [],\n isStreaming: true,\n };\n\n // Only reset metrics at the start of a new turn (idle/submitted → submitted).\n // Mid-turn message_start (after tool_use) should keep accumulating.\n const isNewTurn = state.status === \"idle\" || state.status === \"submitted\";\n const metrics = isNewTurn ? { ...initialMetrics, turnStartedAt: Date.now() } : state.metrics;\n\n return {\n ...state,\n conversations: [...state.conversations, newConv],\n status: \"submitted\",\n metrics,\n };\n}\n\nfunction handleThinkingDelta(state: PresentationState, data: TextDeltaData): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = [...conv.blocks];\n const lastBlock = blocks[blocks.length - 1];\n\n if (lastBlock && lastBlock.type === \"thinking\") {\n blocks[blocks.length - 1] = {\n ...lastBlock,\n content: (lastBlock as any).content + data.text,\n };\n } else {\n blocks.push({ type: \"thinking\", content: data.text } as Block);\n }\n\n return { ...conv, blocks };\n },\n { status: \"thinking\" }\n );\n}\n\nfunction handleTextDelta(state: PresentationState, data: TextDeltaData): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = [...conv.blocks];\n const lastBlock = blocks[blocks.length - 1];\n\n if (lastBlock && lastBlock.type === \"text\") {\n blocks[blocks.length - 1] = {\n ...lastBlock,\n content: lastBlock.content + data.text,\n };\n } else {\n blocks.push({ type: \"text\", content: data.text } as TextBlock);\n }\n\n return { ...conv, blocks };\n },\n { status: \"responding\" }\n );\n}\n\nfunction handleToolUseStart(state: PresentationState, data: ToolUseStartData): PresentationState {\n const toolBlock: ToolBlock = {\n type: \"tool\",\n toolUseId: data.toolCallId,\n toolName: data.toolName,\n toolInput: {},\n status: \"pending\",\n };\n\n return updateLastConv(state, (conv) => ({ ...conv, blocks: [...conv.blocks, toolBlock] }), {\n status: \"executing\",\n });\n}\n\nfunction handleInputJsonDelta(\n state: PresentationState,\n data: InputJsonDeltaData\n): PresentationState {\n return updateLastConv(state, (conv) => {\n const blocks = conv.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.status === \"pending\") {\n return {\n ...block,\n partialInput: ((block as any).partialInput || \"\") + data.partialJson,\n } as ToolBlock;\n }\n return block;\n });\n return { ...conv, blocks };\n });\n}\n\nfunction handleToolUseStop(state: PresentationState, data: ToolUseStopData): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = conv.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.toolUseId === data.toolCallId) {\n return { ...block, toolInput: data.input, status: \"running\" };\n }\n return block;\n });\n return { ...conv, blocks };\n },\n { status: \"executing\" }\n );\n}\n\nfunction handleMessageDelta(state: PresentationState, data: MessageDeltaData): PresentationState {\n if (!data.usage) return state;\n\n const newState = updateLastConv(state, (conv) => {\n const prev = conv.usage;\n const usage: TokenUsage = {\n inputTokens: (prev?.inputTokens ?? 0) + data.usage!.inputTokens,\n outputTokens: (prev?.outputTokens ?? 0) + data.usage!.outputTokens,\n };\n return { ...conv, usage };\n });\n\n // inputTokens from LLM = current context size (full history sent each call)\n const contextTokens = data.usage.inputTokens;\n const contextLimit = newState.metrics.session.contextLimit;\n const contextUsage = contextLimit > 0 ? contextTokens / contextLimit : 0;\n\n return {\n ...newState,\n metrics: {\n ...newState.metrics,\n inputTokens: newState.metrics.inputTokens + data.usage.inputTokens,\n outputTokens: newState.metrics.outputTokens + data.usage.outputTokens,\n session: {\n contextTokens,\n contextLimit,\n contextUsage,\n },\n },\n };\n}\n\nfunction handleMessageStop(state: PresentationState, data: MessageStopData): PresentationState {\n // tool_use stop → keep streaming, tool results are still incoming\n if (data.stopReason === \"tool_use\") {\n return { ...state, status: \"executing\" };\n }\n\n // end_turn / max_tokens → mark completed, clear turnStartedAt\n return updateLastConv(state, (conv) => ({ ...conv, isStreaming: false }), {\n status: \"idle\",\n metrics: { ...state.metrics, turnStartedAt: null },\n });\n}\n\nfunction handleToolResultMessage(\n state: PresentationState,\n data: ToolResultMessage\n): PresentationState {\n const toolCallId = data.toolCallId;\n\n // Find tool block in any conversation (could be in last streaming or already completed)\n const conversations = state.conversations.map((conv): Conversation => {\n if (conv.role !== \"assistant\") return conv;\n const ac = conv as AssistantConversation;\n const hasMatch = ac.blocks.some((b) => b.type === \"tool\" && b.toolUseId === toolCallId);\n if (!hasMatch) return conv;\n\n const blocks = ac.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.toolUseId === toolCallId) {\n return {\n ...block,\n toolResult: formatToolResultOutput(data.toolResult.output),\n status:\n data.toolResult.output.type === \"error-text\" ||\n data.toolResult.output.type === \"error-json\" ||\n data.toolResult.output.type === \"execution-denied\"\n ? \"error\"\n : \"completed\",\n };\n }\n return block;\n });\n return { ...ac, blocks };\n });\n\n return { ...state, conversations, status: \"responding\" };\n}\n\n/**\n * Handle tool_result from stream layer (raw driver event).\n */\nfunction handleToolResult(\n state: PresentationState,\n data: { toolCallId: string; result: unknown; isError: boolean }\n): PresentationState {\n const { toolCallId, result, isError } = data;\n const resultStr =\n typeof result === \"string\"\n ? result\n : result instanceof Error\n ? result.message\n : JSON.stringify(result);\n\n const conversations = state.conversations.map((conv): Conversation => {\n if (conv.role !== \"assistant\") return conv;\n const ac = conv as AssistantConversation;\n const hasMatch = ac.blocks.some((b) => b.type === \"tool\" && b.toolUseId === toolCallId);\n if (!hasMatch) return conv;\n\n const blocks = ac.blocks.map((block): Block => {\n if (block.type === \"tool\" && block.toolUseId === toolCallId) {\n return { ...block, toolResult: resultStr, status: isError ? \"error\" : \"completed\" };\n }\n return block;\n });\n return { ...ac, blocks };\n });\n\n return { ...state, conversations, status: \"responding\" };\n}\n\nfunction handleError(state: PresentationState, data: ErrorData): PresentationState {\n // If there's a streaming conversation with content, keep it\n const conv = getStreamingConv(state);\n let conversations = state.conversations;\n if (conv && conv.blocks.length > 0) {\n // Mark streaming conv as completed before adding error\n conversations = [...state.conversations];\n conversations[conversations.length - 1] = { ...conv, isStreaming: false };\n }\n\n return {\n ...state,\n conversations: [...conversations, { role: \"error\", message: data.message }],\n status: \"idle\",\n };\n}\n\n/**\n * Interrupt handlers per block type.\n * Each handler receives a block and returns the interrupted version.\n * New block types register here — handleInterrupted stays fixed.\n */\nconst interruptHandlers: Partial<Record<Block[\"type\"], (block: Block) => Block>> = {\n tool: (block) => {\n const tb = block as ToolBlock;\n if (tb.status === \"pending\" || tb.status === \"running\") {\n return { ...tb, status: \"interrupted\", toolResult: \"Interrupted\" };\n }\n return block;\n },\n};\n\nfunction handleInterrupted(state: PresentationState): PresentationState {\n return updateLastConv(\n state,\n (conv) => {\n const blocks = conv.blocks.map((block): Block => {\n const handler = interruptHandlers[block.type];\n return handler ? handler(block) : block;\n });\n return { ...conv, blocks, isStreaming: false };\n },\n { status: \"idle\" }\n );\n}\n\nfunction handleConnectionState(\n state: PresentationState,\n data: { state: string }\n): PresentationState {\n const connection = data.state as ConnectionState;\n if (connection === state.connection) return state;\n return { ...state, connection };\n}\n\nfunction handleRewind(\n state: PresentationState,\n data: { truncatedCount: number }\n): PresentationState {\n // Remove the last N conversations (truncatedCount maps roughly to messages, not conversations)\n // Simplest: re-derive from the event — just drop conversations from the end\n const toRemove = Math.max(1, Math.ceil(data.truncatedCount / 2));\n const conversations = state.conversations.slice(\n 0,\n Math.max(0, state.conversations.length - toRemove)\n );\n return { ...state, conversations, status: \"idle\" };\n}\n\nfunction handleWorkspaceTree(\n state: PresentationState,\n data: { files: FileTreeEntry[] }\n): PresentationState {\n return {\n ...state,\n workspace: { files: data.files },\n };\n}\n\n// ============================================================================\n// Helper: Add user conversation\n// ============================================================================\n\nexport function addUserConversation(\n state: PresentationState,\n content: string | UserContentPart[]\n): PresentationState {\n const blocks: Block[] =\n typeof content === \"string\"\n ? [{ type: \"text\", content }]\n : content.map((part) => {\n switch (part.type) {\n case \"text\":\n return { type: \"text\" as const, content: part.text };\n case \"image\":\n return {\n type: \"image\" as const,\n url: `data:${part.mediaType};base64,${part.data}`,\n alt: part.name,\n };\n case \"file\":\n return {\n type: \"file\" as const,\n filename: part.filename ?? \"file\",\n mediaType: part.mediaType,\n };\n default:\n return { type: \"text\" as const, content: String(part) };\n }\n });\n\n return {\n ...state,\n conversations: [...state.conversations, { role: \"user\", blocks }],\n status: \"submitted\",\n };\n}\n\nexport function createInitialState(): PresentationState {\n return { ...initialPresentationState };\n}\n\n// ============================================================================\n// Helper: Format tool result output\n// ============================================================================\n\nfunction formatToolResultOutput(output: ToolResultOutput): string {\n switch (output.type) {\n case \"text\":\n case \"error-text\":\n return output.value;\n case \"json\":\n case \"error-json\":\n return JSON.stringify(output.value);\n case \"execution-denied\":\n return output.reason ?? \"Execution denied\";\n case \"content\":\n return output.value\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text)\n .join(\"\");\n }\n}\n\n// ============================================================================\n// Message → Conversation Converter\n// ============================================================================\n\n/**\n * Convert persisted Messages to Presentation Conversations.\n *\n * Groups consecutive assistant + tool-result messages\n * into a single AssistantConversation.\n *\n * Tool calls are now part of AssistantMessage.content (as ToolCallPart),\n * so we extract them directly from the assistant message.\n */\nexport function messagesToConversations(messages: Message[]): Conversation[] {\n const conversations: Conversation[] = [];\n let currentAssistant: AssistantConversation | null = null;\n\n function flushAssistant() {\n if (currentAssistant && currentAssistant.blocks.length > 0) {\n conversations.push(currentAssistant);\n }\n currentAssistant = null;\n }\n\n for (const msg of messages) {\n switch (msg.subtype) {\n case \"user\": {\n flushAssistant();\n const m = msg as UserMessage;\n const blocks: Block[] =\n typeof m.content === \"string\"\n ? [{ type: \"text\", content: m.content }]\n : m.content.map((part): Block => {\n switch (part.type) {\n case \"text\":\n return { type: \"text\", content: part.text };\n case \"image\":\n return {\n type: \"image\",\n url: `data:${part.mediaType};base64,${part.data}`,\n alt: part.name,\n };\n case \"file\":\n return {\n type: \"file\",\n filename: part.filename ?? \"file\",\n mediaType: part.mediaType,\n };\n default:\n return { type: \"text\", content: String(part) };\n }\n });\n conversations.push({ role: \"user\", blocks });\n break;\n }\n\n case \"assistant\": {\n if (!currentAssistant) {\n currentAssistant = { role: \"assistant\", blocks: [], isStreaming: false };\n }\n const m = msg as AssistantMessage;\n if (typeof m.content === \"string\") {\n if (m.content) {\n currentAssistant.blocks.push({ type: \"text\", content: m.content } as TextBlock);\n }\n } else {\n // Extract all content parts — must match what real-time streaming produces\n for (const part of m.content) {\n if (part.type === \"text\") {\n if (part.text) {\n currentAssistant.blocks.push({ type: \"text\", content: part.text } as TextBlock);\n }\n } else if (part.type === \"thinking\") {\n if (part.reasoning) {\n currentAssistant.blocks.push({\n type: \"thinking\",\n content: part.reasoning,\n } as Block);\n }\n } else if (part.type === \"tool-call\") {\n const tc = part as ToolCallPart;\n currentAssistant.blocks.push({\n type: \"tool\",\n toolUseId: tc.id,\n toolName: tc.name,\n toolInput: tc.input,\n status: \"completed\",\n } as ToolBlock);\n } else if (part.type === \"file\") {\n currentAssistant.blocks.push({\n type: \"file\",\n filename: (part as any).filename ?? \"file\",\n mediaType: (part as any).mediaType ?? \"application/octet-stream\",\n } as Block);\n }\n }\n }\n break;\n }\n\n case \"tool-result\": {\n const m = msg as ToolResultMessage;\n if (currentAssistant) {\n for (const block of currentAssistant.blocks) {\n if (block.type === \"tool\" && block.toolUseId === m.toolResult.id) {\n block.toolResult = formatToolResultOutput(m.toolResult.output);\n block.status =\n m.toolResult.output.type === \"error-text\" ||\n m.toolResult.output.type === \"error-json\" ||\n m.toolResult.output.type === \"execution-denied\"\n ? \"error\"\n : \"completed\";\n break;\n }\n }\n }\n break;\n }\n\n case \"error\": {\n flushAssistant();\n const m = msg as ErrorMessage;\n conversations.push({\n role: \"error\",\n message: m.content,\n });\n break;\n }\n }\n }\n\n flushAssistant();\n return conversations;\n}\n","/**\n * Presentation Class\n *\n * High-level API for UI integration.\n * Wraps AgentX client and provides presentation state management.\n */\n\nimport type { UserContentPart } from \"@agentxjs/core/agent\";\nimport type { BusEvent, Unsubscribe } from \"@agentxjs/core/event\";\nimport type { AgentX } from \"../types\";\nimport { addUserConversation, createInitialState, presentationReducer } from \"./reducer\";\nimport type { Conversation, PresentationState, PresentationWorkspace } from \"./types\";\nimport { initialPresentationState } from \"./types\";\n\n/**\n * Presentation update handler\n */\nexport type PresentationUpdateHandler = (state: PresentationState) => void;\n\n/**\n * Presentation error handler\n */\nexport type PresentationErrorHandler = (error: Error) => void;\n\n/**\n * Presentation options\n */\nexport interface PresentationOptions {\n /**\n * Called on every state update\n */\n onUpdate?: PresentationUpdateHandler;\n\n /**\n * Called on errors\n */\n onError?: PresentationErrorHandler;\n}\n\n/**\n * Presentation - UI-friendly wrapper for AgentX\n */\nexport class Presentation {\n private agentx: AgentX;\n private instanceId: string;\n private state: PresentationState;\n private updateHandlers: Set<PresentationUpdateHandler> = new Set();\n private errorHandlers: Set<PresentationErrorHandler> = new Set();\n private eventUnsubscribe: Unsubscribe | null = null;\n\n /**\n * Workspace operations — read, write, list files in the agent's workspace.\n * null when the agent has no workspace.\n */\n readonly workspace: PresentationWorkspace | null;\n\n constructor(\n agentx: AgentX,\n instanceId: string,\n options?: PresentationOptions,\n initialConversations?: Conversation[],\n workspace?: PresentationWorkspace | null\n ) {\n this.agentx = agentx;\n this.instanceId = instanceId;\n this.workspace = workspace ?? null;\n this.state = initialConversations?.length\n ? { ...initialPresentationState, conversations: initialConversations }\n : createInitialState();\n\n // Register initial handlers\n if (options?.onUpdate) {\n this.updateHandlers.add(options.onUpdate);\n }\n if (options?.onError) {\n this.errorHandlers.add(options.onError);\n }\n\n // Subscribe to all events\n this.subscribeToEvents();\n\n // Load initial workspace file tree\n if (this.workspace) {\n this.workspace.list(\".\").then((files) => {\n this.state = { ...this.state, workspace: { files } };\n this.notify();\n });\n }\n }\n\n /**\n * Get current state\n */\n getState(): PresentationState {\n return this.state;\n }\n\n /**\n * Subscribe to state updates\n */\n onUpdate(handler: PresentationUpdateHandler): Unsubscribe {\n this.updateHandlers.add(handler);\n // Immediately call with current state\n handler(this.state);\n return () => {\n this.updateHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to errors\n */\n onError(handler: PresentationErrorHandler): Unsubscribe {\n this.errorHandlers.add(handler);\n return () => {\n this.errorHandlers.delete(handler);\n };\n }\n\n /**\n * Send a message (text or content parts with files/images)\n */\n async send(content: string | UserContentPart[]): Promise<void> {\n // Set submitted state and notify\n this.state = addUserConversation(this.state, content);\n this.notify();\n\n // Yield to allow UI frameworks (React, etc.) to render submitted state\n // before stream events arrive and transition to thinking/responding\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n try {\n await this.agentx.runtime.session.send(this.instanceId, content);\n } catch (error) {\n this.notifyError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Interrupt current response\n */\n async interrupt(): Promise<void> {\n try {\n await this.agentx.runtime.session.interrupt(this.instanceId);\n } catch (error) {\n this.notifyError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Rewind conversation to a specific index.\n *\n * Calls runtime.rewind — a system-level operation that:\n * 1. Truncates session messages\n * 2. Resets circuit breaker\n * 3. Emits rewind event → reducer updates state\n *\n * @param index - conversation index to rewind to (0-based, removes this index and after)\n */\n async rewind(index: number): Promise<void> {\n const conversations = this.state.conversations;\n if (index < 0 || index >= conversations.length) return;\n\n try {\n // Map conversation index to message ID\n const messages = await this.agentx.runtime.session.getMessages(this.instanceId);\n if (messages.length === 0) return;\n\n if (index === 0) {\n // Rewind to beginning — use first message\n await this.agentx.rpc(\"runtime.rewind\", {\n imageId: this.instanceId,\n messageId: messages[0].id,\n });\n } else {\n // Find the message that corresponds to the conversation before rewind point\n let msgIndex = -1;\n let convCount = 0;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].subtype === \"user\" || messages[i].subtype === \"assistant\") {\n convCount++;\n }\n if (convCount >= index) {\n msgIndex = i;\n break;\n }\n }\n if (msgIndex >= 0 && msgIndex < messages.length) {\n await this.agentx.rpc(\"runtime.rewind\", {\n imageId: this.instanceId,\n messageId: messages[msgIndex].id,\n });\n }\n }\n } catch (error) {\n this.notifyError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Edit a user message and resend.\n * Rewinds to the message, replaces it, and sends the new content.\n *\n * @param index - conversation index of the user message to edit (0-based)\n * @param content - new content to send\n */\n async editAndResend(index: number, content: string | UserContentPart[]): Promise<void> {\n // Rewind to before this message\n await this.rewind(index);\n\n // Send the new content\n await this.send(content);\n }\n\n /**\n * Reset state\n */\n reset(): void {\n this.state = createInitialState();\n this.notify();\n }\n\n /**\n * Dispose and cleanup\n */\n dispose(): void {\n if (this.eventUnsubscribe) {\n this.eventUnsubscribe();\n this.eventUnsubscribe = null;\n }\n this.updateHandlers.clear();\n this.errorHandlers.clear();\n }\n\n // ==================== Private ====================\n\n private subscribeToEvents(): void {\n // Subscribe to all events and filter by instanceId\n this.eventUnsubscribe = this.agentx.onAny((event: BusEvent) => {\n // Filter events for this agent (if context is available)\n // Note: Events from server may or may not include context with instanceId\n const eventWithContext = event as BusEvent & { context?: { instanceId?: string } };\n const eventAgentId = eventWithContext.context?.instanceId;\n\n // Only filter if event has context and neither instanceId nor imageId matches\n if (eventAgentId && eventAgentId !== this.instanceId) {\n // Also check imageId in context\n const eventImageId = (eventWithContext.context as any)?.imageId;\n if (!eventImageId || eventImageId !== this.instanceId) {\n return;\n }\n }\n\n // Reduce event into state\n const newState = presentationReducer(this.state, event);\n if (newState !== this.state) {\n this.state = newState;\n this.notify();\n }\n });\n }\n\n private notify(): void {\n for (const handler of this.updateHandlers) {\n try {\n handler(this.state);\n } catch (error) {\n console.error(\"Presentation update handler error:\", error);\n }\n }\n }\n\n private notifyError(error: Error): void {\n for (const handler of this.errorHandlers) {\n try {\n handler(error);\n } catch (e) {\n console.error(\"Presentation error handler error:\", e);\n }\n }\n }\n}\n","/**\n * Presentation namespace factory\n *\n * Singleton per imageId — same imageId always returns the same Presentation.\n * First call creates from history, subsequent calls return existing instance.\n * Options (onUpdate, onError) are additive — new handlers are merged in.\n */\n\nimport { messagesToConversations, Presentation, type PresentationOptions } from \"../presentation\";\nimport type { PresentationWorkspace } from \"../presentation/types\";\nimport type { AgentX, PresentationNamespace, SessionNamespace } from \"../types\";\n\n/**\n * Workspace resolver — given an imageId, returns a PresentationWorkspace or null.\n * Provided by the client (local or remote) to decouple from runtime internals.\n */\nexport type WorkspaceResolver = (imageId: string) => Promise<PresentationWorkspace | null>;\n\nexport function createPresentations(\n agentx: AgentX,\n sessionNs: SessionNamespace,\n workspaceResolver?: WorkspaceResolver\n): PresentationNamespace {\n const instances = new Map<string, Presentation>();\n\n return {\n async create(imageId: string, options?: PresentationOptions): Promise<Presentation> {\n // Return existing singleton\n const existing = instances.get(imageId);\n if (existing) {\n // Merge new handlers if provided\n if (options?.onUpdate) existing.onUpdate(options.onUpdate);\n if (options?.onError) existing.onError(options.onError);\n return existing;\n }\n\n // Resolve workspace for this image\n const workspace = workspaceResolver ? await workspaceResolver(imageId) : null;\n\n // Create new from history\n const messages = await sessionNs.getMessages(imageId);\n const conversations = messagesToConversations(messages);\n const presentation = new Presentation(agentx, imageId, options, conversations, workspace);\n\n instances.set(imageId, presentation);\n\n // Clean up on dispose\n const originalDispose = presentation.dispose.bind(presentation);\n presentation.dispose = () => {\n instances.delete(imageId);\n originalDispose();\n };\n\n return presentation;\n },\n };\n}\n","/**\n * Session namespace factories (messaging)\n */\n\nimport type { Message, UserContentPart } from \"@agentxjs/core/agent\";\nimport type { RpcClient } from \"@agentxjs/core/network\";\nimport type { AgentXRuntime } from \"@agentxjs/core/runtime\";\nimport type { BaseResponse, InstanceInfo, MessageSendResponse, SessionNamespace } from \"../types\";\n\n/**\n * Create local session namespace backed by embedded runtime\n */\n/**\n * Resolve an imageId or instanceId to a running agent instanceId.\n * If no agent exists for this imageId, auto-creates one.\n */\nasync function resolveLocal(runtime: AgentXRuntime, id: string): Promise<string> {\n // Direct instanceId\n if (id.startsWith(\"inst_\")) {\n const agent = runtime.getAgent(id);\n if (agent) return id;\n }\n\n // imageId — find existing or auto-create\n const imageId = id.startsWith(\"img_\") ? id : id;\n const existing = runtime\n .getAgents()\n .find((a) => a.imageId === imageId && a.lifecycle === \"running\");\n if (existing) return existing.instanceId;\n\n const agent = await runtime.createAgent({ imageId });\n return agent.instanceId;\n}\n\nexport function createLocalSessions(runtime: AgentXRuntime): SessionNamespace {\n return {\n async send(id: string, content: string | unknown[]): Promise<MessageSendResponse> {\n const instanceId = await resolveLocal(runtime, id);\n await runtime.receive(instanceId, content as string | UserContentPart[]);\n return { instanceId, requestId: \"\" };\n },\n\n async interrupt(id: string): Promise<BaseResponse> {\n const instanceId = await resolveLocal(runtime, id);\n runtime.interrupt(instanceId);\n return { requestId: \"\" };\n },\n\n async getMessages(id: string): Promise<Message[]> {\n // For imageId, get messages directly from session\n if (id.startsWith(\"img_\")) {\n const image = await runtime.platform.imageRepository.findImageById(id);\n if (!image) return [];\n return runtime.platform.sessionRepository.getMessages(image.sessionId);\n }\n const agent = runtime.getAgent(id);\n if (!agent) return [];\n return runtime.platform.sessionRepository.getMessages(agent.sessionId);\n },\n };\n}\n\n/**\n * Create remote session namespace backed by RPC client\n */\n/**\n * Detect whether an ID is an imageId or instanceId based on prefix.\n * imageId starts with \"img_\", instanceId starts with \"inst_\".\n */\nfunction resolveId(id: string): { imageId?: string; instanceId?: string } {\n if (id.startsWith(\"inst_\")) return { instanceId: id };\n return { imageId: id };\n}\n\nexport function createRemoteSessions(rpcClient: RpcClient): SessionNamespace {\n return {\n async send(id: string, content: string | unknown[]): Promise<MessageSendResponse> {\n const result = await rpcClient.call<MessageSendResponse>(\"message.send\", {\n ...resolveId(id),\n content,\n });\n return { ...result, requestId: \"\" };\n },\n\n async interrupt(id: string): Promise<BaseResponse> {\n const result = await rpcClient.call<BaseResponse>(\"instance.interrupt\", {\n ...resolveId(id),\n });\n return { ...result, requestId: \"\" };\n },\n\n async getMessages(id: string): Promise<Message[]> {\n // For instanceId, resolve to imageId first\n if (id.startsWith(\"inst_\")) {\n const agentRes = await rpcClient.call<{ agent: { imageId: string } | null }>(\n \"instance.get\",\n { instanceId: id }\n );\n if (!agentRes.agent) return [];\n id = agentRes.agent.imageId;\n }\n const msgRes = await rpcClient.call<{ messages: Message[] }>(\"image.messages\", {\n imageId: id,\n });\n return msgRes.messages ?? [];\n },\n };\n}\n","/**\n * RemoteClient - AgentX client for remote server\n *\n * Uses RpcClient from @agentxjs/core/network for JSON-RPC communication.\n * This class focuses on business logic, not protocol details.\n */\n\nimport type { AgentXError } from \"@agentxjs/core/error\";\nimport type { BusEvent, BusEventHandler, EventBus, Unsubscribe } from \"@agentxjs/core/event\";\nimport { EventBusImpl } from \"@agentxjs/core/event\";\nimport { RpcClient } from \"@agentxjs/core/network\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { AgentHandleImpl } from \"./AgentHandle\";\nimport { createRemoteImages } from \"./namespaces/images\";\nimport { createRemoteLLM } from \"./namespaces/llm\";\nimport { createPresentations } from \"./namespaces/presentations\";\nimport { createRemoteSessions } from \"./namespaces/sessions\";\nimport type {\n AgentX,\n ChatNamespace,\n LLMNamespace,\n RemoteClientConfig,\n RuntimeNamespace,\n} from \"./types\";\n\nconst logger = createLogger(\"agentx/RemoteClient\");\n\n/**\n * RemoteClient implementation using JSON-RPC 2.0\n */\nexport class RemoteClient implements AgentX {\n private readonly config: RemoteClientConfig;\n private readonly eventBus: EventBus;\n private readonly rpcClient: RpcClient;\n\n readonly chat: ChatNamespace;\n readonly runtime: RuntimeNamespace;\n readonly provider: LLMNamespace;\n\n constructor(config: RemoteClientConfig) {\n this.config = config;\n this.eventBus = new EventBusImpl();\n\n // Create RPC client (WebSocket factory from platform if available)\n this.rpcClient = new RpcClient({\n url: config.serverUrl,\n createWebSocket: config.customPlatform?.channelClient,\n timeout: config.timeout ?? 30000,\n autoReconnect: config.autoReconnect ?? true,\n headers: config.headers as Record<string, string> | undefined,\n debug: false,\n });\n\n // Forward stream events to internal event bus\n this.rpcClient.onStreamEvent((topic, event) => {\n logger.debug(\"Received stream event\", { topic, type: event.type });\n this.eventBus.emit(event as BusEvent);\n });\n\n // Forward connection state changes to event bus\n this.rpcClient.onStateChange((state) => {\n this.eventBus.emit({\n type: \"connection_state\",\n timestamp: Date.now(),\n data: { state },\n } as BusEvent);\n });\n\n // Assemble namespaces\n const image = createRemoteImages(this.rpcClient);\n const session = createRemoteSessions(this.rpcClient);\n const llm = createRemoteLLM(this.rpcClient);\n // Workspace resolver via RPC — server handles workspace access\n const workspaceResolver = async (imageId: string) => {\n const rpc = this.rpcClient;\n return {\n read: async (path: string) => {\n const res = await rpc.call<{ content: string }>(\"workspace.read\", { imageId, path });\n return res.content;\n },\n write: async (path: string, content: string) => {\n await rpc.call(\"workspace.write\", { imageId, path, content });\n },\n list: async (path?: string) => {\n const res = await rpc.call<{\n files: Array<{ name: string; path: string; type: \"file\" | \"directory\" }>;\n }>(\"workspace.list\", { imageId, path });\n return res.files;\n },\n };\n };\n const present = createPresentations(this, session, workspaceResolver);\n\n this.runtime = { image, session, present, llm };\n this.provider = llm;\n this.chat = this.createChatNamespace();\n }\n\n // ==================== Properties ====================\n\n get connected(): boolean {\n return this.rpcClient.connected;\n }\n\n get events(): EventBus {\n return this.eventBus;\n }\n\n // ==================== Connection ====================\n\n async connect(): Promise<void> {\n await this.rpcClient.connect();\n logger.info(\"Connected to server\", { url: this.config.serverUrl });\n }\n\n async disconnect(): Promise<void> {\n this.rpcClient.disconnect();\n logger.info(\"Disconnected from server\");\n }\n\n async dispose(): Promise<void> {\n this.rpcClient.dispose();\n this.eventBus.destroy();\n logger.info(\"RemoteClient disposed\");\n }\n\n // ==================== Event Subscription ====================\n\n on<T extends string>(type: T, handler: BusEventHandler<BusEvent & { type: T }>): Unsubscribe {\n return this.eventBus.on(type, handler);\n }\n\n onAny(handler: BusEventHandler): Unsubscribe {\n return this.eventBus.onAny(handler);\n }\n\n // ==================== Error Handling ====================\n\n onError(handler: (error: AgentXError) => void): Unsubscribe {\n return this.eventBus.on(\"agentx_error\", (event) => {\n handler(event.data as AgentXError);\n });\n }\n\n // ==================== RPC ====================\n\n async rpc<T = unknown>(method: string, params?: unknown): Promise<T> {\n return this.rpcClient.call<T>(method, params);\n }\n\n // ==================== Private ====================\n\n private createChatNamespace(): ChatNamespace {\n const rt = this.runtime;\n return {\n async create(params) {\n const imgRes = await rt.image.create(params);\n const runRes = await rt.image.run(imgRes.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n async list() {\n return rt.image.list();\n },\n async get(id) {\n const res = await rt.image.get(id);\n if (!res.record) return null;\n const runRes = await rt.image.run(res.record.imageId);\n return new AgentHandleImpl(\n {\n instanceId: runRes.instanceId,\n imageId: runRes.imageId,\n containerId: runRes.containerId,\n sessionId: runRes.sessionId,\n },\n rt\n );\n },\n };\n }\n}\n"],"mappings":"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","names":["createLogger","DEFAULT_CONTAINER_ID","agent","createLogger","logger","createLogger","createLogger"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxjs",
3
- "version": "2.9.0-dev-20260317030407",
3
+ "version": "2.9.0-dev-20260317033749",
4
4
  "description": "AgentX Client SDK - Local and remote AI agent management",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,12 +23,12 @@
23
23
  "test": "bun test bdd/"
24
24
  },
25
25
  "dependencies": {
26
- "@agentxjs/core": "2.9.0-dev-20260317030407",
26
+ "@agentxjs/core": "2.9.0-dev-20260317033749",
27
27
  "@deepracticex/id": "^0.2.0",
28
28
  "@deepracticex/logger": "^1.2.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@agentxjs/devtools": "2.2.2-dev-20260317030407",
31
+ "@agentxjs/devtools": "2.2.2-dev-20260317033749",
32
32
  "@deepracticex/bdd": "^0.3.0",
33
33
  "tsx": "^4.19.0",
34
34
  "typescript": "^5.3.3"
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Workspace RPC Handler Tests
3
+ *
4
+ * Verifies the server-side workspace.list/read/write handlers
5
+ * work correctly through the RpcHandlerRegistry.
6
+ */
7
+
8
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
9
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
10
+ import { tmpdir } from "node:os";
11
+ import { join } from "node:path";
12
+ import { RpcHandlerRegistry } from "../../RpcHandlerRegistry";
13
+ import { registerWorkspaceHandlers } from "../workspace";
14
+
15
+ let tempDir: string;
16
+ let registry: RpcHandlerRegistry;
17
+
18
+ // Minimal runtime mock with real workspace
19
+ function createMockRuntime(workspacesDir: string) {
20
+ const { LocalWorkspaceProvider } = require("@agentxjs/node-platform/workspace");
21
+ const workspaceProvider = new LocalWorkspaceProvider(workspacesDir);
22
+
23
+ return {
24
+ platform: {
25
+ workspaceProvider,
26
+ imageRepository: {
27
+ findImageById: async (imageId: string) => {
28
+ if (imageId === "img_test") {
29
+ return { imageId: "img_test", workspaceId: "ws_test" };
30
+ }
31
+ return null;
32
+ },
33
+ },
34
+ },
35
+ } as any;
36
+ }
37
+
38
+ beforeEach(async () => {
39
+ tempDir = await mkdtemp(join(tmpdir(), "agentx-ws-handler-test-"));
40
+ registry = new RpcHandlerRegistry();
41
+ registerWorkspaceHandlers(registry);
42
+ });
43
+
44
+ afterEach(async () => {
45
+ await rm(tempDir, { recursive: true, force: true });
46
+ });
47
+
48
+ describe("workspace.list RPC handler", () => {
49
+ test("returns files from workspace directory", async () => {
50
+ // Create workspace dir and files
51
+ const wsDir = join(tempDir, "ws_test");
52
+ const { mkdir } = await import("node:fs/promises");
53
+ await mkdir(wsDir, { recursive: true });
54
+ await writeFile(join(wsDir, "hello.txt"), "world");
55
+ await writeFile(join(wsDir, "test.js"), "console.log('hi')");
56
+
57
+ const runtime = createMockRuntime(tempDir);
58
+ const result = await registry.handle(runtime, "workspace.list", {
59
+ imageId: "img_test",
60
+ path: ".",
61
+ });
62
+
63
+ expect(result.success).toBe(true);
64
+ if (result.success) {
65
+ const files = result.data.files as Array<{ name: string; type: string }>;
66
+ expect(files.length).toBe(2);
67
+ const names = files.map((f) => f.name).sort();
68
+ expect(names).toEqual(["hello.txt", "test.js"]);
69
+ }
70
+ });
71
+
72
+ test("returns empty array for empty workspace", async () => {
73
+ const wsDir = join(tempDir, "ws_test");
74
+ const { mkdir } = await import("node:fs/promises");
75
+ await mkdir(wsDir, { recursive: true });
76
+
77
+ const runtime = createMockRuntime(tempDir);
78
+ const result = await registry.handle(runtime, "workspace.list", {
79
+ imageId: "img_test",
80
+ });
81
+
82
+ expect(result.success).toBe(true);
83
+ if (result.success) {
84
+ expect(result.data.files).toEqual([]);
85
+ }
86
+ });
87
+
88
+ test("returns error for unknown imageId", async () => {
89
+ const runtime = createMockRuntime(tempDir);
90
+ const result = await registry.handle(runtime, "workspace.list", {
91
+ imageId: "img_unknown",
92
+ });
93
+
94
+ expect(result.success).toBe(false);
95
+ });
96
+ });
97
+
98
+ describe("workspace.read RPC handler", () => {
99
+ test("reads file content", async () => {
100
+ const wsDir = join(tempDir, "ws_test");
101
+ const { mkdir } = await import("node:fs/promises");
102
+ await mkdir(wsDir, { recursive: true });
103
+ await writeFile(join(wsDir, "data.txt"), "hello world");
104
+
105
+ const runtime = createMockRuntime(tempDir);
106
+ const result = await registry.handle(runtime, "workspace.read", {
107
+ imageId: "img_test",
108
+ path: "data.txt",
109
+ });
110
+
111
+ expect(result.success).toBe(true);
112
+ if (result.success) {
113
+ expect(result.data.content).toBe("hello world");
114
+ }
115
+ });
116
+ });
117
+
118
+ describe("workspace.write RPC handler", () => {
119
+ test("writes file and can read it back", async () => {
120
+ const wsDir = join(tempDir, "ws_test");
121
+ const { mkdir } = await import("node:fs/promises");
122
+ await mkdir(wsDir, { recursive: true });
123
+
124
+ const runtime = createMockRuntime(tempDir);
125
+
126
+ // Write
127
+ const writeResult = await registry.handle(runtime, "workspace.write", {
128
+ imageId: "img_test",
129
+ path: "output.txt",
130
+ content: "written via RPC",
131
+ });
132
+ expect(writeResult.success).toBe(true);
133
+
134
+ // Read back
135
+ const readResult = await registry.handle(runtime, "workspace.read", {
136
+ imageId: "img_test",
137
+ path: "output.txt",
138
+ });
139
+ expect(readResult.success).toBe(true);
140
+ if (readResult.success) {
141
+ expect(readResult.data.content).toBe("written via RPC");
142
+ }
143
+ });
144
+ });
@@ -121,12 +121,15 @@ export class Presentation {
121
121
  * Send a message (text or content parts with files/images)
122
122
  */
123
123
  async send(content: string | UserContentPart[]): Promise<void> {
124
- // Add user conversation
124
+ // Set submitted state and notify
125
125
  this.state = addUserConversation(this.state, content);
126
126
  this.notify();
127
127
 
128
+ // Yield to allow UI frameworks (React, etc.) to render submitted state
129
+ // before stream events arrive and transition to thinking/responding
130
+ await new Promise((resolve) => setTimeout(resolve, 0));
131
+
128
132
  try {
129
- // Send message via agentx
130
133
  await this.agentx.runtime.session.send(this.instanceId, content);
131
134
  } catch (error) {
132
135
  this.notifyError(error instanceof Error ? error : new Error(String(error)));
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Tool Call History Restore Tests
3
+ *
4
+ * Verifies that messagesToConversations correctly restores
5
+ * tool calls from persisted messages (page refresh scenario).
6
+ */
7
+
8
+ import { describe, expect, test } from "bun:test";
9
+ import type {
10
+ AssistantMessage,
11
+ Message,
12
+ ToolResultMessage,
13
+ UserMessage,
14
+ } from "@agentxjs/core/agent";
15
+ import { messagesToConversations } from "../reducer";
16
+ import type { AssistantConversation, ToolBlock } from "../types";
17
+
18
+ describe("Tool call history restore", () => {
19
+ test("restores single tool call with result", () => {
20
+ const messages: Message[] = [
21
+ {
22
+ id: "msg_1",
23
+ role: "user",
24
+ subtype: "user",
25
+ content: "List files in /tmp",
26
+ timestamp: 1000,
27
+ } as UserMessage,
28
+ {
29
+ id: "msg_2",
30
+ role: "assistant",
31
+ subtype: "assistant",
32
+ content: [
33
+ { type: "text", text: "Let me check that for you." },
34
+ { type: "tool-call", id: "call_1", name: "bash", input: { command: "ls /tmp" } },
35
+ ],
36
+ timestamp: 2000,
37
+ } as AssistantMessage,
38
+ {
39
+ id: "msg_3",
40
+ role: "tool",
41
+ subtype: "tool-result",
42
+ toolCallId: "call_1",
43
+ toolResult: {
44
+ type: "tool-result",
45
+ id: "call_1",
46
+ name: "bash",
47
+ output: { type: "text", value: "file1.txt\nfile2.txt" },
48
+ },
49
+ timestamp: 3000,
50
+ } as ToolResultMessage,
51
+ {
52
+ id: "msg_4",
53
+ role: "assistant",
54
+ subtype: "assistant",
55
+ content: [{ type: "text", text: "Found 2 files." }],
56
+ timestamp: 4000,
57
+ } as AssistantMessage,
58
+ ];
59
+
60
+ const conversations = messagesToConversations(messages);
61
+
62
+ // Should be: user + assistant (with tool call + text)
63
+ expect(conversations.length).toBe(2);
64
+ expect(conversations[0].role).toBe("user");
65
+ expect(conversations[1].role).toBe("assistant");
66
+
67
+ const assistant = conversations[1] as AssistantConversation;
68
+ // Blocks: text + tool + text (all in one assistant turn)
69
+ const toolBlock = assistant.blocks.find((b) => b.type === "tool") as ToolBlock;
70
+ expect(toolBlock).toBeDefined();
71
+ expect(toolBlock.toolName).toBe("bash");
72
+ expect(toolBlock.toolUseId).toBe("call_1");
73
+ expect(toolBlock.toolResult).toBe("file1.txt\nfile2.txt");
74
+ expect(toolBlock.status).toBe("completed");
75
+ });
76
+
77
+ test("restores multiple tool calls in sequence", () => {
78
+ const messages: Message[] = [
79
+ {
80
+ id: "msg_1",
81
+ role: "user",
82
+ subtype: "user",
83
+ content: "Read two files",
84
+ timestamp: 1000,
85
+ } as UserMessage,
86
+ {
87
+ id: "msg_2",
88
+ role: "assistant",
89
+ subtype: "assistant",
90
+ content: [
91
+ { type: "tool-call", id: "call_1", name: "read", input: { path: "a.txt" } },
92
+ { type: "tool-call", id: "call_2", name: "read", input: { path: "b.txt" } },
93
+ ],
94
+ timestamp: 2000,
95
+ } as AssistantMessage,
96
+ {
97
+ id: "msg_3",
98
+ role: "tool",
99
+ subtype: "tool-result",
100
+ toolCallId: "call_1",
101
+ toolResult: {
102
+ type: "tool-result",
103
+ id: "call_1",
104
+ name: "read",
105
+ output: { type: "text", value: "content A" },
106
+ },
107
+ timestamp: 3000,
108
+ } as ToolResultMessage,
109
+ {
110
+ id: "msg_4",
111
+ role: "tool",
112
+ subtype: "tool-result",
113
+ toolCallId: "call_2",
114
+ toolResult: {
115
+ type: "tool-result",
116
+ id: "call_2",
117
+ name: "read",
118
+ output: { type: "text", value: "content B" },
119
+ },
120
+ timestamp: 3001,
121
+ } as ToolResultMessage,
122
+ {
123
+ id: "msg_5",
124
+ role: "assistant",
125
+ subtype: "assistant",
126
+ content: [{ type: "text", text: "Both files read." }],
127
+ timestamp: 4000,
128
+ } as AssistantMessage,
129
+ ];
130
+
131
+ const conversations = messagesToConversations(messages);
132
+
133
+ expect(conversations.length).toBe(2);
134
+ const assistant = conversations[1] as AssistantConversation;
135
+ const toolBlocks = assistant.blocks.filter((b) => b.type === "tool") as ToolBlock[];
136
+ expect(toolBlocks.length).toBe(2);
137
+ expect(toolBlocks[0].toolResult).toBe("content A");
138
+ expect(toolBlocks[1].toolResult).toBe("content B");
139
+ });
140
+
141
+ test("restores tool call with error result", () => {
142
+ const messages: Message[] = [
143
+ {
144
+ id: "msg_1",
145
+ role: "user",
146
+ subtype: "user",
147
+ content: "Run something",
148
+ timestamp: 1000,
149
+ } as UserMessage,
150
+ {
151
+ id: "msg_2",
152
+ role: "assistant",
153
+ subtype: "assistant",
154
+ content: [{ type: "tool-call", id: "call_1", name: "bash", input: { command: "bad" } }],
155
+ timestamp: 2000,
156
+ } as AssistantMessage,
157
+ {
158
+ id: "msg_3",
159
+ role: "tool",
160
+ subtype: "tool-result",
161
+ toolCallId: "call_1",
162
+ toolResult: {
163
+ type: "tool-result",
164
+ id: "call_1",
165
+ name: "bash",
166
+ output: { type: "error-text", value: "command not found" },
167
+ },
168
+ timestamp: 3000,
169
+ } as ToolResultMessage,
170
+ ];
171
+
172
+ const conversations = messagesToConversations(messages);
173
+ const assistant = conversations[1] as AssistantConversation;
174
+ const toolBlock = assistant.blocks.find((b) => b.type === "tool") as ToolBlock;
175
+ expect(toolBlock.status).toBe("error");
176
+ expect(toolBlock.toolResult).toBe("command not found");
177
+ });
178
+
179
+ test("handles assistant message with only text (no tools)", () => {
180
+ const messages: Message[] = [
181
+ {
182
+ id: "msg_1",
183
+ role: "user",
184
+ subtype: "user",
185
+ content: "Hello",
186
+ timestamp: 1000,
187
+ } as UserMessage,
188
+ {
189
+ id: "msg_2",
190
+ role: "assistant",
191
+ subtype: "assistant",
192
+ content: [{ type: "text", text: "Hi there!" }],
193
+ timestamp: 2000,
194
+ } as AssistantMessage,
195
+ ];
196
+
197
+ const conversations = messagesToConversations(messages);
198
+ expect(conversations.length).toBe(2);
199
+ const assistant = conversations[1] as AssistantConversation;
200
+ expect(assistant.blocks.length).toBe(1);
201
+ expect(assistant.blocks[0].type).toBe("text");
202
+ });
203
+ });
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Workspace Initialization Tests
3
+ *
4
+ * Verifies that Presentation correctly loads initial workspace file tree.
5
+ * Covers the timing issue: workspace_tree event may be lost if Presentation
6
+ * hasn't subscribed yet, so the constructor must call workspace.list(".").
7
+ */
8
+
9
+ import { describe, expect, mock, test } from "bun:test";
10
+ import { Presentation } from "../Presentation";
11
+ import type { PresentationWorkspace } from "../types";
12
+
13
+ // Minimal AgentX mock
14
+ function createMockAgentX() {
15
+ return {
16
+ runtime: {
17
+ session: { send: mock(() => Promise.resolve({ instanceId: "inst_1" })) },
18
+ image: {},
19
+ present: {},
20
+ llm: {},
21
+ },
22
+ onAny: mock(() => () => {}),
23
+ rpc: mock(() => Promise.resolve({})),
24
+ } as any;
25
+ }
26
+
27
+ describe("Workspace initialization in Presentation", () => {
28
+ test("constructor calls workspace.list('.') when workspace is provided", async () => {
29
+ const mockFiles = [
30
+ { name: "src", path: "src", type: "directory" as const },
31
+ { name: "package.json", path: "package.json", type: "file" as const },
32
+ ];
33
+
34
+ const mockWorkspace: PresentationWorkspace = {
35
+ read: mock(() => Promise.resolve("")),
36
+ write: mock(() => Promise.resolve()),
37
+ list: mock(() => Promise.resolve(mockFiles)),
38
+ };
39
+
40
+ const ax = createMockAgentX();
41
+ const pres = new Presentation(ax, "img_test", undefined, undefined, mockWorkspace);
42
+
43
+ // Wait for async list to complete
44
+ await new Promise((resolve) => setTimeout(resolve, 50));
45
+
46
+ expect(mockWorkspace.list).toHaveBeenCalledWith(".");
47
+ expect(pres.getState().workspace).not.toBeNull();
48
+ expect(pres.getState().workspace!.files).toEqual(mockFiles);
49
+ });
50
+
51
+ test("constructor does NOT call list when workspace is null", async () => {
52
+ const ax = createMockAgentX();
53
+ const pres = new Presentation(ax, "img_test", undefined, undefined, null);
54
+
55
+ await new Promise((resolve) => setTimeout(resolve, 50));
56
+
57
+ expect(pres.getState().workspace).toBeNull();
58
+ });
59
+
60
+ test("onUpdate receives workspace state after initial load", async () => {
61
+ const mockFiles = [{ name: "test.txt", path: "test.txt", type: "file" as const }];
62
+ const mockWorkspace: PresentationWorkspace = {
63
+ read: mock(() => Promise.resolve("")),
64
+ write: mock(() => Promise.resolve()),
65
+ list: mock(() => Promise.resolve(mockFiles)),
66
+ };
67
+
68
+ const states: any[] = [];
69
+ const ax = createMockAgentX();
70
+ const pres = new Presentation(
71
+ ax,
72
+ "img_test",
73
+ {
74
+ onUpdate: (state) => {
75
+ states.push(state);
76
+ },
77
+ },
78
+ undefined,
79
+ mockWorkspace
80
+ );
81
+
82
+ // Wait for async list + notify
83
+ await new Promise((resolve) => setTimeout(resolve, 50));
84
+
85
+ // Should have received at least one update with workspace files
86
+ const withWorkspace = states.find((s) => s.workspace !== null);
87
+ expect(withWorkspace).toBeDefined();
88
+ expect(withWorkspace.workspace.files).toEqual(mockFiles);
89
+ });
90
+
91
+ test("workspace_tree event still works after initial load", async () => {
92
+ const initialFiles = [{ name: "init.txt", path: "init.txt", type: "file" as const }];
93
+ const mockWorkspace: PresentationWorkspace = {
94
+ read: mock(() => Promise.resolve("")),
95
+ write: mock(() => Promise.resolve()),
96
+ list: mock(() => Promise.resolve(initialFiles)),
97
+ };
98
+
99
+ // Capture the onAny handler
100
+ let eventHandler: ((event: any) => void) | null = null;
101
+ const ax = createMockAgentX();
102
+ ax.onAny = mock((handler: any) => {
103
+ eventHandler = handler;
104
+ return () => {};
105
+ });
106
+
107
+ const pres = new Presentation(ax, "img_test", undefined, undefined, mockWorkspace);
108
+ await new Promise((resolve) => setTimeout(resolve, 50));
109
+
110
+ // Initial load should have files
111
+ expect(pres.getState().workspace!.files).toEqual(initialFiles);
112
+
113
+ // Now simulate a workspace_tree event (e.g. from watcher)
114
+ const updatedFiles = [
115
+ { name: "init.txt", path: "init.txt", type: "file" as const },
116
+ { name: "new.txt", path: "new.txt", type: "file" as const },
117
+ ];
118
+
119
+ eventHandler!({
120
+ type: "workspace_tree",
121
+ timestamp: Date.now(),
122
+ data: { files: updatedFiles },
123
+ });
124
+
125
+ // State should reflect the new files
126
+ expect(pres.getState().workspace!.files).toEqual(updatedFiles);
127
+ });
128
+ });