Context & registries¶
Hierarchical context (no parent pollution)¶
Every LLM call or sub-agent call runs in a temporary child context. The child can accumulate tool-call messages and scratch reasoning freely; when the call finishes, only the final output is merged back into the parent — so parents stay small no matter how deep the call tree gets.
from langstitch import Context, run_llm, run_worker_agent, get_llm_provider
ctx = Context(data={"question": q}, messages=[{"role": "user", "content": q}])
def call_model(llm_ctx):
# llm_ctx.system = resolved persona
# llm_ctx.tools = selected (by tag/name/role) and materialized just for this call
return get_llm_provider().invoke(
[{"role": "system", "content": llm_ctx.system}] + llm_ctx.messages,
)
answer = run_llm(ctx, call_model, persona="assistant",
tool_tags=["billing"], key="answer", as_message="assistant")
# ctx.data["answer"] is set; the child's tool traffic + scratch were discarded.
# Delegate to a sub-agent (runs with only its allowed tools, isolated context):
findings = run_worker_agent(ctx, "researcher", carry=["question"])
ContextBuilder does the lazy selection; Context.scope(...) / ContextScope give
you the raw building blocks if you need finer control. LLMContext is the object
your model callback receives.
Dynamic registries & lazy materialization¶
Tools and worker agents are not eagerly loaded when a request arrives. The
registries hold cheap specs and refresh themselves automatically when anything
new registers (and on demand via refresh_registries()); the actual callables are
materialized only when a node selects them.
The graph server exposes introspection helpers (each hits the live registries):
Server.get_all_tools() # [ToolSpec, ...]
Server.get_all_worker_agents() # [AgentSpec, ...]
Server.get_input_guardrails()
Server.get_output_guardrails()
Server.get_skills(); Server.get_policies(); Server.get_personas()
Server.get_tool("now"); Server.get_worker_agent("researcher")
Server.refresh_registries()
The same accessors are module-level functions:
import langstitch
langstitch.get_all_tools()
langstitch.get_all_worker_agents()
langstitch.refresh_registries()
Worker agents¶
Register a delegatable sub-agent with @worker_agent; it runs with only its allowed
tools in an isolated context, and only its result merges back into the parent.
from langstitch import worker_agent
@worker_agent(role="researcher", tools=["web_search"], persona="researcher")
def researcher(ctx):
...
Why isolation matters
Deep tool/agent call trees can balloon a single message history. Hierarchical context keeps each parent small and deterministic, which improves latency, cost, and reproducibility.