/** * The wire half of the runtime — build contract §1.6: "converts HarnessEvents * plus mirrored tool calls into the existing ai-SDK UIMessage stream with today's * `data-vendo-*` parts (packages/core/src/stream-parts.ts — UNCHANGED; no new * wire format)". Harness adapters contain no wire code; this is the only file * that knows what a chunk looks like. * * The `data-vendo-*` parts are NOT written here: the view channel, the approval * card, the connect card, the build-failed banner and the citations part all come * from the shipped bridge (`guardedCall`/`previewApproval` in ./tool-bridge.ts), * so a harness turn produces the identical wire the legacy agent path produced. * * ONE addition, and deliberately NOT in core's stream-parts.ts: `status` (§1.5) * has no existing part and must be screen-only. The ai-SDK's own * `transient: true` data chunk is exactly "delivered to the client, never added * to message history", so a transient `data-vendo-status` is the native * mechanism rather than a persisted format. See VENDO_STATUS_PART. */ import { type VendoStepLimitPart, type AppId, type BeatPhase, type VendoViewPart } from "@vendoai/core"; import type { UIMessage, UIMessageStreamWriter } from "ai"; import type { MirrorEvent } from "./turn-tools.js"; import type { WorkbenchPart } from "./workbench.js"; /** * The one wire name this lane adds. Transient, so it is screen-only by the SDK's * own rule and never lands in a persisted UIMessage — which is what §1.5 asks * for. It lives here rather than in core because §1.6 freezes stream-parts.ts. */ export declare const VENDO_STATUS_PART: "data-vendo-status"; /** * The workbench's part — dev-only diagnostics (`VENDO_WORKBENCH=1`), on the same * transient mechanism and for the same reason: a fact about how the turn is * thinking is screen-only by definition, and persisting one would put the * machine's internals in the user's history forever. Off, nothing opens a channel * and none of these are ever written (see ./workbench.ts). */ export declare const VENDO_DEBUG_PART: "data-vendo-debug"; /** The effective thread id every turn response carries (03 §1), so a caller * that began without one can adopt it. Every door that serves a turn stamps the * SAME header — the wire reads it to register turn liveness — so it is named * once, here, beside the rest of the wire vocabulary. */ export declare const THREAD_ID_HEADER = "x-vendo-thread-id"; type Writer = UIMessageStreamWriter; /** * The assistant's words for one turn. A turn is NOT one text part: a reply that * spans tool calls must render as prose, then tool, then prose — so the channel * closes the current part whenever something else is mirrored and opens a fresh * one on the next delta. Collapsing it into a single part destroys the * interleaving the thread UI renders. */ export declare class TextChannel { private readonly writer; private open; private index; private id; constructor(writer: Writer); delta(delta: string): void; /** Close the current part, so whatever comes next renders after it. */ break(): void; end(): void; } /** * §1.5 `status` → screen only — one BEAT. * * `phase` and `appId` ride the same transient part rather than a second channel: * a beat with a phase is still a beat, and the receiver reads one part type. Both * are omitted when absent, so a harness that only says `label` puts the exact * chunk on the wire it always did. */ export declare function writeStatus(writer: Writer, beat: { label: string; phase?: BeatPhase; appId?: AppId; }): void; /** One workbench fact, on the same transient mechanism as `status` above. */ export declare function writeDebug(writer: Writer, part: WorkbenchPart): void; /** §1.6 hot-path render seam — today's part, today's stable per-app stream id. */ export declare function writeView(writer: Writer, part: VendoViewPart): void; /** * §1.5 `error` → the screen's failure affordance. The ai-SDK error chunk is what * the thread UI renders as a banner with Retry and (for a Vendo-shaped message) a * detail line — the same affordance the legacy agent path's `onError` produced, * carrying the same `wireErrorMessage` string, meter-exhausted sentence included. */ export declare function writeError(writer: Writer, message: string): void; /** * self-serve P — the failure as part of the ASSISTANT MESSAGE, not only of the * client's transient state. The `error` chunk above belongs to no message and is * gone on the next mount, so a reloaded thread showed the user's question * answered by a blank reply. This part persists beside it, carrying the same * gated sentence the screen was given (core `stream-parts.ts` — an existing * name, no new wire format). */ export declare function writeTurnError(write: (part: unknown) => void, message: string): void; /** * §1.5 `notice` → a SYSTEM fact persisted into the transcript (2026-08-10 * ruling: code never speaks in the assistant's voice). Not transient — the * note must survive settle and reload, unlike a status beat. */ export declare function writeNotice(writer: Writer, notice: VendoStepLimitPart): void; /** * Mirror one tool call onto the wire. Dynamic tools are the right shape: a * harness's tool set is resolved at runtime from the registry, exactly like the * agent bridge's `dynamicTool` calls, so hosts render these with the component * they already have. */ export declare function writeMirror(writer: Writer, event: MirrorEvent): void; export {}; //# sourceMappingURL=wire.d.ts.map