Skip to content

Guided Agents

Experimental & deprecated

GuidedAgent and the journeys/guidelines API are experimental and deprecated — not recommended for new code and may be removed in a future release. For new agents prefer ReActAgent with Pipeline Agents for deterministic control flow.

GuidedAgent is a ReActAgent subclass that narrows context per turn. Instead of handing the LLM one large static system prompt and every tool, it matches behavioral rules ("guidelines") against the current conversation, injects only the rules that apply, and exposes only the tools those rules unlock. The design is inspired by Parlant-style context narrowing.

How it works

Each turn, stream() performs four steps before delegating to the parent ReAct loop:

  1. Match guidelines — evaluate each guideline's when condition against the conversation using the configured strategy (always, batch_llm, or embedding), then resolve excludes and sort by priority.
  2. Build a narrowed system prompt — start from the base system_prompt and inject only the matched guidelines, plus glossary terms mentioned in the conversation and the current journey step.
  3. Gate tools — ungated tools are always available; a gated tool (named by any guideline's or journey step's tools) is exposed only when an active guideline or the current journey step unlocks it.
  4. Delegate to ReActAgent.stream() with the narrowed prompt and tool set, then check whether the active journey should advance.
from latent.agents.guided import GuidedAgent, Guideline

agent = GuidedAgent(
    name="support",
    model="gpt-4o",
    system_prompt="You are a helpful support agent.",
    guidelines=[
        Guideline(
            when="the user reports a billing problem",
            then="apologize, then look up their account before answering",
            tools=("lookup_account",),
            priority=10,
        ),
    ],
    tools=[lookup_account, search_docs],
)

answer = await agent.ask("I was charged twice this month")

Constructor

Parameter Type Default Purpose
name str Agent name.
model str LLM model id.
system_prompt str \| None None Base prompt; guidelines are injected on top of it.
guidelines list[Guideline] \| None None Behavioral rules.
canned_responses list[CannedResponse] \| None None Pre-approved templates (used in strict mode).
glossary Glossary \| None None Domain terms injected when mentioned.
journeys list[Journey] \| None None Multi-step SOPs; names must be unique.
mode "fluid" \| "strict" "fluid" strict enforces canned responses.
match_strategy "always" \| "batch_llm" \| "embedding" \| None None Auto-selected: always for ≤5 guidelines, else batch_llm.
match_threshold float 0.75 Similarity threshold for the embedding strategy.
embedding_model str \| None None Defaults to model.
infer_relationships bool False Advisory background check for conflicting guidelines (needs ≥2).
tools list[Callable] \| None None Tool functions to gate.

GuidedAgent.from_config(name, model, ...) loads guidelines, glossary, canned responses, and journeys from flows/<name>/guidelines.yaml.

Guidelines

Guideline

A frozen dataclass expressing a when condition → then behavior rule.

Field Type Default Purpose
when str Condition that activates the rule.
then str Instruction injected when active.
id str auto Stable hash derived from the other fields if omitted.
priority int 0 Higher priority sorts first.
tools tuple[str, ...] () Tool names unlocked while this rule is active.
excludes tuple[str, ...] () Guideline ids suppressed when this one matches.
from latent.agents.guided import Guideline

refund = Guideline(
    when="the user asks for a refund",
    then="confirm the order id, then issue the refund",
    tools=("issue_refund",),
    priority=5,
    excludes=("upsell_rule",),
)

CannedResponse

A frozen pre-approved response template for strict mode.

Field Type Default Purpose
id str Template identifier.
template str str.format_map template.
variables dict[str, str] {} Default substitution values.
from latent.agents.guided import CannedResponse

greeting = CannedResponse(
    id="greeting",
    template="Hi {name}, how can I help with your {topic}?",
    variables={"topic": "account"},
)
greeting.render({"name": "Dana"})  # -> "Hi Dana, how can I help with your account?"

Glossary

A frozen mapping of domain terms to definitions. Terms are injected into the prompt only when they appear in the conversation.

Field Type Purpose
terms dict[str, str] Term → definition.
from latent.agents.guided import Glossary

glossary = Glossary(terms={"MRR": "monthly recurring revenue"})
glossary.find_mentioned("what is our MRR?")  # -> {"MRR": "monthly recurring revenue"}

GuidelineMatch

The result of evaluating a guideline against the conversation.

Field Type Default Purpose
guideline Guideline The evaluated guideline.
matched bool Whether the condition held.
reason str "" Optional rationale from the matcher.

Journeys

Journeys model multi-step standard operating procedures (SOPs). The agent walks the user through ordered Steps, advancing when each step's advance_when condition is met (checked by a quick LLM call after each turn). Journey progress is tracked per conversation_id — pass config={"conversation_id": <id>} so state persists across turns.

Step

A frozen dataclass for one journey step.

Field Type Default Purpose
name str Step name.
instructions str Guidance injected while on this step.
advance_when str "" Condition to move to the next step.
tools tuple[str, ...] () Tool names unlocked on this step.

Journey

A frozen dataclass: a named, ordered list of steps (at least one required).

Field Type Purpose
name str Unique journey name.
steps list[Step] Ordered steps.

JourneyState

Mutable runtime state for one active journey conversation.

Field / member Type Purpose
journey Journey The journey being walked.
current_step_index int Index of the active step (default 0).
completed bool Whether all steps are done (default False).
current_step Step (property) The active step.
advance() -> bool Advance one step; returns True if now complete.
from latent.agents.guided import GuidedAgent, Journey, Step

onboarding = Journey(
    name="onboarding",
    steps=[
        Step(
            name="collect_email",
            instructions="Ask the user for their work email.",
            advance_when="the user has provided an email address",
        ),
        Step(
            name="verify",
            instructions="Send a verification code and confirm it.",
            advance_when="the user confirmed the code",
            tools=("send_code",),
        ),
    ],
)

agent = GuidedAgent(
    name="onboarder",
    model="gpt-4o",
    journeys=[onboarding],
    tools=[send_code],
)

async for event in agent.stream(
    [Message(role="user", content="Hi, I'd like to sign up")],
    config={"conversation_id": "user-42"},
):
    ...

Events

Beyond the standard Agent Protocol events, GuidedAgent emits three guided-specific events you can import from latent.protocol:

Event When Fields
GuidelineMatched A guideline is matched and injected for the turn. guideline_id, when, then
JourneyStepAdvanced The active journey moves to a new step. journey_name, step_name, step_index, conversation_id
JourneyCompleted The active journey finishes its last step. journey_name, conversation_id
from latent.protocol import GuidelineMatched, JourneyCompleted, JourneyStepAdvanced

async for event in agent.stream(messages, config={"conversation_id": "user-42"}):
    match event:
        case GuidelineMatched(guideline_id=gid, when=when):
            print(f"matched {gid}: {when}")
        case JourneyStepAdvanced(step_name=step):
            print(f"advanced to {step}")
        case JourneyCompleted(journey_name=name):
            print(f"{name} complete")

See Also