Skip to content

Programmatic API

Everything hg does is available as plain Python. Use this when you want to embed Hellig in a larger app or test agents deterministically.

Minimal example

from hellig import Agent, Runtime, Session, StubCompiler

session = Session(
    compiler=StubCompiler(default_agent="main"),
    runtime=Runtime().register_agent(Agent(name="main")),
)
session.turn("? What's your name? -> name\n: Hi {name}!")
print(session.runtime.scope["name"])

Deterministic tests with ScriptedIO

ScriptedIO replays a queue of answers and records a transcript, so unit tests don't need a TTY.

from hellig import Agent, Runtime, Session, StubCompiler
from hellig.io import ScriptedIO

io = ScriptedIO(answers=["Hang", "cats"])
runtime = (
    Runtime(io=io)
    .register_agent(Agent(name="main", runtime=lambda p, **_: f"<{p}>"))
)
session = Session(compiler=StubCompiler(), runtime=runtime)

session.turn("? Name? -> name\n: Hi {name}!")
session.turn(
    "? Topic? -> topic\n"
    "@main write about {topic} -> essay\n"
    ": Done. essay={essay}"
)

assert runtime.scope == {
    "name": "Hang",
    "topic": "cats",
    "essay": "<write about cats>",
}
assert ("say", "Hi Hang!") in io.transcript

Building a program by hand

Skip the compiler entirely when you already know the steps:

from hellig import Instruction, Program, Runtime, Agent
from hellig.io import ScriptedIO

program = Program(
    source="(manual)",
    instructions=[
        Instruction.ask("city", "city"),
        Instruction.call("weather", "forecast for {city}", "fc"),
        Instruction.say("Forecast: {fc}"),
        Instruction.done(),
    ],
)

io = ScriptedIO(answers=["Beijing"])
runtime = Runtime(io=io).register_agent(
    Agent(name="weather", runtime=lambda p, **_: f"sunny in {p}"),
)
runtime.execute(program)
print(io.transcript)

Registering tools

Tools are any Python callable. The runtime calls them with rendered string kwargs:

runtime.register_tool(
    "uppercase",
    lambda text="": text.upper(),
)

Then from the stub compiler:

!uppercase text=hello -> shout
: {shout}

Inspecting a session

for turn in session.history:
    print(turn.user)
    print(turn.program.to_text())
    print(turn.scope)

turn.program.to_text() returns the human-readable opcode dump that hg compile prints.