Conversation
|
Warning Your comment is too long (maximum is 65536 characters), so the coverage report was not added. See the job log for how to reduce it. |
8802ccb to
d7f2e0b
Compare
d7f2e0b to
d31a2c9
Compare
d31a2c9 to
d2f3da3
Compare
d2f3da3 to
40b2756
Compare
40b2756 to
310e84b
Compare
|
@all-hands-bot Please review the current head and explicitly approve it if there are no blocking findings. |
|
🤖 OpenHands is reviewing this PR. Head commit: This comment was posted by an AI agent (OpenHands). |
Review of
|
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was created by an AI agent (OpenHands) on behalf of the repository maintainers.
Summary
This PR adds a scoped POST /v1/runs/{run_id}/subject-turns endpoint that lets a running automation script submit work for an external subject (issue, PR, ticket) without receiving conversation credentials or managing runtime lifecycle. The service owns conversation identity, profile selection, and runtime attachment. The implementation reuses existing subject locking, coalescing, deterministic conversation IDs, and the agent-turn run machinery from #467.
Analysis
Security model is sound. The run token is a short-lived (24h) HS256 JWT scoped to subject_turn:submit and bound to a specific automation_id + run_id. The router validates the bearer token, checks scope, verifies run_id and automation_id match the URL path and DB record, and requires the requester run to be RUNNING. The script inside the sandbox cannot forge tokens for other runs or automations, and cannot choose an arbitrary conversation ID.
Idempotency and retry logic is well-designed. The unique constraint on (automation_id, source, subject_key, idempotency_key) prevents duplicates at the DB level. The transaction-scoped advisory lock (pg_advisory_xact_lock) serializes concurrent submissions for the same subject, so the SELECT-then-INSERT idempotency check is race-free. The retry path correctly releases failed/skipped runs from the subject lookup (subject_released_at) before creating a replacement, and reuses the deterministic conversation ID so the new attempt continues the same conversation. The single idempotency record is repointed to the new attempt while the superseded run remains in history.
Migration is cross-database compatible. Uses generic sa.Uuid, sa.String, sa.DateTime types. The unique constraint creates an implicit index that covers the idempotency lookup query. The test_migrations_run_on_sqlite test is updated.
Test coverage is strong. 9 test functions (11 with parameterization) cover first-turn creation, deduplication, retry of released failed/canceled/skipped runs, retry of a skipped run that never started, waiting for a failed run that hasn't released, source isolation, token-for-another-run rejection, endpoint acceptance, and continuation without a second run. The tests exercise real DB state and assert on outcomes, not just mocked calls.
Minor Observations (non-blocking)
-
No test for the "queued" disposition. The
queuedpath (turn coalesced into a not-yet-started run) is not directly tested. It's exercised indirectly through_continue_conversation_locked's coalescing logic, but a test that submits two turns for the same subject before the first run is dispatched would close the gap. -
Token signing key reuse.
signing_secret()falls back toservice_key(used for per-user API key minting) orlocal_api_key. The KV token uses a separatekv_secret. Key separation would be marginally better, but both secrets are server-side and never exposed to users, so the risk is theoretical. This follows the same pragmatic pattern as other service-level operations.
Risk Assessment
🟢 LOW — The change adds a new endpoint and table without modifying existing behavior. The dispatcher injection is additive (wrapped in try/except, silently disabled when no secret is configured). The security model is properly scoped. Race conditions are handled with advisory locks and unique constraints. No breaking changes to existing APIs.
Verdict
✅ Worth merging — The design is clean, the security model is sound, and the retry/idempotency logic is correct. The minor testing gap for the "queued" disposition is non-blocking.
Improve this review? If any feedback above seems incorrect or irrelevant to this repository, you can teach the reviewer to do better:
- Add a
.agents/skills/custom-codereview-guide.mdfile to your branch (or edit it if one already exists) with the/codereviewtrigger and the context the reviewer is missing (e.g., "Security concerns about X do not apply here because Y"). See the customization docs for the required frontmatter format.- Re-request a review - the reviewer reads guidelines from the PR branch, so your changes take effect immediately.
- When your PR is merged, the guideline file goes through normal code review by repository maintainers.
Resolve with AI? Install the iterate skill in your agent and run
/iterateto automatically drive this PR through CI, review, and QA until it's merge-ready.Was this review helpful? React with 👍 or 👎 to give feedback.
Automated review used the wrong decision (APPROVED instead of COMMENT) and is dismissed. Findings are reposted as a comment.
|
Successfully posted an APPROVE review to PR #468 (OpenHands/automation). Review summary: The PR adds a scoped
Two minor non-blocking observations were noted in the review body: (1) no direct test for the "queued" disposition, and (2) token signing key reuse with Verdict: ✅ Worth merging — 🟢 LOW risk. Review submitted as APPROVED (Review ID: 5204429946). This comment was posted by an AI agent (OpenHands). |
|
👋 This PR needs a couple of things fixed before OpenHands can review it:
Push an update once this is addressed and this check re-runs automatically. This is an automated check - no AI was used to generate this comment. |
|
@all-hands-bot The current head adds the requested queued-disposition coverage. Please review it and submit an APPROVE review if there are no blocking findings. |
|
🤖 OpenHands is reviewing this PR. Head commit: This comment was posted by an AI agent (OpenHands). |
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was created by an AI agent (OpenHands) on behalf of the repository maintainers.
Summary
This PR adds a scoped POST /v1/runs/{run_id}/subject-turns endpoint that lets a running automation script submit work for an external subject (issue, PR, ticket) without receiving conversation credentials or managing runtime lifecycle. The service owns conversation identity, profile selection, and runtime attachment. The implementation reuses existing subject locking, coalescing, deterministic conversation IDs, and the agent-turn run machinery from #467.
The current head (577c99f) adds a test covering the "queued" disposition that was flagged as a gap in the prior review on cc76156.
What changed since the last review
The new commit 577c99f ("test: cover queued subject turns") adds a single test, test_new_turn_is_queued_on_the_subject_run_before_dispatch, to tests/test_subject_turns.py. No production code was modified.
Analysis of the new test
The test exercises the queued-disposition path end to end:
-
First turn —
submit_subject_turnwithidempotency_key="issue-7-ready-v1"finds no existing subject run, socreate_agent_turn_runcreates a newPENDINGrun withstarted_at=Noneandevent_payload=None. Disposition is"created". -
Second turn —
submit_subject_turnwith a different idempotency key ("issue-7-ready-v2") and different turn text. The duplicate check passes (different key)._continue_conversation_lockedfinds the existing subject run (subject_released_at=None,started_at=None), so it takes the_coalesce_turnbranch, parking"Acceptance criteria changed"intoevent_payload["_automation_follow_up_turns"]and returningcoalesced=True.submit_subject_turnthen setsdisposition = "queued". -
Assertions —
disposition == "queued",run_id == first.run_id(same subject run, not a new one), andevent_payload == {"_automation_follow_up_turns": ["Acceptance criteria changed"]}. I verified thatcreate_agent_turn_rundoes not setstarted_atorevent_payload, so the coalesce path is taken and theevent_payloadassertion is exact.
This directly closes the gap noted in the prior review's minor observation #1 ("No test for the queued disposition"). The queued path is now covered with a real DB-backed run, not an indirect exercise.
Full diff review (unchanged from prior review)
The production code across conversations.py, subject_router.py, utils/run_token.py, models.py, schemas.py, dispatcher.py, app.py, and migration 028 was reviewed on the prior head and is unchanged on this head. The findings from that review remain valid:
- Security model is sound — scoped HS256 JWT bound to
automation_id+run_id, withverify_run_tokenenforcing signature, expiration, scope, run/automation match, andRUNNINGstatus. - Idempotency and retry logic is correct — transaction-scoped
pg_advisory_xact_lockserializes submissions; theUNIQUE(automation_id, source, subject_key, idempotency_key)constraint prevents duplicates; the retry path releases failed/skipped runs before creating a replacement in the same deterministic conversation. - Migration is cross-database compatible — generic SQLAlchemy types, chain
026 → 027 → 028intact.
Lint / format
ruff check and ruff format --check pass on all changed files and on the full openhands/automation/ package.
Test execution note
The subject-turn suite requires Docker/PostgreSQL via testcontainers, which is unavailable in this environment, so I could not execute the 12 tests locally. I verified every code path statically against the models, helpers, and config, including a full trace of the new queued-disposition test.
Risk Assessment
🟢 LOW — The new commit adds test coverage only; no production code changed. The prior review's non-blocking observations are now addressed or remain theoretical.
Verdict
✅ Worth merging — The queued-disposition gap is closed, and the rest of the PR is unchanged from the previously reviewed head. No blocking findings.
Improve this review? If any feedback above seems incorrect or irrelevant to this repository, you can teach the reviewer to do better:
- Add a
.agents/skills/custom-codereview-guide.mdfile to your branch (or edit it if one already exists) with the/codereviewtrigger and the context the reviewer is missing (e.g., "Security concerns about X do not apply here because Y"). See the customization docs for the required frontmatter format.- Re-request a review - the reviewer reads guidelines from the PR branch, so your changes take effect immediately.
- When your PR is merged, the guideline file goes through normal code review by repository maintainers.
Resolve with AI? Install the iterate skill in your agent and run
/iterateto automatically drive this PR through CI, review, and QA until it's merge-ready.Was this review helpful? React with 👍 or 👎 to give feedback.
|
I reviewed the current head ( The new commit adds
No production code was modified in this commit — only the test file. Ruff lint and format pass on all changed files and the full No blocking findings. Approving. Generated by OpenHands AI on behalf of the user. |
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was created by an AI agent (OpenHands) on behalf of the repository maintainers.
Summary
This PR adds a scoped POST /v1/runs/{run_id}/subject-turns endpoint that lets a running automation script submit work for an external subject (issue, PR, ticket) without receiving conversation credentials or managing runtime lifecycle. The service owns conversation identity, profile selection, runtime attachment, and serialization. The implementation reuses existing subject locking, coalescing, deterministic conversation IDs, and the agent-turn run machinery from #467.
Analysis
Security model is sound. The run token is a short-lived (24h) HS256 JWT scoped to subject_turn:submit and bound to a specific automation_id + run_id. The router validates the bearer token, checks scope, verifies run_id and automation_id match the URL path and DB record, and requires the requester run to be RUNNING. The script inside the sandbox cannot forge tokens for other runs or automations, and cannot choose an arbitrary conversation ID.
Idempotency and retry logic is well-designed. The unique constraint on (automation_id, source, subject_key, idempotency_key) prevents duplicates at the DB level. The transaction-scoped advisory lock (pg_advisory_xact_lock) serializes concurrent submissions for the same subject, so the SELECT-then-INSERT idempotency check is race-free. The retry path correctly releases failed/skipped runs from the subject lookup (subject_released_at) before creating a replacement, and reuses the deterministic conversation ID so the new attempt continues the same conversation. The single idempotency record is repointed to the new attempt while the superseded run remains in history.
Migration is cross-database compatible. Uses generic sa.Uuid, sa.String, sa.DateTime types. The unique constraint creates an implicit index that covers the idempotency lookup query. The test_migrations_run_on_sqlite test is updated.
Test coverage is strong. 12 tests cover first-turn creation, deduplication, queued coalescing, retry of released failed/canceled/skipped runs (parameterized), retry of a skipped run that never started, waiting for a failed run that hasn't released, source isolation, token-for-another-run rejection, endpoint acceptance, and continuation without a second run. The tests exercise real DB state and assert on outcomes, not just mocked calls.
Risk Assessment
🟢 LOW — The change adds a new endpoint and table without modifying existing behavior. The dispatcher injection is additive (wrapped in try/except, silently disabled when no secret is configured). The security model is properly scoped. Race conditions are handled with advisory locks and unique constraints. No breaking changes to existing APIs.
Verdict
✅ Worth merging — The design is clean, the security model is sound, and the retry/idempotency logic is correct. No material findings.
Automated review used the wrong decision (APPROVED instead of COMMENT) and is dismissed. Findings are reposted as a comment.
|
I reviewed PR #468 ("feat: add scoped subject-turn submission") in OpenHands/automation and posted an APPROVED review to GitHub. Key findings:
Risk: 🟢 LOW — Additive change, no modifications to existing behavior. Verdict: ✅ Worth merging — submitted as APPROVED per the repository's custom code review guidelines. Review URL: #468 (review) This comment was posted by an AI agent (OpenHands). |
577c99f to
fa3cb65
Compare
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
fa3cb65 to
1cc5af1
Compare
Why
Scheduled automation scripts can identify work, but they have no general way to ask the Automation service to create or resume the agent conversation for a stable external subject. Extension workers consequently duplicate conversation attachment, runtime credentials, and local/Docker lifecycle logic.
The API must also recover after an attempt never completes. A paused automation can skip queued subjects, and a running subject can time out. Permanently deduplicating later submissions against either outcome leaves the external issue or PR stuck forever.
Summary
Add a scoped
POST /v1/runs/{run_id}/subject-turnsoperation. A running automation supplies a source, opaque subject key, prompt, and idempotency key. The service reuses existing subject locking, coalescing, deterministic conversation identity, and the tracked agent-turn run from #467. It reports whether work was created, queued, delivered, or deduplicated.Repeated submissions deduplicate queued, running, successful, and not-yet-released work. Once a failed, canceled, or skipped attempt no longer owns a runtime, the same idempotency key creates another tracked attempt in the same deterministic conversation. The one unique idempotency record follows the current attempt; superseded attempts remain in run history.
The caller receives a short-lived capability token limited to subject submission for its own run and automation. It never receives conversation credentials and cannot choose an arbitrary conversation ID. Extension code only selects work; the Automation service owns conversation and runtime lifecycle.
Issue Number
Closes #463.
Closes #470.
How to Test
Review order and dependencies
Stack #454: #449 → #453 → #466 → #467 → #468. Review and merge in that order.