Skip to content

fix(sessions): guard Stop by execution and cancel pending approvals - #6504

Merged
mmabrouk merged 32 commits into
feat/session-controlfrom
feat/session-stop-guard
Sep 4, 2026
Merged

fix(sessions): guard Stop by execution and cancel pending approvals#6504
mmabrouk merged 32 commits into
feat/session-controlfrom
feat/session-stop-guard

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Sep 2, 2026

Copy link
Copy Markdown
Member

Context

Pressing Stop in the desktop chat marked the turn as stopped and cut the stream before the server had accepted the request. If the request failed, the warning showed but the turn stayed "stopped" and the stream was gone, while the runner kept working and billing. The same pattern existed in the mobile chat. This is the client half of the Stop package in the session-control design (PR #6495); the original slice on this branch added the execution guard and the approval handling.

Changes

The desktop Stop now has three states. On click the composer shows "Stopping" with the stream still attached. On 200 or 202 it stays in "Stopping" until the stream's terminal event or the session's terminal state arrives, then "Stopped". A response with an empty cancelled_turn_ids (the session was already idle) goes straight to idle. A failed request (network, 5xx, 409 execution_mismatch) restores the running state, keeps the stream, and shows the warning with the server's error message.

An accepted Stop that never terminates does not trap the button: after 30 s the button re-enables and a second click sends Stop again with the same expected execution id. Only after an accepted retry does the client fall back to a local abort.

Mobile LiveConversation follows the same rule. The mobile StopButton is unchanged.

Before: click → stopped=true, stream aborted, request in flight; on failure a warning and a dead stream.
After: click → "Stopping", stream attached; on failure the running state is back and the stream continues.

Tests

  • @agenta/oss stopState.test.ts: 7 passed; full package 430 passed, 1 skipped.
  • @agenta/entities session-cancel-stream.test.ts: 9 passed; full package 1,473 passed.
  • @agenta/mobile: 144 passed; production build 6/6.
  • Type checks pass for oss, entities, chat, ui, mobile; package lint clean.
  • Reviewed by an Opus agent in three rounds. Round two had replaced the idle check with a field the server never sends; round three restored cancelled_turn_ids, which the API does send.
  • Browser pass on 2026-09-04 (below).

What to QA

  • Start a long answer, press Stop. The button reads "Stopping", the partial text stays, then the turn shows "Stopped" and the composer re-enables. Send another message; it continues in the same session.
  • Stop the API container, press Stop. The warning shows the error, the turn is still running, the stream still moves.
  • Regression: press Stop on an idle session. Nothing changes and no warning shows.

Browser pass, 2026-09-04

Stack agenta-ee-dev-session-integration at 8e746d66f1, Pi on the local sandbox, desktop at 8580 and mobile at /m. Fifty screenshots under ~/agenta-qa-evidence/2026-09-04-browser-stop/.

Scenario Result What was seen
Warm Stop during output pass Stop clicked mid-stream; cancel returned 202 with the command and execution ids; the UI showed "Stopped / Resend" and the composer re-enabled in 1 to 2 s; "What was the codeword?" answered PLUM-42 with a 161 to 179 ms invoke (screenshots 03 to 09)
Stop on an idle session pass no Stop control is shown while idle; a direct cancel call is a no-op (screenshot 10)
Stop during a long tool mechanism pass, defect found Stop during a running sleep returned 202 and the UI showed Stopped in 1 to 2 s; but in a clean session a codeword committed in an EARLIER completed turn was not recalled afterwards (session d602e8bf, screenshots 38 to 45). Root cause in progress; the QA driver missed it because it replays the transcript while the desktop sends only the last message
Stop while an approval waits fail no Stop control exists while the approval card is shown; a direct cancel returns 202 but the card stays pending, and a later Approve or Deny gets 404 "Interaction not found or already terminal" (screenshots 11 to 14)
Mobile at /m partial Stop works at the same speed; the turn shows the red "The agent run failed / aborted" card instead of a neutral "Stopped"; one follow-up hit a transient "running somewhere else" banner with a concurrent desktop tab open (screenshots 46 to 50)

Also: the same user Stop sometimes renders as neutral "Stopped / Resend" and sometimes as the red failure card (screenshots 21, 37, 44). Fixes for the missing Stop during approval, the card not updating on cancel, and the styling are being prepared on this branch.

Agent-generated, low weight. Not merged.

https://claude.ai/code/session_01GAqSs7fw6QRi2n1ZJ2tmAV

@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agenta-documentation Ready Ready Preview Sep 4, 2026 11:11pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • release/.*

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 10667aba-2d8c-4fa2-b4de-40a32f06b343

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 5c593072-dfb7-4541-8ed8-47b725b41efb

📥 Commits

Reviewing files that changed from the base of the PR and between 69db342 and 3982337.

⛔ Files ignored due to path filters (6)
  • api/uv.lock is excluded by !**/*.lock
  • clients/python/uv.lock is excluded by !**/*.lock
  • sdks/python/uv.lock is excluded by !**/*.lock
  • services/uv.lock is excluded by !**/*.lock
  • web/packages/agenta-api-client/src/generated/api/resources/sessions/client/requests/SessionStreamCommandRequest.ts is excluded by !**/generated/**
  • web/packages/agenta-api-client/src/generated/api/types/SessionStreamCommandResponse.ts is excluded by !**/generated/**
📒 Files selected for processing (119)
  • .agents/skills/agent-release-gate/SKILL.md
  • .agents/skills/agent-release-gate/resources/path_triggers.py
  • .agents/skills/agent-release-gate/resources/qa_product.py
  • .agents/skills/agent-release-gate/resources/session_control.py
  • .agents/skills/agent-release-gate/resources/test_qa_product_concurrency.py
  • .agents/skills/agent-release-gate/resources/test_session_control.py
  • .all-contributorsrc
  • README.md
  • api/ee/src/dbs/postgres/sessions/records/dao.py
  • api/entrypoints/worker_streams.py
  • api/oss/src/apis/fastapi/evaluations/router.py
  • api/oss/src/apis/fastapi/sessions/router.py
  • api/oss/src/core/sessions/streams/dtos.py
  • api/oss/src/core/sessions/streams/service.py
  • api/oss/src/core/sessions/streams/types.py
  • api/oss/src/dbs/redis/sessions/contract.py
  • api/oss/src/dbs/redis/sessions/locks.py
  • api/oss/src/routers/user_profile.py
  • api/oss/src/services/db_manager.py
  • api/oss/src/tasks/asyncio/sessions/records_worker.py
  • api/oss/src/tasks/asyncio/shared/consumer.py
  • api/oss/src/tasks/taskiq/triggers/worker.py
  • api/oss/src/utils/caching.py
  • api/oss/src/utils/crypting.py
  • api/oss/src/utils/env.py
  • api/oss/src/utils/exceptions.py
  • api/oss/src/utils/helpers.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_stop_guard.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_is_current_turn.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_lock_races.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_turn_handover.py
  • api/oss/tests/pytest/unit/sessions/test_project_scoped_locks.py
  • api/oss/tests/pytest/unit/sessions/test_records_worker_durability.py
  • api/oss/tests/pytest/unit/sessions/test_watch_publish.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_worker_lifecycle.py
  • api/oss/tests/pytest/unit/utils/test_caching.py
  • api/pyproject.toml
  • clients/python/pyproject.toml
  • docs/design/agent-workflows/documentation/adapters/agenta.md
  • docs/design/agent-workflows/documentation/tools.md
  • docs/design/agent-workflows/interfaces/README.md
  • docs/design/agent-workflows/interfaces/in-service/harness-adapters.md
  • docs/design/agent-workflows/interfaces/public-edge/agent-config-schema.md
  • docs/design/agent-workflows/projects/default-agent-builtins/addendum-always-active.md
  • docs/design/session-control-and-live-events/README.md
  • docs/design/session-control-and-live-events/context.md
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/plan.md
  • docs/design/session-control-and-live-events/records-invariants.md
  • docs/design/session-control-and-live-events/requirements.md
  • docs/design/session-control-and-live-events/research.md
  • docs/design/session-control-and-live-events/rfc.md
  • docs/design/session-control-and-live-events/slice-admission.md
  • docs/design/session-control-and-live-events/slice-records-ack.md
  • docs/design/session-control-and-live-events/slice-stop-guard.md
  • docs/design/session-control-and-live-events/status.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • hosting/kubernetes/helm/Chart.yaml
  • sdks/python/agenta/sdk/agents/adapters/vercel/stream.py
  • sdks/python/oss/tests/pytest/unit/agents/adapters/test_vercel_stream_conformance.py
  • sdks/python/pyproject.toml
  • services/pyproject.toml
  • services/runner/src/engines/sandbox_agent/errors.ts
  • services/runner/src/lifecycle/session-coordinator.ts
  • services/runner/src/protocol.ts
  • services/runner/src/server.ts
  • services/runner/src/sessions/admission.ts
  • services/runner/src/sessions/alive.ts
  • services/runner/tests/unit/session-admission.test.ts
  • services/runner/tests/unit/session-alive-interrupt.test.ts
  • services/runner/tests/unit/session-keepalive-dispatch.test.ts
  • services/runner/tests/unit/session-steer-mount-loss.test.ts
  • web/ee/package.json
  • web/mobile/package.json
  • web/mobile/src/features/chat/Composer.tsx
  • web/mobile/src/features/chat/LiveConversation.tsx
  • web/mobile/src/features/chat/StopButton.tsx
  • web/mobile/src/features/chat/stopHereState.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/oss/package.json
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts
  • web/oss/src/components/AgentChatSlice/hooks/useSessionHydration.ts
  • web/package.json
  • web/packages/agenta-api-client/package.json
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/src/hooks/useAgentChatQueue.ts
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/error.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentChatQueue.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentConversation.test.ts
  • web/packages/agenta-chat/tests/unit/model/error.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-entities/src/session/api/api.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-entities/src/workflow/state/store.ts
  • web/packages/agenta-entities/tests/unit/agent-build-kit-ui-state-atom.test.ts
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
🚧 Files skipped from review as they are similar to previous changes (36)
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/mobile/src/features/chat/stopHereState.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • docs/design/session-control-and-live-events/README.md
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/mobile/src/features/chat/StopButton.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • api/oss/src/core/sessions/streams/dtos.py
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • api/oss/src/core/sessions/streams/types.py
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/src/apis/fastapi/sessions/router.py
  • web/packages/agenta-entities/src/session/api/api.ts
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review.


📝 Summary

Summary by CodeRabbit

  • New Features

    • Added reliable Stop controls for desktop and mobile chat, including progress states, retries, and stale-request handling.
    • Stop requests now target the active execution, report cancelled turns, and clear related pending approvals.
    • Messages refused while a session is busy are clearly marked as not sent, with the original text restored.
    • Build-kit preferences now persist independently for each revision.
  • Bug Fixes

    • Improved session turn-race protection and record delivery recovery.
  • Documentation

    • Added design documentation for session control and live events.

Walkthrough

The change adds guarded session cancellation, single-turn admission, durable record redelivery, release-gate validation, persisted build-kit UI state, and related client, runner, API, documentation, and maintenance updates.

Changes

Session control and cancellation

Layer / File(s) Summary
Backend cancellation and admission
api/oss/src/apis/fastapi/sessions/router.py, api/oss/src/core/sessions/streams/*, api/oss/src/dbs/redis/sessions/*, services/runner/src/sessions/*, services/runner/src/server.ts
Cancel requests accept execution guards, Redis records turn-start times, stale cancellations return HTTP 409, and busy sessions refuse competing turns without evicting the active environment.
Client cancellation and transcript state
web/packages/agenta-entities/src/session/*, web/packages/agenta-chat/src/{assets,model,state,hooks}/*, web/oss/src/components/AgentChatSlice/*, web/mobile/src/features/chat/*
Clients expose structured cancellation outcomes, preserve stopped turns, hide cancelled approvals, propagate turn IDs, restore refused messages, and track Stop lifecycle state.
Session validation
api/oss/tests/pytest/unit/sessions/*, services/runner/tests/unit/session-*, sdks/python/oss/tests/pytest/unit/agents/adapters/*, web/packages/agenta-chat/tests/*, web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
Tests cover cancellation guards, admission refusal, turn metadata, pending-interaction cleanup, transcript state, and Stop outcomes.

Records durability

Layer / File(s) Summary
Redelivery and durable acknowledgement
api/oss/src/tasks/asyncio/shared/consumer.py, api/oss/src/tasks/asyncio/sessions/records_worker.py, api/entrypoints/worker_streams.py, api/oss/src/utils/env.py
Record messages remain pending until durable commit, failed batches retry per record, pending entries are reclaimed, and repeated failures are bounded by configurable delivery limits.
Durability validation
api/oss/tests/pytest/unit/sessions/test_records_worker_durability.py, api/oss/tests/pytest/unit/sessions/test_watch_publish.py, api/ee/src/dbs/postgres/sessions/records/dao.py
Tests cover commit-scoped acknowledgement, poison records, outages, quota handling, reclaim behavior, and corrected retention deletion matching.

Release validation and UI persistence

Layer / File(s) Summary
Release-gate session-control coverage
.agents/skills/agent-release-gate/*
A standalone session-control driver is registered as mandatory for relevant paths, and its results are validated and incorporated into the release gate.
Build-kit UI persistence
web/packages/agenta-entities/src/workflow/state/store.ts, web/packages/agenta-entities/tests/unit/agent-build-kit-ui-state-atom.test.ts
Build-kit enabled and disabled-operation state is persisted per revision with malformed-state normalization and reload tests.
Maintenance and documentation
docs/design/session-control-and-live-events/*, docs/design/agent-workflows/*, api/oss/src/utils/*, api/oss/src/tasks/taskiq/triggers/worker.py, package manifests, README.md, .all-contributorsrc
Design records, tool-path documentation, utility behavior, schedule validation, package versions, and contributor metadata are updated.

Estimated code review effort: 5 (Critical) | ~120 minutes

Merge Risk: 🟠 High · up to 39823

Accepted Stops can remain running, valid later Stops can be rejected, refused attachments can be lost, and invalid redelivery settings can delete pending records. These issues should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
  participant ChatUI
  participant SessionClient
  participant SessionsAPI
  participant Redis
  participant Runner
  ChatUI->>SessionClient: Submit Stop with expected execution ID
  SessionClient->>SessionsAPI: Send cancellation request
  SessionsAPI->>Redis: Validate owner and turn start
  Redis-->>SessionsAPI: Cancelled turn IDs or stale mismatch
  SessionsAPI-->>SessionClient: Structured cancellation outcome
  Runner->>ChatUI: Stream admitted turn metadata and terminal events
  ChatUI->>SessionClient: Update Stop and transcript state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.54% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 279 functions across 50 files. (68 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly identifies session Stop fixes, including execution guarding and pending-approval cancellation. These are substantial changes in the pull request.
Description check ✅ Passed The description is directly related to the changeset. It explains Stop lifecycle behavior, execution guards, retries, client behavior, tests, and known QA findings.
Full details: Docstring Coverage

Explanation

Docstring coverage is 31.54% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 279 functions across 50 files. (68 skipped: 32 unsupported, 36 over the file limit.)

✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch feat/session-stop-guard
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/session-stop-guard

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.

@mmabrouk mmabrouk changed the title [overnight] fix(sessions): Stop names the turn it means, cancels its approvals, and reaches the user fix(sessions): guard Stop by execution and cancel pending approvals Sep 3, 2026
@mmabrouk
mmabrouk changed the base branch from agent/session-execution-rfc to main September 4, 2026 07:04
@mmabrouk
mmabrouk marked this pull request as ready for review September 4, 2026 15:40
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📘 Docs preview

Status ✅ Ready
Preview https://pr-6504-agenta-docs-preview.mahmoud-637.workers.dev/docs
Inspect Actions run
Commit 8a8b2ae7f8253c929db1e00ec83264476b88fd9e

This comment updates in place on every push.

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review summary

  • Risky: api/oss/src/core/sessions/streams/service.py:283 - Stop checks the current owners, then removes the Redis locks in separate operations. A replacement turn can acquire the session between those operations and be cancelled.
  • Missing tests: web/packages/agenta-chat/tests/unit/model/userStop.test.ts and web/packages/agenta-chat/tests/unit/hooks/useAgentConversation.test.ts do not load in a fresh install because the new model import pulls UI modules into the package test boundary.

Reviewed at 017ab21a53cf92c7107488e63c47c584c0c59a70. The committed backend tests pass, but a forced interleaving test reproduces the lock race. The focused entities, desktop stop-state, and mobile stop-state tests pass. The focused chat run passes 69 tests, but the two suites above fail before collecting tests with TypeError: jsxDEV is not a function.

Comment thread api/oss/src/core/sessions/streams/service.py Outdated
Comment thread web/packages/agenta-chat/src/model/userStop.ts Outdated
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Status Destroyed (PR closed)

Updated at 2026-09-04T23:20:00.071Z

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 19

Caution

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

⚠️ Outside diff range comments (1)
web/oss/src/components/AgentChatSlice/AgentConversation.tsx (1)

433-442: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear session status after a stopped parked turn.

When stopped becomes true, this effect can still publish "awaiting" from the stale approval part. The approval dock is hidden and sends are unblocked, but the session status remains incorrect until a later transcript update. Derive "idle" for stopped before pending states and include stopped in the dependencies.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 692c9546-94a7-488a-9c01-6c68a4281722

📥 Commits

Reviewing files that changed from the base of the PR and between ded2cc3 and 017ab21.

⛔ Files ignored due to path filters (2)
  • web/packages/agenta-api-client/src/generated/api/resources/sessions/client/requests/SessionStreamCommandRequest.ts is excluded by !**/generated/**
  • web/packages/agenta-api-client/src/generated/api/types/SessionStreamCommandResponse.ts is excluded by !**/generated/**
📒 Files selected for processing (53)
  • api/oss/src/apis/fastapi/sessions/router.py
  • api/oss/src/core/sessions/streams/dtos.py
  • api/oss/src/core/sessions/streams/service.py
  • api/oss/src/core/sessions/streams/types.py
  • api/oss/src/dbs/redis/sessions/contract.py
  • api/oss/src/dbs/redis/sessions/locks.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_stop_guard.py
  • docs/design/session-control-and-live-events/README.md
  • docs/design/session-control-and-live-events/context.md
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/plan.md
  • docs/design/session-control-and-live-events/records-invariants.md
  • docs/design/session-control-and-live-events/requirements.md
  • docs/design/session-control-and-live-events/research.md
  • docs/design/session-control-and-live-events/rfc.md
  • docs/design/session-control-and-live-events/slice-stop-guard.md
  • docs/design/session-control-and-live-events/status.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • web/mobile/src/features/chat/Composer.tsx
  • web/mobile/src/features/chat/LiveConversation.tsx
  • web/mobile/src/features/chat/StopButton.tsx
  • web/mobile/src/features/chat/stopHereState.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts
  • web/oss/src/components/AgentChatSlice/hooks/useSessionHydration.ts
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentConversation.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-entities/src/session/api/api.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread api/oss/src/apis/fastapi/sessions/router.py Outdated
Comment thread api/oss/src/apis/fastapi/sessions/router.py Outdated
Comment thread api/oss/src/core/sessions/streams/service.py Outdated
Comment thread docs/design/session-control-and-live-events/decisions.md
Comment thread docs/design/session-control-and-live-events/rfc.md Outdated
Comment thread web/packages/agenta-chat/src/assets/composerState.ts Outdated
Comment thread web/packages/agenta-chat/src/assets/transcriptToMessages.ts
Comment thread web/packages/agenta-chat/src/hooks/useAgentConversation.ts
Comment thread web/packages/agenta-chat/src/model/approvals.ts Outdated
Comment thread web/packages/agenta-entities/src/session/api/api.ts Outdated
@mmabrouk
mmabrouk force-pushed the feat/session-stop-guard branch from 017ab21 to 3982337 Compare September 4, 2026 17:01
@mmabrouk
mmabrouk changed the base branch from main to feat/session-control September 4, 2026 17:01
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

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

⚠️ Outside diff range comments (1)
docs/design/agent-workflows/projects/default-agent-builtins/addendum-always-active.md (1)

97-102: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Authorization Bypass (CWE-863): Incorrect Authorization

Document the mixed-version authorization impact.

During a staggered deployment, an old runner can interpret the SDK's seven request.tools names as a grant list and restore previously deselected tools. State this migration risk explicitly.

🧹 Nitpick comments (5)
api/oss/src/tasks/asyncio/sessions/records_worker.py (1)

221-225: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Bound the per-record retry when the write path itself is down.

The retry issues one append_many call per entry. When Postgres is unreachable, every call fails, so a 50-entry group produces 50 additional failing calls. The reclaim pass repeats this in each window, which adds load to a database that is already unavailable.

Consider stopping the loop after a few consecutive failures. The remaining entries stay pending either way, so the outcome does not change and the cost drops.

♻️ Proposed bound on consecutive failures
         total_appended = 0
         committed_ids: List[bytes] = []
-        for entry in entries:
+        consecutive_failures = 0
+        for entry in entries:
             appended, ok = await self._append(project_id=project_id, entries=[entry])
             if ok:
                 total_appended += appended
                 committed_ids.append(entry[0])
+                consecutive_failures = 0
+                continue
+            consecutive_failures += 1
+            # Consecutive failures mean the write path is down, not a poison record.
+            # The rest stays pending, so stop hammering it.
+            if consecutive_failures >= 3:
+                break
web/packages/agenta-entities/src/workflow/state/store.ts (1)

1469-1473: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reduce the added comments to one short line each. Keep only the non-obvious invariant in the comments at lines 1469–1473, 1481–1486, and 1522.

web/packages/agenta-chat/src/hooks/useAgentChatQueue.ts (1)

86-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reduce each added comment to one short line. The web/AGENTS.md hard rule covers all six files; longer comments are allowed only for genuinely surprising constraints and must remain brief.

api/ee/src/dbs/postgres/sessions/records/dao.py (1)

102-103: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the historical failure explanation. The query and RecordDBE definition already show the composite (project_id, record_id) key, so this comment adds past-defect narration instead of non-obvious rationale.

web/packages/agenta-chat/tests/unit/model/error.test.ts (1)

87-90: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Keep each test comment to one short line. web/AGENTS.md applies to both files and prohibits multi-line explanatory blocks. Collapse the four-line admission comment and the three-line localStorage comment to one line each.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 5c593072-dfb7-4541-8ed8-47b725b41efb

📥 Commits

Reviewing files that changed from the base of the PR and between 69db342 and 3982337.

⛔ Files ignored due to path filters (6)
  • api/uv.lock is excluded by !**/*.lock
  • clients/python/uv.lock is excluded by !**/*.lock
  • sdks/python/uv.lock is excluded by !**/*.lock
  • services/uv.lock is excluded by !**/*.lock
  • web/packages/agenta-api-client/src/generated/api/resources/sessions/client/requests/SessionStreamCommandRequest.ts is excluded by !**/generated/**
  • web/packages/agenta-api-client/src/generated/api/types/SessionStreamCommandResponse.ts is excluded by !**/generated/**
📒 Files selected for processing (119)
  • .agents/skills/agent-release-gate/SKILL.md
  • .agents/skills/agent-release-gate/resources/path_triggers.py
  • .agents/skills/agent-release-gate/resources/qa_product.py
  • .agents/skills/agent-release-gate/resources/session_control.py
  • .agents/skills/agent-release-gate/resources/test_qa_product_concurrency.py
  • .agents/skills/agent-release-gate/resources/test_session_control.py
  • .all-contributorsrc
  • README.md
  • api/ee/src/dbs/postgres/sessions/records/dao.py
  • api/entrypoints/worker_streams.py
  • api/oss/src/apis/fastapi/evaluations/router.py
  • api/oss/src/apis/fastapi/sessions/router.py
  • api/oss/src/core/sessions/streams/dtos.py
  • api/oss/src/core/sessions/streams/service.py
  • api/oss/src/core/sessions/streams/types.py
  • api/oss/src/dbs/redis/sessions/contract.py
  • api/oss/src/dbs/redis/sessions/locks.py
  • api/oss/src/routers/user_profile.py
  • api/oss/src/services/db_manager.py
  • api/oss/src/tasks/asyncio/sessions/records_worker.py
  • api/oss/src/tasks/asyncio/shared/consumer.py
  • api/oss/src/tasks/taskiq/triggers/worker.py
  • api/oss/src/utils/caching.py
  • api/oss/src/utils/crypting.py
  • api/oss/src/utils/env.py
  • api/oss/src/utils/exceptions.py
  • api/oss/src/utils/helpers.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_stop_guard.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_is_current_turn.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_lock_races.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_turn_handover.py
  • api/oss/tests/pytest/unit/sessions/test_project_scoped_locks.py
  • api/oss/tests/pytest/unit/sessions/test_records_worker_durability.py
  • api/oss/tests/pytest/unit/sessions/test_watch_publish.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_worker_lifecycle.py
  • api/oss/tests/pytest/unit/utils/test_caching.py
  • api/pyproject.toml
  • clients/python/pyproject.toml
  • docs/design/agent-workflows/documentation/adapters/agenta.md
  • docs/design/agent-workflows/documentation/tools.md
  • docs/design/agent-workflows/interfaces/README.md
  • docs/design/agent-workflows/interfaces/in-service/harness-adapters.md
  • docs/design/agent-workflows/interfaces/public-edge/agent-config-schema.md
  • docs/design/agent-workflows/projects/default-agent-builtins/addendum-always-active.md
  • docs/design/session-control-and-live-events/README.md
  • docs/design/session-control-and-live-events/context.md
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/plan.md
  • docs/design/session-control-and-live-events/records-invariants.md
  • docs/design/session-control-and-live-events/requirements.md
  • docs/design/session-control-and-live-events/research.md
  • docs/design/session-control-and-live-events/rfc.md
  • docs/design/session-control-and-live-events/slice-admission.md
  • docs/design/session-control-and-live-events/slice-records-ack.md
  • docs/design/session-control-and-live-events/slice-stop-guard.md
  • docs/design/session-control-and-live-events/status.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • hosting/kubernetes/helm/Chart.yaml
  • sdks/python/agenta/sdk/agents/adapters/vercel/stream.py
  • sdks/python/oss/tests/pytest/unit/agents/adapters/test_vercel_stream_conformance.py
  • sdks/python/pyproject.toml
  • services/pyproject.toml
  • services/runner/src/engines/sandbox_agent/errors.ts
  • services/runner/src/lifecycle/session-coordinator.ts
  • services/runner/src/protocol.ts
  • services/runner/src/server.ts
  • services/runner/src/sessions/admission.ts
  • services/runner/src/sessions/alive.ts
  • services/runner/tests/unit/session-admission.test.ts
  • services/runner/tests/unit/session-alive-interrupt.test.ts
  • services/runner/tests/unit/session-keepalive-dispatch.test.ts
  • services/runner/tests/unit/session-steer-mount-loss.test.ts
  • web/ee/package.json
  • web/mobile/package.json
  • web/mobile/src/features/chat/Composer.tsx
  • web/mobile/src/features/chat/LiveConversation.tsx
  • web/mobile/src/features/chat/StopButton.tsx
  • web/mobile/src/features/chat/stopHereState.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/oss/package.json
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts
  • web/oss/src/components/AgentChatSlice/hooks/useSessionHydration.ts
  • web/package.json
  • web/packages/agenta-api-client/package.json
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/src/hooks/useAgentChatQueue.ts
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/error.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentChatQueue.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentConversation.test.ts
  • web/packages/agenta-chat/tests/unit/model/error.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-entities/src/session/api/api.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-entities/src/workflow/state/store.ts
  • web/packages/agenta-entities/tests/unit/agent-build-kit-ui-state-atom.test.ts
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
🚧 Files skipped from review as they are similar to previous changes (36)
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/mobile/src/features/chat/stopHereState.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • docs/design/session-control-and-live-events/README.md
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/mobile/src/features/chat/StopButton.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • api/oss/src/core/sessions/streams/dtos.py
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • api/oss/src/core/sessions/streams/types.py
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/src/apis/fastapi/sessions/router.py
  • web/packages/agenta-entities/src/session/api/api.ts
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 10

Caution

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

⚠️ Outside diff range comments (1)
docs/design/agent-workflows/projects/default-agent-builtins/addendum-always-active.md (1)

97-102: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Authorization Bypass (CWE-863): Incorrect Authorization

Document the mixed-version authorization impact.

During a staggered deployment, an old runner can interpret the SDK's seven request.tools names as a grant list and restore previously deselected tools. State this migration risk explicitly.

🧹 Nitpick comments (5)
api/oss/src/tasks/asyncio/sessions/records_worker.py (1)

221-225: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Bound the per-record retry when the write path itself is down.

The retry issues one append_many call per entry. When Postgres is unreachable, every call fails, so a 50-entry group produces 50 additional failing calls. The reclaim pass repeats this in each window, which adds load to a database that is already unavailable.

Consider stopping the loop after a few consecutive failures. The remaining entries stay pending either way, so the outcome does not change and the cost drops.

♻️ Proposed bound on consecutive failures
         total_appended = 0
         committed_ids: List[bytes] = []
-        for entry in entries:
+        consecutive_failures = 0
+        for entry in entries:
             appended, ok = await self._append(project_id=project_id, entries=[entry])
             if ok:
                 total_appended += appended
                 committed_ids.append(entry[0])
+                consecutive_failures = 0
+                continue
+            consecutive_failures += 1
+            # Consecutive failures mean the write path is down, not a poison record.
+            # The rest stays pending, so stop hammering it.
+            if consecutive_failures >= 3:
+                break
web/packages/agenta-entities/src/workflow/state/store.ts (1)

1469-1473: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reduce the added comments to one short line each. Keep only the non-obvious invariant in the comments at lines 1469–1473, 1481–1486, and 1522.

web/packages/agenta-chat/src/hooks/useAgentChatQueue.ts (1)

86-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reduce each added comment to one short line. The web/AGENTS.md hard rule covers all six files; longer comments are allowed only for genuinely surprising constraints and must remain brief.

api/ee/src/dbs/postgres/sessions/records/dao.py (1)

102-103: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the historical failure explanation. The query and RecordDBE definition already show the composite (project_id, record_id) key, so this comment adds past-defect narration instead of non-obvious rationale.

web/packages/agenta-chat/tests/unit/model/error.test.ts (1)

87-90: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Keep each test comment to one short line. web/AGENTS.md applies to both files and prohibits multi-line explanatory blocks. Collapse the four-line admission comment and the three-line localStorage comment to one line each.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 5c593072-dfb7-4541-8ed8-47b725b41efb

📥 Commits

Reviewing files that changed from the base of the PR and between 69db342 and 3982337.

⛔ Files ignored due to path filters (6)
  • api/uv.lock is excluded by !**/*.lock
  • clients/python/uv.lock is excluded by !**/*.lock
  • sdks/python/uv.lock is excluded by !**/*.lock
  • services/uv.lock is excluded by !**/*.lock
  • web/packages/agenta-api-client/src/generated/api/resources/sessions/client/requests/SessionStreamCommandRequest.ts is excluded by !**/generated/**
  • web/packages/agenta-api-client/src/generated/api/types/SessionStreamCommandResponse.ts is excluded by !**/generated/**
📒 Files selected for processing (119)
  • .agents/skills/agent-release-gate/SKILL.md
  • .agents/skills/agent-release-gate/resources/path_triggers.py
  • .agents/skills/agent-release-gate/resources/qa_product.py
  • .agents/skills/agent-release-gate/resources/session_control.py
  • .agents/skills/agent-release-gate/resources/test_qa_product_concurrency.py
  • .agents/skills/agent-release-gate/resources/test_session_control.py
  • .all-contributorsrc
  • README.md
  • api/ee/src/dbs/postgres/sessions/records/dao.py
  • api/entrypoints/worker_streams.py
  • api/oss/src/apis/fastapi/evaluations/router.py
  • api/oss/src/apis/fastapi/sessions/router.py
  • api/oss/src/core/sessions/streams/dtos.py
  • api/oss/src/core/sessions/streams/service.py
  • api/oss/src/core/sessions/streams/types.py
  • api/oss/src/dbs/redis/sessions/contract.py
  • api/oss/src/dbs/redis/sessions/locks.py
  • api/oss/src/routers/user_profile.py
  • api/oss/src/services/db_manager.py
  • api/oss/src/tasks/asyncio/sessions/records_worker.py
  • api/oss/src/tasks/asyncio/shared/consumer.py
  • api/oss/src/tasks/taskiq/triggers/worker.py
  • api/oss/src/utils/caching.py
  • api/oss/src/utils/crypting.py
  • api/oss/src/utils/env.py
  • api/oss/src/utils/exceptions.py
  • api/oss/src/utils/helpers.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/tests/pytest/unit/sessions/test_cancel_stop_guard.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_is_current_turn.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_lock_races.py
  • api/oss/tests/pytest/unit/sessions/test_heartbeat_turn_handover.py
  • api/oss/tests/pytest/unit/sessions/test_project_scoped_locks.py
  • api/oss/tests/pytest/unit/sessions/test_records_worker_durability.py
  • api/oss/tests/pytest/unit/sessions/test_watch_publish.py
  • api/oss/tests/pytest/unit/triggers/test_triggers_worker_lifecycle.py
  • api/oss/tests/pytest/unit/utils/test_caching.py
  • api/pyproject.toml
  • clients/python/pyproject.toml
  • docs/design/agent-workflows/documentation/adapters/agenta.md
  • docs/design/agent-workflows/documentation/tools.md
  • docs/design/agent-workflows/interfaces/README.md
  • docs/design/agent-workflows/interfaces/in-service/harness-adapters.md
  • docs/design/agent-workflows/interfaces/public-edge/agent-config-schema.md
  • docs/design/agent-workflows/projects/default-agent-builtins/addendum-always-active.md
  • docs/design/session-control-and-live-events/README.md
  • docs/design/session-control-and-live-events/context.md
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/plan.md
  • docs/design/session-control-and-live-events/records-invariants.md
  • docs/design/session-control-and-live-events/requirements.md
  • docs/design/session-control-and-live-events/research.md
  • docs/design/session-control-and-live-events/rfc.md
  • docs/design/session-control-and-live-events/slice-admission.md
  • docs/design/session-control-and-live-events/slice-records-ack.md
  • docs/design/session-control-and-live-events/slice-stop-guard.md
  • docs/design/session-control-and-live-events/status.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • hosting/kubernetes/helm/Chart.yaml
  • sdks/python/agenta/sdk/agents/adapters/vercel/stream.py
  • sdks/python/oss/tests/pytest/unit/agents/adapters/test_vercel_stream_conformance.py
  • sdks/python/pyproject.toml
  • services/pyproject.toml
  • services/runner/src/engines/sandbox_agent/errors.ts
  • services/runner/src/lifecycle/session-coordinator.ts
  • services/runner/src/protocol.ts
  • services/runner/src/server.ts
  • services/runner/src/sessions/admission.ts
  • services/runner/src/sessions/alive.ts
  • services/runner/tests/unit/session-admission.test.ts
  • services/runner/tests/unit/session-alive-interrupt.test.ts
  • services/runner/tests/unit/session-keepalive-dispatch.test.ts
  • services/runner/tests/unit/session-steer-mount-loss.test.ts
  • web/ee/package.json
  • web/mobile/package.json
  • web/mobile/src/features/chat/Composer.tsx
  • web/mobile/src/features/chat/LiveConversation.tsx
  • web/mobile/src/features/chat/StopButton.tsx
  • web/mobile/src/features/chat/stopHereState.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/oss/package.json
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts
  • web/oss/src/components/AgentChatSlice/hooks/useSessionHydration.ts
  • web/package.json
  • web/packages/agenta-api-client/package.json
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/src/hooks/useAgentChatQueue.ts
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/error.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentChatQueue.test.ts
  • web/packages/agenta-chat/tests/unit/hooks/useAgentConversation.test.ts
  • web/packages/agenta-chat/tests/unit/model/error.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-entities/src/session/api/api.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-entities/src/workflow/state/store.ts
  • web/packages/agenta-entities/tests/unit/agent-build-kit-ui-state-atom.test.ts
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
🚧 Files skipped from review as they are similar to previous changes (36)
  • web/packages/agenta-chat/tests/unit/assets/composerState.test.ts
  • web/packages/agenta-chat/tests/unit/model/liveApprovals.test.ts
  • web/packages/agenta-entities/src/session/index.ts
  • web/packages/agenta-chat/src/assets/index.ts
  • web/packages/agenta-chat/src/model/approvals.ts
  • web/packages/agenta-chat/src/model/index.ts
  • web/mobile/src/features/chat/useSessionWatch.ts
  • web/mobile/tests/unit/stopHereState.test.ts
  • web/mobile/src/features/chat/stopHereState.ts
  • web/packages/agenta-entities/src/session/core/schema.ts
  • docs/design/session-control-and-live-events/README.md
  • web/packages/agenta-ui/src/RichChatInput/plugins/SendButton.tsx
  • web/packages/agenta-chat/tests/unit/model/userStop.test.ts
  • web/packages/agenta-chat/src/assets/agentTurn.ts
  • web/oss/src/components/AgentChatSlice/assets/stopState.test.ts
  • web/mobile/src/features/chat/StopButton.tsx
  • web/oss/src/components/AgentChatSlice/assets/stopState.ts
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx
  • web/packages/agenta-entities/tests/unit/session-cancel-stream.test.ts
  • web/packages/agenta-chat/src/model/userStop.ts
  • web/packages/agenta-chat/src/hooks/useAgentConversation.ts
  • api/oss/src/core/sessions/streams/dtos.py
  • web/packages/agenta-chat/src/assets/composerState.ts
  • web/packages/agenta-chat/src/components/ChatComposer.tsx
  • web/packages/agenta-chat/tests/unit/assets/agentTurn.test.ts
  • api/oss/src/core/sessions/streams/types.py
  • web/oss/src/components/AgentChatSlice/components/AgentComposerDock.tsx
  • web/packages/agenta-chat/src/state/sessionEphemera.ts
  • web/packages/agenta-chat/tests/unit/assets/transcriptToMessages.test.ts
  • api/oss/tests/pytest/unit/sessions/test_cancel_cancels_pending_interactions.py
  • api/oss/src/apis/fastapi/sessions/router.py
  • web/packages/agenta-entities/src/session/api/api.ts
  • docs/design/session-control-and-live-events/decisions.md
  • docs/design/session-control-and-live-events/tonight-handoff.md
  • web/packages/agenta-chat/src/assets/transcriptToMessages.ts
  • web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review.

🛑 Comments failed to post (10)
.agents/skills/agent-release-gate/resources/qa_product.py (1)

3166-3173: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Report the recorded SKIP cells; PASS currently hides them.

status is PASS whenever no cell failed, so an artifact where every cell SKIPped records PASS. Eight of the sixteen cells SKIP whenever the standalone run omits --project (see SKILL.md lines 207-212). The loader collects skipped, but no consumer reads it: the "where" line (Line 3456), the mandatory table (Line 3561), and the exit code (Line 3595) all use status only. A release run without --project therefore prints recorded PASS for coverage that never executed.

Surface the skip count where the status is displayed.

🔧 Proposed fix: carry the skip count into the displayed status
     failed = sorted(name for name, status in statuses.items() if status == "FAIL")
     skipped = sorted(name for name, status in statuses.items() if status == "SKIP")
     return {
         "path": str(result_path),
         "status": "FAIL" if failed else "PASS",
+        # A SKIP is untested coverage, never a pass. The label the gate prints has to say so,
+        # or a run without --project reads as green on eight cells that never executed.
+        "label": ("FAIL" if failed else "PASS")
+        + (f" ({len(skipped)}/{len(statuses)} SKIPPED)" if skipped else ""),
         "failed": failed,
         "skipped": skipped,
     }

Then print session_control_result['label'] at Lines 3456 and 3561.

api/oss/src/utils/env.py (1)

528-532: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject non-positive redelivery settings. SessionsRecordsConfig accepts zero and negative integers without validation, and worker_streams passes them to RecordsWorker. With reclaim_idle_ms=0, reclaim_batch() disables its cooldown and Redis idle filter, so failed records can be reclaimed in a tight loop. With max_deliveries <= 0, every reclaimed record is over budget; after an unrelated commit makes the write path healthy, drop_expired() ACKs and deletes the failed record. Add model-level validation requiring both values to be at least 1.

docs/design/session-control-and-live-events/records-invariants.md (1)

198-200: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🤖 get_repo_knowledge executed:

get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings

Length of output: 28313


🏁 Script executed:

#!/bin/bash
set -eu
file="docs/design/session-control-and-live-events/records-invariants.md"
printf '%s\n' '--- target document ---'
sed -n '90,125p;185,235p' "$file"
printf '%s\n' '--- related files ---'
git ls-files | rg '(^|/)(records|session|live|event|worker|invariant)' | head -200
printf '%s\n' '--- acknowledgement and drop references ---'
rg -n -i 'acknowledge|acknowledg|deliberate.?drop|permanent.?drop|retryable|commit.?scoped|failed database|incomplete.?history' --glob '!**/node_modules/**' .

Repository: Agenta-AI/agenta

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -eu
doc="docs/design/session-control-and-live-events/records-invariants.md"
printf '%s\n' '--- document ---'
sed -n '100,122p;190,230p' "$doc"
printf '%s\n' '--- scoped files ---'
git ls-files 'docs/design/session-control-and-live-events/**' 'services/**' 'api/**' | rg -i 'record|event|session|worker|queue|redis|live'
printf '%s\n' '--- scoped references ---'
rg -n -i 'commit.?scoped|deliberate.?drop|permanent.?drop|retryable|failed database|acknowledg|incomplete.?history' \
  docs/design/session-control-and-live-events services api \
  --glob '!**/*.jsonl' --glob '!**/*.json' --glob '!**/node_modules/**' \
  --glob '!**/dist/**' --glob '!**/build/**' | head -300

Repository: Agenta-AI/agenta

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- records worker ---'
sed -n '45,85p;220,355p' api/oss/src/tasks/asyncio/sessions/records_worker.py
printf '%s\n' '--- consumer acknowledgement contract ---'
sed -n '175,285p;305,350p' api/oss/src/tasks/asyncio/shared/consumer.py
printf '%s\n' '--- worker durability tests ---'
sed -n '1,185p;235,285p;400,445p' api/oss/tests/pytest/unit/sessions/test_records_worker_durability.py
printf '%s\n' '--- records acknowledgement design slice ---'
sed -n '1,82p;110,182p' docs/design/session-control-and-live-events/slice-records-ack.md
printf '%s\n' '--- current diff for target document ---'
git diff -- docs/design/session-control-and-live-events/records-invariants.md

Repository: Agenta-AI/agenta

Length of output: 32461


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- exact drop handling ---'
sed -n '260,315p' api/oss/src/tasks/asyncio/shared/consumer.py
sed -n '330,395p' api/oss/src/tasks/asyncio/sessions/records_worker.py
printf '%s\n' '--- history-gap contract ---'
sed -n '1,35p;145,175p;212,225p' docs/design/session-control-and-live-events/records-invariants.md
rg -n -i 'incomplete|gap|dropped|drop|loss' docs/design/session-control-and-live-events api/oss/src/tasks/asyncio/sessions/records_worker.py api/oss/src/tasks/asyncio/shared/consumer.py --glob '!*.json' --glob '!*.jsonl' | head -160

Repository: Agenta-AI/agenta

Length of output: 17832


Define acknowledgement and loss handling consistently.

The worker acknowledges committed records, undecodable messages, and over-quota drops. Retryable database and quota failures remain pending for reclamation. Replace the absolute “only successfully committed” rule with these cases, and require intentional or unrecoverable drops to mark history incomplete before acknowledgement. Otherwise, the contract does not distinguish accounted loss from silent data loss.

docs/design/session-control-and-live-events/rfc.md (2)

304-313: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🤖 get_repo_knowledge executed:

get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions

Length of output: 21940


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(requirements\.md|rfc\.md)$|session-control-and-live-events'
printf '%s\n' '--- RFC references ---'
rg -n -C 5 'stopp|terminal|settle|watchdog|lost|claim|Redis|Stream|acknow|delet|execution_id|generation' docs/design/session-control-and-live-events/rfc.md
printf '%s\n' '--- requirements references ---'
for f in $(git ls-files | rg '(^|/)requirements\.md$|session-control-and-live-events'); do
  printf '\n--- %s ---\n' "$f"
  rg -n -C 5 'exactly one|terminal|settle|stale|writer|watchdog|lost|idempot|claim|ownership|generation' "$f" || true
done

Repository: Agenta-AI/agenta

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -eu
f=docs/design/session-control-and-live-events/rfc.md
printf '%s\n' '--- RFC terminal/race contract ---'
rg -n -C 8 'terminal outcome|terminal settlement|settle|settlement|compare-and-set|compare|CAS|late|duplicate|idempot|race|watchdog|runner disappears|lost|failed|stopped' "$f"
printf '%s\n' '--- requirements and decisions contract ---'
for f in \
  docs/design/session-control-and-live-events/requirements.md \
  docs/design/session-control-and-live-events/decisions.md \
  docs/design/session-control-and-live-events/records-invariants.md; do
  printf '\n--- %s ---\n' "$f"
  rg -n -C 6 'exactly one|terminal outcome|terminal|settle|settlement|late|duplicate|idempot|race|watchdog|lost|stopped|failed' "$f"
done

Repository: Agenta-AI/agenta

Length of output: 31978


Define an atomic terminal claim for each execution.

The runner and watchdog can both settle the same execution, but the RFC does not define race arbitration or handling for late reports. Add an execution-keyed compare-and-set rule, make losing reports idempotent, and add a runner/watchdog race test.


331-333: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🤖 get_repo_knowledge executed:

get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings

Length of output: 7556


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
fd -t f . docs/design/session-control-and-live-events | sort
printf '%s\n' '--- RFC structure and target context ---'
rg -n -C 4 'Redis Stream|stream entries|acknowledge|acknowledged|deleted|consumer group|consumer-group|live reader|durable projector|projector|watchdog|terminal|settle|ownership|generation|fenc' docs/design/session-control-and-live-events/rfc.md
printf '%s\n' '--- requirements references ---'
if [ -f docs/design/session-control-and-live-events/requirements.md ]; then
  rg -n -C 4 'durable terminal|terminal outcome|stale|writer|ownership|generation|fenc|project|stream|acknowledge|delete' docs/design/session-control-and-live-events/requirements.md
fi

Repository: Agenta-AI/agenta

Length of output: 12842


🏁 Script executed:

#!/bin/bash
set -e
for f in \
  docs/design/session-control-and-live-events/rfc.md \
  docs/design/session-control-and-live-events/records-invariants.md \
  docs/design/session-control-and-live-events/slice-records-ack.md \
  docs/design/session-control-and-live-events/requirements.md \
  docs/design/session-control-and-live-events/research.md
do
  printf '\n--- %s: matching terms ---\n' "$f"
  rg -n -C 3 'Redis|Stream|XADD|XREAD|XREADGROUP|XACK|acknowledge|delete|retention|consumer|reader|projector|temporary|durable|replay|pending|claim' "$f" || true
done
printf '\n--- RFC live-ingress and replay sections ---\n'
sed -n '329,420p' docs/design/session-control-and-live-events/rfc.md
printf '\n--- record acknowledgement slice ---\n'
sed -n '1,260p' docs/design/session-control-and-live-events/slice-records-ack.md

Repository: Agenta-AI/agenta

Length of output: 50374


Define Redis Stream acknowledgement and deletion ownership.

The RFC does not state whether live readers and the durable projector use separate consumer groups or who may acknowledge and delete entries. If a live reader deletes an entry before projector commit, a disconnect or retry can create a durable history gap. Define retention, acknowledgement, and deletion rules. Delete entries only after durable projection commits.

docs/design/session-control-and-live-events/slice-stop-guard.md (1)

186-189: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Clear the guard when the newest assistant message has no turn ID.

useAgentConversation clears the guard before sending, but its latestTurnId effect scans the preceding assistant message and restores its ID. If the next turn has no metadata, Stop sends that stale expected_execution_id and can be rejected. Update the effect to call clearSessionTurnId when latestTurnId returns null, and extend the second-send regression test with metadata on the first turn only.

🧰 Tools
🪛 LanguageTool

[style] ~186-~186: To elevate your writing, consider using more formal language here.
Context: ...ssion's first turn carried the metadata and a later turn did not, the stored id wou...

(AND_WHEREAS)


[style] ~189-~189: Consider an alternative for the overused word “exactly”.
Context: ...he guard, because retrying unguarded is exactly the behavior #6417 is about. ## The ho...

(EXACTLY_PRECISELY)

services/runner/src/lifecycle/session-coordinator.ts (1)

1337-1338: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

The backstop refusal carries no stable error code.

This branch returns only error: SESSION_TURN_IN_USE_MESSAGE. It emits no error event, so SESSION_TURN_IN_USE_CODE never reaches the client on this path. Two consequences follow in the fail-open window this branch exists for:

  • The client cannot key on session_turn_in_use and renders the refusal as a generic run failure instead of "not sent, try again".
  • server.ts (Lines 637-639) assumes a failed engine run already emitted its own error event. This branch breaks that assumption, so nothing is persisted and the terminal result is the only signal.

Emit the coded error event here, as the edge gate does.

♻️ Proposed change
     klog(`refuse (busy) key=${key}; another turn owns this session`);
+    trackedEmit?.({
+      type: "error",
+      message: SESSION_TURN_IN_USE_MESSAGE,
+      code: SESSION_TURN_IN_USE_CODE,
+    });
     return { ok: false, error: SESSION_TURN_IN_USE_MESSAGE };

This needs SESSION_TURN_IN_USE_CODE added to the Line 43 import.

web/mobile/src/features/chat/LiveConversation.tsx (1)

290-294: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Retry the accepted Stop request automatically. The watchdog only sets retryStopRef and clears stoppingHere; it never sends the required retry, so a non-terminating accepted cancellation remains active until the user clicks Stop again.

web/oss/src/components/AgentChatSlice/AgentConversation.tsx (1)

444-445: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Restore the complete refused payload. A session-busy refusal loses attached files: desktop discards file-only messages and restores only text, while mobile clears the submission with no refusal recovery.

  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx#L444-L445: recover or requeue the full QueuedMessage, including fileParts.
  • web/mobile/src/features/chat/LiveConversation.tsx#L598-L598: detect the session-busy refusal and restore or requeue text and file parts before the composer clears them.
📍 Affects 2 files
  • web/oss/src/components/AgentChatSlice/AgentConversation.tsx#L444-L445 (this comment)
  • web/mobile/src/features/chat/LiveConversation.tsx#L598-L598
web/packages/agenta-entities/src/workflow/state/store.ts (1)

1488-1488: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
set -eu

file='web/packages/agenta-entities/src/workflow/state/store.ts'
printf '%s\n' '--- focused source ---'
sed -n '1,35p' "$file"
sed -n '1440,1545p' "$file"

printf '%s\n' '--- related tests and symbols ---'
rg -n -C 4 'readBuildKitUiState|buildKitUiStateByRevisionAtom|atomWithStorage|malformed|null|reload|revision' \
  web/packages/agenta-entities/src/workflow/state/store.ts \
  web/packages/agenta-entities -g '*test*' -g '*spec*' | head -240

Repository: Agenta-AI/agenta

Length of output: 28222


🤖 get_repo_knowledge executed:

get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions

Length of output: 44747


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- build-kit references and tests ---'
rg -n -C 8 'buildKitUiState|BuildKitUiState|build-kit|disabledOps' \
  web/packages/agenta-entities web/packages -g '*test*' -g '*spec*' -g '*.tsx' -g '*.ts' \
  | head -320

printf '%s\n' '--- Jotai dependency declarations ---'
rg -n -C 3 '"jotai"|jotai@' \
  package.json web/package.json web/packages/*/package.json pnpm-lock.yaml 2>/dev/null \
  | head -120

Repository: Agenta-AI/agenta

Length of output: 39785


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- persistence test ---'
cat -n web/packages/agenta-entities/tests/unit/agent-build-kit-ui-state-atom.test.ts

printf '%s\n' '--- agenta-entities package metadata ---'
cat -n web/packages/agenta-entities/package.json | sed -n '1,140p'

printf '%s\n' '--- resolved Jotai entries ---'
rg -n -m 12 '(^|/ )jotai(@|:)|jotai:' pnpm-lock.yaml

Repository: Agenta-AI/agenta

Length of output: 13044


Guard the persisted value before indexing it: JSON null makes readBuildKitUiState throw; treat it as empty and add the reload regression case.

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agent-generated Codex review, low weight.

CHANGES NEEDED

The atomic Stop displacement fix is sound: ownership validation, tombstones, and lock deletion happen in one Redis EVAL, and the new test replaces the owner immediately before that EVAL and proves the replacement survives. The userStop import boundary is also local to @agenta/chat and its focused test passes. The LiveConversation rebase retained the pending-task and blocked-model changes from its base.

Four frontend state races remain in the inline comments. In addition, feat/session-control has advanced to 40e8f80; GitHub currently reports this PR as CONFLICTING, with prospective conflicts in api/oss/src/core/sessions/streams/service.py and two session-control design documents.

AGENTA_SESSIONS_DURABLE_STOP is not present in this head or the fetched base, so its off-path cannot be established from this PR. At this head both clients still use the legacy /sessions/streams command endpoint, while the desktop and mobile presentation behavior intentionally changes to server-first Stop. The later durable-cancel flag adapter is outside this reviewed diff and needs an integration-level flag-off check.

Comment thread web/packages/agenta-chat/src/hooks/useAgentConversation.ts
Comment thread web/packages/agenta-chat/src/model/userStop.ts Outdated
Comment thread web/mobile/src/features/chat/LiveConversation.tsx Outdated
Comment thread web/mobile/src/features/chat/LiveConversation.tsx Outdated
The turn id arrives as a `message-metadata` chunk on `message.metadata.turnId`,
not as a `data-agent-turn` part. Updates the mechanism, the path:line table, the
runner commit, and adds why the store stays in memory: metadata round-trips
through the message cache, so a persisted id would name a turn from a past page
load.

Claude-Session: https://claude.ai/code/session_01GAqSs7fw6QRi2n1ZJ2tmAV
… a callback

The pinned ai@6.0.0-beta.150 exposes exactly four client chat callbacks —
onError, onToolCall, onFinish and onData — and no metadata hook. onData takes a
DataUIPart, so it never sees a `message-metadata` chunk, and onFinish is too
late for a Stop that happens mid-turn. `messageMetadataSchema` is a validation
schema, not a hook. Reading the merged metadata off the streaming message is
the only channel this version offers. Verified in the installed package.

Claude-Session: https://claude.ai/code/session_01GAqSs7fw6QRi2n1ZJ2tmAV
Move ownership validation, tombstoning, and lock removal into one Redis operation. Use the Redis clock for both cancellation arrival and turn acquisition, and keep accepted cancellation independent from approval cleanup.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Keep the Stop predicate inside the chat package dependency boundary. Close cancelled approval replays, clear stale execution guards before new turns, and require cancellation evidence from the API response.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Settle parked Stop only after the server accepts cancellation. Ignore stale mobile responses after a session switch and keep idle state neutral on desktop and mobile.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Document the Postgres and Redis transaction boundary, the id-less arrival guard, and capability-qualified warm resume. Remove environment-specific identifiers and unsafe permission guidance from the verification record.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Update heartbeat race coverage to assert behavior at the new atomic Redis boundary. Preserve the same-turn ownership assertion without patching removed displacement helpers.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Keep the desktop Stop comments focused on the execution guard and accepted-cancellation invariants. Remove protocol history already captured in the design documents.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Clear cached execution identifiers at every desktop turn entry point and at the shared transport boundary so automatic approval and client-tool resumes cannot inherit the parked turn guard. Add shared approval-resume and desktop hook regression coverage.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Track the stopped turn identity across transcript updates. Preserve the local latch while the same turn settles, but clear it when watch or revalidation adopts a newer sent or resumed turn.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Evaluate both the request-time and response-time HITL state after cancellation succeeds. This preserves the stopped presentation when a streaming run becomes approval-paused before the response arrives.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Gate approval, elicitation, and connection actions on the Stop request phase for desktop and mobile. Failed requests restore the actions when the stopping state returns to idle.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Keep the mocked transcript and reducer identities stable so the desktop hook regression does not schedule an artificial render loop in the complete OSS suite.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Apply the OSS import grouping required by the package lint configuration.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Keep the missing-start guard focused on an actively running legacy turn and format the durable reconciliation coverage after moving atomic cleanup onto the durable path.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk
Keep one guard-clearing wrapper around the aliased chat send and regenerate methods so hook initialization and immediate-Stop fencing both remain correct.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agent-generated Codex review, low weight.

CHANGES NEEDED

The four round-two fixes and their regression tests survived the rebase. The range-diff accounts for every old feature change; the apparent generated/schema drops are already in the base. The public cancel route still feature-gates durable Stop, preserves the flag-off legacy call, and both legacy displacement and durable settlement are atomic.

One refresh gap remains: accepted Stop state is mount-local, so a paused approval is re-enabled if the page reloads before cancellation settles.

Focused validation: @agenta/chat useAgentConversation.test.ts — 11 passed.

Comment thread web/oss/src/components/AgentChatSlice/hooks/useAgentChatSession.ts
Preserve the backend stopping turn marker through the frontend session schema.

Recover matching desktop and mobile stop guards across remounts until settlement clears the marker.

Claude-Session: https://claude.ai/code/session_0164kzT6ttwpBtzvcDC6YzYk

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agent-generated Codex review, low weight.

SHIP

8a8b2ae7f825 closes the remount gap on desktop and mobile. The durable guard applies only when stopping_turn_id matches the current turn_id; settlement clears that marker, and a newer turn makes an older marker non-owning. With durable Stop disabled, no marker is written and the existing local Stop lifecycle remains in control.

Focused validation: useAgentChatSession.test.ts — 2 passed, including pause → accepted Stop → remount → settlement.

@mmabrouk
mmabrouk merged commit e65e624 into feat/session-control Sep 4, 2026
45 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes requested lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant