Skip to content

fix(mothership): run client-routed workflow tools server-side in headless execution#4870

Merged
TheodoreSpeaks merged 2 commits into
stagingfrom
fix/mothership-block-run-workflow
Jun 3, 2026
Merged

fix(mothership): run client-routed workflow tools server-side in headless execution#4870
TheodoreSpeaks merged 2 commits into
stagingfrom
fix/mothership-block-run-workflow

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

Summary

  • Fix headless Mothership (Mothership block, no browser) being unable to run workflows — run_workflow, run_workflow_until_block, run_block, and run_from_block all failed with Tool not found
  • These tools are registered with route: 'client', so the executor gate (isSimExecuted) skipped their registered server handlers and fell through to executeAppTool, which threw. Interactive runs delegate them to the browser before reaching the executor, so only the headless path was broken
  • Allow a client-routed tool to use its registered server handler when one exists. Blast radius is exactly the four run tools — the only route: 'client' tools, all of which already have server handlers

Type of Change

  • Bug fix

Testing

Tested manually. Added unit tests for the new headless routing (handler used for client tool with a registered handler; still falls back to executeAppTool when none). Confirmed against production ECS logs on /api/mothership/execute: 7x run_workflow, 2x run_workflow_until_block, plus run_block/run_from_block, all Tool not found from the autonomous run subagent (executor: client, simExecutable: false). Lint and check:api-validation:strict pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…less execution

Headless Mothership (Mothership block, no browser) could not run workflows.
The run_workflow/run_workflow_until_block/run_block/run_from_block tools are
registered with route 'client', so the executor gate (isSimExecuted) skipped
their registered server handlers and fell through to executeAppTool, throwing
'Tool not found'. Interactive runs delegate these to the browser before reaching
the executor, so only the headless path broke.

Allow a client-routed tool to use its registered server handler when one exists,
which only affects the four run tools (the only client-routed tools, all of which
have server handlers).
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 3, 2026 8:38pm

Request Review

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

@greptile review

@cursor
Copy link
Copy Markdown

cursor Bot commented Jun 3, 2026

PR Summary

Low Risk
Narrow change to copilot tool routing for the four client workflow tools when a server handler is registered; interactive client execution is unchanged.

Overview
Fixes headless Mothership runs failing with Tool not found when the copilot invokes workflow run tools (run_workflow, run_workflow_until_block, run_block, run_from_block). Those tools are cataloged with route: 'client', so the executor only treated route: 'sim' tools as eligible for registered server handlers; headless paths then fell through to executeAppTool, which does not implement them. Interactive sessions never hit this because the client runs those tools before the server executor.

The executor now routes client tools through their registered handler when one exists (isClientExecuted + hasHandler), matching the existing sim-route behavior. Adds isClientExecuted on the router, clearHandlers for tests, and unit coverage for headless handler use vs app-tool fallback.

Reviewed by Cursor Bugbot for commit 688c738. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 3, 2026

Greptile Summary

This PR fixes headless Mothership execution (no browser context) for the four workflow-runner tools (run_workflow, run_workflow_until_block, run_block, run_from_block). These tools carry route: 'client', so the executor's isSimExecuted guard previously skipped their registered server-side handlers and fell through to executeAppTool, which threw "Tool not found". Interactive runs never hit this path because the browser intercepts them first.

  • router.ts: Adds isClientExecuted(toolId) predicate mirroring the existing isSimExecuted/isGoExecuted helpers.
  • executor.ts: Extends canUseRegisteredHandler to also be true when the tool is client-routed AND a server handler exists; exports clearHandlers() for test isolation.
  • executor.test.ts: Adds two new test cases (headless handler path + fallback when no handler), wires in clearHandlers() in beforeEach, and mocks the new isClientExecuted function.

Confidence Score: 5/5

Safe to merge — the change is a minimal, well-guarded extension of the existing routing gate with no risk of unintended tool promotion.

The routing condition now adds isClientExecuted(toolId) && hasHandler(toolId) as an alternative path. Both guards must be true simultaneously, so only tools that are explicitly registered as client-routed AND have a server handler registered will take the new path. The four affected tools already had working server handlers; this just removes the gate that was blocking them in headless mode. Test isolation is correctly handled with clearHandlers() in beforeEach.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/copilot/tool-executor/executor.ts Core fix: extends canUseRegisteredHandler to cover client-routed tools that have a registered server handler; adds clearHandlers() export for test isolation. Logic is minimal and correct.
apps/sim/lib/copilot/tool-executor/router.ts Adds isClientExecuted() predicate following the identical pattern of isSimExecuted/isGoExecuted — straightforward and consistent.
apps/sim/lib/copilot/tool-executor/executor.test.ts Two new tests covering the happy path and fallback path; clearHandlers() now called in beforeEach, fixing the previously flagged registry isolation issue.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[executeTool called] --> B{isKnownTool?}
    B -- No --> C[buildAppToolParams]
    C --> D[executeAppTool]
    B -- Yes --> E{isSimExecuted?}
    E -- Yes --> F[canUseRegisteredHandler = true]
    E -- No --> G{isClientExecuted?}
    G -- No --> C
    G -- Yes --> H{hasHandler?}
    H -- No --> C
    H -- Yes --> F
    F --> I{abortSignal aborted?}
    I -- Yes --> J[Return abort error]
    I -- No --> K{handler in registry?}
    K -- No --> L[Return no handler error]
    K -- Yes --> M[handler params, context]
    M --> N[Return ToolExecutionResult]
    D --> N
Loading

Reviews (3): Last reviewed commit: "test(mothership): clear handler registry..." | Re-trigger Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 3, 2026

Greptile Summary

This PR fixes headless Mothership execution by allowing client-routed tools (run_workflow, run_workflow_until_block, run_block, run_from_block) to use their registered server-side handlers when running without a browser. Previously, the executor gate only checked isSimExecuted, so client-routed tools fell through to executeAppTool and threw "Tool not found".

  • router.ts: Adds isClientExecuted alongside the existing isSimExecuted/isGoExecuted helpers.
  • executor.ts: Extends canUseRegisteredHandler with isClientExecuted(toolId) && hasHandler(toolId), keeping the fallback to executeAppTool when no server handler is registered.
  • executor.test.ts: Adds two tests covering the new headless routing path and the no-handler fallback; the module-level handlerRegistry is mutated without cleanup between tests.

Confidence Score: 4/5

Safe to merge; the fix is narrowly scoped to client-routed tools that already have a registered server handler, which today are exactly the four Mothership run tools.

The logic change is well-bounded: the new branch only activates when both isClientExecuted and hasHandler are true, so no existing behavior is altered for sim- or go-routed tools, and client tools without a server handler continue to fall back to executeAppTool as before. The one flag is that handlerRegistry is mutated in a test without cleanup, which could cause subtle inter-test ordering effects in watch mode.

executor.test.ts — the registerHandler call inside the test body leaves state in the module-level registry with no afterEach cleanup.

Important Files Changed

Filename Overview
apps/sim/lib/copilot/tool-executor/router.ts Adds isClientExecuted helper that mirrors the existing isSimExecuted/isGoExecuted pattern; minimal, low-risk change.
apps/sim/lib/copilot/tool-executor/executor.ts Widens canUseRegisteredHandler to cover client-routed tools that have an explicitly registered server-side handler; logic is correct and conservatively scoped by the hasHandler guard.
apps/sim/lib/copilot/tool-executor/executor.test.ts Two new tests cover the happy path and the fallback; registerHandler mutates a module-level singleton that is not cleaned up between tests, which could cause inter-test pollution.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[executeTool called] --> B{isKnownTool?}
    B -- No --> C[buildAppToolParams to executeAppTool]
    B -- Yes --> D{isSimExecuted?}
    D -- Yes --> G[Use registered handler]
    D -- No --> E{isClientExecuted AND hasHandler?}
    E -- Yes --> G
    E -- No --> C
    G --> H{abortSignal aborted?}
    H -- Yes --> I[Return aborted error]
    H -- No --> J{handler in registry?}
    J -- No --> K[Return no handler error]
    J -- Yes --> L[handler params context to ToolExecutionResult]
Loading

Reviews (1): Last reviewed commit: "fix(mothership): run client-routed workf..." | Re-trigger Greptile

Comment thread apps/sim/lib/copilot/tool-executor/executor.test.ts
Add clearHandlers() helper and reset the module-level handler registry in
beforeEach so handlers registered in one test do not leak into the next.
@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

@greptile review

@TheodoreSpeaks TheodoreSpeaks merged commit 4b84f06 into staging Jun 3, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/mothership-block-run-workflow branch June 3, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant