Marketing Agency
A sequential three-agent pipeline. The SEO Specialist researches a product via Wikipedia and extracts keywords. The Copywriter drafts advertising copy from that context. The Creative Director reviews the draft, applies prior feedback from memory, and either approves or rejects it with a confidence gate.
This example demonstrates:
- Sequential multi-agent pipelines using Turn closures
- Cross-session campaign memory via
rememberandrecall confidence-gated approval with a typed fallback- Live HTTP calls to the Wikipedia REST API
// Turn Language: Marketing Agency
// Sequential pipeline: SEO Specialist -> Copywriter -> Creative Director.
struct ProductContext { product_name: Str, background: Str, seo_keywords: Str };
struct DraftCopy { hook: Str, body: Str, call_to_action: Str };
struct FinalCampaign { campaign_id: Num, product: Str, approved: Bool, final_copy: Str, conf_score: Num };
let net = use "std/net";
let json = use "std/json";
let regex = use "std/regex";
let run_seo_specialist = turn(product: Str) -> ProductContext {
call("echo", "[SEO Specialist] Researching " + product + "...");
let topic = regex.replace(" ", product, "_");
let id = grant identity::network("public");
let raw = net.get({ "url": "https://en.wikipedia.org/api/rest_v1/page/summary/" + topic, "identity": id });
let wiki = json.parse(raw);
if wiki != null {
context.append("Product background: " + wiki["extract"]);
}
let ctx = infer ProductContext { "SEO Specialist for " + product + ". Extract 3 to 5 keywords." };
return ctx;
};
let run_copywriter = turn(ctx: ProductContext) -> DraftCopy {
call("echo", "[Copywriter] Drafting copy for " + ctx.product_name + "...");
context.append("Keywords: " + ctx.seo_keywords);
let draft = infer DraftCopy { "Write a high-converting ad for: " + ctx.product_name };
return draft;
};
let run_creative_director = turn(ctx: ProductContext, draft: DraftCopy, campaign_id: Num) -> FinalCampaign {
call("echo", "[Creative Director] Reviewing draft...");
let prior = recall("agency_feedback_" + ctx.product_name);
if prior != null {
context.append("Prior feedback: " + prior);
}
let campaign = infer FinalCampaign {
"Creative Director: approve or reject the draft for " + ctx.product_name + ". Hook: " + draft.hook
};
if confidence campaign < 0.85 {
call("echo", "[Creative Director] Draft rejected. Low confidence.");
let fallback = FinalCampaign {
campaign_id: campaign_id,
product: ctx.product_name,
approved: false,
final_copy: "Draft rejected. Confidence below threshold.",
conf_score: 0.0
};
return fallback;
}
remember("agency_feedback_" + ctx.product_name, "Campaign " + campaign_id + ": " + campaign.final_copy);
return campaign;
};
turn {
let campaign_id = 1;
let target_product = "Electric bicycle";
call("echo", "=== MARKETING AGENCY: Campaign #" + campaign_id + " ===");
let ctx = run_seo_specialist(target_product);
let draft = run_copywriter(ctx);
let result = run_creative_director(ctx, draft, campaign_id);
call("echo", json.stringify(result));
return result;
}How It Works
Each agent is a Turn closure with a typed input and a typed return value. The pipeline is sequential: each stage receives the output of the previous one as a typed argument.
The SEO Specialist makes a live HTTP call to Wikipedia, appends the article extract to its context window, and infers a ProductContext struct from that grounded information. The Copywriter receives the product context and produces a draft. The Creative Director checks recall for prior campaign feedback (available if the agent has run before), appends it to context, and infers a final campaign verdict.
The confidence gate means the Creative Director will reject drafts where the model's certainty is low, returning a safe fallback rather than publishing weak copy.
Running It
export TURN_LLM_PROVIDER=openai
export OPENAI_API_KEY=sk-...
turn run impl/examples/marketing_agency.tn --id marketing_agency
The full source is in impl/examples/marketing_agency.tn.