/** * THE FIRST RENDERER THAT CAN DISPLAY AN AG-UI FRAME. * * A frame carries **no text part by design** — its content is a list of AG-UI events — so every * surface that renders a message as flat text draws one as `[unrenderable part kind "ag-ui.frame"]`. * This is the provider that fixes that for the console family: a core {@link PartRenderer} of kind * `part-renderer`, named for the part kind it draws, self-registering on import exactly as a * terminal-layout provider does. * * **IT LANDED BEFORE ANY PRODUCER, AND THAT ORDERING WAS THE POINT.** It shipped while nothing in * production published a frame, and the Claude connector's emitter followed it. The alternative * ordering is the one that fails: a cutover shipped first would have replaced a mirror a human can * read with a part every surface shows as a marker, and the regression would have been invisible to * the change that caused it. Display first, then the producer. * * **CORE NEVER LEARNS AG-UI.** `partsToText` resolves a renderer by the part's own kind and calls * it. The knowledge of what a `TOOL_CALL_ARGS` means lives here, in the package that defined the * vocabulary, which is where `AGENTS.md` requires an adapter's concepts to stay. What moved into * core is only the frame's IDENTITY (`agui-kind.ts`) and the channel's NAME (`event-channel.ts`), * both of which a reader needs to recognise a frame without knowing who produced it. * * ── WHAT IT DELIBERATELY DOES NOT DO ──────────────────────────────────────────────────────────── * * **It does not print raw event-type tokens.** A reader wants `bash({"cmd":"ls"}) -> ok`, not * `TOOL_CALL_START TOOL_CALL_ARGS TOOL_CALL_RESULT`. So the suite must not assert the token either: * gating on `TOOL_CALL_ARGS` appearing in the output would fail a correct renderer, which is why the * cells assert the FOLD (name, arguments, result) rather than the vocabulary. * * **It does not validate the frame as a schema.** `parseAguiFrame` checks the envelope and that each * event's `type` is in the vocabulary, and nothing else, which is measured rather than assumed. So * this renderer treats event fields as untrusted: every field access is guarded and a malformed * event degrades to a named marker rather than throwing. A renderer is the wrong place to discover a * producer's bug, and a very good place to make one visible. * * ── WHY IT ROUTES ON THE KIND AND NEVER ON SHAPE ──────────────────────────────────────────────── * * Two formats will share one channel for exactly as long as the cutover takes: `events..` * is designed to carry frames, while the connectors that have not cut over still publish plain text * parts to their own mirror. Registration is for `ag-ui.frame` ONLY, so a text part renders as the * text it is and never as a degenerate frame. The two cannot be confused because the routing is on * the part kind and not on a guess about shape. */ import { type PartRenderer } from "@cotal-ai/core"; /** * A line this renderer is allowed to emit: one that cannot open a block construct. * * **Exported so the suite asserts the invariant against the SAME expression the renderer is * documented by**, rather than a second copy of it that can drift. It is a property of the emitted * lines and nothing more, deliberately not a claim about what any consumer does downstream, which * would be an assertion outside this module that no test here could hold up. * * **IT TESTS THE FIRST CHARACTER, NOT A LIST OF CONSTRUCTS, AND THAT IS THE WHOLE POINT.** The * previous version enumerated the openers it knew (ATX heading, bullet, ordered list, blockquote, * table row, indented code) and called them "the block-level openers". An enumeration of a syntax * someone else defines is incomplete the moment it is written, and this one was: a bare `---`, `***` * and a fence line all PASSED it while being a thematic break, a setext underline and a code fence. * The suite stayed green because the PREFIXES stop the renderer from emitting such a line at all, * which means the predicate was passing for a reason unrelated to what it claimed to check, and a * weakened prefix would not have been caught by the thing whose job is to catch exactly that. * * So the rule is a property of one character: a line is safe when its first non-space character * arrives within three columns and is not one markdown can read as beginning a block. That is * stricter than the constructs strictly require (`1x` and `-x` open nothing and are refused anyway), * and strictness is the correct direction here, because this constrains what THIS renderer emits and * every line it emits carries a glyph prefix that is not punctuation at all. */ export declare const LINE_START_SAFE: (line: string) => boolean; /** * The registered provider. `name` IS the part kind, which is how core resolves it without ever * learning what the kind means. */ export declare const aguiFramePartRenderer: PartRenderer; /** * Register the provider, once, however many copies of this module get loaded. * * **THIS PACKAGE LEGITIMATELY EXISTS TWICE IN ONE PROCESS, AND A BARE `register` CRASHES THERE.** * Measured, not anticipated: `cotal ext add ` failed with * `extension already registered: part-renderer:ag-ui.frame`, and the mechanism is the extension * prefix's layout. The CLI imports this module from its OWN copy of `connector-core`. Materializing * an installed connector imports `connector-core` again, from the extension prefix's `node_modules`, * which is a different physical file and therefore a second module instance with its own top-level * evaluation. `@cotal-ai/core` is LINKED to the CLI's single copy (`ext add` writes that link on * purpose), so both instances see ONE registry, and `registry.register` throws on the duplicate * `kind:name`. That throw took down `ext add` for every connector. * * **WHY THIS IS NOT THE SILENT DEGRADE THE PROJECT REFUSES.** `register`'s refusal exists to catch * TWO EXTENSIONS CLAIMING ONE NAME, which is a genuine conflict nobody can adjudicate. This is one * extension arriving twice, which is not a conflict: `ag-ui.frame` is defined by this package, no * other package may claim it, and every copy of this file registers a provider that draws it the * same way. First one wins, deterministically, and the second is a no-op rather than a fatal error * on a path a customer runs. Skipping a duplicate self-registration is a different act from * swallowing a failure. * * It is a named function rather than a bare guard so the property is executable: a cell calls it * twice and asserts the second call neither throws nor displaces the first. */ export declare function registerAguiFramePartRenderer(): void; //# sourceMappingURL=agui-render.d.ts.map