Skip to content

Agent framework 2 - #57

Merged
thorrester merged 3 commits into
mainfrom
agent-framework-2
Mar 26, 2026
Merged

Agent framework 2#57
thorrester merged 3 commits into
mainfrom
agent-framework-2

Conversation

@thorrester

@thorrester thorrester commented Mar 26, 2026

Copy link
Copy Markdown
Member

Pull Request

Short summary

Adds the full agent execution engine to potato_agent and a new potato_spec crate for loading agents and workflows from YAML. The crate previously had Agent, Task, and TaskStatus. Everything else was missing.

Context

potato_agent

AgentBuilder is a fluent builder for Arc<Agent>. It takes provider, model, system prompt, sync and async tools, sub-agents, memory, completion criteria, and callbacks. It's the main construction path for everything that follows.

Completion criteria plug in via CompletionCriteria. Three built-ins: MaxIterationsCriteria, KeywordCriteria (stops when the response contains a given string), StructuredOutputCriteria (stops when the response is valid JSON, optionally checked against a schema). You can combine them — all must pass to stop.

Lifecycle callbacks fire at before_model_call, after_model_call, before_tool_call, and after_tool_call. LoggingCallback is built in and uses tracing::info! on all four. Custom implementations come in as Arc<dyn AgentCallback>.

Three memory backends: InMemoryMemory (unbounded), WindowedMemory (last N turns), PersistentMemory (backed by any MemoryStore impl, with optional windowing). SQLite implementations for all four store traits are gated behind feature = "sqlite" and scoped by (app_name, user_id, session_id).

Orchestration: SequentialAgent runs A → B → C with optional pass_output to feed each agent the previous response. ParallelAgent spawns via tokio::spawn and merges with MergeStrategy::CollectAll or First. Both implement AgentRunner and can be nested. AgentTool wraps any AgentRunner as an async tool so agents can call other agents through the standard tool-use loop.

SessionState/SessionSnapshot is a scoped key-value map shared across runs. Parallel child sessions merge user data back into the parent after joining.

potato_spec — new crate

Load agents and workflows from YAML instead of writing builder code. Pre-register Arc<dyn AsyncTool> and Arc<dyn AgentCallback> by name, then call load_file(). DAG workflows run topological sort before inserting tasks, so out-of-order declarations work and circular dependencies fail with a clear error at load time rather than at runtime.

Three entry points:

  • SpecLoader::from_spec(yaml) — parse from string
  • SpecLoader::from_spec_path(path) — read from file
  • SpecLoader::new().register_async_tool(...).register_callback(...).load_file(path) — with pre-registered tools/callbacks

Before:

let agent = AgentBuilder::new()
    .provider(Provider::Anthropic)
    .model("claude-haiku-4-5")
    .system_prompt("You are a summarization assistant.")
    .with_windowed_memory(10)
    .stop_on_keyword("DONE")
    .with_callback(Arc::new(LoggingCallback))
    .build()
    .await?;

After:

agents:
  - id: summarizer
    provider: anthropic
    model: claude-haiku-4-5
    system_prompt: You are a summarization assistant.
    memory:
      type: windowed
      window_size: 10
    criteria:
      - type: keyword
        keyword: "DONE"
    callbacks:
      - type: logging
let spec = SpecLoader::from_spec_path("agents.yaml").await?;
let agent = spec.agent("summarizer").unwrap();

Tests

9 new test modules in baked_potato against the mock LLM server, 18 tests in potato_spec:

Test file Coverage
agent/agentic_loop_test.rs Full tool-use loop, max iterations
agent/builder_test.rs Builder configurations, provider validation
agent/callbacks_test.rs All 4 lifecycle hooks, LoggingCallback
agent/criteria_test.rs Keyword, structured output, max iterations
agent/memory_test.rs In-memory, windowed, persistent
agent/orchestration_test.rs Sequential (with/without pass_output), parallel (both merge strategies)
agent/session_test.rs Session state read/write, snapshot/merge
agent/store_test.rs All 4 SQLite store types
agent/tool_ext_test.rs AgentTool composition, AgentToolPolicy
crates/potato_spec/tests/load_spec.rs 16 parser/builder tests + 2 topo-sort unit tests

Docs

7 MkDocs pages covering agents overview, memory, criteria, callbacks, orchestration, session state, and tools.

File Change
crates/potato_agent/src/agents/builder.rs New AgentBuilder (292 lines)
crates/potato_agent/src/agents/callbacks.rs AgentCallback trait + LoggingCallback
crates/potato_agent/src/agents/criteria.rs 3 CompletionCriteria implementations
crates/potato_agent/src/agents/memory/ InMemoryMemory, WindowedMemory, PersistentMemory
crates/potato_agent/src/agents/orchestration/ SequentialAgent, ParallelAgent + builders
crates/potato_agent/src/agents/session.rs SessionState / SessionSnapshot
crates/potato_agent/src/agents/store/ 4 trait interfaces + 4 SQLite implementations
crates/potato_agent/src/agents/tool_ext.rs AgentTool, AgentToolPolicy
crates/potato_agent/src/lib.rs Re-exports all new public types
crates/potato_spec/src/ New crate: SpecLoader, LoadedSpec, SpecError, spec structs
crates/potato_spec/tests/ 18 tests + fixture YAML
crates/potato_head/src/lib.rs Re-exports SpecLoader, LoadedSpec, SpecError, PotatoSpec
crates/baked_potato/tests/agent/ 9 new test modules
py-potato/docs/docs/agents/ 7 MkDocs pages
crates/potato_type/src/tools/ AsyncTool trait, tool type additions
Cargo.toml potato-spec added to workspace

Is this a breaking change?

No. Agent, Task, TaskStatus, AgentError, and GenAiClient are unchanged. potato_head gains re-exports that don't affect existing imports.


Open with Devin

thorrester and others added 3 commits March 25, 2026 21:05
…oggingCallback

- New crate `potato-spec` with PotatoSpec/AgentSpec/WorkflowSpec deserialization structs
- SpecError with 7 variants for clear load-time error messages
- LoggingCallback added to potato-agent for built-in tracing support
- Workspace and potato-head facade wired up

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uction

- SpecLoader with tool/callback registry for declarative agent loading
- Builds Agent, SequentialAgent, ParallelAgent, and DAG Workflow from YAML
- Topological sort for DAG tasks with cycle detection
- 18 tests covering deserialization, error paths, and sort correctness
- LoggingCallback available as built-in callback type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@thorrester
thorrester merged commit 19bfbe7 into main Mar 26, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant