Tokenomics Content System
A multi-agent content pipeline built on Google ADK, where specialized agents research, plan, write, illustrate and publish, and a deterministic quality gate decides whether they get to stop.
Architecture Overview
Two SequentialAgent roots over a shared pool of single-responsibility agents. 'Carl' runs research (Riley) then planning (Maya) then a bounded LoopAgent pairing a writer (Quill) with a quality gate (MayaQA). 'SamBlogPipeline' runs research then a LoopAgent pairing the SEO writer (Sam) with a schema-constrained validator (SamQA). I let agents communicate only through ADK outputKey slots in session state (research_brief, content_plan, drafts, qa_result, blog_output) with conversation history disabled, so each stage receives exactly its declared inputs. Deterministic work lives in tools rather than prompts: topic queueing, research retrieval with citations, image generation, Mermaid rendering, published-post registry lookups for internal linking, and CMS publishing.
The Challenges
Problem
The obvious design is an LLM reviewer agent that reads the drafts and decides whether they pass. In practice this fails in the least useful way: the reviewer is as prone to instruction drift as the writer, so a batch with 19 posts instead of 25, or with placeholder text like 'this post will cover...', gets waved through. The pipeline then reports success while producing unusable output.
Solution
I declared MayaQA as an agent for orchestration purposes, then threw its LLM output away entirely. All QA runs programmatically in an afterAgentCallback: exact draft-count assertion, regex detection of placeholder phrasing, and per-platform length thresholds. This is the decision the whole pipeline rests on, and I would defend it as the general rule rather than a workaround: generation stays probabilistic, validation is deterministic code, and the agent boundary survives only because the loop needs something to schedule.
agents/src/agents/maya-qa.ts
Problem
A write-then-review loop needs a stopping rule. 'Loop until the reviewer is satisfied' either terminates immediately on a lenient pass or never terminates on a strict one, and free-text verdicts cannot be branched on reliably.
Solution
I gave SamQA a constrained output schema whose verdict is an enum (ALL_PASSED, NEEDS_MINOR_EDITS, NEEDS_REWRITE) alongside structured failure counts. The LoopAgent branches on that enum and I hard-capped it at three iterations, so the pipeline always terminates, and always terminates with a known state rather than an opinion.
agents/src/agents/sam-qa.ts
Problem
By default each agent in a chain inherits the accumulated conversation. That bleed is expensive and actively harmful: the writer starts echoing the researcher's phrasing, the QA agent sees the writer's justifications and is anchored by them, and no stage can be tested on its own because its behaviour depends on everything upstream.
Solution
I run every agent with includeContents set to none, reading only its declared state keys. That makes each stage a pure function of its inputs, which is what made per-agent smoke harnesses possible and kept token cost flat as the pipeline grew.
agents/src/agents/*.ts
Problem
ADK resolves models through its own registry, which makes it easy to hard-wire a pipeline to one vendor. That is a poor bet when model quality, pricing and rate limits move month to month, and it makes it impossible to route different stages to different models.
Solution
I wrote a custom LLM connector implementing the ADK model interface and registered it into LLMRegistry, so non-Gemini model strings resolve like first-class citizens. Routing a stage to a different provider becomes a string change rather than a rewrite.
agents/src/agents/kimi-llm.ts