Algolia-Central

Knowledge/AgentStudio/05-output-shape-decision.md

05 — Output Shape Decision

The single biggest design decision after picking an archetype: how does your agent's output reach the user — as text, or as structured tool calls? This section is the framework for that decision and the cost analysis that explains why our current "XML output spec inside the prompt" approach is wrong.

Three output shapes

Shape A: Pure text

  • Agent emits markdown. Frontend renders markdown.
  • Examples: Maverick today, Category Page Pitch, Suggestion Generator (older variants), one of two AskAI patterns
  • Pro: Simplest. No tool integration needed. Works with any frontend.
  • Con: No structured affordances (can't render product cards, comparison tables, interactive components from markdown). Frontend can't reliably parse it.

Shape B: Pure tool-driven

  • Agent emits ZERO meaningful text. All UI rendering happens via tool calls. The text the agent does emit is conversational glue ("Here's what I found.").
  • Example: Shopping assistants. Every meaningful output is a suggest_searches, show_products, compare_products, view_product, etc. tool call.
  • Pro: Frontend renders structured components. Each tool gets its own layoutComponent. No tag parsing. The agent's role narrows to picking tools and arguments.
  • Con: Requires building/maintaining the tool set. Text answers don't fit (can't put "Here's why running shoes are great" inside a tool — it's just narrative).

Shape C: Hybrid (text + tools)

  • Agent emits markdown for narrative parts AND calls tools for structured artifacts.
  • Examples: AskAI agents (markdown answer + occasionally a welcome_prompts tool); fashion shopping assistant (text glue + 13 tools).
  • Pro: Right shape for most non-trivial agents. Markdown for narrative, tools for cards and structured data.
  • Con: Boundary between "narrative" and "structured" needs to be designed — what goes where.

Shape D: XML-tags-in-text (what Elena/Bruno do today)

  • Agent emits markdown with custom XML tags that the frontend parses.
  • Example: Elena — <specialist_summary>...</specialist_summary>, <implementation_steps>...</implementation_steps>, etc.
  • Pro: Looks like Shape C without needing tools.
  • Con: This is a HACK. The "tags" are not enforced by the platform; they're a convention the prompt teaches the model. The frontend has to write a parser. The model can break the tag format and the parser fails. Token waste — every closing tag is overhead. We have a 350-line stream adapter that does nothing but JSON→XML conversion fighting this exact problem.

Shape D is what we have. Shape C is what we should have. The migration is the unlock.

The cost of XML-in-text (Shape D)

Concrete cost breakdown for Elena today:

Cost dimension Today (Shape D) After migration (Shape C with tools)
Tokens per response ~2,000-2,500 (XML tags + content + persona overhead) ~800-1,200 (narrative + tool args)
Latency 30+ seconds (full XML doc generation, single-shot) ~5-10 seconds (parallel tool calls + brief narrative)
Frontend complexity 350-line stream-adapter.ts + paragraph buffering + footnote stripping + tag parser layoutComponent per tool, ~30-50 lines per component
Failure modes Malformed XML breaks frontend; agent forgets a tag; model swaps <analogy_canvas> for <analogycanvas> Tool schema enforces structure; strict mode rejects malformed args
Adding a new section Update Elena prompt + update parser + update render component Add tool schema + add layoutComponent
Removing a section Forgotten tags accumulate; conditional sections hard to detect "not relevant" Tool simply not called; clean absence
Streaming UX Whole document streams; frontend can't render section X until it's fully arrived Each tool call renders independently as it arrives

The XML-in-text approach was reasonable when we built Elena/Bruno because we hadn't fully understood Agent Studio's tool model. It's not reasonable now that we have.

When each shape is right

Use Shape A (pure text) when

  • The output is genuinely just narrative — a category page pitch, an answer to a single factual question.
  • There's no interactive or structured artifact to render.
  • The agent has zero tools (classifier, suggestion generator, query builder).

Use Shape B (pure tool-driven) when

  • The agent's job is to manipulate a UI: filter products, show cards, build comparisons.
  • The frontend has dedicated components for each tool's output.
  • There's no narrative needed — "Here's what you asked for" is enough glue.

Use Shape C (hybrid) when

  • The agent has BOTH narrative work (explanation, recommendation, evidence) AND structured artifacts (cards, diagrams, tables, code blocks).
  • This is the right shape for Elena/Bruno post-refactor: a brief narrative recommendation + structured artifacts via tools.
  • Most AskAI agents fit here.

Avoid Shape D (XML in text)

  • If the structure matters, use a tool. The platform enforces tool schemas. It does not enforce XML conventions. Every Shape D system reinvents schema enforcement badly.

Mapping Elena's XML output to tools (worked example)

Elena today has 9 XML sections (5 always + 4 conditional):

XML tag (today) What it contains Tool migration
<specialist_summary> 2-3 paragraphs recommending strategy Stays in narrative text
<business_impact_roi> Customer metric or quote render_evidence_card({ source: "case_study", metric: "...", driver_action_result: "..." })
<implementation_steps> Numbered steps with doc links render_implementation_plan({ steps: [...], links: [...] })
<operational_gotchas> Risks with mitigations render_risk_list({ risks: [{ name, description, mitigation }] })
<project_handoff> Verbatim "Handing back to Maverick" Eliminate — handoff is platform-level (or a separate tool call), not text
<analogy_canvas> (conditional) Powerful analogy Stays in narrative if helpful, OR a render_analogy_card tool
<customer_quote> (conditional) Real attributed quote Subsumed into render_evidence_card
<code_intro> (conditional) One bridge sentence Eliminate — narrative does this
<production_code> (conditional) Code snippet render_code_block({ language, code, explanation })

Result: 9 XML tags collapse to ~3-4 tools (render_evidence_card, render_implementation_plan, render_risk_list, render_code_block) plus narrative text. Within the 3-5 tool ceiling. Each tool has a layoutComponent in the frontend that renders the artifact in the right panel (or inline in chat). No XML parser. No 350-line stream adapter.

The <specialist_summary> and <analogy_canvas> and <code_intro> stay as narrative — they ARE narrative. Don't tool-ify narrative.

Bruno's mandatory <strategic_architecture> Mermaid block becomes a single render_architecture_diagram({ mermaid_source: "...", description: "..." }) tool call. The frontend renders Mermaid in the right panel.

The "polymorphic single tool" alternative (option D from prior brainstorm)

Instead of N specialized render tools, one tool with a typed kind enum:

{
  "name": "render_specialist_artifact",
  "type": "client_side",
  "inputSchema": {
    "type": "object",
    "properties": {
      "kind": { "type": "string", "enum": ["recommendation", "implementation", "evidence", "risks", "architecture", "code"] },
      "data": { "type": "object", "description": "Shape varies by kind" }
    },
    "required": ["kind", "data"],
    "additionalProperties": false
  }
}

Pro: One tool, one frontend component (with switch-on-kind rendering). Maximum room under the 3-5 ceiling. Easy to add new kinds without adding tools.

Con: The LLM has less semantic guidance. Tool descriptions are how the LLM picks tools — when there's only one tool with a polymorphic body, the LLM has to reason about "which kind do I want now" inside its argument generation, where it gets less help. Multiple specialized tools give the LLM clearer signals.

Recommendation: Start with 3-4 specialized tools. If they bloat past 5, consolidate into the polymorphic shape later. Don't pre-optimize.

Output shape and the prompt

If you migrate from Shape D to Shape C, the prompt CHANGES:

  • Out: "Use these EXACT XML tags. STRUCTURE your response as <specialist_summary>...</specialist_summary>."
  • In: "When you have a recommendation, narrate it briefly in plain text. For each artifact (evidence, implementation steps, risks, code), call the corresponding render tool with structured arguments."

The prompt no longer dictates output structure. The tool schemas dictate output structure. The prompt dictates when to call which tool. This is a meaningful simplification.

Streaming UX consequence

In Shape D, the user waits for the full XML document before the frontend can render anything (or the parser produces partial garbage during streaming).

In Shape C, the agent's narrative streams as text (immediate). Tool calls arrive as discrete events (each rendered as it arrives). Each <Chat>-rendered tool can show a loading skeleton while waiting for the tool result. The total perceived latency drops because the user sees movement immediately.

What this section does NOT cover