Skip to main content

The Core Difference

  • Magic Functions are stateless—each call is independent
  • Agents are stateful—they maintain context across calls

Choosing Between Them

  • Single jump vs journey: Use a magic function when the job is “Given X, return Y” in one call; use an agent when you naturally say “First do A, then based on that do B, then refine with C…”.
  • Isolation vs shared context: Magic calls are independent and great for extraction, transformation, and batch jobs; agents keep conversation and REPL history, so later steps can build on earlier reasoning.
  • Pipeline step vs orchestrator: Magic functions plug in as pure steps inside existing pipelines; agents own longer-lived workflows, conversations, and tool orchestration where the AI is steering the process.
  • Cost profile: Magic functions scale to many cheap calls with predictable behavior; agents are heavier but better suited for deeper, higher-value tasks where the extra context and adaptability pay off.
Situation / RequirementMagic FunctionsAgentsWhy
You can phrase the job as “Given X, produce Y” in one shotBest fit⚠️ OverkillMagic functions are optimized for single, stateless transforms.
Each input item is independent (batches, lists, records)Best fit❌ Not appropriateNo cross-item memory needed; agent state adds no benefit.
You need to keep and reuse context across multiple steps❌ Loses context each callBest fitAgents maintain conversation and REPL history.
Later steps depend tightly on earlier AI outputs⚠️ Must manually pass everything back inBest fitWith agents, the prior reasoning is “already in the room.”
The workflow is conversational or exploratory❌ Awkward (you’d simulate a chat)Best fitAgents are built for back-and-forth refinement.
You want strict, predictable “pure function” behaviorBest fit⚠️ Possible but harder to reason aboutStateless calls are easier to test, debug, and cache.
You want the AI to orchestrate tools over time (plan → act → adjust)⚠️ Only for simple tool callsBest fitAgents shine in multi-step orchestration loops.
You need to run at scale (thousands of similar calls)Best fit❌ Expensive & complexStateless calls parallelize and scale horizontally.
You have strict latency or cost budgets per operation✅ Typically cheaper, more predictable⚠️ Higher overheadAgent state and multiple turns increase cost/latency.
You’re integrating into an existing pipeline as a “smart function”✅ Natural drop-in⚠️ Integration overheadMagic functions look like any other function; agents introduce sessions.
You need to inspect / audit behavior per call✅ Narrow, local reasoning⚠️ State makes it harder to replayStateless calls are easier to log and replay in isolation.

Magic Functions

Stateless AI operations. Each call has a fresh REPL, and is independent with no memory of previous calls. Use these for:
  • Extraction, transformation, loading data into structures
  • Batch processing independent items
  • Single-shot generation or classification
  • Pure functions with AI logic
@magic()
def extract_order_from_email(email: str) -> Order:
    """Extract the customer order details"""
    ...

@magic(get_bug_reports)
def group_by_severity() -> dict[Literal["severe", "medium", "low"], list[BugReport]]:
    """Obtain the bug reports, read them, and group by severity"""
    ...

Agents

Stateful AI workflows. Maintains conversation and REPL history and builds on previous interactions. Use these for:
  • Multi-step workflows where the steps have serial dependencies
  • Conversational interfaces
  • Iterative refinement
  • Complex orchestration
agent = await spawn(premise="You are a data analyst")

analysis = await agent.call(str, "Analyze these sales figures", sales_data=data)
recommendation = await agent.call(str, "Based on those trends, what should we focus on?")
revised = await agent.call(str, "Revise that assuming a 20% budget cut")

Next Steps