import type { AttachConversation, ConversationSnapshot, DetachConversation, HarnessConversationService, HarnessEventEnvelope, SendHarnessTurn, TurnReceipt, } from '@mosaicstack/types'; import type { ChatRuntime } from './chat-runtime.js'; /** * The `pi-rpc` chat runtime. It executes browser chat exclusively through the * harness-neutral {@link HarnessConversationService} RPC boundary — it never * touches the embedded `AgentService`/`ProviderService`/`RoutingEngineService` * stack, and it forwards the caller's exact selection tuple and idempotency key * without substitution. * * It owns no state and adds no policy: every method forwards the caller's exact * argument to the injected {@link HarnessConversationService} and returns its * result unchanged, so the requested selection tuple and idempotency key can * never be substituted on the way through. */ export class HarnessChatRuntime implements ChatRuntime { readonly kind = 'harness' as const; constructor(private readonly conversations: HarnessConversationService) {} attach(input: AttachConversation & { afterSequence?: number }): Promise { return this.conversations.attach(input); } detach(input: DetachConversation): Promise { return this.conversations.detach(input); } send(input: SendHarnessTurn & { idempotencyKey: string }): Promise { return this.conversations.send(input); } subscribeFrom( conversationId: string, afterSequence: number, ): AsyncIterable { return this.conversations.subscribeFrom(conversationId, afterSequence); } }