Conversation
Add event-driven per-session consciousness actors that replace the blocking request-response pattern in run_session. Each session gets a long-lived tokio::spawn task with a select! event loop that handles concurrent message queuing, preemption at tool boundaries, and mode transitions (Idle → Active → Sleeping → ShuttingDown). Key components: - ConsciousnessEvent enum (UserMessage, TimerTick, Shutdown) - SessionConsciousness actor with run_agent_cycle using tick_on_branch - ConsciousnessRegistry mapping session IDs to actor handles - ConsciousnessHandle with send/shutdown/is_alive - Feature flag: ARCAN_CONSCIOUSNESS=true enables consciousness mode - Queue integration: MessageQueue from arcan-core with steering semantics Also fixes: export arcan-core queue module (was private/uncompiled), fix queue.rs compilation errors (drain_after_run return type, trait impl). 5 integration tests + 15 queue unit tests passing. 1085 workspace tests green, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds a new per-session "consciousness" Tokio actor system gated by an env flag, exports a core Changes
Sequence DiagramsequenceDiagram
participant Client
participant CanonicalHandler as Canonical Handler
participant ConsRegistry as Consciousness Registry
participant SessionActor as Session Consciousness Actor
participant KernelRT as Kernel Runtime
participant MsgQueue as Message Queue
Client->>CanonicalHandler: UserMessage Request
alt Consciousness Enabled
CanonicalHandler->>ConsRegistry: get_or_create(session_id, branch, runtime)
ConsRegistry-->>CanonicalHandler: ConsciousnessHandle
CanonicalHandler->>SessionActor: send(UserMessageEvent + ack)
activate SessionActor
SessionActor->>KernelRT: tick_on_branch/run agent cycle
KernelRT->>MsgQueue: check_preemption()
MsgQueue-->>KernelRT: Result<SteeringAction, QueueError>
KernelRT-->>SessionActor: cycle result
SessionActor->>CanonicalHandler: send(ConsciousnessAck)
deactivate SessionActor
CanonicalHandler-->>Client: HTTP Response (Accepted/Rejected or error)
else Consciousness Disabled
CanonicalHandler->>KernelRT: direct tick_on_branch execution
KernelRT-->>CanonicalHandler: Standard response
CanonicalHandler-->>Client: HTTP Response
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
docs/superpowers/plans/2026-04-04-consciousness-actor-loop.md (1)
15-23: Add language specifier to fenced code block.The dependency chain diagram should specify a language (or use
text/plainfor non-code diagrams) to satisfy markdown linting rules.-``` +```text aios-protocol (EventKind, SteeringMode, OperatingMode) — READ ONLY🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/superpowers/plans/2026-04-04-consciousness-actor-loop.md` around lines 15 - 23, The fenced code block that contains the dependency chain diagram is missing a language specifier, which triggers markdown linting; update the block delimiter from ``` to ```text (or ```plain) so the diagram is treated as plain text, e.g., change the opening fence for the dependency chain diagram to ```text to satisfy linters while leaving the diagram content unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/arcand/src/canonical.rs`:
- Around line 1632-1638: The RunResponse currently returns events_emitted: 0
which breaks callers that expect a positive event count; update the return in
crates/arcand/src/canonical.rs (the RunResponse construction) to use a sentinel
for async/consciousness mode (e.g., events_emitted: u64::MAX) or compute the
actual count before responding, and remove the redundant explicit mode
assignment if both branches always set OperatingMode::Execute (i.e., adjust the
RunResponse fields: session_id, mode (only set where meaningful), state:
AgentStateVector::default(), events_emitted: <sentinel or computed>,
last_sequence). Ensure the sentinel choice is documented in comments or tests so
clients know how to interpret it.
In `@crates/arcand/src/consciousness.rs`:
- Around line 454-462: Queued messages are currently processed with
RunContext::default() in the drain loop (see drained iteration and
run_agent_cycle call), which discards the original RunContext (system_prompt,
allowed_tools, proposed_tool); modify the queue to carry the original RunContext
(e.g., add a run_context: RunContext field to QueuedMessage or persist it on the
consciousness state when enqueueing) and then pass that stored RunContext into
self.run_agent_cycle(...) instead of RunContext::default(); ensure enqueue logic
that creates QueuedMessage captures the current RunContext and the drain loop
sets self.state.mode = ConsciousnessMode::Active and invokes
run_agent_cycle(msg.content, self.state.branch.clone(), msg.run_context) (or
equivalent using the preserved context).
---
Nitpick comments:
In `@docs/superpowers/plans/2026-04-04-consciousness-actor-loop.md`:
- Around line 15-23: The fenced code block that contains the dependency chain
diagram is missing a language specifier, which triggers markdown linting; update
the block delimiter from ``` to ```text (or ```plain) so the diagram is treated
as plain text, e.g., change the opening fence for the dependency chain diagram
to ```text to satisfy linters while leaving the diagram content unchanged.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2dc4879b-408b-4aa4-9a81-f00b0082088e
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
crates/arcan-core/src/lib.rscrates/arcan-core/src/queue.rscrates/arcand/Cargo.tomlcrates/arcand/src/canonical.rscrates/arcand/src/consciousness.rscrates/arcand/src/lib.rscrates/arcand/tests/consciousness_test.rsdocs/superpowers/plans/2026-04-04-consciousness-actor-loop.md
| return Ok(Json(RunResponse { | ||
| session_id, | ||
| mode: OperatingMode::Execute, | ||
| state: AgentStateVector::default(), | ||
| events_emitted: 0, | ||
| last_sequence: 0, | ||
| })); |
There was a problem hiding this comment.
events_emitted: 0 breaks API contract for clients expecting event counts.
The relevant context snippet from crates/arcan/tests/praxis_integration.rs:238-240 shows tests assert events_emitted > 0. When consciousness mode is enabled, this response always returns 0, which could break client integrations that rely on this field to confirm work was done.
Consider either:
- Documenting this as expected behavior for async/consciousness mode
- Returning a sentinel value (e.g.,
u64::MAX) to indicate "async processing" - Waiting briefly for actual event count before responding
Additionally, the mode assignment is redundant—both branches return OperatingMode::Execute:
return Ok(Json(RunResponse {
session_id,
- mode: if queued {
- OperatingMode::Execute
- } else {
- OperatingMode::Execute
- },
+ mode: OperatingMode::Execute,
state: AgentStateVector::default(),
events_emitted: 0,
last_sequence: 0,
}));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/arcand/src/canonical.rs` around lines 1632 - 1638, The RunResponse
currently returns events_emitted: 0 which breaks callers that expect a positive
event count; update the return in crates/arcand/src/canonical.rs (the
RunResponse construction) to use a sentinel for async/consciousness mode (e.g.,
events_emitted: u64::MAX) or compute the actual count before responding, and
remove the redundant explicit mode assignment if both branches always set
OperatingMode::Execute (i.e., adjust the RunResponse fields: session_id, mode
(only set where meaningful), state: AgentStateVector::default(), events_emitted:
<sentinel or computed>, last_sequence). Ensure the sentinel choice is documented
in comments or tests so clients know how to interpret it.
| for msg in drained { | ||
| self.state.mode = ConsciousnessMode::Active; | ||
| self.run_agent_cycle( | ||
| msg.content, | ||
| self.state.branch.clone(), | ||
| RunContext::default(), | ||
| ) | ||
| .await; | ||
| } |
There was a problem hiding this comment.
Queued messages lose original RunContext during drain.
When processing drained messages, RunContext::default() is used, which means queued messages won't inherit the original system_prompt, allowed_tools, or proposed_tool. This could cause behavioral differences between immediate execution and queued execution.
Consider storing the RunContext in QueuedMessage or the consciousness state to preserve it:
for msg in drained {
self.state.mode = ConsciousnessMode::Active;
self.run_agent_cycle(
msg.content,
self.state.branch.clone(),
- RunContext::default(),
+ // TODO: Preserve original RunContext for queued messages
+ // For now, use default which loses system_prompt/allowed_tools
+ RunContext::default(),
)
.await;
}Would you like me to propose a design for preserving RunContext through the queue, or open an issue to track this as a follow-up enhancement?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/arcand/src/consciousness.rs` around lines 454 - 462, Queued messages
are currently processed with RunContext::default() in the drain loop (see
drained iteration and run_agent_cycle call), which discards the original
RunContext (system_prompt, allowed_tools, proposed_tool); modify the queue to
carry the original RunContext (e.g., add a run_context: RunContext field to
QueuedMessage or persist it on the consciousness state when enqueueing) and then
pass that stored RunContext into self.run_agent_cycle(...) instead of
RunContext::default(); ensure enqueue logic that creates QueuedMessage captures
the current RunContext and the drain loop sets self.state.mode =
ConsciousnessMode::Active and invokes run_agent_cycle(msg.content,
self.state.branch.clone(), msg.run_context) (or equivalent using the preserved
context).
Pre-existing lint triggered by CI's newer Rust toolchain. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
tokio::select!event loops that replace the blockingrun_sessionhandler whenARCAN_CONSCIOUSNESS=trueConsciousnessRegistrymapping session IDs to actor handles, withget_or_create,get, andshutdown_allarcan-core::queuemodule (was private/uncompiled) — MessageQueue with steering semantics (Collect/Steer/Followup/Interrupt)New files
crates/arcand/src/consciousness.rs— types, actor, registry, handle (~640 lines)crates/arcand/tests/consciousness_test.rs— 5 integration testsdocs/superpowers/plans/2026-04-04-consciousness-actor-loop.md— implementation planModified files
crates/arcand/src/canonical.rs— consciousness dispatch inrun_session, registry inCanonicalStatecrates/arcan-core/src/queue.rs— fix compilation bugs (return types, trait impl)crates/arcan-core/src/lib.rs— exportpub mod queueTest plan
cargo clippy --workspace— zero warningscargo build --workspace— clean buildARCAN_CONSCIOUSNESS=true cargo run -p arcan+ curl POST /runs🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements
Tests
Documentation