Skip to content

fix(agent-control): tag control messages with dedicated role and resume paused team runs - #129

Merged
w0wl0lxd merged 12 commits into
mainfrom
fix/agent-control-steer
Jul 27, 2026
Merged

w0wl0lxd merged 12 commits into
mainfrom
fix/agent-control-steer

Conversation

@w0wl0lxd

@w0wl0lxd w0wl0lxd commented Jul 27, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Add control flag to Message, AgentInput, and QueuedMessage so agent-to-agent control messages are visually and structurally distinct from user prompts.
  • Introduce DisplayRole::Control with theme styling so control messages render separately in the UI.
  • Wire n00n.session.prompt control option; agent_control message and resume now send steer=true, control=true.
  • Extend SessionRequest::Status with last_user so agent_control resume can read the paused team run_id from the target session history and construct a continuation prompt.
  • Include run_id in team run_waves pause payload for consistency.

Test plan

  • cargo fmt --all
  • cargo check --all --tests
  • cargo clippy --all --tests -- -D warnings
  • cargo nextest run --workspace (3873 passed, 1 skipped)
  • cargo deny check shows pre-existing license/source/advisory warnings unrelated to this change.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@w0wl0lxd, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3fdf42e8-8807-44a2-ad7b-050560a164a2

📥 Commits

Reviewing files that changed from the base of the PR and between 7a715ea and f0d43d3.

📒 Files selected for processing (17)
  • n00n-agent/src/agent/run.rs
  • n00n-lua/src/api/session.rs
  • n00n-lua/src/api/util/command.rs
  • n00n-lua/tests/plugin_host.rs
  • n00n-providers/src/providers/devin.rs
  • n00n-storage/src/sessions.rs
  • n00n-ui/src/agent/mod.rs
  • n00n-ui/src/agent/shared_queue.rs
  • n00n-ui/src/app/mod.rs
  • n00n-ui/src/app/queue.rs
  • n00n-ui/src/app/session.rs
  • n00n-ui/src/app/tests.rs
  • n00n-ui/src/components/input.rs
  • n00n-ui/src/event_loop.rs
  • plugins/agent_control/init.lua
  • plugins/team/init.lua
  • site/docs/content/lua-api/_index.md
📝 Walkthrough

Walkthrough

The PR adds control-message metadata across agent inputs, queues, storage, events, and UI rendering. Lua session prompts can steer control messages, while paused team status exposes resume metadata and team execution preserves mode and run state.

Changes

Agent control message flow

Layer / File(s) Summary
Control metadata and compatibility
n00n-agent/..., n00n-providers/..., n00n-storage/...
Adds backward-compatible control fields to agent inputs, messages, stored queue entries, and queue-consumed events.
Queue delivery and display
n00n-ui/src/agent/*, n00n-ui/src/app/*, n00n-ui/src/chat.rs, n00n-ui/src/components/*
Routes steering messages with control metadata and renders them with dedicated control roles, surfaces, styles, and theme support.

Paused team resume

Layer / File(s) Summary
Session prompt wiring
n00n-ui/src/event_loop.rs, n00n-lua/src/api/session.rs, site/docs/content/lua-api/_index.md
Adds steer and control prompt options and exposes validated paused_team status metadata.
Resume orchestration
plugins/agent_control/init.lua, plugins/team/init.lua, n00n-lua/tests/plugin_host.rs
Builds structured resume prompts and preserves paused team mode, run IDs, checkpoints, and resume-step guidance.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • w0wl0lxd/n00n#21: Both modify agent-control message handling and session prompt steering.
  • w0wl0lxd/n00n#34: Both modify queue-consumed event payload propagation through the UI.

Sequence Diagram(s)

sequenceDiagram
  participant AgentControl
  participant SessionEventLoop
  participant MessageQueue
  participant TeamPlugin
  AgentControl->>SessionEventLoop: request status
  SessionEventLoop->>AgentControl: return paused_team metadata
  AgentControl->>SessionEventLoop: submit resume prompt with steer=true and control=true
  SessionEventLoop->>MessageQueue: queue control steering message
  MessageQueue->>TeamPlugin: resume paused run with preserved mode and run_id
Loading

Poem

A bunny sends a control cue,
Through queues where gentle signals flew.
A paused team wakes with mode in hand,
Resuming steps as they were planned.
“Hop onward!” twitches every ear.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: control-message tagging and paused team-run resume support.
Description check ✅ Passed The description is clearly aligned with the changeset and covers the new control flag, UI role, prompt wiring, and resume flow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/agent-control-steer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@codecov

codecov Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

@github-actions github-actions 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.

Criterion

Details
Benchmark suite Current: f0d43d3 Previous: 9f141ea Ratio
fib/jit_mlua_hook 6768349 ns/iter (± 269460) 6812960 ns/iter (± 90866) 0.99
fib/jit_watchdog 2221422 ns/iter (± 6031) 2221884 ns/iter (± 14410) 1.00
fib/jit_none 2220932 ns/iter (± 7487) 2221511 ns/iter (± 61848) 1.00
fib/interp_mlua_hook 7978906 ns/iter (± 92610) 7974083 ns/iter (± 51292) 1.00
fib/interp_watchdog 4337138 ns/iter (± 32070) 4320307 ns/iter (± 19095) 1.00
fib/interp_none 4282319 ns/iter (± 14059) 4271546 ns/iter (± 18837) 1.00
buffer_rw/jit_mlua_hook 583936 ns/iter (± 1350) 588077 ns/iter (± 2625) 0.99
buffer_rw/jit_watchdog 191666 ns/iter (± 315) 192371 ns/iter (± 550) 1.00
buffer_rw/jit_none 191574 ns/iter (± 329) 192286 ns/iter (± 391) 1.00
buffer_rw/interp_mlua_hook 1039697 ns/iter (± 9418) 1619333 ns/iter (± 22599) 0.64
buffer_rw/interp_watchdog 589026 ns/iter (± 1461) 1050720 ns/iter (± 5338) 0.56
buffer_rw/interp_none 588118 ns/iter (± 1248) 589332 ns/iter (± 2822) 1.00
splash_render_120x40 51928 ns/iter (± 1645) 52724 ns/iter (± 10231) 0.98
splash_render_200x60 195960 ns/iter (± 1128) 194530 ns/iter (± 7674) 1.01

This comment was automatically generated by workflow using github-action-benchmark.

…am runs

- Add `control` flag to `Message`, `AgentInput`, and `QueuedMessage`
  so agent-control messages are tagged independently of user prompts.
- Propagate the flag through `AgentEvent::QueueItemConsumed` and the
  UI display pipeline, adding `DisplayRole::Control` with its own theme
  style so control messages render distinctly from user messages.
- Wire `n00n.session.prompt` `control` option and update `agent_control`
  `message`/`resume` to use both `steer` and `control`.
- Surface `last_user` from `SessionRequest::Status` so `agent_control`
  resume can retrieve the paused `team` `run_id` from the target session
  history and build a continuation prompt.
- Include `run_id` in `team` `run_waves` pause payload for consistency.

Tests: cargo nextest run --workspace (3873 passed), cargo clippy --all --tests -- -D warnings.
@w0wl0lxd w0wl0lxd changed the title fix(agent-control): route message/resume as steering interrupts, not queued prompts fix(agent-control): tag control messages with dedicated role and resume paused team runs Jul 27, 2026
@w0wl0lxd
w0wl0lxd marked this pull request as ready for review July 27, 2026 03:09

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c59a5ad7d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/agent_control/init.lua Outdated
Comment thread n00n-ui/src/app/queue.rs
Comment thread n00n-ui/src/app/session.rs Outdated
w0wl0lxd added a commit that referenced this pull request Jul 27, 2026
Wire PluginHost ui_action_tx into an in-process daemon listener so CLI
agent list unions TUI sessions while the UI is up. Document stacked
follow-ups for worker absorb (#134) and steer/control (#129).

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
n00n-ui/src/app/queue.rs (1)

109-130: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the control tag when editing queued messages.

The caller converts this message to Submission, dropping control; re-queueing then rebuilds AgentInput with control: false. Keep the original flag in MessageQueue::editing and apply it in replace_editing.

🤖 Prompt for 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.

In `@n00n-ui/src/app/queue.rs` around lines 109 - 130, Preserve the original
control flag across queued-message editing: extend MessageQueue::editing to
store input.control, capture it in take_focused_for_edit, and have
replace_editing reuse that stored value when rebuilding AgentInput instead of
forcing control to false.
n00n-ui/src/app/session.rs (1)

70-121: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Persist queued delivery mode, not only control.

A control prompt queued while streaming uses Delivery::Steering, but restoration calls queue_restored_submission, which hard-codes Delivery::TurnEnd. After restart, a resume/control message waits for turn end instead of interrupting safely. Persist and restore Delivery alongside the AgentInput; extend the restart test to assert Delivery::Steering.

🤖 Prompt for 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.

In `@n00n-ui/src/app/session.rs` around lines 70 - 121, Persist the queued
message’s Delivery value alongside the existing control and AgentInput fields in
stored_message, then restore it in restored_submission so resumed control
prompts retain Delivery::Steering instead of defaulting to Delivery::TurnEnd.
Update the restart test covering queued delivery to assert the restored message
uses Delivery::Steering.
plugins/team/init.lua (1)

749-757: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Waves-mode pause payload is missing paused = true, breaking resume detection for waves runs.

Unlike run_autonomous's and run_single_pass's pause objects (which both include paused = true), the pause table built here from wave_result never sets paused. Since n00n-ui/src/event_loop.rs::paused_team_run requires payload["paused"] == true before surfacing status.paused_team, this means agent_control resume can never detect a paused waves-mode team run — it will always report "no paused team run found", silently defeating this PR's resume feature for that mode.

🐛 Proposed fix
           if wave_result.paused then
             pause = {
+              paused = true,
               run_id = run_id,
               mode = input.mode,
               failed_step = failed_step_index,
               failed_role = failed_role,
               error = wave_result.error,
             }
           end
🤖 Prompt for 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.

In `@plugins/team/init.lua` around lines 749 - 757, Update the pause payload
constructed when wave_result.paused in the waves-mode flow to include paused =
true, matching the pause objects created by run_autonomous and run_single_pass.
Preserve the existing run_id, mode, failure, and error fields so paused_team_run
can detect and resume waves runs.
🤖 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 `@n00n-agent/src/agent/run.rs`:
- Around line 744-762: Update the initial message creation in Agent::run to
preserve input.control, using the appropriate control-message constructor or
classification instead of always calling Message::user_with_images. Keep the
existing user-message behavior when input.control is false, and add a direct-run
test verifying a control input produces a control-tagged first history message.

In `@n00n-lua/tests/plugin_host.rs`:
- Around line 4780-4828: Strengthen
agent_control_resume_preserves_paused_team_mode by destructuring the Prompt
request’s submission flags and asserting that resume is submitted with steer and
control enabled. Keep the existing prompt text assertion and response flow
unchanged.

In `@n00n-ui/src/event_loop.rs`:
- Around line 128-172: Update paused_team_run so malformed team tool-result JSON
is treated as no paused run instead of returned as an error: log the parse
failure with structured context and continue scanning or return Ok(None). Remove
the ? propagation from the SessionRequest::Status call that computes the
auxiliary paused-team field, while preserving the rest of the status response
fields and behavior.
- Around line 147-151: Replace the inline "team" comparison in the
is_team_result history scan with a named tool-name constant. Define the constant
immediately after imports, following the existing TASK_TOOL_NAME,
WRITE_TOOL_NAME, and WIRE_TOOL_NAME convention, then use it in the tool_uses
predicate.

In `@site/docs/content/lua-api/_index.md`:
- Around line 2680-2687: Update the return-value documentation for
n00n.session.status() to describe the nested paused_team JSON payload, including
its available fields such as run_id, rather than only marking paused_team as
optional. Keep the existing top-level return shape and condition unchanged.

---

Outside diff comments:
In `@n00n-ui/src/app/queue.rs`:
- Around line 109-130: Preserve the original control flag across queued-message
editing: extend MessageQueue::editing to store input.control, capture it in
take_focused_for_edit, and have replace_editing reuse that stored value when
rebuilding AgentInput instead of forcing control to false.

In `@n00n-ui/src/app/session.rs`:
- Around line 70-121: Persist the queued message’s Delivery value alongside the
existing control and AgentInput fields in stored_message, then restore it in
restored_submission so resumed control prompts retain Delivery::Steering instead
of defaulting to Delivery::TurnEnd. Update the restart test covering queued
delivery to assert the restored message uses Delivery::Steering.

In `@plugins/team/init.lua`:
- Around line 749-757: Update the pause payload constructed when
wave_result.paused in the waves-mode flow to include paused = true, matching the
pause objects created by run_autonomous and run_single_pass. Preserve the
existing run_id, mode, failure, and error fields so paused_team_run can detect
and resume waves runs.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: b585cd42-130c-4fcf-a66a-5ba7c9ea0530

📥 Commits

Reviewing files that changed from the base of the PR and between 6351b86 and 7a715ea.

📒 Files selected for processing (36)
  • changelog.d/agent-control-resume.fixed.md
  • n00n-acp/src/server.rs
  • n00n-acp/src/translate.rs
  • n00n-agent/src/agent/history.rs
  • n00n-agent/src/agent/run.rs
  • n00n-agent/src/headless.rs
  • n00n-agent/src/lib.rs
  • n00n-agent/src/mcp/mod.rs
  • n00n-agent/src/types.rs
  • n00n-lua/src/api/agent.rs
  • n00n-lua/src/api/session.rs
  • n00n-lua/src/api/util/command.rs
  • n00n-lua/tests/plugin_host.rs
  • n00n-providers/src/providers/anthropic/shared.rs
  • n00n-providers/src/providers/devin.rs
  • n00n-providers/src/types.rs
  • n00n-storage/src/sessions.rs
  • n00n-ui/src/agent/agent_loop.rs
  • n00n-ui/src/agent/shared_queue.rs
  • n00n-ui/src/app/mod.rs
  • n00n-ui/src/app/mode.rs
  • n00n-ui/src/app/queue.rs
  • n00n-ui/src/app/session.rs
  • n00n-ui/src/app/tests.rs
  • n00n-ui/src/chat.rs
  • n00n-ui/src/components/messages/mod.rs
  • n00n-ui/src/components/messages/render.rs
  • n00n-ui/src/components/messages/segment.rs
  • n00n-ui/src/components/mod.rs
  • n00n-ui/src/components/tool_display.rs
  • n00n-ui/src/event_loop.rs
  • n00n-ui/src/theme.rs
  • plugins/agent_control/init.lua
  • plugins/team/init.lua
  • site/docs/content/lua-api/_index.md
  • src/sdk_mode.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Analyze (python)
  • GitHub Check: Criterion
  • GitHub Check: Analyze (rust)
🧰 Additional context used
📓 Path-based instructions (6)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Non-trivial or multi-file changes should use a dedicated git worktree and new branch; do not modify unrelated user changes, force-push, or push to main.
Ship finished work with a clear Conventional Commit message, a pushed branch, and a draft pull request; never add AI-agent attribution to authored content.
Before investigating unfamiliar failures or third-party behavior, research documented behavior first and distinguish unrelated baseline failures from regressions in the touched surface.
Use structural tools before broad searches: prefer codegraph or arbor for cross-file relationships, index before reading files, targeted reads, parallel calls, and code_execution for filtering large outputs.

Files:

  • changelog.d/agent-control-resume.fixed.md
  • n00n-ui/src/app/mode.rs
  • n00n-agent/src/headless.rs
  • src/sdk_mode.rs
  • n00n-agent/src/lib.rs
  • n00n-ui/src/components/messages/render.rs
  • n00n-ui/src/components/tool_display.rs
  • n00n-ui/src/components/mod.rs
  • n00n-agent/src/types.rs
  • n00n-agent/src/mcp/mod.rs
  • n00n-ui/src/components/messages/segment.rs
  • n00n-providers/src/providers/devin.rs
  • n00n-lua/src/api/util/command.rs
  • n00n-storage/src/sessions.rs
  • n00n-lua/tests/plugin_host.rs
  • n00n-agent/src/agent/history.rs
  • n00n-ui/src/agent/agent_loop.rs
  • n00n-ui/src/app/session.rs
  • n00n-ui/src/theme.rs
  • n00n-lua/src/api/session.rs
  • n00n-providers/src/providers/anthropic/shared.rs
  • n00n-lua/src/api/agent.rs
  • n00n-acp/src/server.rs
  • n00n-ui/src/chat.rs
  • plugins/agent_control/init.lua
  • site/docs/content/lua-api/_index.md
  • n00n-agent/src/agent/run.rs
  • n00n-ui/src/app/mod.rs
  • n00n-acp/src/translate.rs
  • n00n-ui/src/app/queue.rs
  • n00n-providers/src/types.rs
  • n00n-ui/src/components/messages/mod.rs
  • n00n-ui/src/event_loop.rs
  • n00n-ui/src/agent/shared_queue.rs
  • n00n-ui/src/app/tests.rs
  • plugins/team/init.lua
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Workspace Rust lint rules are mandatory: deny unsafe code, production unwrap_used, expect_used, panic, todo!, unimplemented!, dbg!, wildcard imports, and silent-default error handling.
Do not add unsafe code, FFI, global mutable state, static mut, or unchecked transmute-like behavior without written review and an explicit crate-level lint exception.
Use explicit error handling with Result<T, E> rather than panics; propagate typed errors with ?, ok_or_else, and map_err.
Use thiserror for library and domain-specific errors, and color-eyre at binary edges.
Do not silently discard errors with .ok(), unwrap_or, unwrap_or_default, or equivalent defaults; return an error, reject the operation, or use an explicitly named fallback with sanitized structured logging.
Follow Rust idioms, use descriptive variable and function names, avoid unnecessary state and bloat, and keep each line justified.
Import types at the top of the file, use short imported names instead of inline qualified paths, and place constants immediately after imports.
Do not use inline magic numbers or strings; derive Copy only for structs with one primitive field.
Use structured logging with useful fields and provide helpful, sanitized error messages.
Do not commit credentials, API keys, tokens, cookies, authorization headers, or user data, and do not log raw provider payloads, prompts, credentials, or session data.
Validate and authorize HTTP, file, queue, configuration/environment, LLM output, and provider callbacks before mutation or persistence.
Tool execution requires allowlisted tools, scoped credentials, explicit user context, audit events, and refusal or denial tests.
Write meaningful, non-tautological, non-flaky tests; avoid arbitrary sleeps, and define shared constant error/status messages for assertions.

Files:

  • n00n-ui/src/app/mode.rs
  • n00n-agent/src/headless.rs
  • src/sdk_mode.rs
  • n00n-agent/src/lib.rs
  • n00n-ui/src/components/messages/render.rs
  • n00n-ui/src/components/tool_display.rs
  • n00n-ui/src/components/mod.rs
  • n00n-agent/src/types.rs
  • n00n-agent/src/mcp/mod.rs
  • n00n-ui/src/components/messages/segment.rs
  • n00n-providers/src/providers/devin.rs
  • n00n-lua/src/api/util/command.rs
  • n00n-storage/src/sessions.rs
  • n00n-lua/tests/plugin_host.rs
  • n00n-agent/src/agent/history.rs
  • n00n-ui/src/agent/agent_loop.rs
  • n00n-ui/src/app/session.rs
  • n00n-ui/src/theme.rs
  • n00n-lua/src/api/session.rs
  • n00n-providers/src/providers/anthropic/shared.rs
  • n00n-lua/src/api/agent.rs
  • n00n-acp/src/server.rs
  • n00n-ui/src/chat.rs
  • n00n-agent/src/agent/run.rs
  • n00n-ui/src/app/mod.rs
  • n00n-acp/src/translate.rs
  • n00n-ui/src/app/queue.rs
  • n00n-providers/src/types.rs
  • n00n-ui/src/components/messages/mod.rs
  • n00n-ui/src/event_loop.rs
  • n00n-ui/src/agent/shared_queue.rs
  • n00n-ui/src/app/tests.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (AGENTS.md)

All crates must opt into the workspace lint configuration with [lints] workspace = true; the root workspace lint configuration is authoritative.

Files:

  • n00n-ui/src/app/mode.rs
  • n00n-agent/src/headless.rs
  • src/sdk_mode.rs
  • n00n-agent/src/lib.rs
  • n00n-ui/src/components/messages/render.rs
  • n00n-ui/src/components/tool_display.rs
  • n00n-ui/src/components/mod.rs
  • n00n-agent/src/types.rs
  • n00n-agent/src/mcp/mod.rs
  • n00n-ui/src/components/messages/segment.rs
  • n00n-providers/src/providers/devin.rs
  • n00n-lua/src/api/util/command.rs
  • n00n-storage/src/sessions.rs
  • n00n-lua/tests/plugin_host.rs
  • n00n-agent/src/agent/history.rs
  • n00n-ui/src/agent/agent_loop.rs
  • n00n-ui/src/app/session.rs
  • n00n-ui/src/theme.rs
  • n00n-lua/src/api/session.rs
  • n00n-providers/src/providers/anthropic/shared.rs
  • n00n-lua/src/api/agent.rs
  • n00n-acp/src/server.rs
  • n00n-ui/src/chat.rs
  • n00n-agent/src/agent/run.rs
  • n00n-ui/src/app/mod.rs
  • n00n-acp/src/translate.rs
  • n00n-ui/src/app/queue.rs
  • n00n-providers/src/types.rs
  • n00n-ui/src/components/messages/mod.rs
  • n00n-ui/src/event_loop.rs
  • n00n-ui/src/agent/shared_queue.rs
  • n00n-ui/src/app/tests.rs
**/*.{rs,ron,json,toml,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Treat LLM and provider output as untrusted input; validate it against schemas, domain constraints, and source evidence before persistence or action.

Files:

  • n00n-ui/src/app/mode.rs
  • n00n-agent/src/headless.rs
  • src/sdk_mode.rs
  • n00n-agent/src/lib.rs
  • n00n-ui/src/components/messages/render.rs
  • n00n-ui/src/components/tool_display.rs
  • n00n-ui/src/components/mod.rs
  • n00n-agent/src/types.rs
  • n00n-agent/src/mcp/mod.rs
  • n00n-ui/src/components/messages/segment.rs
  • n00n-providers/src/providers/devin.rs
  • n00n-lua/src/api/util/command.rs
  • n00n-storage/src/sessions.rs
  • n00n-lua/tests/plugin_host.rs
  • n00n-agent/src/agent/history.rs
  • n00n-ui/src/agent/agent_loop.rs
  • n00n-ui/src/app/session.rs
  • n00n-ui/src/theme.rs
  • n00n-lua/src/api/session.rs
  • n00n-providers/src/providers/anthropic/shared.rs
  • n00n-lua/src/api/agent.rs
  • n00n-acp/src/server.rs
  • n00n-ui/src/chat.rs
  • n00n-agent/src/agent/run.rs
  • n00n-ui/src/app/mod.rs
  • n00n-acp/src/translate.rs
  • n00n-ui/src/app/queue.rs
  • n00n-providers/src/types.rs
  • n00n-ui/src/components/messages/mod.rs
  • n00n-ui/src/event_loop.rs
  • n00n-ui/src/agent/shared_queue.rs
  • n00n-ui/src/app/tests.rs
plugins/**/*.lua

📄 CodeRabbit inference engine (AGENTS.md)

Built-in Lua plugins belong under ./plugins and should use the repository's plugin tooling and conventions.

Files:

  • plugins/agent_control/init.lua
  • plugins/team/init.lua
site/docs/**/*

📄 CodeRabbit inference engine (AGENTS.md)

User documentation should be warm, simple, concise, easy for non-native English speakers, story-oriented, and contain no em-dashes, emojis, or AI-like tone.

Files:

  • site/docs/content/lua-api/_index.md
🪛 markdownlint-cli2 (0.23.0)
changelog.d/agent-control-resume.fixed.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🔇 Additional comments (36)
n00n-agent/src/lib.rs (1)

92-92: LGTM!

n00n-providers/src/types.rs (1)

303-304: LGTM!

Also applies to: 323-359, 830-847

n00n-storage/src/sessions.rs (1)

135-136: LGTM!

Also applies to: 3132-3132

n00n-agent/src/types.rs (1)

876-876: LGTM!

n00n-ui/src/agent/agent_loop.rs (1)

173-178: LGTM!

n00n-agent/src/agent/run.rs (1)

1109-1146: LGTM!

Also applies to: 1292-1348

n00n-agent/src/agent/history.rs (1)

276-276: LGTM!

Also applies to: 532-532

n00n-lua/src/api/agent.rs (1)

1262-1262: LGTM!

Also applies to: 1371-1371

n00n-agent/src/headless.rs (1)

244-244: LGTM!

src/sdk_mode.rs (1)

745-745: LGTM!

n00n-providers/src/providers/devin.rs (1)

1737-1737: LGTM!

n00n-lua/tests/plugin_host.rs (1)

59-59: LGTM!

Also applies to: 4759-4759

n00n-ui/src/agent/shared_queue.rs (1)

31-51: LGTM!

Also applies to: 346-354, 368-460

n00n-acp/src/server.rs (1)

238-248: LGTM!

Also applies to: 521-528

n00n-providers/src/providers/anthropic/shared.rs (1)

632-664: LGTM!

Also applies to: 699-714

n00n-agent/src/mcp/mod.rs (1)

1655-1664: LGTM!

Also applies to: 1739-1748

n00n-acp/src/translate.rs (1)

285-291: LGTM!

Also applies to: 319-328, 372-381

n00n-ui/src/app/mode.rs (1)

124-135: LGTM!

n00n-ui/src/app/queue.rs (1)

238-254: LGTM!

Also applies to: 379-392, 470-492

n00n-ui/src/app/mod.rs (1)

1610-1621: LGTM!

Also applies to: 1901-1921, 1954-1958, 2163-2177

n00n-ui/src/app/session.rs (1)

233-255: LGTM!

n00n-ui/src/app/tests.rs (1)

262-339: LGTM!

Also applies to: 690-774, 4036-4052

site/docs/content/lua-api/_index.md (1)

2795-2809: LGTM!

changelog.d/agent-control-resume.fixed.md (1)

1-1: LGTM!

n00n-ui/src/chat.rs (1)

34-51: LGTM!

Also applies to: 154-165, 452-473, 688-698

n00n-ui/src/components/mod.rs (1)

421-429: LGTM!

n00n-ui/src/components/messages/mod.rs (1)

14-15: LGTM!

Also applies to: 1735-1738, 1748-1751, 1882-1885, 1895-1898, 2130-2133

n00n-ui/src/components/messages/render.rs (1)

66-92: LGTM!

Also applies to: 164-187

n00n-ui/src/components/messages/segment.rs (1)

74-81: LGTM!

Also applies to: 240-243

n00n-ui/src/components/tool_display.rs (1)

74-82: LGTM!

n00n-ui/src/theme.rs (1)

295-340: LGTM!

Also applies to: 343-416, 733-850

n00n-ui/src/event_loop.rs (1)

912-1014: LGTM!

Also applies to: 1545-1591

n00n-lua/src/api/session.rs (1)

60-64: LGTM!

Also applies to: 145-177, 310-348

n00n-lua/src/api/util/command.rs (1)

406-436: LGTM!

plugins/agent_control/init.lua (1)

278-291: LGTM!

Also applies to: 367-369, 386-423

plugins/team/init.lua (1)

374-464: LGTM!

Also applies to: 469-540, 542-644, 646-648, 660-747, 758-842, 846-926

Comment thread n00n-agent/src/agent/run.rs
Comment thread n00n-lua/tests/plugin_host.rs
Comment thread n00n-ui/src/event_loop.rs Outdated
Comment thread n00n-ui/src/event_loop.rs
Comment thread site/docs/content/lua-api/_index.md Outdated
w0wl0lxd added a commit that referenced this pull request Jul 27, 2026
Bring control-message role, SessionRequest Prompt steer/control flags,
and team resume via paused_team. Keep scoped agent_list/status/control
tools with human cards; wire MessageOpts through the TUI daemon bridge.
@w0wl0lxd

Copy link
Copy Markdown
Owner Author

Absorbed into #149 (merge commit on feat/n00n-daemon-session-bridge). Prefer closing this once #149 lands, or leave open only if you want an independent review trail.

Preserve control tags through run start, edit, and session restore;
persist queue Delivery; harden paused_team status parsing; document
paused_team shape; assert resume steer/control flags.
Resolve SessionRequest parent_id + steer/control and storage test imports.
@w0wl0lxd
w0wl0lxd merged commit dbce7ae into main Jul 27, 2026
27 checks passed
@linear-code

linear-code Bot commented Jul 27, 2026

Copy link
Copy Markdown

N00N-11

@w0wl0lxd
w0wl0lxd deleted the fix/agent-control-steer branch July 27, 2026 08:57
w0wl0lxd added a commit that referenced this pull request Jul 27, 2026
* fix(agent-control): route message/resume as steering interrupts, not queued prompts

* fix(agent-control): distinguish control messages and resume paused team runs

- Add `control` flag to `Message`, `AgentInput`, and `QueuedMessage`
  so agent-control messages are tagged independently of user prompts.
- Propagate the flag through `AgentEvent::QueueItemConsumed` and the
  UI display pipeline, adding `DisplayRole::Control` with its own theme
  style so control messages render distinctly from user messages.
- Wire `n00n.session.prompt` `control` option and update `agent_control`
  `message`/`resume` to use both `steer` and `control`.
- Surface `last_user` from `SessionRequest::Status` so `agent_control`
  resume can retrieve the paused `team` `run_id` from the target session
  history and build a continuation prompt.
- Include `run_id` in `team` `run_waves` pause payload for consistency.

Tests: cargo nextest run --workspace (3873 passed), cargo clippy --all --tests -- -D warnings.

* fix(agent-control): harden paused team resume

* feat(agent): add structured output helper and agent CLI command

Phase 2 implementation:

- Create plugins/lib/n00n/structured_output.lua with constants and helper functions for schema validation
- Create plugins/lib/n00n/subagent.lua with unified subagent launch API
- Migrate plugins/task/init.lua to use n00n.structured_output helper
- Migrate plugins/workflow/init.lua to use n00n.structured_output helper
- Add n00n agent run CLI command with stubs for future daemon commands
- Add tests for structured_output helper in plugins/lib/tests/spec.lua
- Keep team/roles.lua unchanged due to custom patterns (hardcoded audience, budget handling, preview support)

All tests pass. Lua syntax validated with luac.

* fix(agent-orchestration): repair route_tier and structured_output helpers

* feat(agent): add background agent server and management CLI

Implement `n00n agent run --background` Unix-socket server plus
`message`, `stop`, and `list` client commands. Background agents keep
state in `state_dir/agents/<id>/agent.json` and a `control.sock`.

Server streams `TextDelta`/`ToolOutput`/`Done` events as NDJSON, and
supports an initial `--prompt` before entering the command loop. The
`--mode` flag selects the same workflow/team/etc modes used by the
one-shot runner.

- Add `AgentMode` CLI enum (General, Research, Task, Team, Workflow)
- Add `async-lock` for per-agent message serialization
- Add unit tests for CLI parsing, state serde, and state listing

Phase 3 stubs (status, pause, resume, policy) remain unimplemented.

* feat(agent): implement status, pause, and resume commands

Add `ClientCommand::Pause` and `Resume` to the background agent
protocol. The server stores a shared `paused` flag and rejects new
messages while paused, updating `agent.json` status accordingly.

Implement `n00n agent status`, `pause`, and `resume` client commands.
`status` reads the persisted agent state; `pause`/`resume` send a
control command over the Unix socket. The `policy` subcommand remains
a stub.

* fix(agent): avoid duplicate text when message run ends with error

The text-mode client was streaming TextDelta chunks and then printing
the full Done.text again when the run ended with an error. Only print
the error in that case; the streamed text is already on the terminal.

* refactor(team): migrate roles and supervisor to n00n.subagent

Extend `plugins/lib/n00n/subagent.lua` with options the team plugin needs:
- `system` override for role-specific prompts
- `preview` and `activity_label` for ActivityPreview integration
- `budget` with `:consume()` for agent-call budgets
- `fail_on_pricing_error` to keep the existing team semantics
- return the resolved `model_spec` as a fifth value

Migrate `plugins/team/roles.lua` to launch subagents through the shared
helper, preserving its `{ok, text, cost, model, usage, error}` return
shape and all existing tests.

Simplify `plugins/team/init.lua` `run_supervisor` by delegating the
structured-output plan generation to `n00n.subagent.launch` with
`output_schema = PLANNER_OUTPUT`.

* fix(agent): log cleanup warnings in stop handler

Surface failed socket/directory removals in the background agent stop
handler instead of silently ignoring them. The process still exits, but
the warning gives operators a signal that stale state may remain.

* fix(agent): validate agent ids and lock down socket permissions

Prevent path traversal from user-supplied agent ids by validating them
before any filesystem operation, and reject ids that contain path
separators, control characters, or other unsafe content. Limit ids to
64 ASCII alphanumeric/hyphen/underscore characters.

Set the agent state directory to 0o700 and the Unix control socket to
0o600 so only the owning user can read or connect to background agent
state.

* refactor(agent): share one-shot and background agent setup

Extract `prepare_agent_env` and `PreparedEnv` to remove the duplicated
plugin/model/MCP initialization between `run` and `server`. Both paths now
build their `HeadlessParams`/`InteractiveParams` from the same prepared
environment, making the two entry points easier to keep in sync.

* docs(changelog): add fragments for agent CLI and team refactor

Record the user-facing additions, refactor, and security hardening from
PR #134 in changelog.d.

* fix(agent): await task completion before stop exits

The background agent Stop command now waits for the agent task to finish
after sending the cancel signal, instead of exiting immediately. This
prevents dropping active tool calls and unfinished MCP sessions and
ensures state is persisted before cleanup.

* refactor(cli): remove unused goal arg and stub policy commands

The `goal` flag on `n00n agent run` was parsed but never used, and the
`policy` subcommands were stubs. Remove both until they are wired to
actual behavior.

* fix(task,workflow): pass thinking config to subagent sessions

Thread the `thinking` option through `n00n.agent.session` in both the
task and workflow plugins, and include it in the workflow journal key so
cached results honor the thinking setting.

* fix(n00n-agent): make yolo enable rather than toggle in spawn_interactive

`headless::spawn_interactive` was calling `permissions.toggle_yolo()` when
`params.yolo` was true, which flipped an already-true yolo state back to
false. This broke `--yolo` in background agent mode (and TUI/ACP when
always_yolo was set). Add `PermissionManager::set_yolo` and use it to
reliably enable yolo when requested, leaving the config-derived default
otherwise.

* feat(agent): add --goal and mode-aware team/workflow/task prompts

Re-add --goal to n00n agent run and wire it into mode-specific prompts.
Team mode now emits a team tool call with goal, mode, max_agents,
waves, and auto-tier flags. Workflow mode emits a workflow tool call
with the prompt as the script and goal merged into inputs. Task mode
emits a task tool call with description/prompt. General/Research
modes prepend the goal to the prompt.

Also introduce AgentRunOptions to keep run/server signatures tidy and
avoid excessive boolean parameters.

* feat(agent): configurable agent-call limits and runaway guard

Remove the hard-coded 24/32 agent-call ceilings in team and workflow.
- team `max_agents` is now configurable with no hard maximum and an
  optional `timeout_secs`.
- workflow `max_agents_per_run` is configurable with no hard maximum.
- Add `plugins/lib/n00n/guard.lua` to enforce call budgets, wall-clock
  timeouts, repeated-prompt loops, and consecutive subagent errors.
- Wire the guard through `n00n.subagent.launch`, `team`, and `workflow`.

* fix(guard): reserve call budget atomically in check and guard consecutive errors

- Move the used counter increment from record() into check() so the
  budget is reserved before any async yield; this prevents concurrent
  subagent calls from overshooting max_calls.
- Check consecutive_errors in check() and use > in record() so the
  guard blocks the next call after the threshold instead of wasting
  a token on the failing call.
- Add lib spec coverage for budget, repeated-prompt, consecutive-error,
  and legacy consume() behavior.

* docs: regenerate after main merge

* docs: regenerate lua-api from branch sources

* feat(daemon): add n00n-daemon control plane and scoped agent tools

Introduce an on-device registry/proxy over TUI session APIs and PR#134
worker socks, with sonic-rs NDJSON wire encoding, a thin `n00n agent`
CLI, and split agent_list/agent_status/agent_control tools that render
human cards and tooned structured output instead of raw JSON dumps.

* feat(daemon): register live TUI sessions on daemon.sock

Wire PluginHost ui_action_tx into an in-process daemon listener so CLI
agent list unions TUI sessions while the UI is up. Document stacked
follow-ups for worker absorb (#134) and steer/control (#129).

* docs(daemon): mark #129/#134 absorb status in followups plan

* feat(daemon): add lockfile transport, peercred auth, and headless registration

Advertise daemon listeners via daemon.lock, route clients through UDS or
Windows loopback TCP, reject mismatched UDS peers on Linux, and register
print/ACP sessions for remote list/status/control.

* test(daemon): add smoke gate, integration tests, and --state-dir

Automate manual verification with scripts/smoke-daemon.sh, cover worker
pause roundtrip and TUI+worker UDS list, fall back to disk when daemon
sock is absent, and add --state-dir to agent control verbs.

* feat(daemon): complete sprint 2 polish for agent control

Add stale daemon.lock recovery, TUI paused-team resume via daemon,
agent_control Lua spec tests with shared helpers, Windows TCP smoke
test, and user docs for the n00n agent CLI.

* fix(daemon): route pause/resume via backend resolution

Let the control plane try TUI before worker so pause returns typed
unsupported for live sessions and resume can reach paused-team paths.
Drain worker message streams until done when proxying through daemon.

* fix(token-profile): update cold_start baseline for new tool

* feat(agent): scripting parity for agent list/status (#151)

* feat(agent): add scripting parity for agent list and status

Close competitor gaps vs claude agents --json: dedicated --json output
with normalized state, --all for terminal workers, --cwd filtering,
and cwd plumbed through TUI/worker agent records.

* fix(daemon): route pause/resume via backend resolution

Let the control plane try TUI before worker so pause returns typed
unsupported for live sessions and resume can reach paused-team paths.
Drain worker message streams until done when proxying through daemon.

* feat(agent): add scripting parity for agent list and status

Close competitor gaps vs claude agents --json: dedicated --json output
with normalized state, --all for terminal workers, --cwd filtering,
and cwd plumbed through TUI/worker agent records.

* feat(openai): split Codex plan into its own provider (#136)

* feat(openai): split Codex plan into its own provider

Codex (ChatGPT Coding Plan) OAuth and the full OpenAI API key flow were
both exposed under the `openai` provider, causing identical model IDs to
appear with different context windows and auth requirements. Introduce a
dedicated `codex` provider so:

- Codex plan models (`codex/gpt-5.6-luna`, `codex/gpt-5.3-codex`, etc.)
  resolve to the 272K plan context and OAuth auth.
- Full OpenAI API models (`openai/gpt-5.5`, `openai/gpt-5.6-luna`, etc.)
  keep their larger context and API-key auth.
- Auth commands (`n00n auth login/logout codex`) and the status table
  treat Codex separately while sharing OAuth state with OpenAI.

* chore(changelog): add fragment for Codex provider split

* fix(agent): import BackendKind in tests and sync CI artifacts

Add changelog fragment, token-profile baseline for 27 tools, and fix
missing BackendKind import in agent command unit tests.
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