Repository navigation
fix(agent-control): tag control messages with dedicated role and resume paused team runs - #129
Conversation
|
Warning Review limit reached
Next review available in: 18 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (17)
📝 WalkthroughWalkthroughThe 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. ChangesAgent control message flow
Paused team resume
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
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
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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 winPreserve the control tag when editing queued messages.
The caller converts this message to
Submission, droppingcontrol; re-queueing then rebuildsAgentInputwithcontrol: false. Keep the original flag inMessageQueue::editingand apply it inreplace_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 liftPersist queued delivery mode, not only
control.A control prompt queued while streaming uses
Delivery::Steering, but restoration callsqueue_restored_submission, which hard-codesDelivery::TurnEnd. After restart, a resume/control message waits for turn end instead of interrupting safely. Persist and restoreDeliveryalongside theAgentInput; extend the restart test to assertDelivery::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 winWaves-mode pause payload is missing
paused = true, breaking resume detection forwavesruns.Unlike
run_autonomous's andrun_single_pass's pause objects (which both includepaused = true), thepausetable built here fromwave_resultnever setspaused. Sincen00n-ui/src/event_loop.rs::paused_team_runrequirespayload["paused"] == truebefore surfacingstatus.paused_team, this meansagent_control resumecan 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
📒 Files selected for processing (36)
changelog.d/agent-control-resume.fixed.mdn00n-acp/src/server.rsn00n-acp/src/translate.rsn00n-agent/src/agent/history.rsn00n-agent/src/agent/run.rsn00n-agent/src/headless.rsn00n-agent/src/lib.rsn00n-agent/src/mcp/mod.rsn00n-agent/src/types.rsn00n-lua/src/api/agent.rsn00n-lua/src/api/session.rsn00n-lua/src/api/util/command.rsn00n-lua/tests/plugin_host.rsn00n-providers/src/providers/anthropic/shared.rsn00n-providers/src/providers/devin.rsn00n-providers/src/types.rsn00n-storage/src/sessions.rsn00n-ui/src/agent/agent_loop.rsn00n-ui/src/agent/shared_queue.rsn00n-ui/src/app/mod.rsn00n-ui/src/app/mode.rsn00n-ui/src/app/queue.rsn00n-ui/src/app/session.rsn00n-ui/src/app/tests.rsn00n-ui/src/chat.rsn00n-ui/src/components/messages/mod.rsn00n-ui/src/components/messages/render.rsn00n-ui/src/components/messages/segment.rsn00n-ui/src/components/mod.rsn00n-ui/src/components/tool_display.rsn00n-ui/src/event_loop.rsn00n-ui/src/theme.rsplugins/agent_control/init.luaplugins/team/init.luasite/docs/content/lua-api/_index.mdsrc/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: prefercodegraphorarborfor cross-file relationships,indexbefore reading files, targeted reads, parallel calls, andcode_executionfor filtering large outputs.
Files:
changelog.d/agent-control-resume.fixed.mdn00n-ui/src/app/mode.rsn00n-agent/src/headless.rssrc/sdk_mode.rsn00n-agent/src/lib.rsn00n-ui/src/components/messages/render.rsn00n-ui/src/components/tool_display.rsn00n-ui/src/components/mod.rsn00n-agent/src/types.rsn00n-agent/src/mcp/mod.rsn00n-ui/src/components/messages/segment.rsn00n-providers/src/providers/devin.rsn00n-lua/src/api/util/command.rsn00n-storage/src/sessions.rsn00n-lua/tests/plugin_host.rsn00n-agent/src/agent/history.rsn00n-ui/src/agent/agent_loop.rsn00n-ui/src/app/session.rsn00n-ui/src/theme.rsn00n-lua/src/api/session.rsn00n-providers/src/providers/anthropic/shared.rsn00n-lua/src/api/agent.rsn00n-acp/src/server.rsn00n-ui/src/chat.rsplugins/agent_control/init.luasite/docs/content/lua-api/_index.mdn00n-agent/src/agent/run.rsn00n-ui/src/app/mod.rsn00n-acp/src/translate.rsn00n-ui/src/app/queue.rsn00n-providers/src/types.rsn00n-ui/src/components/messages/mod.rsn00n-ui/src/event_loop.rsn00n-ui/src/agent/shared_queue.rsn00n-ui/src/app/tests.rsplugins/team/init.lua
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Workspace Rust lint rules are mandatory: deny unsafe code, productionunwrap_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 withResult<T, E>rather than panics; propagate typed errors with?,ok_or_else, andmap_err.
Usethiserrorfor library and domain-specific errors, andcolor-eyreat 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; deriveCopyonly 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.rsn00n-agent/src/headless.rssrc/sdk_mode.rsn00n-agent/src/lib.rsn00n-ui/src/components/messages/render.rsn00n-ui/src/components/tool_display.rsn00n-ui/src/components/mod.rsn00n-agent/src/types.rsn00n-agent/src/mcp/mod.rsn00n-ui/src/components/messages/segment.rsn00n-providers/src/providers/devin.rsn00n-lua/src/api/util/command.rsn00n-storage/src/sessions.rsn00n-lua/tests/plugin_host.rsn00n-agent/src/agent/history.rsn00n-ui/src/agent/agent_loop.rsn00n-ui/src/app/session.rsn00n-ui/src/theme.rsn00n-lua/src/api/session.rsn00n-providers/src/providers/anthropic/shared.rsn00n-lua/src/api/agent.rsn00n-acp/src/server.rsn00n-ui/src/chat.rsn00n-agent/src/agent/run.rsn00n-ui/src/app/mod.rsn00n-acp/src/translate.rsn00n-ui/src/app/queue.rsn00n-providers/src/types.rsn00n-ui/src/components/messages/mod.rsn00n-ui/src/event_loop.rsn00n-ui/src/agent/shared_queue.rsn00n-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.rsn00n-agent/src/headless.rssrc/sdk_mode.rsn00n-agent/src/lib.rsn00n-ui/src/components/messages/render.rsn00n-ui/src/components/tool_display.rsn00n-ui/src/components/mod.rsn00n-agent/src/types.rsn00n-agent/src/mcp/mod.rsn00n-ui/src/components/messages/segment.rsn00n-providers/src/providers/devin.rsn00n-lua/src/api/util/command.rsn00n-storage/src/sessions.rsn00n-lua/tests/plugin_host.rsn00n-agent/src/agent/history.rsn00n-ui/src/agent/agent_loop.rsn00n-ui/src/app/session.rsn00n-ui/src/theme.rsn00n-lua/src/api/session.rsn00n-providers/src/providers/anthropic/shared.rsn00n-lua/src/api/agent.rsn00n-acp/src/server.rsn00n-ui/src/chat.rsn00n-agent/src/agent/run.rsn00n-ui/src/app/mod.rsn00n-acp/src/translate.rsn00n-ui/src/app/queue.rsn00n-providers/src/types.rsn00n-ui/src/components/messages/mod.rsn00n-ui/src/event_loop.rsn00n-ui/src/agent/shared_queue.rsn00n-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.rsn00n-agent/src/headless.rssrc/sdk_mode.rsn00n-agent/src/lib.rsn00n-ui/src/components/messages/render.rsn00n-ui/src/components/tool_display.rsn00n-ui/src/components/mod.rsn00n-agent/src/types.rsn00n-agent/src/mcp/mod.rsn00n-ui/src/components/messages/segment.rsn00n-providers/src/providers/devin.rsn00n-lua/src/api/util/command.rsn00n-storage/src/sessions.rsn00n-lua/tests/plugin_host.rsn00n-agent/src/agent/history.rsn00n-ui/src/agent/agent_loop.rsn00n-ui/src/app/session.rsn00n-ui/src/theme.rsn00n-lua/src/api/session.rsn00n-providers/src/providers/anthropic/shared.rsn00n-lua/src/api/agent.rsn00n-acp/src/server.rsn00n-ui/src/chat.rsn00n-agent/src/agent/run.rsn00n-ui/src/app/mod.rsn00n-acp/src/translate.rsn00n-ui/src/app/queue.rsn00n-providers/src/types.rsn00n-ui/src/components/messages/mod.rsn00n-ui/src/event_loop.rsn00n-ui/src/agent/shared_queue.rsn00n-ui/src/app/tests.rs
plugins/**/*.lua
📄 CodeRabbit inference engine (AGENTS.md)
Built-in Lua plugins belong under
./pluginsand should use the repository's plugin tooling and conventions.
Files:
plugins/agent_control/init.luaplugins/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
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.
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.
* 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.
Summary
controlflag toMessage,AgentInput, andQueuedMessageso agent-to-agent control messages are visually and structurally distinct from user prompts.DisplayRole::Controlwith theme styling so control messages render separately in the UI.n00n.session.promptcontroloption;agent_controlmessageandresumenow sendsteer=true, control=true.SessionRequest::Statuswithlast_usersoagent_control resumecan read the pausedteamrun_idfrom the target session history and construct a continuation prompt.run_idinteamrun_wavespause payload for consistency.Test plan
cargo fmt --allcargo check --all --testscargo clippy --all --tests -- -D warningscargo nextest run --workspace(3873 passed, 1 skipped)cargo deny checkshows pre-existing license/source/advisory warnings unrelated to this change.