jeevesagent.architecture.base

Architecture protocol + supporting types.

Three pieces:

  • AgentSession — mutable per-run state shared between Agent and the Architecture. The architecture reads messages and writes turns, output, cumulative_usage, interrupted, interruption_reason, and metadata as iteration progresses. The Agent reads the final state to build a RunResult.

  • Dependencies — every protocol implementation an architecture might need (model, memory, runtime, tools, budget, permissions, hooks, telemetry, audit log, max_turns), bundled into one struct so an architecture’s run() signature stays short. Stable for the lifetime of a run.

  • Architecture — the protocol architectures implement. One method (run) plus a name and declared_workers for introspection.

Setup events (Event.started) and teardown events (Event.completed) are emitted by Agent, NOT the architecture. Architectures yield the events that happen during iteration: per-turn, per-tool, per-step, budget warnings, errors.

This keeps every architecture’s run() focused on its own strategy without re-implementing setup/teardown plumbing.

Classes

AgentSession

Mutable per-run state shared between Agent and an

Architecture

Strategy interface for driving the agent loop.

Dependencies

Bundled protocol implementations passed to every architecture.

Module Contents

class jeevesagent.architecture.base.AgentSession[source]

Mutable per-run state shared between Agent and an Architecture.

The Agent constructs this once per run, the architecture mutates it as iteration progresses, and the Agent reads the final state to build a RunResult.

metadata is a free-form dict architectures use for things that don’t deserve their own field — multi-agent architectures stash worker handoff state, planners stash plans, etc.

cumulative_usage: jeevesagent.core.types.Usage
id: str
instructions: str
interrupted: bool = False
interruption_reason: str | None = None
messages: list[jeevesagent.core.types.Message] = []
metadata: dict[str, Any]
output: str = ''
turns: int = 0
class jeevesagent.architecture.base.Architecture[source]

Bases: Protocol

Strategy interface for driving the agent loop.

Implementations are async generators: they yield Event values for every milestone they want surfaced (model chunks, tool calls, tool results, budget warnings, errors, architecture-specific progress events).

See Subagent.md for the catalogue of architectures and the design rationale behind the protocol shape.

declared_workers() dict[str, jeevesagent.agent.api.Agent][source]

Sub-Agents this architecture composes, keyed by role name.

Used by multi-agent architectures (Supervisor, Actor-Critic, Debate, Router, Blackboard, Swarm) to expose their workers for introspection (logging, telemetry, eval). Single-agent architectures return {}.

run(session: AgentSession, deps: Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]

Drive iteration; yield events as they happen.

The architecture mutates session (turns, output, cumulative_usage, messages, interrupted, interruption_reason, metadata) as it iterates and yields Events for the caller to forward (or ignore, in non-streaming runs).

Implementations are async generators — declared async def run(...) -> AsyncIterator[Event]: with yield statements in the body.

name: str
class jeevesagent.architecture.base.Dependencies[source]

Bundled protocol implementations passed to every architecture.

Constructed once per run from the Agent’s configured backends. Architectures treat this as read-only — they call methods on the contained protocols but don’t mutate the struct itself.

Multi-agent architectures (Supervisor, Router, etc.) will grow helper methods on this class — fresh_session, scope_for_worker, with_extra_tools, spawn_child — as they land in v0.5+. v0.3 keeps it as a passive struct.

audit_log: jeevesagent.security.audit.AuditLog | None
budget: jeevesagent.core.protocols.Budget
context: jeevesagent.core.context.RunContext

Typed scope for the run — user_id (memory namespace), session_id (conversation thread), run_id (this specific invocation), and metadata (free-form app context). See RunContext for the per-field semantics.

fast_audit: bool = True

Skip _audit(...) calls when audit_log is None.

fast_budget: bool = True

Skip budget.allows_step() and budget.consume(...) when budget is NoBudget.

fast_hooks: bool = True

Skip hooks.pre_tool / hooks.post_tool dispatch when no hooks have been registered.

fast_permissions: bool = True

Skip per-tool permissions.check(...) when permissions is the no-op AllowAll.

fast_runtime: bool = True

Inline await fn(*args) (skipping runtime.step(...) wrapping + idempotency-key derivation) when runtime is InProcRuntime.

fast_telemetry: bool = True

Skip telemetry.trace(...) contextmanagers + emit_metric calls when telemetry is NoTelemetry.

hooks: jeevesagent.security.hooks.HookRegistry
max_turns: int
memory: jeevesagent.core.protocols.Memory
model: jeevesagent.core.protocols.Model
permissions: jeevesagent.core.protocols.Permissions
runtime: jeevesagent.core.protocols.Runtime
streaming: bool = False

Whether a downstream consumer is reading from agent.stream(). When True, architectures should preserve real-time event-arrival semantics so a consumer that breaks out of the iterator triggers prompt cancellation. When False (the default for agent.run()), architectures may batch events for fewer task-group / channel allocations on the hot path.

telemetry: jeevesagent.core.protocols.Telemetry
tools: jeevesagent.core.protocols.ToolHost