Skip to content

research-agent

A bounded research agent: loop … until, budgets, monitors, and tool calling.

Run it from sema/:

Terminal window
sema check examples/research-agent
SEMA_STRICT=1 sema run examples/research-agent
sema assure examples/research-agent --grade silver
"""research-agent — a small end-to-end pipeline built on the Sema standard library.
A compact replica of a search→write research flow, showing the neurosymbolic
components composing in real Sema app code — all imported from `std.*`, compiled
and run:
• provenance — assign global citation ids + rewrite markers (std.provenance)
• semantic — de-duplicate candidate facts (semantic.dedup verb)
• agent loop — iterate until a belief crosses threshold (std.agent_loop + std.belief)
• metering — track model spend ambiently (`with meter`)
• document — render a typed report to markdown (std.document)
Run: sema run examples/research-agent
"""
from std.provenance import Cit, Doc, build_url_to_id, rewrite
from std.belief import Belief
from std.document import Report, render
from std.collections import join_str
def main() -> None !{model.invoke, model.embed, observe.record}:
# 1. Sources with local citations → stable global ids + rewritten text.
docs = [
Doc(text="Solar capacity grew [1]. Costs fell [2].",
citations=[Cit(url="iea.org", start=20, end=23), Cit(url="irena.org", start=36, end=39)]),
Doc(text="Costs fell sharply [1].",
citations=[Cit(url="irena.org", start=19, end=22)]),
]
ids = build_url_to_id(docs)
mut sections: list[str] = []
for d in docs:
sections.append(rewrite(d.text, d.citations, ids))
# 2. Candidate facts, de-duplicated semantically.
unique_facts = semantic.dedup(["costs fell", "costs fell", "capacity grew"], 0.99)
# 3. Belief-driven loop: iterate until confidence crosses the threshold,
# bounded by the evidence available — the `loop … until` surface syntax.
decisions = [0.7, 0.85, 0.95]
mut belief = Belief(alpha=1.0, beta=1.0, history=[0.5])
mut iters = 0
loop until belief.confidence() >= 0.7 max_iters len(decisions):
belief.update(decisions[iters])
iters = iters + 1
# 4. Draft a synthesis with ambient usage metering — no usage tuples.
mut calls = 0
mut cost = 0.0
with meter as u:
_synthesis = generate("Summarize renewable energy findings", 64)
calls = u.total_calls
cost = u.cost
# 5. Render a typed report to markdown.
r = Report(
title="Renewable Energy Findings",
context="Auto-synthesized from " + str(len(docs)) + " sources.",
confidence=belief.confidence(),
rationale="Confidence is a Beta-Bernoulli posterior over iteration evidence.",
takeaways=unique_facts,
section_titles=["Findings"],
sections_text=join_str(sections, "\n\n"),
conclusion="Costs continue to decline as capacity scales.",
)
print(render(r, "\n"))
log.info("run", stopped_iter=iters, confidence=belief.confidence(), model_calls=calls, cost=cost)

research-agent — a small end-to-end pipeline built on the Sema standard library.

A compact replica of a search→write research flow, showing the neurosymbolic components composing in real Sema app code — all imported from std.*, compiled and run:

• provenance — assign global citation ids + rewrite markers (std.provenance) • semantic — de-duplicate candidate facts (semantic.dedup verb) • agent loop — iterate until a belief crosses threshold (std.agent_loop + std.belief) • metering — track model spend ambiently (with meter) • document — render a typed report to markdown (std.document)

Run: sema run examples/research-agent

def main() -> None !{model.invoke, model.embed, observe.record}

Returns None

Effects !{model.invoke, model.embed, observe.record}