Skip to content

code_mode_tools breaks transfer_task (and handoff): runtime-handled tools wrapped into run_tools_with_javascript #4713

Open

Description

@aheritier

Summary

When an agent sets code_mode_tools: true and has sub_agents (or handoffs), the transfer_task (and handoff) tool is wrapped into the code mode toolset. Calling it from JavaScript fails with tool "transfer_task" is not available in code mode. The agent cannot delegate at all.

Tool 'TransferTask' is not available. You can only use the tools provided to you.

Reproduction

version: "16"

agents:
  root:
    model: my_model
    instruction: You are a coordinator. Delegate every task to helper.
    code_mode_tools: true
    sub_agents:
      - helper
  helper:
    model: my_model
    description: Answers questions
    instruction: Answer briefly.

models:
  my_model:
    provider: openai
    model: gpt-4o

Run docker agent run agent.yaml and ask: "Ask helper to say hello."

Expected vs actual

  • Expected: root transfers the task to helper, as it does without code_mode_tools.
  • Actual: the model sees declare function TransferTask(...) in the run_tools_with_javascript description, calls it, and receives tool "transfer_task" is not available in code mode. Retrying gives the same error.

Root cause

Pinned to main at 223f940.

  1. getToolsForAgent appends the transfer and handoff toolsets, then wraps all toolsets in code mode
    (pkg/teamloader/teamloader.go):

    if len(a.SubAgents) > 0 {
        toolSets = append(toolSets, transfertask.New())
    }
    if len(a.Handoffs) > 0 {
        toolSets = append(toolSets, handoff.New())
    }
    ...
    if a.CodeModeTools || runConfig.GlobalCodeMode {
        ...
        toolSets = []tools.ToolSet{loadOpts.codeMode(toolSets...)}
    }
  2. transfer_task is handled by the runtime and has no Handler
    (pkg/tools/builtin/transfertask/transfertask.go):

    Name:           ToolNameTransferTask,
    RuntimeHandler: ToolNameTransferTask,
    Category:       "transfer",
  3. Code mode rejects any tool without a Handler
    (pkg/tools/codemode/exec.go):

    if tool.Handler == nil {
        return "", args, fmt.Errorf("tool %q is not available in code mode", tool.Name)
    }
  4. isExcludedTool only keeps todo and AllowRepeatedCalls tools out of the wrapper
    (pkg/tools/codemode/codemode.go):

    return tool.Category == "todo" || tool.AllowRepeatedCalls

    So transfer_task is listed in the generated TypeScript declarations (TransferTask, PascalCase via typeName() in functions.go) even though it can never run there.

Proposed fix

In isExcludedTool, also exempt tools that have a non-empty RuntimeHandler (or category transfer / handoff), so they stay top-level tools next to run_tools_with_javascript:

func isExcludedTool(tool tools.Tool) bool {
    return tool.Category == "todo" || tool.AllowRepeatedCalls || tool.RuntimeHandler != ""
}

Alternative: in teamloader, append transfertask.New() and handoff.New() after the code mode wrap, so they are never passed to loadOpts.codeMode.

Test: add a case next to codemode_test.go that wraps a toolset containing a tool with RuntimeHandler set and no Handler. Assert it is not in the run_tools_with_javascript description and is still returned by the wrapper's Tools() as a top-level tool.

Side note: permissions and tool_guard

Inner calls made inside run_tools_with_javascript are not seen by the permissions or tool_guard hooks. Only the outer run_tools_with_javascript call is. An agent with a shell tool and code_mode_tools: true can run shell commands that skip per-command permission checks. Either document this or apply the checks to each inner call.

Environment

  • docker-agent: main at 223f940
  • Config version: 16
  • Config: a multi-agent team config with sub_agents

Activity

  1. added
    area/toolsFor features/issues/fixes related to the usage of built-in and MCP tools
    area/runtimeRuntime engine, agent loop execution, tool dispatch, loop detection
    area/agentFor work that has to do with the general agent loop/agentic features of the app
    on Oct 24, 2026
  2. added theissue type on Oct 24, 2026
  3. aheritier commented on Oct 24, 2026

    @aheritier
    CollaboratorAuthor

    Does it ring any bell on your side @rumpl @dgageot ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/agentFor work that has to do with the general agent loop/agentic features of the apparea/runtimeRuntime engine, agent loop execution, tool dispatch, loop detectionarea/toolsFor features/issues/fixes related to the usage of built-in and MCP tools

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions