Commit Graph

147 Commits

Author SHA1 Message Date
YeonGyu-Kim b4e13883b1 fix(background-agent): fix 3 memory leaks in task lifecycle management
H3: cancelTask(skipNotification=true) now schedules task removal.
Previously the early return path skipped cleanup, leaking task objects
in this.tasks Map permanently. Extracted scheduleTaskRemoval() helper
called from both skipNotification and normal paths.

H2: Per-task completion cleanup timer decoupled from allComplete check.
Previously cleanup timer only ran when ALL sibling tasks completed. Now
each finished task gets its own removal timer regardless of siblings.

H1+C2: TaskHistory.clearAll() added and wired into shutdown(). Added
clearSession() calls on session error/deletion and prune cycles.
taskHistory was the only data structure missed by shutdown().

Tests: 10 pass (3 cancel + 3 completion + 4 history)
2026-03-12 01:37:03 +09:00
YeonGyu-Kim 4b5c47172d Merge pull request #2449 from code-yeongyu/fix/issue-2330-v2
fix(background-agent): cap recursive subagent spawning
2026-03-11 21:00:34 +09:00
YeonGyu-Kim 594233183b fix(background-agent): fail closed on spawn lineage lookup errors
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-11 20:57:09 +09:00
YeonGyu-Kim e3b17da4bd fix(background-agent): preserve terminal tasks until notification cleanup
Route terminal task cleanup through parent notifications so cancelled and errored tasks stay visible until delayed cleanup finishes.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-11 20:50:49 +09:00
YeonGyu-Kim a179ebe0b9 Count sync subagent spawns against descendant limits 2026-03-11 20:50:11 +09:00
YeonGyu-Kim 4a39c83eb5 Limit recursive subagent spawning 2026-03-11 20:50:10 +09:00
YeonGyu-Kim 3550305af8 Merge branch 'dev' into fix/issue-2232 2026-03-11 20:20:04 +09:00
YeonGyu-Kim 413e8b73b7 Add session permission support to background agents for denying questions
Implements question-denied session permission rules when creating child
sessions via background task delegation. This prevents subagents from
asking questions by passing explicit permission configuration during
session creation.

🤖 GENERATED WITH ASSISTANCE OF OhMyOpenCode
2026-03-11 19:42:46 +09:00
YeonGyu-Kim 1120885fd0 fix(background-agent): release interrupted task slots during startup cleanup
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-09 12:36:49 +09:00
YeonGyu-Kim 85aa744c8a fix(background-agent): clear toast tracking when tasks stop
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2026-03-09 11:39:04 +09:00
YeonGyu-Kim dc370f7fa8 fix: handle undefined sessionStatus in pollRunningTasks (#2387)
When a completed session is no longer returned by session.status(),
allStatuses[sessionID] is undefined. Previously this fell through to
a 'still running' log, leaving the task stuck as running forever.

Match the sync-session-poller pattern: only continue (skip completion
check) when sessionStatus EXISTS and is not idle. When undefined,
fall through to validateSessionHasOutput + checkSessionTodos +
tryCompleteTask, same as idle.
2026-03-08 23:42:11 +09:00
YeonGyu-Kim 2b5dec5333 fix(background-agent): use compaction-aware prompt context in manager
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-08 02:23:33 +09:00
YeonGyu-Kim 050b93bebb fix(background-agent): clean pendingNotifications on session.deleted 2026-02-27 03:00:39 +09:00
YeonGyu-Kim 840c612be8 fix(background-agent): queue notifications for idle parent sessions
When a background task completes and the parent session is waiting for
user input, promptAsync() fails with an aborted error. Previously the
notification was silently dropped — lost forever.

Fix: queue the notification text in-memory on the BackgroundManager
when promptAsync fails with an aborted/idle error. On the user's next
message to that session, the queued notifications are injected into the
chat context before the agent sees the message.

- BackgroundManager: add pendingNotifications map + queuePendingNotification()
  and injectPendingNotificationsIntoChatMessage() methods
- background-notification hook: add chat.message handler that calls injection
- chat-message.ts: wire backgroundNotificationHook.chat.message into the
  message processing chain
- Add tests covering queue-on-abort and next-message delivery
2026-02-25 16:26:31 +09:00
YeonGyu-Kim 2428a46e6d refactor(features/background-agent): remove dead code submodules
Delete 15 unused files in background-agent module:

- background-task-completer.ts

- format-duration.ts

- message-dir.ts

- parent-session-context-resolver.ts

- parent-session-notifier.ts (and its test file)

- result-handler-context.ts

- result-handler.ts

- session-output-validator.ts

- session-task-cleanup.ts

- session-todo-checker.ts

- spawner/background-session-creator.ts

- spawner/concurrency-key-from-launch-input.ts

- spawner/spawner-context.ts

- spawner/tmux-callback-invoker.ts

Update index.ts barrel and manager.ts/spawner.ts imports

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-23 02:43:01 +09:00
YeonGyu-Kim a3e4f904a6 refactor(background-agent): wire session-idle-event-handler into manager, add unit tests
The extracted handleSessionIdleBackgroundEvent was never imported by
manager.ts — dead code from incomplete refactoring (d53bcfbc). Replace
the inline session.idle handler (58 LOC) with a call to the extracted
function, remove unused MIN_IDLE_TIME_MS import, and add 13 unit tests
covering all edge cases.
2026-02-22 15:30:40 +09:00
YeonGyu-Kim d1e5bd63c1 fix: address Oracle + Cubic review feedback for background-agent refactoring
- Revert getMessageDir to original join(MESSAGE_STORAGE, sessionID) behavior
- Fix dead subagentSessions.delete by capturing previousSessionID before tryFallbackRetry
- Add .unref() to process cleanup setTimeout to prevent 6s hang on Ctrl-C
- Add missing isUnstableAgent to fallback retry input mapping
- Fix process-cleanup tests to use exit listener instead of SIGINT at index 0
- Swap test filenames in compaction-aware-message-resolver to exercise skip logic correctly
2026-02-22 12:14:26 +09:00
YeonGyu-Kim d53bcfbced refactor(background-agent): extract inline logic from manager.ts into focused modules
Extract 5 concerns from BackgroundManager into dedicated modules:
- error-classifier.ts: enhance with extractErrorName, extractErrorMessage, getSessionErrorMessage, isRecord
- fallback-retry-handler.ts: standalone tryFallbackRetry with full retry logic
- process-cleanup.ts: registerManagerForCleanup/unregisterManagerForCleanup
- compaction-aware-message-resolver.ts: isCompactionAgent/findNearestMessageExcludingCompaction
- Delete notification-builder.ts (duplicate of background-task-notification-template.ts)

Manager.ts method bodies now delegate to extracted modules.
Wire duration-formatter.ts and task-poller.ts (existing but unused).

manager.ts: 2036 -> 1647 LOC (19% reduction).
All 161 existing tests pass unchanged.
2026-02-22 11:58:57 +09:00
YeonGyu-Kim fe415319e5 fix: resolve publish blockers for v3.7.4→v3.8.0 release
- Fix #1991 crash: optional chaining for task-history sessionID access
- Fix #1992 think-mode: add antigravity entries to HIGH_VARIANT_MAP
- Fix #1949 Copilot premium misattribution: use createInternalAgentTextPart
- Fix #1982 load_skills: pass directory to discoverSkills for project-level skills
- Fix command priority: sort scopePriority before .find(), project-first return
- Fix Google provider transform: apply in userFallbackModels path
- Fix ralph-loop TUI: optional chaining for event handler
- Fix runtime-fallback: unify dual fallback engines, remove HTTP 400 from retry,
  fix pendingFallbackModel stuck state, add priority gate to skip model-fallback
  when runtime-fallback is active
- Fix Prometheus task system: exempt from todowrite/todoread deny
- Fix background_output: default full_session to true
- Remove orphan hooks: hashline-edit-diff-enhancer (redundant with hashline_edit
  built-in diff), task-reminder (dead code)
- Remove orphan config entries: 3 stale hook names from Zod schema
- Fix disabled_hooks schema: accept arbitrary strings for forward compatibility
- Register json-error-recovery hook in tool-guard pipeline
- Add disabled_hooks gating for question-label-truncator, task-resume-info,
  claude-code-hooks
- Update test expectations to match new behavior
2026-02-21 16:24:18 +09:00
YeonGyu-Kim fb4530cafe fix(provider-matching): normalize provider names to lowercase for connectivity checks
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
2026-02-21 03:33:20 +09:00
YeonGyu-Kim 481106a12e Merge branch 'pr-1959' into dev
# Conflicts:
#	src/hooks/index.ts
#	src/plugin/event.ts
#	src/tools/delegate-task/sync-task.ts
2026-02-21 02:49:39 +09:00
youming.tang cd3e0ca124 fix(session-category-registry): cleanup entries for task sessions 2026-02-21 02:31:42 +09:00
sjawhar 03f7643ee1 fix(background-agent): respect agent tool restrictions in background task launch
Reorder tool permission spread so getAgentToolRestrictions() comes
last, allowing agent-specific restrictions to override defaults.
Fixes all 3 sites: task-starter.ts (startTask), manager.ts (startTask
and resume paths).

Previously, defaults like call_omo_agent:true would stomp agent
restrictions (e.g., explore's call_omo_agent:false) due to JS
spread semantics.
2026-02-21 02:29:00 +09:00
VespianRex f5f1d1d4c2 Fix model fallback across main/background/sync agents 2026-02-20 17:45:53 +02:00
Maxim Harizanov 64e8e164aa fix(copilot): mark internal background notifications as agent-initiated 2026-02-19 13:17:02 +02:00
YeonGyu-Kim 096db59399 fix(run): inherit main-session tool permissions for continuation prompts 2026-02-18 21:10:21 +09:00
YeonGyu-Kim 2b5887aca3 fix: prevent overlapping poll cycles in managers
Guarding polling re-entry avoids stacked async polls under slow responses, and unref on pending-call cleanup timer reduces idle wakeups.
2026-02-17 03:06:40 +09:00
YeonGyu-Kim 285d8d58dd fix: skip compaction messages in parent-session context lookup 2026-02-17 02:03:03 +09:00
YeonGyu-Kim 5aa9ecdd5d Merge pull request #1870 from dankochetov/fix/background-notification-hook-gate
fix(background-agent): honor disabled background-notification for system reminders
2026-02-17 01:35:21 +09:00
YeonGyu-Kim 1ba330f8ca refactor: remove unused code from background-agent, background-task, call-omo-agent 2026-02-16 22:11:29 +09:00
Dan Kochetov 9b187e2128 Merge remote-tracking branch 'origin/dev' into fix/background-notification-hook-gate
# Conflicts:
#	src/features/background-agent/manager.ts
2026-02-16 13:56:33 +02:00
YeonGyu-Kim 1a6810535c refactor: create normalizeSDKResponse helper and replace scattered patterns across 37 files 2026-02-16 18:20:19 +09:00
YeonGyu-Kim 5a6a9e9800 fix: defensive SDK response handling & parts-reader normalization
- Replace all response.data ?? [] with (response.data ?? response)
  pattern across 14 files to handle SDK array-shaped responses
- Normalize SDK parts in parts-reader.ts by injecting sessionID/
  messageID before validation (P1: SDK parts lack these fields)
- Treat unknown part types as having content in
  recover-empty-content-message-sdk.ts to prevent false placeholder
  injection on image/file parts
- Replace local isRecord with shared import in parts-reader.ts
2026-02-16 16:13:40 +09:00
YeonGyu-Kim d3574a392f fix: cancel completion timer on resume and prevent silent notification drop 2026-02-16 16:06:36 +09:00
YeonGyu-Kim 33d290b346 fix: add toast cleanup to all BackgroundManager task removal paths
TaskToastManager entries were never removed when tasks completed via
error, session deletion, stale pruning, or cancelled with
skipNotification. Ghost entries accumulated indefinitely, causing the
'Queued (N)' count in toast messages to grow without bound.

Added toastManager.removeTask() calls to all 4 missing cleanup paths:
- session.error handler
- session.deleted handler
- cancelTask with skipNotification
- pruneStaleTasksAndNotifications

Closes #1866
2026-02-16 13:50:57 +09:00
Dan Kochetov 5298ff2879 fix(background-agent): allow disabling parent session reminders 2026-02-16 00:58:33 +02:00
YeonGyu-Kim 8a5f61724d fix(background-agent): handle message.part.delta for heartbeat (OpenCode >=1.2.0)
OpenCode 1.2.0+ changed reasoning-delta and text-delta to emit
'message.part.delta' instead of 'message.part.updated'. Without
handling this event, lastUpdate was only refreshed at reasoning-start
and reasoning-end, leaving a gap where extended thinking (>3min)
could trigger stale timeout.

Accept both event types as heartbeat sources for forward compatibility.
2026-02-15 14:26:25 +09:00
YeonGyu-Kim 3f557e593c fix(background-agent): use correct OpenCode session status for stale guard
OpenCode uses 'busy'/'retry'/'idle' session statuses, not 'running'.
The stale timeout guard checked for type === 'running' which never
matched, leaving all background tasks vulnerable to stale-kill even
when their sessions were actively processing.

Change sessionIsRunning to check type !== 'idle' instead, protecting
busy and retrying sessions from premature termination.
2026-02-15 14:24:45 +09:00
YeonGyu-Kim a0c9381672 fix: prevent stale timeout from killing actively running background tasks
The stale detection was checking lastUpdate timestamps BEFORE
consulting session.status(), causing tasks to be unfairly killed
after 3 minutes even when the session was actively running
(e.g., during long tool executions or extended thinking).

Changes:
- Reorder pollRunningTasks to fetch session.status() before stale check
- Skip stale-kill entirely when session status is 'running'
- Port no-lastUpdate handling from task-poller.ts into manager.ts
  (previously manager silently skipped tasks without lastUpdate)
- Add sessionStatuses parameter to checkAndInterruptStaleTasks
- Add 7 new test cases covering session-status-aware stale detection
2026-02-14 17:59:01 +09:00
YeonGyu-Kim 8514906c3d fix: inherit parent session tool restrictions in background task notifications
Pass parentTools from session-tools-store through the background task
lifecycle (launch → task → notify) so that when notifyParentSession
sends promptAsync, the original tool restrictions (e.g., question: false)
are preserved. This prevents the Question tool from re-enabling after
call_omo_agent background tasks complete.
2026-02-14 14:58:25 +09:00
YeonGyu-Kim 4ab93c0cf7 fix: refresh lastUpdate on all message.part.updated events, not just tool events
Reasoning/thinking models (Oracle, Claude Opus) were being killed by the
stale timeout because lastUpdate was only refreshed on tool-type events.
During extended thinking, no tool events fire, so after 3 minutes the
task was incorrectly marked as stale and aborted.

Move progress initialization and lastUpdate refresh before the tool-type
conditional so any message.part.updated event (text, thinking, tool)
keeps the task alive.
2026-02-14 13:33:01 +09:00
YeonGyu-Kim c8cd6370e2 Merge pull request #1817 from code-yeongyu/fix/todo-continuation-always-fire
fix(todo-continuation-enforcer): fire continuation for all sessions with incomplete todos
2026-02-14 11:43:10 +09:00
YeonGyu-Kim 9fe48d252c Merge pull request #1787 from popododo0720/fix/memory-leak-session-messages-caching
fix: reduce session.messages() calls with event-based caching to prevent memory leaks
2026-02-13 18:44:00 +09:00
YeonGyu-Kim e3924437ce feat(compaction): wire TaskHistory into BackgroundManager and compaction pipeline
Records task history at 6 status transitions (pending, running×2, error,
cancelled, completed). Exports TaskHistory from background-agent barrel.
Passes backgroundManager and sessionID through compaction hook chain.
2026-02-13 17:40:44 +09:00
YeonGyu-Kim 1ceaaa4311 fix(background-agent): handle session.error and prevent zombie queue starts
Marks background tasks as error on session.error to release concurrency immediately, and skips/removes error tasks from queues to avoid zombie starts.
2026-02-12 18:26:03 +09:00
popododo0720 eb56701996 fix: reduce session.messages() calls with event-based caching to prevent memory leaks
- Replace session.messages() fetch in context-window-monitor with message.updated event cache
- Replace session.messages() fetch in preemptive-compaction with message.updated event cache
- Add per-session transcript cache (5min TTL) to avoid full rebuild per tool call
- Remove session.messages() from background-agent polling (use event-based progress)
- Add TTL pruning to todo-continuation-enforcer session state Map
- Add setInterval.unref() to tool-input-cache cleanup timer

Fixes #1222
2026-02-12 11:38:11 +09:00
YeonGyu-Kim b0c570e054 fix(subagent): remove permission.question=deny override that caused zombie sessions
Child session creation was injecting permission: { question: 'deny' } which
conflicted with OpenCode's child session permission handling, causing subagent
sessions to hang with 0 messages after creation (zombie state).

Remove the permission override from all session creators (BackgroundManager,
sync-session-creator, call-omo-agent) and rely on prompt-level tool restrictions
(tools.question=false) to maintain the intended policy.

Closes #1711
2026-02-11 13:52:20 +09:00
YeonGyu-Kim 5b34a98e0a feat(background-agent): use "interrupt" status for promptAsync errors
Change promptAsync catch blocks to set status = "interrupt" instead of "error".

This distinguishes prompt errors from stale timeouts (cancelled) and TTL expirations (error).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-09 18:25:54 +09:00
YeonGyu-Kim 0e49214ee7 fix(background-agent): rename getCompletedTasks to getNonRunningTasks for semantic accuracy 2026-02-09 11:45:20 +09:00
YeonGyu-Kim 1324fee30f feat(cli/run, background-agent): manage session permissions for CLI and background tasks
- Deny question prompts in CLI run mode since there's no TUI to answer them
- Inherit parent session permission rules in background task sessions
- Force deny questions while preserving other parent permission settings
- Add test coverage for permission inheritance behavior

🤖 Generated with assistance of OhMyOpenCode
2026-02-08 18:41:26 +09:00