Skip to content

feat: bare loop, tokio dep added, clean up - #19

Merged
bobrykov merged 5 commits into
masterfrom
feat/bare-loop
May 8, 2026
Merged

feat: bare loop, tokio dep added, clean up#19
bobrykov merged 5 commits into
masterfrom
feat/bare-loop

Conversation

@bobrykov

@bobrykov bobrykov commented May 8, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6829beb1-6ecb-4e34-aff9-3f26a5e56862

📥 Commits

Reviewing files that changed from the base of the PR and between 83f9ef7 and 8cf85d3.

📒 Files selected for processing (2)
  • README.md
  • src/engine/bare.rs
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/engine/bare.rs

📝 Walkthrough

Walkthrough

This PR introduces BareLoop, the framework's default agentic execution loop with cooperative cancellation and tool dispatch orchestration. It adds Tokio as a runtime dependency, implements CancelSignal for cancel-aware streaming, refactors tool-result types from ToolResult to ToolContent, and wires everything into a multi-turn agent loop that streams LLM responses, extracts and dispatches tools sequentially, converts tool failures to soft errors, and notifies observers throughout the session lifecycle.

Changes

Agentic Loop and Tool Content Refactoring

Layer / File(s) Summary
Dependencies and Cancellation Primitive
Cargo.toml, src/cancel.rs
Adds tokio with sync and macros features; implements CancelSignal with AtomicBool flag and tokio::sync::Notify for cancel-aware async waiting and wake-on-cancel semantics; includes Default impl and unit tests.
Message Type Refactoring: ToolContent
src/message.rs
Renames ToolResult/ToolResultPart to ToolContent/ToolContentPart. Adds Text and Multipart(Vec<ToolContentPart>) variants, From<String>/From<&str>/Default trait impls, and Display formatting that joins multipart text with newlines; updates MessagePart constructors and tests.
ToolOutput API Migration
src/tool.rs
Updates ToolOutput field type and constructor signatures from MessageToolResult to MessageToolContent; refactors text_content helper to flatten ToolContentPart variants.
Engine Module & Crate Exports
src/engine.rs, src/lib.rs
Creates engine module entry point with bare submodule re-export; adds cancel module export to crate root and updates crate-level module docs.
BareLoop Structure & Constructors
src/engine/bare.rs
Defines BareLoop<C> struct with Arc<ApiClient>, ToolRegistry, AgentConfig, conversation Vec, AgentObservers, ManagerBundle, and CancelSignal; provides new, with_observers, with_managers, from_parts constructors and accessors for conversation, config, tools, and cancellation.
BareLoop Main Execution Loop
src/engine/bare.rs
Implements run() async method: appends user message, iterates with cancellation/max-turn checks, notifies observers on session/turn lifecycle, streams turns via stream_turn, extracts assistant text and tool calls, sequentially dispatches tools via dispatch_tools with soft error handling, injects tool-result messages, and returns SessionResult with final output and token accounting or returns errors on cancel/API failure.
Streaming and Tool Dispatch Helpers
src/engine/bare.rs
Implements stream_turn to accumulate stream events into a single assistant Message with cancel-aware tokio::select!, capturing per-turn usage and stop reason; implements dispatch_tools to run tools sequentially with pre/post observer notifications and convert missing/execution failures into soft ToolCallResult entries so the session continues unless cancelled.
Internal Helpers and Observers
src/engine/bare.rs
Adds extract_text, extract_tool_calls, build_tool_result_message, build_tool_schemas, build_tool_context helpers; observer notification helpers for session/turn/tool lifecycle; internal ToolCallInfo and ToolCallResult structs.
Documentation and Test Updates
src/api_client.rs, src/api_error.rs, src/stream.rs, src/loop_control/*, README.md
Minor rustdoc formatting edits; removes #[cfg(test)] gating from api_error tests module; updates doctest example for ConvergenceDetector::clear; reflowed docs for LoopDetector area without functional changes; adds README.md; and adds/updates unit tests for CancelSignal, ToolContent, and BareLoop.

Possibly related PRs

  • dch-labs/loopctl#15: Modifies tool-related API (tool module exports and Tool/ToolOutput types) that are now integrated into BareLoop.
  • dch-labs/loopctl#13: Adds ManagerBundle and DetectionManager types referenced by BareLoop's managers field.
  • dch-labs/loopctl#2: Introduced earlier Message/ToolResult types that this PR refactors to ToolContent.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: implementing BareLoop (the default agent execution engine), adding tokio dependency, and cleaning up documentation/code.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 50.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/bare-loop

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cancel.rs`:
- Around line 89-94: The notified() method has a lost-wakeup race: create the
Notify::notified() future before checking the cancellation flag so a concurrent
cancel() cannot wake before we register; specifically, call let notified =
self.notify.notified() first, then if self.flag.load(Ordering::Acquire) {
return; } else await notified.await; keep using the same Ordering on self.flag
and the Notified future to ensure the wakeup is not missed.

In `@src/engine/bare.rs`:
- Around line 491-497: The cancellation branch in bare.rs currently returns
Ok(SessionResult::failed(...)) which is inconsistent with cancellations from
stream_turn()/dispatch_tools() that return Err(AgentError::Cancelled); change
the branch that checks self.is_cancelled() to notify_session_end(...) and then
return Err(AgentError::Cancelled) instead of Ok(SessionResult::failed(...));
apply the same change to the corresponding cancellation branch around the other
occurrence (the block referenced at 541-544) so all cancellations surface as
Err(AgentError::Cancelled).
- Around line 652-667: The branch handling tool.call currently calls
result.text_content() which discards multipart/image payloads and flattens
ToolOutput; update the logic in the tool call handling (the match arm that
builds ToolCallResult and calls notify_tool_complete) to preserve the full
ToolOutput.payload (or the ToolContent model) instead of converting to text,
pass that preserved payload into notify_tool_complete and into
ToolCallResult.output, and ensure the "success" flag passed to
notify_tool_complete is derived from !result.is_error (so observers see failures
when result.is_error is true); apply the same change to the other similar
branches that use result.text_content() (the blocks around the other occurrences
referenced).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1430b44b-5bc8-433b-a29c-ef7115aca410

📥 Commits

Reviewing files that changed from the base of the PR and between b1ae390 and 7260263.

📒 Files selected for processing (12)
  • Cargo.toml
  • src/api_client.rs
  • src/api_error.rs
  • src/cancel.rs
  • src/engine.rs
  • src/engine/bare.rs
  • src/lib.rs
  • src/loop_control/convergence.rs
  • src/loop_control/loop_detector.rs
  • src/message.rs
  • src/stream.rs
  • src/tool.rs
💤 Files with no reviewable changes (5)
  • src/stream.rs
  • src/api_client.rs
  • src/api_error.rs
  • src/loop_control/convergence.rs
  • src/loop_control/loop_detector.rs

Comment thread src/cancel.rs
Comment thread src/engine/bare.rs
Comment thread src/engine/bare.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 18-31: The README's module list uses reference-style names like
`[`api_client`]`, `[`api_error`]`, `[`builder`]`, `[`builtin`]`, `[`cancel`]`,
`[`core`]`, `[`engine`]`, `[`loop_control`]`, `[`message`]`, `[`stream`]`,
`[`tool`]`, and `[`testing`]` but no reference link definitions exist; fix this
by either converting each bracketed module token to an inline link (e.g.,
replace `[`api_client`]` with `[api_client](<target>)`) or by adding matching
reference definitions for each symbol at the bottom of the README (e.g.,
`[api_client]: <target>`), ensuring every listed module name resolves to its
documentation or crate/module path so the links become clickable.
- Line 132: The markdown code fence containing the ASCII architecture diagram is
missing a language specifier causing markdownlint MD040; update the opening
fence from ``` to ```text so the diagram block (the fence that contains the
ASCII art showing ApiClient and related components) is explicitly marked as
text, leaving the closing ``` unchanged.

In `@src/engine/bare.rs`:
- Around line 431-438: The doc comment listing loop termination conditions is
out of date: update the cancellation bullet to reflect the current contract by
stating that calling BareLoop::cancel results in an Err(AgentError::Cancelled)
being returned (rather than producing Ok(SessionResult::failed(...))); locate
the doc block in src/engine/bare.rs that documents the loop termination cases
and replace the sentence about cancellation so it mentions
Err(AgentError::Cancelled) and the caller should handle that error variant.
- Around line 505-506: The branch handling Ok((assistant_msg, usage,
_stop_reason)) treats any non-tool response as a successful end_turn; change it
to inspect the StreamStopReason returned by stream_turn() (e.g., the
`_stop_reason` variable) and only mark success true when that reason equals
StreamStopReason::EndTurn (or equivalent), otherwise set success to false (or
mark as truncated/partial) and propagate the actual stop reason into the
outgoing response/metadata; apply the same fix to the similar handling around
the other branch (lines ~523-538) so truncated/token-exhaustion stops are not
reported as clean successes.
- Around line 517-522: When calling self.dispatch_tools(&tool_calls).await in
the has_tool_calls branch, capture the Result instead of using ? so you can
detect AgentError::Cancelled and still emit end events before returning: call
self.notify_turn_end(true, None) and self.notify_session_end(...) as appropriate
when Err(AgentError::Cancelled) is returned, then return the error; for other
Errs propagate as before; only build_tool_result_message, push to conversation,
and increment total_tool_calls when dispatch_tools returns Ok. Ensure you
reference dispatch_tools, run, notify_turn_end, notify_session_end, and
AgentError::Cancelled in your changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3d41e2ee-ef33-45c2-b226-c260c12b63c4

📥 Commits

Reviewing files that changed from the base of the PR and between 7260263 and bfa4857.

📒 Files selected for processing (3)
  • README.md
  • src/cancel.rs
  • src/engine/bare.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/cancel.rs

Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread src/engine/bare.rs
Comment thread src/engine/bare.rs Outdated
Comment thread src/engine/bare.rs Outdated
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