`inputData.method` is stripped before it is read, so `result.toolCalls` names tools after the task type

Open
#172 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
38/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
typescript
Domain
api, backend

Research direction

Start in src/agents/runtime.ts at _extractToolCalls and its call sites, then inspect _fetchExecution to compare the fields available from run() and workflow executions. Verify which tool names can be recovered on each path and separate SDK extraction behavior from the server-side AgentEventListener behavior; done means the required scope and validation path are established without treating assertions.ts as toolCalls coverage.

Written by the indexing model from the issue text.

Description

Bug Description

result.toolCalls is unreliable in three ways after run():

  • Tool names for HTTP, MCP and human tools come back as "http", "call_mcp_tool" and
    "human" instead of the tool's name.
  • An agent invoked as a tool never appears at all.
  • Nothing is detected for a non-OpenAI provider, because selection keys on the provider's
    tool-call ID format.

result.events is not affected. Events are populated correctly from the stream's own
accumulator (src/agents/stream.ts:413).

Root Cause

All in _extractToolCalls (src/agents/runtime.ts:2049), called at :262, :406, :1660
and :1740.

method is deleted before the line that reads it. INTERNAL_KEYS includes "method"
(:1970) and is stripped from the copied inputData at :2069-2071. Five lines later, :2074
does:

const toolName = String(inputData.method ?? taskType).toLowerCase();

inputData.method is always undefined at that point, so the name is unconditionally
taskType.toLowerCase(). The comment at :2073 ("Use the tool name from inputData.method (set
by compiler) if available") describes behaviour the strip above makes impossible, and the
delete inputData.method at :2075 is redundant.

For a worker tool this happens to work, since an executed SIMPLE task's taskType is the task's
own name. For every other kind it yields the system task type. It also case-folds, so a tool
named getWeather is reported as getweather.

SUB_WORKFLOW is on the skip list. SYSTEM_TASK_TYPES (:1957-1967) includes it at
:1966, and :2064 skips on that set. agent_tool compiles to SUB_WORKFLOW, so an agent
used as a tool is dropped.

Selection keys on the provider's tool-call ID. :2062 requires ref.startsWith("call_"). A
real reference name is call_PMnNIdOPvm9EQ8e6tn2kbxPY_0__1: provider ID, fork index, loop
iteration. call_ is OpenAI's format; Anthropic gives toolu_…; a blank ID becomes a UUID.
Adding toolu_ is not a fix, since the next provider picks its own format.

Steps to Reproduce

Register an agent with one HTTP tool and one worker tool named in camelCase, then:

const runtime = new AgentRuntime(config);
const result = await runtime.run(agent, "use both tools");

result.toolCalls;
// HTTP tool reported as { name: "http", ... }
// worker tool "getWeather" reported as { name: "getweather", ... }

Add another agent as a tool and it is absent from result.toolCalls entirely.

Expected Behavior

Read the tool name before stripping internal keys, or resolve it from a field that survives:
inputData._agent_tool_name is set by the server's tool dispatch and is not read anywhere
today. Drop the case folding, since the server returns the name verbatim.

Select tool tasks by task type rather than by reference-name prefix, and do not skip
SUB_WORKFLOW unconditionally, since it is both an orchestration construct and a tool kind.

Additional Notes

Verified against origin/main @ 816e5f5.

Corrections, from verifying this against a live Conductor 5.5.0 server. The reproduction
holds: main returns ["getweather", "http"] with the agent tool absent. Three claims above
do not.

  1. run() sees neither field. GET /agent/execution/{id}, which _fetchExecution reads,
    returns tasks carrying only taskType, referenceTaskName, status and outputData:
    inputData is null and there is no taskDefName. No declared name reaches the SDK on
    that path, so HTTP and MCP tools cannot be named from it. A workflow execution does carry
    inputData, and the same extraction over one returns the real names.
  2. The marker is not on every dispatched tool. For an agent tool the sub-workflow task mapper
    rebuilds inputData, so it arrives nested under workflowInput. An agent that discovers
    tools at runtime compiles through enrichToolsScriptDynamic, which never writes it.
  3. result.events being populated correctly is not something this issue established. A real
    three-tool run returned a single done event with streaming enabled. Not chased here.

An earlier revision of this issue claimed run() discarded collected events. That was wrong:
runtime.ts:254 builds the result via agentStream.getResult(), which supplies
events: [...this.events] from the stream's accumulator. The local array at :248-251 is dead
code. The assertions in src/agents/testing/assertions.ts are not broken by this SDK.

Where those assertions do come back empty for HTTP, MCP, agent-as-tool and human tools, the
cause is server-side: AgentEventListener.isToolTask in conductor-oss/conductor emits no tool
event for those kinds. Filed there separately.

No assertion in assertions.ts reads toolCalls (only eval.ts:90, for its length), so this is
wrong data rather than broken tests.

Same family of defects filed against python-sdk, java-sdk and csharp-sdk.

Dominant language
TypeScript
Stars
58
Forks
20
Avg merge
2d 9h
Merged PRs (30d)
2

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from conductor-oss/javascript-sdk

All issues in conductor-oss/javascript-sdk

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.