agent-orchestrator/packages/core/src
Joakim Sigvardt a64c051e9f
fix(lifecycle): implement stuck detection using agent-stuck threshold (#376)
* fix(lifecycle): implement stuck detection using agent-stuck threshold

The agent-stuck reaction config supported a threshold field (e.g.
"10m"), but determineStatus() never returned "stuck" — there was no
code path that consumed the threshold or transitioned sessions based
on idle time. Sessions would stay parked at pr_open/working forever
even when the agent had been idle for hours.

Added idle-time check in determineStatus(): when getActivityState()
reports "idle" or "blocked" with a timestamp, compare the idle
duration against the agent-stuck.threshold config. If exceeded,
return "stuck" so the reaction system can fire notifications.

Also removed the priority !== "info" guard on transition
notifications, so all priority levels (including info) are routed
through notificationRouting. This lets the config control which
notifiers receive each priority level, rather than silently dropping
info-level transition events.

* fix(lifecycle): add post-PR stuck detection as safety net

The original stuck check in step 2 (before PR checks) can be bypassed
when getActivityState() returns null (session file not found, cache miss,
I/O failure). When this happens, the code falls through to the PR path
which returns 'pr_open' without ever checking idle duration.

Fix: extract isIdleBeyondThreshold() helper and call it in three places:
1. Step 2: before PR checks (fast path, catches most cases)
2. Step 4b: after PR checks return 'pr_open' (safety net)
3. Step 5: after all checks, for agents that finish without a PR

This ensures stuck detection fires even when the JSONL activity detection
fails to return idle state. Sessions can no longer get permanently stuck
at 'pr_open' when the agent has been idle beyond the threshold.

Also removes the debug console.error calls from the previous commit.

* fix(lifecycle): treat reviewDecision 'none' as approved for merge readiness

PRs with no required reviewers never reached 'mergeable' status because
getReviewDecision returned 'none', which was not handled. The lifecycle
poll fell through to 'review_pending' or the default, so merge.ready
never fired and the approved-and-green reaction never triggered.

Also: skip stuck short-circuit when session has an open PR so merge
readiness checks in step 4 can still run. Without this, idle agents
with open PRs get stuck status and never transition to mergeable.

Closes composio#0 (internal fix)

* fix(opencode): classify activity state from session timestamps

* test(lifecycle): cover opencode idle-threshold stuck transition

* fix(lifecycle): preserve global stuck threshold with project overrides

* fix(lifecycle): run PR auto-detection before stuck transitions

---------

Co-authored-by: Harsh <harshb012@gmail.com>
2026-03-13 10:02:33 +05:30
..
__tests__ fix(lifecycle): implement stuck detection using agent-stuck threshold (#376) 2026-03-13 10:02:33 +05:30
recovery feat: support distinct worker and orchestrator agents (#439) 2026-03-12 20:58:55 +05:30
utils fix: preserve project ownership for legacy sessions 2026-03-11 23:27:48 +05:30
agent-selection.ts feat: support distinct worker and orchestrator agents (#439) 2026-03-12 20:58:55 +05:30
atomic-write.ts feat(core): add feedback tools contracts, validation, storage, and dedupe 2026-03-10 22:31:39 +05:30
config-generator.ts feat: add `ao start <url>` one-command project onboarding (#267) 2026-03-03 13:52:49 +05:30
config.ts feat: support distinct worker and orchestrator agents (#439) 2026-03-12 20:58:55 +05:30
decomposer.ts feat: lifecycle manager, backlog auto-claim, task decomposition, and verification gate (#365) 2026-03-10 12:31:25 +05:30
feedback-tools.ts feat(core): add feedback tools contracts, validation, storage, and dedupe 2026-03-10 22:31:39 +05:30
global-pause.ts fix: pause workers on model limits and stabilize session visibility (#367) 2026-03-10 08:42:17 +05:30
index.ts feat: add end-to-end observability across core, web, and terminal (#436) 2026-03-12 16:57:40 +05:30
key-value.ts feat(core): add feedback tools contracts, validation, storage, and dedupe 2026-03-10 22:31:39 +05:30
lifecycle-manager.ts fix(lifecycle): implement stuck detection using agent-stuck threshold (#376) 2026-03-13 10:02:33 +05:30
metadata.ts feat(core): add feedback tools contracts, validation, storage, and dedupe 2026-03-10 22:31:39 +05:30
observability.ts feat: add end-to-end observability across core, web, and terminal (#436) 2026-03-12 16:57:40 +05:30
opencode-session-id.ts feat: OpenCode session lifecycle and CLI controls (#315) 2026-03-08 09:55:44 +05:30
orchestrator-prompt.ts fix: prevent orchestrator sessions from owning PRs (#432) 2026-03-11 22:04:38 +05:30
orchestrator-session-strategy.ts feat: OpenCode session lifecycle and CLI controls (#315) 2026-03-08 09:55:44 +05:30
paths.ts feat: add end-to-end observability across core, web, and terminal (#436) 2026-03-12 16:57:40 +05:30
plugin-registry.ts fix(core): wire built-in GitLab integrations (#393) 2026-03-10 12:57:35 +05:30
prompt-builder.ts feat: lifecycle manager, backlog auto-claim, task decomposition, and verification gate (#365) 2026-03-10 12:31:25 +05:30
scm-webhook-utils.ts feat: add SCM webhook lifecycle triggers (#394) 2026-03-11 10:34:41 +05:30
session-manager.ts fix: protect orchestrators from session cleanup (#453) 2026-03-13 09:39:49 +05:30
tmux.ts fix: increase delays in spawn prompt submission to ensure Enter is processed (#62) 2026-02-16 20:31:07 +05:30
types.ts feat: support distinct worker and orchestrator agents (#439) 2026-03-12 20:58:55 +05:30
utils.ts feat(ao): add OpenClaw notifier plugin for AO escalations 2026-03-09 18:24:30 +05:30