jeevesagent.architecture¶
Architecture layer.
An Architecture is a strategy for driving the agent loop.
The canonical default is ReAct — observe / think / act in a
tight loop. Other architectures (Plan-and-Execute, Reflexion,
Self-Refine, Tree of Thoughts, Supervisor, Router, …) plug into the
same Agent by satisfying the Architecture protocol.
See Subagent.md in the repo root for the full architecture
catalogue and design rationale.
Public surface:
Architecture— the protocol architectures implementAgentSession— mutable per-run stateDependencies— bundled protocol implementationsReAct— the canonical default (observe / think / act)resolve_architecture()— string -> Architecture instance
Submodules¶
- jeevesagent.architecture.actor_critic
- jeevesagent.architecture.base
- jeevesagent.architecture.blackboard
- jeevesagent.architecture.debate
- jeevesagent.architecture.helpers
- jeevesagent.architecture.plan_and_execute
- jeevesagent.architecture.react
- jeevesagent.architecture.reflexion
- jeevesagent.architecture.resolver
- jeevesagent.architecture.rewoo
- jeevesagent.architecture.router
- jeevesagent.architecture.self_refine
- jeevesagent.architecture.supervisor
- jeevesagent.architecture.swarm
- jeevesagent.architecture.tool_host_wrappers
- jeevesagent.architecture.tree_of_thoughts
Classes¶
Actor + adversarial critic with optional different models. |
|
Mutable per-run state shared between |
|
Strategy interface for driving the agent loop. |
|
Public + per-agent private state for the architecture. |
|
Coordinator + agents + decider, mediated by a shared |
|
One contribution on the blackboard. |
|
Bundled protocol implementations passed to every architecture. |
|
Per-peer handoff configuration. |
|
N debaters + optional judge orchestration. |
|
A list of plan steps in execution order. |
|
Planner → step executor → synthesizer. |
|
One step of a plan. |
|
Observe-think-act in a tight loop. |
|
Plan-then-tool-execute with placeholder substitution. |
|
A list of ReWOO steps (no required ordering — dependencies |
|
One step of a ReWOO plan: id + tool + args. |
|
!!! abstract "Usage Documentation" |
|
Wrap a base architecture with evaluator + reflector + lesson |
|
Classify input → dispatch to ONE specialist |
|
One specialist + classification metadata. |
|
Wrap a base architecture with iterative critique / refine. |
|
The output of executing one step. |
|
Coordinator + workers, glued by a |
|
Peer agents passing control through handoff tools. |
|
One node in the Tree-of-Thoughts search tree. |
|
Branch + evaluate + prune. BFS beam search over thoughts. |
Functions¶
|
Coerce |
Package Contents¶
- class jeevesagent.architecture.ActorCritic(*, actor: jeevesagent.agent.api.Agent, critic: jeevesagent.agent.api.Agent, max_rounds: int = 3, approval_threshold: float = 0.9, critique_template: str | None = None, refine_template: str | None = None)[source]¶
Actor + adversarial critic with optional different models.
Constructor parameters:
actor(required): the generatingAgent. Sees the original prompt on round 0 and a refine prompt on subsequent rounds.critic(required): the reviewingAgent. Sees the original prompt + the actor’s current output and produces structured JSON critique.max_rounds: cap on critique-refine cycles after the initial generation. Default 3.approval_threshold: terminate whencritique.scoreis at or above this value. Default 0.9.critique_template/refine_template: override the default prompts. Templates use{prompt},{output},{critique},{issues_bulleted}.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'actor-critic'¶
- class jeevesagent.architecture.AgentSession[source]¶
Mutable per-run state shared between
Agentand anArchitecture.The
Agentconstructs this once per run, the architecture mutates it as iteration progresses, and theAgentreads the final state to build aRunResult.metadatais 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¶
- messages: list[jeevesagent.core.types.Message] = []¶
- class jeevesagent.architecture.Architecture[source]¶
Bases:
ProtocolStrategy interface for driving the agent loop.
Implementations are async generators: they
yieldEventvalues for every milestone they want surfaced (model chunks, tool calls, tool results, budget warnings, errors, architecture-specific progress events).See
Subagent.mdfor 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 yieldsEvents for the caller to forward (or ignore, in non-streaming runs).Implementations are async generators — declared
async def run(...) -> AsyncIterator[Event]:withyieldstatements in the body.
- class jeevesagent.architecture.Blackboard[source]¶
Public + per-agent private state for the architecture.
- post(author: str, content: str, *, kind: str = 'contribution', private_to: str | None = None) BlackboardEntry[source]¶
- render_for(agent_name: str) str[source]¶
Format the blackboard state as a string for
agent_name.Includes every public entry and the agent’s own private scratchpad if any.
- private: dict[str, list[BlackboardEntry]]¶
- public: list[BlackboardEntry] = []¶
- class jeevesagent.architecture.BlackboardArchitecture(*, agents: dict[str, jeevesagent.agent.api.Agent], coordinator: jeevesagent.agent.api.Agent | None = None, decider: jeevesagent.agent.api.Agent | None = None, max_rounds: int = 10, coordinator_instructions: str | None = None, decider_instructions: str | None = None)[source]¶
Coordinator + agents + decider, mediated by a shared blackboard.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'blackboard'¶
- class jeevesagent.architecture.BlackboardEntry[source]¶
One contribution on the blackboard.
- timestamp: datetime.datetime¶
- class jeevesagent.architecture.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¶
- context: jeevesagent.core.context.RunContext¶
Typed scope for the run —
user_id(memory namespace),session_id(conversation thread),run_id(this specific invocation), andmetadata(free-form app context). SeeRunContextfor the per-field semantics.
- fast_budget: bool = True¶
Skip
budget.allows_step()andbudget.consume(...)when budget isNoBudget.
- fast_hooks: bool = True¶
Skip
hooks.pre_tool/hooks.post_tooldispatch when no hooks have been registered.
- fast_permissions: bool = True¶
Skip per-tool
permissions.check(...)when permissions is the no-opAllowAll.
- fast_runtime: bool = True¶
Inline
await fn(*args)(skippingruntime.step(...)wrapping + idempotency-key derivation) when runtime isInProcRuntime.
- fast_telemetry: bool = True¶
Skip
telemetry.trace(...)contextmanagers +emit_metriccalls whentelemetryisNoTelemetry.
- 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 foragent.run()), architectures may batch events for fewer task-group / channel allocations on the hot path.
- telemetry: jeevesagent.core.protocols.Telemetry¶
- class jeevesagent.architecture.Handoff[source]¶
Per-peer handoff configuration.
agent— the peerAgent.input_type— optional Pydantic model. When set, the generated handoff tool’s input schema mirrors this model’s fields, so the calling model gets a typed schema (instead of a stringmessage). The validated payload is exposed toinput_filterand surfaces in theswarm.handoffevent.input_filter— optional callback(history, payload) → promptfor selective context forwarding. Default behavior respects the Swarm’spass_full_historyflag.description— override the generated tool’s description. Useful when the agent’s name is opaque (“billing_v2”) but the description should be user-friendly.tool_name— override the auto-generated tool name. Default is"transfer_to_<key>"where<key>is the peer’s key in the swarm’sagentsdict.
- agent: jeevesagent.agent.api.Agent¶
- input_filter: InputFilter | None = None¶
- input_type: type[pydantic.BaseModel] | None = None¶
- class jeevesagent.architecture.MultiAgentDebate(*, debaters: list[jeevesagent.agent.api.Agent], judge: jeevesagent.agent.api.Agent | None = None, rounds: int = 2, convergence_check: bool = True, convergence_similarity: float = 0.85, debater_instructions: str | None = None, judge_instructions: str | None = None)[source]¶
N debaters + optional judge orchestration.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'debate'¶
- class jeevesagent.architecture.Plan(/, **data: Any)[source]¶
Bases:
pydantic.BaseModelA list of plan steps in execution order.
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.PlanAndExecute(*, max_steps: int = 8, planner_prompt: str | None = None, executor_prompt: str | None = None, synthesizer_prompt: str | None = None)[source]¶
Planner → step executor → synthesizer.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'plan-and-execute'¶
- class jeevesagent.architecture.PlanStep(/, **data: Any)[source]¶
Bases:
pydantic.BaseModelOne step of a plan.
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.ReAct(*, max_turns: int | None = None)[source]¶
Observe-think-act in a tight loop.
The default architecture for every
Agent. Other architectures wrap or replace this strategy; seeSubagent.md.max_turnsoverridesDependencies.max_turnsfor this architecture only — useful when wrapping ReAct inside another architecture that sets its own per-leaf cap (Reflexion, Plan-and-Execute, etc.).Nonemeans “use whatever the Agent was configured with”.- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'react'¶
- class jeevesagent.architecture.ReWOO(*, max_steps: int = 8, planner_prompt: str | None = None, solver_prompt: str | None = None, parallel_levels: bool = True)[source]¶
Plan-then-tool-execute with placeholder substitution.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'rewoo'¶
- class jeevesagent.architecture.ReWOOPlan(/, **data: Any)[source]¶
Bases:
pydantic.BaseModelA list of ReWOO steps (no required ordering — dependencies are inferred from
{{En}}placeholders).Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.ReWOOStep(/, **data: Any)[source]¶
Bases:
pydantic.BaseModelOne step of a ReWOO plan: id + tool + args.
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.ReWOOStepResult(/, **data: Any)[source]¶
Bases:
pydantic.BaseModel- !!! abstract “Usage Documentation”
[Models](../concepts/models.md)
A base class for creating Pydantic models.
- __class_vars__¶
The names of the class variables defined on the model.
- __private_attributes__¶
Metadata about the private attributes of the model.
- __signature__¶
The synthesized __init__ [Signature][inspect.Signature] of the model.
- __pydantic_complete__¶
Whether model building is completed, or if there are still undefined fields.
- __pydantic_core_schema__¶
The core schema of the model.
- __pydantic_custom_init__¶
Whether the model has a custom __init__ function.
- __pydantic_decorators__¶
Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
- __pydantic_generic_metadata__¶
Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
- __pydantic_parent_namespace__¶
Parent namespace of the model, used for automatic rebuilding of models.
- __pydantic_post_init__¶
The name of the post-init method for the model, if defined.
- __pydantic_root_model__¶
Whether the model is a [RootModel][pydantic.root_model.RootModel].
- __pydantic_serializer__¶
The pydantic-core SchemaSerializer used to dump instances of the model.
- __pydantic_validator__¶
The pydantic-core SchemaValidator used to validate instances of the model.
- __pydantic_fields__¶
A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
- __pydantic_computed_fields__¶
A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
- __pydantic_extra__¶
A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to ‘allow’.
- __pydantic_fields_set__¶
The names of fields explicitly set during instantiation.
- __pydantic_private__¶
Values of private attributes set on the model instance.
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.Reflexion(*, base: jeevesagent.architecture.base.Architecture | None = None, max_attempts: int = 3, threshold: float = 0.8, evaluator_prompt: str | None = None, reflector_prompt: str | None = None, lessons_block_name: str = 'reflexion_lessons', lesson_store: jeevesagent.vectorstore.base.VectorStore | None = None, top_k_lessons: int = 5)[source]¶
Wrap a base architecture with evaluator + reflector + lesson memory.
See module docstring for the full mechanism. Constructor parameters:
base— architecture to retry. DefaultReAct.max_attempts— cap on retries within a single run. Default 3.threshold— minimum evaluator score to terminate as success. Default 0.8.evaluator_prompt/reflector_prompt— override the default system prompts.lessons_block_name— memory working-block name for persisted lessons. Default"reflexion_lessons". Multiple Reflexion-wrapped agents in the same memory should pick distinct names.lesson_store— optionalVectorStoreenabling selective recall. When set, lessons are stored as embedded chunks and only the top-top_k_lessonsmost relevant lessons are surfaced on each attempt (instead of all past lessons). Avoids context bloat as lessons accumulate.top_k_lessons— how many lessons to recall per attempt (selective-recall mode only). Default 5.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'reflexion'¶
- class jeevesagent.architecture.Router(*, routes: list[RouterRoute], fallback_route: str | None = None, require_confidence_above: float = 0.0, classifier_prompt: str | None = None)[source]¶
Classify input → dispatch to ONE specialist
Agent.- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'router'¶
- class jeevesagent.architecture.RouterRoute[source]¶
One specialist + classification metadata.
nameis what the classifier emits in itsroute:line and must be unique within a Router.descriptionis shown to the classifier alongside the name — keep it specific and distinguishing so the classifier picks reliably.- agent: jeevesagent.agent.api.Agent¶
- class jeevesagent.architecture.SelfRefine(*, base: jeevesagent.architecture.base.Architecture | None = None, max_rounds: int = 3, critic_prompt: str | None = None, refiner_prompt: str | None = None, stop_phrase: str = 'no issues')[source]¶
Wrap a base architecture with iterative critique / refine.
basedefaults toReAct; the round-0 generator runs the base architecture’s full strategy. Subsequent rounds are text-only model calls — no tools, just critique and rewrite.- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'self-refine'¶
- class jeevesagent.architecture.StepResult(/, **data: Any)[source]¶
Bases:
pydantic.BaseModelThe output of executing one step.
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.Supervisor(*, workers: dict[str, jeevesagent.agent.api.Agent], base: jeevesagent.architecture.base.Architecture | None = None, instructions_template: str | None = None, delegate_tool_name: str = 'delegate', forward_tool_name: str = 'forward_message')[source]¶
Coordinator + workers, glued by a
delegatetool.The supervisor’s base architecture (default
ReAct) sees a freshdelegate(worker, instructions)tool that routes calls to the named workerAgent. Worker outputs come back as tool results just like any other tool call.Constructor¶
workers: dict mapping role-names to fully-builtAgentinstances. Names must be valid identifiers (the model emits them as theworkerargument).base: the architecture the supervisor itself runs. DefaultReAct. Wrap insideReflexionto learn delegation patterns across runs.instructions_template: format string with{worker_descriptions}. Default teaches the supervisor to delegate effectively. The agent’s owninstructionsare prepended (so domain context survives).delegate_tool_name: defaults to"delegate". Customize to avoid clashes with user-defined tools that happen to have the same name.forward_tool_name: defaults to"forward_message". The supervisor calls this with a worker name to return that worker’s last output VERBATIM as the supervisor’s final response. Skips a synthesis round-trip — the `langchain.com/blog/benchmarking-multi-agent-architectures`_ benchmark showed +50% quality on tasks where the supervisor would otherwise paraphrase a worker’s output.
- add_worker(name: str, agent: jeevesagent.agent.api.Agent) None[source]¶
Register a worker between runs.
Safe to call between
Agent.run()invocations on the agent that owns this supervisor; the new worker becomes available fordelegate(name, ...)on the next run. Calling mid-run is undefined — the supervisor’s prompt is composed at run start.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- remove_worker(name: str) jeevesagent.agent.api.Agent | None[source]¶
Unregister a worker by name. Returns the removed Agent if it was registered,
Noneotherwise. Same lifecycle rules asadd_worker().
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'supervisor'¶
- class jeevesagent.architecture.Swarm(*, agents: dict[str, jeevesagent.agent.api.Agent | Handoff], entry_agent: str, max_handoffs: int = 8, detect_cycles: bool = True, pass_full_history: bool = True, handoff_tool_name: str = 'handoff')[source]¶
Peer agents passing control through handoff tools.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'swarm'¶
- class jeevesagent.architecture.ThoughtNode(/, **data: Any)[source]¶
Bases:
pydantic.BaseModelOne node in the Tree-of-Thoughts search tree.
Children are stored implicitly (each node has a
parent_id). The full tree is reconstructable from the node list ToT keeps in its session metadata.Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
self is explicitly positional-only to allow self as a field name.
- class jeevesagent.architecture.TreeOfThoughts(*, branch_factor: int = 3, max_depth: int = 3, beam_width: int = 2, solved_threshold: float = 1.0, min_score: float = 0.0, parallel: bool = True, proposer_prompt: str | None = None, evaluator_prompt: str | None = None)[source]¶
Branch + evaluate + prune. BFS beam search over thoughts.
- declared_workers() dict[str, jeevesagent.agent.api.Agent][source]¶
- async run(session: jeevesagent.architecture.base.AgentSession, deps: jeevesagent.architecture.base.Dependencies, prompt: str) collections.abc.AsyncIterator[jeevesagent.core.types.Event][source]¶
- name = 'tree-of-thoughts'¶
- jeevesagent.architecture.resolve_architecture(spec: jeevesagent.architecture.base.Architecture | str | None) jeevesagent.architecture.base.Architecture[source]¶
Coerce
specto a concreteArchitecture.None→ReAct(the default)str→ looked up inKNOWN(only"react"in v0.3)Architecture instance → returned as-is
Unknown strings raise
ConfigErrorwith a list of known names.