Skip to content

feat: add sync mode to task tool (blocking execution alongside async default) #182

@randomm

Description

@randomm

Task Description

Add a sync: boolean parameter to the task tool that enables blocking (synchronous) execution alongside our default async mode. When sync: true, the parent agent waits for the child session to complete and receives the result directly — matching upstream's blocking behavior. When sync: false (default), the current async behavior is preserved.

Context

  • Upstream (anomalyco/opencode): Task tool always blocks — await SessionPrompt.prompt() returns full result
  • Our fork: Task tool is always async — trackBackgroundTask() dispatches and returns task_id immediately
  • Goal: Support both modes without losing our async default

Why

  1. Some tasks should block — quick lookups, single-file edits, simple questions
  2. Upstream-designed PM agents expect blocking behavior — sync mode enables compatibility
  3. Gives the LLM flexibility to choose the right mode per task

Implementation

File: packages/opencode/src/tool/task.ts

  1. Add sync parameter to the Zod schema:

    sync: z.boolean().optional().default(false).describe("If true, block until task completes and return result directly. Default false (async).")
  2. Branch at the dispatch point (around line 300-334):

    • sync: true: await SessionPrompt.prompt() directly, extract text result, return it in the tool output (similar to upstream's return format with task_result tag)
    • sync: false (default): Current behavior — trackBackgroundTask(), return { task_id, status: "started" }
  3. Sync mode should:

    • Still respect the task timeout (DEFAULT_TASK_TIMEOUT = 10 * 60 * 1000)
    • Still use task slots for concurrency control
    • Release the slot when done (success or failure)
    • Propagate abort signals
    • NOT use trackBackgroundTask() or event bus — result goes directly in tool response
  4. The check_task tool remains unchanged — only relevant for async tasks

File: packages/opencode/src/tool/task.txt

Update the tool description to document the sync parameter so the LLM knows when to use it.

Key Design Decisions

  • sync: false is the DEFAULT — our async behavior is preserved as-is
  • Sync mode bypasses the event bus entirely — no trackBackgroundTask, no auto-wakeup needed
  • Sync mode still uses task slots to prevent unbounded concurrency
  • Timeout applies to both modes equally
  • Session creation (Session.createNext) is the same for both modes
  • The session_id parameter for resuming sessions works with both modes

Related Code

File Role
packages/opencode/src/tool/task.ts Main implementation — add sync branch
packages/opencode/src/tool/task.txt Tool description — document sync param
packages/opencode/src/session/async-tasks.ts Async infrastructure — unchanged
packages/opencode/src/tool/check_task.ts Check task tool — unchanged

Fork Governance — .fork-features/ Updates Required

Update the async-tasks feature in .fork-features/manifest.json:

  1. Add "sync" to the criticalCode array (to catch if sync mode is accidentally removed during upstream sync)
  2. Add task.txt to modifiedFiles if not already there
  3. Update description to mention dual-mode (async default + sync option)

Absorption signals to watch: If upstream adds any async/background task concept, or if upstream adds a sync/mode/blocking parameter to their task tool, our absorption signals should catch it.

Add to upstreamTracking.absorptionSignals:

  • "sync.*task"
  • "blocking.*task"
  • "task.*mode"

Quality Gates (Non-Negotiable)

  • TDD: Write tests for sync mode before implementing
    • Test: sync mode returns result directly (not task_id)
    • Test: sync mode respects timeout
    • Test: async mode (default) still works as before
    • Test: sync mode releases task slot on completion and failure
  • Coverage: 80%+ for new sync code path
  • Linting: All code passes project linting rules
  • Documentation: Update task.txt, update .fork-features/manifest.json
  • Local Verification: bun test passes, bun test .fork-features/verify.ts passes

Acceptance Criteria

  • sync: true blocks and returns full result in tool output
  • sync: false (default) preserves current async behavior exactly
  • Task slots enforced for both modes
  • Timeout enforced for both modes
  • Abort signal propagation works for both modes
  • task.txt updated with sync parameter documentation
  • .fork-features/manifest.json updated with new criticalCode markers and absorption signals
  • bun test .fork-features/verify.ts passes
  • All existing tests pass + new sync mode tests
  • Binary rebuilt and installed to ~/bin/opencode

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions