All checks were successful
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 1m48s
standards workspaces build + test / aac-rs (pull_request) Successful in 36s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 37s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 34s
standards workspaces build + test / map-rs (pull_request) Successful in 31s
standards workspaces build + test / mesh-rs (pull_request) Successful in 25s
standards workspaces build + test / openpay (pull_request) Successful in 1m27s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m50s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m18s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m12s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 2m38s
standards workspaces build + test / arl-rs (pull_request) Successful in 2m6s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 2m35s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 2m39s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 2m39s
standards workspaces build + test / sense-rs (pull_request) Successful in 2m33s
standards workspaces build + test / macOS energy backend (jcp-energy) (pull_request) Successful in 2m14s
LlmReply carried a bare `microjoules`, and charge_llm_step tagged every model step Estimated. A backend that ran a model in this process and read it on a live counter (an eoc-local backend's MeterSpan, now backed by the per-process counter) had no way to say so. Its measured figure was recorded as an estimate. - LlmReply carries a JouleCost. LlmReply::new is the provider's estimate, as before, and LlmReply::with_cost gives a figure with its grade. - charge_llm_step records the provider's cost as graded and charges the budget that figure. - NeuralProvider wraps any in-process NeuralBackend as an LlmProvider. The reply's energy is the backend's own JouleCost. Tokens are counted from the text (approx_tokens, or the model's tokenizer through with_token_counter) and feed only the token budget. A model served over the network still reports an estimate: it ran on hardware no counter here reads. Tests: an MlcBackend metered by an advancing counter gives a measured span, and a held, failed or stub counter gives the estimate. A whole ReAct run records the model step measured. Reverting charge_llm_step to always-estimated fails both end-to-end tests. Co-Authored-By: Claude Opus 5.5 <[email protected]>
59 lines
2.4 KiB
Rust
59 lines
2.4 KiB
Rust
//! EOC — agentic loops with per-step energy accounting.
|
|
//!
|
|
//! Modern agent systems are not single-shot completions: they iterate
|
|
//! through *think → act → observe* cycles, sometimes branching, sometimes
|
|
//! reflecting, sometimes planning ahead. EOC takes that loop and threads
|
|
//! a **joule meter** through every step, so an agent's total cost is the
|
|
//! sum of (a) its model steps, each at the figure and grade its provider
|
|
//! reports: measured when a model running in this process was read by a
|
|
//! live counter ([`NeuralProvider`]), estimated for a model served over the
|
|
//! network; (b) tool-execution energy; and (c) any local inference performed
|
|
//! between steps.
|
|
//!
|
|
//! ## Loops shipped
|
|
//!
|
|
//! | Module | Pattern |
|
|
//! |--------------------------------|--------------------------------------|
|
|
//! | [`react`] | ReAct (Thought / Action / Observation) |
|
|
//! | [`reflexion`] | Reflexion (self-critique + episodic memory) |
|
|
//! | [`tot`] | Tree of Thoughts (BFS / DFS) |
|
|
//! | [`lats`] | LATS / MCTS-UCT |
|
|
//! | [`plan_execute`] | Plan-and-Execute (planner + worker) |
|
|
//! | [`codeact`] | CodeAct (tool calls expressed as code) |
|
|
//!
|
|
//! ## Budgets
|
|
//!
|
|
//! Every loop accepts a [`Budget`](agent::Budget) that combines
|
|
//! [`TokenBudget`](budget::TokenBudget), [`JouleBudget`](budget::JouleBudget),
|
|
//! and a tool-call cap. The first cap to be exhausted produces an
|
|
//! [`StopReason::BudgetExhausted`](agent::StopReason) — no loop in this
|
|
//! crate is allowed to run unbounded.
|
|
//!
|
|
//! ## No unsafe, no `unwrap` outside tests.
|
|
|
|
#![forbid(unsafe_code)]
|
|
#![warn(missing_docs)]
|
|
|
|
pub mod agent;
|
|
pub mod budget;
|
|
pub mod codeact;
|
|
pub mod error;
|
|
pub mod lats;
|
|
pub mod plan_execute;
|
|
pub mod provider;
|
|
pub mod react;
|
|
pub mod reflexion;
|
|
pub mod tot;
|
|
pub mod trace;
|
|
|
|
pub use agent::{Agent, AgentLoop, AgentStep, Budget, StopReason};
|
|
pub use budget::{JouleBudget, TokenBudget};
|
|
pub use codeact::CodeActLoop;
|
|
pub use error::{AgentError, AgentResult};
|
|
pub use lats::{LatsConfig, LatsLoop};
|
|
pub use plan_execute::{PlanExecuteLoop, Planner, Worker};
|
|
pub use provider::NeuralProvider;
|
|
pub use react::{ReActLoop, ReActStep};
|
|
pub use reflexion::{ReflexionLoop, ReflexionMemory};
|
|
pub use tot::{Search, ToTLoop, Thought};
|
|
pub use trace::{Span, Trace};
|