Runtime API¤
This page is generated from the runtime source with mkdocstrings. The narrative
walkthroughs explain why the pieces exist; this reference exposes the callable
surface and implementation docstrings directly from code.
Authoring DSL¤
dsl
¤
The authoring surface: combinators. You build a skill by nesting calls, not tagged literals — the tree structure is the call structure. act is typed with ParamSpec, so literal args are checked against the tool's real signature.
Classes:
-
Tool–Named, still-callable wrapper around a function; carries name/description
Functions:
-
tool–Register a callable as a tool. Bare (@tool) or with args (@tool(description=...)).
-
act–Leaf calling fn(args, *kwargs). Literal args are type-checked; a ref(...)
-
ref–A blackboard reference for an act argument: act(fetch, ref("query")).
-
store–Capture an action's return value onto the blackboard under key.
-
seq–Run children in order; fail fast (AND).
-
sel–Try children until one succeeds (OR).
-
check–Guard leaf: succeeds iff blackboard[key] == equals.
-
guard–Compiled state predicate over the blackboard using the restricted expression
-
guard_call–Guard backed by a trusted runtime predicate (§21.2). arguments may contain
-
repeat–Run child up to
maxtimes, stopping early whenuntil(e.g. a check) succeeds. -
invert–Flip a child's status: SUCCESS <-> FAILURE (e.g. invert(check(...))).
-
optional–Fail-soft wrapper: run the child but always succeed, so it can't abort a seq.
-
timeout–Bound a child to
secondsof wall-clock time; FAILURE if it overruns. -
oneshot–Run the child at most once per run; replay its status on later ticks.
-
predict–DSPy-style LLM leaf from a signature like "question -> answer".
-
react–Agentic LLM leaf: the model reasons and calls the given @tools in a loop
-
root–Entry point of a skill. Chain .model(id) and .do(child).
Tool
dataclass
¤
Tool(fn: Callable[..., Any], name: str, description: str = '')
Named, still-callable wrapper around a function; carries name/description used by react to expose it to the model for function-calling.
tool
¤
tool(fn: Callable[P, R]) -> Callable[P, R]
tool(*, name: str | None = ..., description: str | None = ...) -> Callable[[Callable[P, R]], Callable[P, R]]
tool(fn: Callable[P, R] | None = None, *, name: str | None = None, description: str | None = None) -> Any
Register a callable as a tool. Bare (@tool) or with args (@tool(description=...)).
Source code in jdsl/dsl.py
51 52 53 54 55 56 | |
act
¤
act(fn: Callable[P, Any], *args: args, **kwargs: kwargs) -> Action
Leaf calling fn(args, *kwargs). Literal args are type-checked; a ref(...) arg resolves from the blackboard at run time. Wrap with store to capture the result.
Pass an id= (as a kwarg) to give the node a stable compiled identity (§20);
it is popped before the call so it never reaches the tool.
Source code in jdsl/dsl.py
65 66 67 68 69 70 71 72 | |
ref
¤
ref(name: str) -> Ref
A blackboard reference for an act argument: act(fetch, ref("query")).
Source code in jdsl/dsl.py
75 76 77 | |
store
¤
store(node: Action, key: str) -> Action
Capture an action's return value onto the blackboard under key.
Source code in jdsl/dsl.py
80 81 82 83 | |
seq
¤
seq(*children: Node, context: str | None = None, id: str | None = None) -> Sequence
Run children in order; fail fast (AND).
Source code in jdsl/dsl.py
86 87 88 | |
sel
¤
sel(*children: Node, context: str | None = None, id: str | None = None) -> Selector
Try children until one succeeds (OR).
Source code in jdsl/dsl.py
91 92 93 | |
check
¤
check(key: str, equals: Any, *, id: str | None = None) -> Check
Guard leaf: succeeds iff blackboard[key] == equals.
Source code in jdsl/dsl.py
96 97 98 | |
guard
¤
guard(expression: dict[str, Any], *, id: str | None = None) -> Guard
Compiled state predicate over the blackboard using the restricted expression language (§21.2), e.g. guard({"in": [{"ref": "order.status"}, ["pending"]]}).
Source code in jdsl/dsl.py
101 102 103 104 | |
guard_call
¤
guard_call(predicate: Callable[..., Any], arguments: dict[str, Any] | None = None, *, predicate_id: str | None = None, id: str | None = None) -> GuardCall
Guard backed by a trusted runtime predicate (§21.2). arguments may contain ref(...) values resolved from the blackboard at run time.
Source code in jdsl/dsl.py
107 108 109 110 111 112 | |
repeat
¤
repeat(child: Node, *, until: Node | None = None, max: int = 3, context: str | None = None, id: str | None = None) -> Repeat
Run child up to max times, stopping early when until (e.g. a check) succeeds.
Source code in jdsl/dsl.py
115 116 117 118 | |
invert
¤
invert(child: Node, *, context: str | None = None, id: str | None = None) -> Invert
Flip a child's status: SUCCESS <-> FAILURE (e.g. invert(check(...))).
Source code in jdsl/dsl.py
121 122 123 | |
optional
¤
optional(child: Node, *, context: str | None = None, id: str | None = None) -> Optional
Fail-soft wrapper: run the child but always succeed, so it can't abort a seq.
Source code in jdsl/dsl.py
126 127 128 | |
timeout
¤
timeout(child: Node, *, seconds: float = 30.0, context: str | None = None, id: str | None = None) -> Timeout
Bound a child to seconds of wall-clock time; FAILURE if it overruns.
Source code in jdsl/dsl.py
131 132 133 | |
oneshot
¤
oneshot(child: Node, *, context: str | None = None, id: str | None = None) -> OneShot
Run the child at most once per run; replay its status on later ticks.
Source code in jdsl/dsl.py
136 137 138 | |
predict
¤
predict(signature: str, *, instructions: str | None = None, context: str | None = None, id: str | None = None) -> Predict
DSPy-style LLM leaf from a signature like "question -> answer".
Source code in jdsl/dsl.py
141 142 143 144 145 146 | |
react
¤
react(signature: str, *, tools: list[Any], instructions: str | None = None, max_steps: int = 6, context: str | None = None, id: str | None = None) -> React
Agentic LLM leaf: the model reasons and calls the given @tools in a loop (native function-calling) until it answers. Signature is "inputs -> answer" with a single output field.
Source code in jdsl/dsl.py
149 150 151 152 153 154 155 156 157 158 | |
root
¤
root(name: str, *, system: str | None = None) -> Root
Entry point of a skill. Chain .model(id) and .do(child).
Source code in jdsl/dsl.py
161 162 163 | |
Runtime Nodes¤
tree
¤
Behavior-tree nodes and the tree-walking interpreter (no codegen).
seq=AND, sel=OR, act=call a tool, check=guard on the blackboard, predict=LLM leaf, root=entry point. Every node ticks to a Status; determinism is in the tree, the model only at predict.
Classes:
-
Status– -
Node–Base node. Subclasses implement
_tick;tickwraps it with trace -
Action–Leaf calling a tool. SUCCESS = didn't raise; a returned Status is honored;
-
Sequence–Run children in order; fail fast (AND).
-
Selector–Try children until one succeeds (OR).
-
Repeat–Run child up to
maxtimes, stopping early whenuntilsucceeds (checked -
Check–Guard leaf: SUCCESS iff blackboard[key] matches equals. String matches are
-
Guard–Compiled state predicate (§21.2): SUCCESS iff the restricted expression is
-
GuardCall–Guard backed by a trusted runtime predicate (§21.2
guard_call). Domain -
Predict–DSPy-style LLM leaf: read input fields, ask for output fields as JSON,
-
React–Agentic LLM leaf: the model reasons and calls @tools in a loop (native
-
Invert–Flip the child's status: SUCCESS <-> FAILURE.
-
Optional–Fail-soft: run the child but always report SUCCESS, so a failing step never
-
Timeout–Run the child with a wall-clock bound; FAILURE if it doesn't finish in
-
OneShot–Run the child at most once per run; latch and replay its status on any
-
Root–Entry point: one child + name/system/model. Also a builder.
Status
¤
Bases: Enum
Node
¤
Base node. Subclasses implement _tick; tick wraps it with trace
emission (node.enter/node.exit, §35 PR1). Context is scoped to the subtree.
node_id is the optional stable identity used by compiled artifacts (§20):
author-supplied via the DSL id= argument, otherwise a path-derived runtime
id is assigned by assign_runtime_ids when a run is being traced. Tree path
is deliberately not the persistent identity — a compiler may insert nodes.
Methods:
-
effective_id–The id used in traces/IR: author id if set, else the runtime path id.
-
label–Short human-readable label for rendering / write provenance.
-
tick–Public entry: emit enter/exit around the subclass
_tickwhen tracing.
effective_id
¤
effective_id() -> str | None
The id used in traces/IR: author id if set, else the runtime path id.
Source code in jdsl/tree.py
55 56 57 | |
label
¤
label() -> str
Short human-readable label for rendering / write provenance.
Source code in jdsl/tree.py
63 64 65 | |
tick
¤
tick(ctx: RunContext) -> Status
Public entry: emit enter/exit around the subclass _tick when tracing.
Source code in jdsl/tree.py
43 44 45 46 47 48 49 50 51 52 53 | |
Action
dataclass
¤
Action(fn: Callable[..., Any], args: tuple[Any, ...] = (), kwargs: dict[str, Any] = dict(), store_as: str | None = None, context_system: str | None = None)
Bases: Node
Leaf calling a tool. SUCCESS = didn't raise; a returned Status is honored; any other return is stored under store_as.
Sequence
dataclass
¤
Sequence(children: list[Node] = list(), context_system: str | None = None)
Selector
dataclass
¤
Selector(children: list[Node] = list(), context_system: str | None = None)
Repeat
dataclass
¤
Repeat(child: Node, until: Node | None = None, max: int = 3, context_system: str | None = None)
Bases: Node
Run child up to max times, stopping early when until succeeds (checked
after each pass). SUCCESS when until is satisfied — or when there's no
until (a fixed loop). FAILURE if max is reached unsatisfied, or the child
fails. Behavior-tree repeat/retry decorator; do-while, not while.
Check
dataclass
¤
Check(key: str, equals: Any, context_system: str | None = None)
Bases: Node
Guard leaf: SUCCESS iff blackboard[key] matches equals. String matches are lenient — case-insensitive, whitespace- and surrounding-punctuation-trimmed — because the value is usually fuzzy model text ("Yes." should match "yes"). Non-string values compare with plain ==.
Guard
dataclass
¤
Guard(expression: dict[str, Any], context_system: str | None = None)
Bases: Node
Compiled state predicate (§21.2): SUCCESS iff the restricted expression is
true over the blackboard. This is the general guard check is too narrow for
(§5.4) — it reads refs/paths and combines them with eq/in/and/or/… . The
expression is a safe JSON tree, never arbitrary code.
GuardCall
dataclass
¤
GuardCall(predicate: Callable[..., Any], arguments: dict[str, Any] = dict(), predicate_id: str | None = None, context_system: str | None = None)
Bases: Node
Guard backed by a trusted runtime predicate (§21.2 guard_call). Domain
logic that exceeds the expression system references a named capability the
runtime supplies; the package only names it, it never ships its code.
Predict
dataclass
¤
Predict(inputs: tuple[str, ...], outputs: tuple[str, ...], instructions: str | None = None, context_system: str | None = None, output_schemas: dict[str, dict[str, Any]] | None = None, signature_id: str | None = None)
Bases: Node
DSPy-style LLM leaf: read input fields, ask for output fields as JSON, write them back. FAILURE if nothing parseable comes back.
output_schemas (compiled signatures, §18) attaches a JSON-schema fragment
per output; when present the parsed value is coerced to the declared type and
validated (integer index, enum, …) before it is written. Absent (the authoring
default) leaves behavior unchanged — a single free-text output stored verbatim.
React
dataclass
¤
React(inputs: tuple[str, ...], outputs: tuple[str, ...], tools: list[Any] = list(), instructions: str | None = None, max_steps: int = 6, context_system: str | None = None)
Bases: Node
Agentic LLM leaf: the model reasons and calls @tools in a loop (native
provider function-calling) until it answers. Reads input fields, runs each
tool the model picks, feeds results back, and writes the final answer to the
single output field. FAILURE if the model answers empty or max_steps is hit
without a final answer.
Invert
dataclass
¤
Invert(child: Node, context_system: str | None = None)
Bases: Decorator
Flip the child's status: SUCCESS <-> FAILURE.
Optional
dataclass
¤
Optional(child: Node, context_system: str | None = None)
Bases: Decorator
Fail-soft: run the child but always report SUCCESS, so a failing step never aborts its parent sequence (py_trees' FailureIsSuccess).
Timeout
dataclass
¤
Timeout(child: Node, context_system: str | None = None, seconds: float = 30.0)
Bases: Decorator
Run the child with a wall-clock bound; FAILURE if it doesn't finish in
seconds. The child runs in a worker thread — on timeout it is abandoned
(Python can't kill it), so use this for read-only/idempotent work like an LLM
or lookup call.
OneShot
dataclass
¤
OneShot(child: Node, context_system: str | None = None)
Bases: Decorator
Run the child at most once per run; latch and replay its status on any later tick (only observable inside a repeat/loop). State is per-run.
Root
dataclass
¤
Root(name: str, child: Node | None = None, context_system: str | None = None, model_id: str | None = None)
Bases: Node
Entry point: one child + name/system/model. Also a builder.
Methods:
-
run–Execute the skill and return the final RunContext (read ctx.blackboard).
run
¤
run(*, model: Any = None, trace_sink: Any = None, capture_id: str = 'cap_local', episode_id: str = 'ep_local', trace_source: Any = None, **inputs: Any) -> RunContext
Execute the skill and return the final RunContext (read ctx.blackboard).
Pass a trace_sink to capture a canonical event stream for this run
(episode episode_id under capture_id); omit it and the run is
untraced and behaves exactly as before.
Source code in jdsl/tree.py
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | |
Runtime State¤
context
¤
Runtime state threaded through a run: the blackboard, the context window, and the model handle. Nodes read/write the blackboard and scope system text on the window as the tree is walked.
Classes:
-
Write–One record of a blackboard write: what, to what, by whom, over what.
-
Blackboard–Shared key/value store for one run — a dict with provenance. Every write is
-
Ref–Placeholder for blackboard[name], resolved when an act runs.
-
ToolCall–A provider-neutral tool call the model asked for: name + parsed arguments.
-
ModelTurn–One provider-neutral assistant turn: free text and/or tool calls. Empty
-
ContextWindow–A stack of system fragments, pushed/popped so context is subtree-scoped.
-
RunContext–
Write
dataclass
¤
Write(key: str, value: Any, writer: str, previous: Any = None, overwrote: bool = False)
One record of a blackboard write: what, to what, by whom, over what.
Blackboard
¤
Blackboard(initial: dict[str, Any] | None = None, /, **kwargs: Any)
Bases: dict[str, Any]
Shared key/value store for one run — a dict with provenance. Every write is
recorded in activity with its writer, and overwrites by a different writer are
flagged (the silent-clobber bug when two leaves share an output name). Read with
normal dict access; write via set(key, value, writer=...) to attribute it.
Source code in jdsl/context.py
33 34 35 36 37 38 39 40 41 42 | |
ToolCall
dataclass
¤
ToolCall(id: str, name: str, arguments: dict[str, Any])
A provider-neutral tool call the model asked for: name + parsed arguments.
ModelTurn
dataclass
¤
ModelTurn(text: str = '', tool_calls: list[ToolCall] = list())
One provider-neutral assistant turn: free text and/or tool calls. Empty
tool_calls means the model is done and text is its final answer.
ContextWindow
dataclass
¤
ContextWindow(_system: list[str] = list())
A stack of system fragments, pushed/popped so context is subtree-scoped.
RunContext
dataclass
¤
RunContext(blackboard: Blackboard = Blackboard(), window: ContextWindow = ContextWindow(), model: LanguageModel | None = None, model_id: str | None = None, state: dict[int, Any] = dict(), trace_sink: TraceSink | None = None, capture_id: str = 'cap_local', episode_id: str = 'ep_local', trace_source: EventSource | None = None, _event_tail: str | None = None)
Methods:
-
emit–Emit one canonical trace event on this run's sink. No-op (returns None)
emit
¤
emit(kind: str, *, payload: dict[str, Any] | None = None, actor: str = 'system', parent_event_id: str | None = None, blob_refs: list[str] | None = None) -> TraceEvent | None
Emit one canonical trace event on this run's sink. No-op (returns None) when there is no sink. The sink assigns sequence + hash chain.
Source code in jdsl/context.py
143 144 145 146 147 148 149 150 151 152 153 | |
Providers¤
provider
¤
The LLM backend. LanguageModel.generate dispatches by model-id prefix, pulls keys from per-provider routers, and rotates them on auth/rate-limit failures. Tinker base models use its OpenAI-compatible text-completions API.
Classes:
-
LanguageModel–Provider-dispatching language model with key rotation.
Attributes:
LanguageModel
¤
LanguageModel()
Provider-dispatching language model with key rotation.
Methods:
-
converse–One tool-calling turn.
messagesis neutral history (user/assistant/tool
Source code in jdsl/provider.py
24 25 | |
converse
¤
converse(*, system: str, messages: list[dict], tools: list[dict], model_id: str | None = None) -> ModelTurn
One tool-calling turn. messages is neutral history (user/assistant/tool
items), tools is neutral specs (name/description/parameters). Returns a
ModelTurn: final text, or tool calls to run and feed back. Used by react.
Source code in jdsl/provider.py
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | |
config
¤
Credential storage + provider inference. Keys live in
~/.local/share/recon/auth.json as {"
Functions:
-
provider_for_model– -
config_dir– -
auth_path– -
load– -
save– -
add_keys–Merge keys into provider's list, de-duplicating. Returns the merged list.
-
keys_for–Stored keys for provider, else the provider's env var.
Attributes:
SUPPORTED_PROVIDERS
module-attribute
¤
SUPPORTED_PROVIDERS = ('anthropic', 'openai', 'deepseek', 'google', 'tinker')
ENV_KEYS
module-attribute
¤
ENV_KEYS = {'anthropic': 'ANTHROPIC_API_KEY', 'openai': 'OPENAI_API_KEY', 'deepseek': 'DEEPSEEK_API_KEY', 'google': 'GOOGLE_API_KEY', 'tinker': 'TINKER_API_KEY'}
BASE_URLS
module-attribute
¤
BASE_URLS = {'deepseek': 'https://api.deepseek.com', 'openai': None, 'tinker': 'https://tinker.thinkingmachines.dev/services/tinker-prod/oai/api/v1'}
provider_for_model
¤
provider_for_model(model_id: str) -> str
Source code in jdsl/config.py
33 34 35 36 37 38 39 40 | |
config_dir
¤
config_dir() -> Path
Source code in jdsl/config.py
43 44 45 | |
auth_path
¤
auth_path() -> Path
Source code in jdsl/config.py
48 | |
load
¤
load() -> dict[str, dict[str, list[str]]]
Source code in jdsl/config.py
51 52 53 | |
save
¤
save(config: dict[str, dict[str, list[str]]]) -> None
Source code in jdsl/config.py
56 57 58 59 | |
add_keys
¤
add_keys(provider: str, keys: list[str]) -> list[str]
Merge keys into provider's list, de-duplicating. Returns the merged list.
Source code in jdsl/config.py
62 63 64 65 66 67 68 69 70 71 72 | |
keys_for
¤
keys_for(provider: str) -> list[str]
Stored keys for provider, else the provider's env var.
Source code in jdsl/config.py
75 76 77 78 79 80 | |