Commit Graph

6139 Commits

Author SHA1 Message Date
wjiuxing adfa8befbb feat: add Chinese error patterns to RETRYABLE_ERROR_PATTERNS 2026-05-15 22:21:06 +09:00
YeonGyu-Kim e24e495a6b Merge pull request #3322 from RaviTharuma/fix/runtime-fallback-equivalent-skip 2026-05-15 22:17:43 +09:00
Ravi Tharuma d9033d73ae fix(runtime-fallback): keep variant in equivalence
Treat parsed variant as part of runtime-fallback model equivalence so variant-only fallback hops remain distinct while preserving the existing Claude-family alias handling.

Constraint: Oracle verification flagged unresolved PR #3322 review concerns about variant equivalence and remote state
Rejected: Preserve provider identity in equivalence | contradicted the original live-loop fix for equivalent Claude aliases
Confidence: medium
Scope-risk: narrow
Directive: Any future equivalence broadening must prove both live retry-loop behavior and variant/provider semantics with targeted tests before merging
Tested: bun run typecheck
Tested: bun test src/hooks/runtime-fallback/index.test.ts src/hooks/runtime-fallback/error-classifier.test.ts src/plugin/event.model-fallback.test.ts
Not-tested: Full live end-to-end repro across all provider redundancy policies
2026-05-15 22:05:27 +09:00
Ravi Tharuma f501c47c49 fix(runtime-fallback): skip equivalent claude aliases
Prevent runtime fallback from cycling through provider aliases that resolve to the same underlying Claude family model. This keeps retry handling moving toward a genuinely distinct fallback model instead of appearing to fallback while staying on the same effective model.

Constraint: Live retry/fallback bug is in /Users/ravi/Code/personal/oh-my-opencode, while oh-my-openagent contribution work remains isolated to /Users/ravi/Code/forks/oh-my-openagent
Rejected: Change fallback chain precedence (category vs agent) first | lower-confidence root cause than equivalent-model retry
Confidence: high
Scope-risk: narrow
Directive: Keep alias-equivalence logic limited to model families that are intentionally interchangeable for runtime failover, and expand with targeted tests before broadening provider-family collapsing
Tested: bun run typecheck
Tested: bun test src/hooks/runtime-fallback/index.test.ts src/hooks/runtime-fallback/error-classifier.test.ts src/plugin/event.model-fallback.test.ts
Not-tested: Full live end-to-end session repro against external provider outages
2026-05-15 22:05:00 +09:00
YeonGyu-Kim f54888b2fe Merge pull request #3576 from Disaster-Terminator/fix/background-busy-stall-detection 2026-05-15 21:56:31 +09:00
YeonGyu-Kim 27788b4ab0 fix(session-recovery): audit raw prompt aliases 2026-05-15 21:53:05 +09:00
YeonGyu-Kim 4a1c260d8b test(todo-continuation): cover peer-message reservation holds 2026-05-15 21:52:53 +09:00
YeonGyu-Kim 39fef2042b fix(background-agent): resolve parent wake agent aliases 2026-05-15 21:52:40 +09:00
YeonGyu-Kim 2bd4944bad fix(prompt-gate): scope reservation releases 2026-05-15 21:52:29 +09:00
Disaster-Terminator b6caa5d3e0 fix(background-agent): correct stall timeout guidance 2026-05-15 21:44:29 +09:00
Disaster-Terminator 189af23e96 fix(background-agent): detect stalled active sessions 2026-05-15 21:44:29 +09:00
YeonGyu-Kim 2eec0d96d9 Merge pull request #3319 from EZotoff/fix/remove-activity-stagnation-bypass 2026-05-15 21:36:09 +09:00
YeonGyu-Kim 65c1283338 fix(todo-continuation): clean up idle event diagnostics 2026-05-15 21:29:21 +09:00
Evgeny Zotov 047ca069a2 test: rename test to reflect todo-only stagnation check
Address review feedback: test name no longer references 'tool activity'
since activity tracking was removed.
2026-05-15 21:11:08 +09:00
Evgeny Zotov 68e9d54fa5 fix(todo-continuation): remove activity-based stagnation bypass
Activity signals (tool calls like compress, grep, bash) were treated as
'progress' by the stagnation detector, resetting the stagnation counter
every cycle. This prevented MAX_STAGNATION_COUNT from being reached,
causing infinite continuation loops when models degrade to minimal
responses in long sessions (e.g. GLM-5.1 at ~100K tokens).

Stagnation now only tracks actual todo state changes: incomplete count
decrease, completed count increase, or todo snapshot change. Tool-level
activity no longer resets the stagnation counter.
2026-05-15 21:11:08 +09:00
YeonGyu-Kim fe66c96215 Merge pull request #4053 from code-yeongyu/supersede/3866-tool-result-schema
fix(tool-pair-validator,session-recovery): schema-compatible synthetic tool results (supersedes #3866)
2026-05-15 21:04:45 +09:00
rshks b504fb1deb fix(tool-pair-validator): emit schema-compatible synthetic tool results 2026-05-15 21:04:03 +09:00
YeonGyu-Kim 24f7e560ca Merge pull request #4051 from code-yeongyu/supersede/3952-first-prompt-watchdog
fix(runtime-fallback): first-prompt watchdog for silently-stuck subagents (supersedes #3952)
2026-05-15 20:51:30 +09:00
Ivan Smetanin 3199bd3d90 fix(runtime-fallback): broaden watchdog progress detection + harden test timing
Addresses two issues identified by cubic on PR #3952.

1. Watchdog cancellation was too narrow — only `text`/`reasoning` parts
   counted as progress, so a subagent that immediately ran tools
   (Read/Bash/Edit) emitted `tool`/`tool_use`/`tool_result`/`tool-call`/
   `step-start` parts that the watchdog ignored, risking a false fire
   on actively-working subagents. Broaden to: any assistant part of any
   known type counts as progress (the model has started responding,
   whether or not visible text has arrived yet). `info.error` and
   `info.finish` continue to cancel.

2. Test timing margins were tight (15ms pre-cancel against a 40ms
   timer), risking CI flakiness on loaded runners. Bumped to a 100ms
   threshold with a 40ms pre-cancel window and a 250ms post-fire wait,
   giving a 60ms margin before the timer fires and ~2.5x the threshold
   after — robust against scheduler delay.

Refactor for testability: extracted the OpenCode-event→watchdog-signal
translation out of `hook.ts` into an exported `observeEventForWatchdog`
helper on the watchdog module. This let me add direct unit tests for
every part-type case (text, reasoning, tool, tool_use, tool_result,
tool-call, step-start, file) plus the error/finish/empty-parts branches
without spinning up the full hook. Net diff: hook.ts shrinks, watchdog
module gains a small pure function with parametrised coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:47:03 +09:00
Ivan Smetanin a130fa70d1 fix(runtime-fallback): add first-prompt watchdog for stuck subagents
When a subagent is dispatched to a provider and the underlying SDK
enters a silent internal retry loop on a 429/quota error, no error
event is ever emitted back to OpenCode. The runtime-fallback hook —
which is fully reactive (listens to message.updated/session.error/
session.status) — has nothing to react to and never dispatches the
configured fallback. The subagent sits in `retry` status until the
parent's 30-minute poll timeout (DEFAULT_POLL_TIMEOUT_MS) gives up,
during which the parent's pending task tool call shows "waiting for
subagent" with no indication of failure.

This change adds a first-prompt watchdog that synthesises the missing
error-event trigger:

  - Armed when a user message lands in a subagent session
    (membership check via `subagentSessions`).
  - Cancelled on the first sign of progress: any assistant message
    with text/reasoning content, finish field, or an error field (any
    of which is something the existing handlers will deal with).
  - Cancelled on session terminal events (idle/stop/deleted/error).
  - On fire (90s default): aborts the in-flight request and routes
    into the existing dispatchFallbackRetry path — the same code that
    runs when a session.error arrives. No new fallback mechanism.

Design choices:

  - Dispatch fallback, do not abort the subagent outright. Network
    loss looks identical to a stuck retry from the hook's vantage
    point; with fallback-dispatch behaviour, network loss degrades
    to today's baseline (both attempts fail, 30-min outer timeout
    still ends things) rather than destructively aborting work.
  - Scope strictly to subagents. Parent/user sessions can legitimately
    take 90s+ to produce the first token; subagent dispatches in
    practice produce first content much faster, so a 90s ceiling is
    safe.
  - Threshold is tunable via the third arg to createFirstPromptWatchdog;
    DEFAULT_FIRST_PROMPT_WATCHDOG_MS = 90_000 in constants.ts.

Also adds a diagnostic log in session-status-handler when a
`session.status: retry` event arrives whose message does not match
RETRYABLE_ERROR_PATTERNS. This is the hook's other silent-return
spot for retry events; logging the raw retry message will let us
extend the patterns next time we hit a provider whose phrasing
we don't yet match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:45:46 +09:00
YeonGyu-Kim bda0452b2a Merge pull request #4029 from sandikodev/fix/json-error-recovery-exclude-todowrite
fix(json-error-recovery): add todowrite and todoread to exclude list
2026-05-15 20:27:42 +09:00
YeonGyu-Kim f835244d42 Merge pull request #4047 from PeterPonyu/fix/3894-skip-tmux-layout-when-server-unreachable
fix(team-mode): skip tmux layout when opencode server unreachable
2026-05-15 20:25:22 +09:00
YeonGyu-Kim e66d60f4c5 Merge pull request #3773 from cailgarrisk-collab/fix/glm-rate-limit-fallback-statuscode
fix(model-fallback): add HTTP statusCode check for GLM rate limit fallback
2026-05-15 20:04:22 +09:00
YeonGyu-Kim 5cda8b8fe8 Merge pull request #3330 from codeg-dev/fix/isplan-display-name-getAgentConfigKey
fix(delegate-task): apply getAgentConfigKey normalization to isPlanAgent
2026-05-15 19:57:41 +09:00
YeonGyu-Kim a328343622 Merge pull request #3299 from kilhyeonjun/fix/claude-code-settings-hooks-not-executed
fix: don't early-return on 'allow' in executePreToolUseHooks, accumulate hook outputs
2026-05-15 19:57:37 +09:00
YeonGyu-Kim 0036c203a2 Merge pull request #3934 from Qihao0v0/fix/unifyllm-quota-classifier
fix(runtime-fallback): classify localized balance failures as quota exhaustion
2026-05-15 19:57:34 +09:00
YeonGyu-Kim c6054af9fa Merge pull request #3872 from x-x-gpu/dev
fix: pass resolved model to session.create so sub-agent sessions use the correct model
2026-05-15 19:56:09 +09:00
YeonGyu-Kim 7da44232a1 Merge pull request #4049 from code-yeongyu/supersede/3790-session-firstmessage-no-clear
fix(hooks): do not clear sessionFirstMessageProcessed on session.idle (supersedes #3790)
2026-05-15 19:51:22 +09:00
brooksbUWO 9f6b68118e fix(hooks): do not clear sessionFirstMessageProcessed on session.idle
SessionStart hooks fire on every user prompt instead of only at session
start. The root cause is clearSessionHookState(), called on every
session.idle event, which clears sessionFirstMessageProcessed. This
resets the isFirstMessage guard, making it always return true, so
SessionStart hooks execute on every prompt.

sessionFirstMessageProcessed is session-level state (tracks whether the
first message has been processed) and should only be cleared in
clearAllSessionHookState() on session deletion/disposal, not on idle.

sessionErrorState and sessionInterruptState remain cleared on idle since
they are per-response transient state.
2026-05-15 19:50:14 +09:00
PeterPonyu bd3928e158 fix(team-mode): skip tmux layout when opencode server unreachable
`createManagers` unconditionally called `markServerRunningInProcess()`
whenever `tmuxConfig.enabled` was true, which made `isServerRunning()`
short-circuit to `true` for *any* serverUrl — bypassing the guard in
`createTeamLayout` that is supposed to skip pane creation when the
opencode server is not running.

When a user launches vanilla `opencode` (no `opencode serve` /
`opencode web`), `ctx.serverUrl` is undefined and the TmuxSessionManager
falls back to `http://localhost:4096`. With the in-process flag set, the
team layout proceeded to spawn tmux panes whose `opencode attach`
commands then failed with "Unable to connect" — exactly the symptom in
the bug report.

Only mark the server as in-process running when the SDK actually
provides `ctx.serverUrl`. When it does not, `isServerRunning()` falls
back to a real HTTP probe, the existing guard in `createTeamLayout`
returns null, and no panes are created.

Closes #3894
2026-05-15 06:46:07 -04:00
YeonGyu-Kim ac66a43e99 Merge pull request #4046 from code-yeongyu/fix/3494-strip-zwsp-before-promptasync
fix(atlas,todo-continuation): strip ZWSP sort prefix before promptAsync agent (fixes #3494, supersedes #3547)
2026-05-15 19:45:21 +09:00
YeonGyu-Kim 7caf74a9b9 fix(atlas,todo-continuation): strip ZWSP sort prefix before promptAsync agent
Both injectors call resolveRegisteredAgentName, which returns the
registered alias verbatim. OpenCode TUI registers agent names with
leading zero-width characters (U+200B) for sort ordering, so that
alias can be e.g. "\u200B\u200BAtlas - Plan Executor". Passing it
directly to promptAsync produces "Agent not found" because the
OpenCode SDK does an exact match against its canonical display
name registry.

Strip the ZWSP sort prefix on the resolved name before sending it
to promptAsync in:
- src/hooks/atlas/boulder-continuation-injector.ts
- src/hooks/todo-continuation-enforcer/continuation-injection.ts

Add regression tests asserting promptAsync receives the canonical
display name (no \u200B) even when the registered alias carries
a ZWSP sort prefix. Same root cause class as #3494 / #3547. Tests
were RED on dev before the fix and GREEN after.
2026-05-15 19:44:44 +09:00
YeonGyu-Kim 2b43147c41 Merge pull request #4045 from code-yeongyu/supersede/3901-call-omo-agent-display-name
fix(call-omo-agent): translate config-key subagent_type to display name before SDK dispatch (supersedes #3901)
2026-05-15 19:34:21 +09:00
Sami Jawhar 10f721de1f fix(call-omo-agent): translate config-key subagent_type to display name before SDK dispatch 2026-05-15 19:32:34 +09:00
YeonGyu-Kim 437a8edba6 Merge pull request #4007 from PeterPonyu/feat/runtime-fallback-internal-abort
fix(runtime-fallback): preserve attemptCount when our own abort is the cause
2026-05-15 19:26:53 +09:00
YeonGyu-Kim 5e7ee9418a Merge pull request #3982 from jas32096/fix/category-fallback-ignored-when-primary-set
fix(delegate-task): honor user fallback_models when category primary is unreachable
2026-05-15 19:26:37 +09:00
YeonGyu-Kim 83ab000963 Merge pull request #3972 from MoerAI/fix/circuit-breaker-tool-input-fallback
fix(background-agent): fall back to partInfo.input when state.input is unavailable for circuit breaker (fixes #3962)
2026-05-15 19:20:36 +09:00
YeonGyu-Kim e2b8e49e2f Merge pull request #4044 from code-yeongyu/revert/3825-delegated-bootstrap
Revert "Merge pull request #3825 from tw-yshuang/fix/delegated-child-session-early-failure-fallback"
2026-05-15 19:18:26 +09:00
YeonGyu-Kim 3c7d1299a7 Revert "Merge pull request #3825 from tw-yshuang/fix/delegated-child-session-early-failure-fallback"
This reverts commit cd33f3a397, reversing
changes made to 521c99cf0b.
2026-05-15 19:13:48 +09:00
YeonGyu-Kim cd33f3a397 Merge pull request #3825 from tw-yshuang/fix/delegated-child-session-early-failure-fallback
fix(delegate-task): harden child-session first-prompt fallback recovery
2026-05-15 19:06:43 +09:00
YeonGyu-Kim 521c99cf0b Merge pull request #3950 from ismetanin/fix/surface-subagent-quota-error
fix(runtime-fallback): surface quota errors from stuck subagents
2026-05-15 19:05:34 +09:00
YeonGyu-Kim f00a69398d Merge pull request #3947 from MoerAI/fix/process-cleanup-opt-out-env
fix(background-agent): add OMO_DISABLE_PROCESS_CLEANUP env opt-out for global handlers (fixes #3856)
2026-05-15 18:56:38 +09:00
YeonGyu-Kim c3319c753f Merge pull request #3470 from omer-koren/fix/thinking-block-modified-recovery
fix(session-recovery): add thinking_block_modified error detection and recovery
2026-05-15 18:55:42 +09:00
YeonGyu-Kim 984b8c1a3d Merge pull request #4032 from PeterPonyu/fix/3996-tool-pair-validator-background-sessions
fix(tool-pair-validator): skip placeholder repair for subagent sessions
2026-05-15 18:50:44 +09:00
YeonGyu-Kim 15b0a41fe9 Merge pull request #4043 from code-yeongyu/fix/session-recovery-stale-error-dedupe
fix(session-recovery): persist dedupe across stale repeated session.error
2026-05-15 18:44:44 +09:00
YeonGyu-Kim 8e9dea949b fix(session-recovery): persist dedupe across stale repeated session.error
processingErrors was emptied in a finally block, so a second
session.error fired for the same assistant message id after the
first recovery resolved would re-run abort, history fetch, the
recovery toast, and any auto-resume promptAsync (resumeSession),
producing duplicate internal prompt injections during stale event
re-emission or polling-driven retries.

Drop the in-flight delete and keep the dedupe permanent for the
plugin lifetime. A genuinely new failure starts a new assistant
message with a different id, so this never blocks future legitimate
errors. Same-id duplicates collapse into a single recovery attempt.

Add hook.test.ts asserting that two sequential handleSessionRecovery
calls for the same recoverable info trigger session.abort, the
recovery toast, and any internal promptAsync at most once.
2026-05-15 18:43:53 +09:00
YeonGyu-Kim cb87385086 test(ci): isolate runtime and rules dependencies 2026-05-15 18:36:32 +09:00
YeonGyu-Kim a02686e729 test(ci): remove suite-order mock coupling 2026-05-15 18:21:04 +09:00
YeonGyu-Kim f1fb1e08eb fix(ralph-loop): send registered agent display name on continue
Continuation injector previously called normalizeAgentForPromptKey,
which collapsed agent inputs like "Sisyphus - Ultraworker" or
"sisyphus" down to the lowercase config key (e.g. "sisyphus").
OpenCode's promptAsync rejects that with "Agent not found", so the
ralph-loop continue prompt silently failed to dispatch on parent
sessions whose inherited message used a known display name.

Switch to normalizeAgentForPrompt and add a small wrapper that:
- preserves any agent string already in canonical " - " display form
  verbatim (covers ZWSP-prefixed inheritance and user-defined custom
  agents)
- otherwise normalizes config keys / legacy parenthesized names to the
  registered display name OpenCode expects.

Update the existing regression tests so that ZWSP-prefixed and clean
inherited agents both assert the registered display name reaches
promptAsync.
2026-05-15 18:19:58 +09:00
YeonGyu-Kim b3b2da89c9 test(ci): avoid global module mock leaks 2026-05-15 17:54:59 +09:00