Bug Description
AgentResult.Events is null after WaitAsync, so enumerating it throws. The property is
effectively dead: nothing in the library ever assigns it.
ToolCalls is wrong for every tool kind except plain workers. An HTTP tool is named "HTTP", an
MCP tool "CALL_MCP_TOOL", an agent used as a tool "SUB_WORKFLOW", a human tool "HUMAN", an
image tool "GENERATE_IMAGE".
Tool calls are also missed entirely for non-OpenAI providers, because selection keys on the
provider's tool-call ID format.
Root Cause
Events omitted. Declared at Conductor.AI/Result.cs:156. The object initializer in
BuildResult (:539-548) sets ExecutionId, Status, Output, Error, ToolCalls,
TokenUsage and FinishReason, and omits it. Events appears nowhere else in Conductor.AI, and
AgentResult is not deserialized from a payload that would supply it, so it is always null
rather than empty. StreamAsync (:331) yields events but never builds a result from them.
Name taken from the task type. Result.cs:569:
var tc = new Dictionary<string, object> { ["name"] = task!["taskType"]?.GetValue<string>() ?? "" };
Correct only for a worker tool, because Conductor sets an executed SIMPLE task's taskType to the
task's own name (SimpleTaskMapper.java:86 in conductor-oss/conductor). Every other tool kind
carries its system task type there.
The real name is available and discarded at :576-577. A tool task's inputData:
{"_agent_tool_name": "get_weather", "_agent_state": {},
"method": "get_weather", "city": "San Francisco"}
method, _agent_tool_name and taskDefName all carry it. None is read.
Selection keys on the provider's tool-call ID. Result.cs:566 requires
refName.StartsWith("call_"). The server does not add that prefix. It seeds the reference from the
provider's toolCall.id(), falling back to a UUID, then appends the fork index and loop iteration,
giving call_PMnNIdOPvm9EQ8e6tn2kbxPY_0__1 for OpenAI. Anthropic IDs start toolu_ and are not
matched. Adding toolu_ is not a fix, since the next provider picks its own format.
There is also no system-task-type filter, so selection rests entirely on the reference-name prefix.
Steps to Reproduce
var result = await handle.WaitAsync();
foreach (var e in result.Events) { } // NullReferenceException
result.ToolCalls[0]["name"]; // "HTTP" for an HTTP tool
Expected Behavior
Assign Events in BuildResult, or drop the property if it is not intended to be populated on
that path.
Identify a tool task by task type, allowlisting off the server's ToolCompiler.TYPE_MAP plus the
worker case, and resolve the name from inputData._agent_tool_name, then inputData.method, then
taskDefName. Never from the reference name, which carries provider-controlled data.
Two corrections to the above, found while implementing it:
TYPE_MAP is not the whole allowlist. It has no generate_pdf entry, and media tools take their
task type from toolType.toUpperCase() instead (ToolCompiler.java:427-436), so a generate_pdf
tool compiles to GENERATE_PDF and has to be added by hand.
_agent_tool_name is set for every tool kind only on the static dispatch path
(JavaScriptBuilder.enrichToolsScript, :797). The dynamic-tools path
(enrichToolsScriptDynamic, :1607-1609) sets no _agent_tool_name at all and sets
_agent_state only on SIMPLE tasks, so a non-worker tool dispatched there carries no marker.
Additional Notes
Verified against origin/main @ b5d7f22.
AgentStatusMappingTests.cs:164 covers the worker case and passes for the right reason. Its fixture
(:173-179) omits method and _agent_tool_name, and its reference name (call_echo_1) lacks the
fork index and loop suffix that real payloads carry, so neither name resolution nor detection is
genuinely exercised. Nothing covers Events.
Same family of defects filed against python-sdk, javascript-sdk and java-sdk. This
implementation is a port of the Java one (Result.cs:552 names
AgentHandle.extractFromTasks), itself a port of Python's.
A related server-side issue is filed against conductor-oss/conductor:
AgentEventListener.isToolTask excludes HTTP, CALL_MCP_TOOL, SUB_WORKFLOW and HUMAN, so
those kinds emit no tool events server-side either. Fixing this SDK gets their names right in
ToolCalls.
Bug Description
AgentResult.EventsisnullafterWaitAsync, so enumerating it throws. The property iseffectively dead: nothing in the library ever assigns it.
ToolCallsis wrong for every tool kind except plain workers. An HTTP tool is named"HTTP", anMCP tool
"CALL_MCP_TOOL", an agent used as a tool"SUB_WORKFLOW", a human tool"HUMAN", animage tool
"GENERATE_IMAGE".Tool calls are also missed entirely for non-OpenAI providers, because selection keys on the
provider's tool-call ID format.
Root Cause
Eventsomitted. Declared atConductor.AI/Result.cs:156. The object initializer inBuildResult(:539-548) setsExecutionId,Status,Output,Error,ToolCalls,TokenUsageandFinishReason, and omits it.Eventsappears nowhere else inConductor.AI, andAgentResultis not deserialized from a payload that would supply it, so it is alwaysnullrather than empty.
StreamAsync(:331) yields events but never builds a result from them.Name taken from the task type.
Result.cs:569:Correct only for a worker tool, because Conductor sets an executed SIMPLE task's
taskTypeto thetask's own name (
SimpleTaskMapper.java:86inconductor-oss/conductor). Every other tool kindcarries its system task type there.
The real name is available and discarded at
:576-577. A tool task'sinputData:method,_agent_tool_nameandtaskDefNameall carry it. None is read.Selection keys on the provider's tool-call ID.
Result.cs:566requiresrefName.StartsWith("call_"). The server does not add that prefix. It seeds the reference from theprovider's
toolCall.id(), falling back to a UUID, then appends the fork index and loop iteration,giving
call_PMnNIdOPvm9EQ8e6tn2kbxPY_0__1for OpenAI. Anthropic IDs starttoolu_and are notmatched. Adding
toolu_is not a fix, since the next provider picks its own format.There is also no system-task-type filter, so selection rests entirely on the reference-name prefix.
Steps to Reproduce
Expected Behavior
Assign
EventsinBuildResult, or drop the property if it is not intended to be populated onthat path.
Identify a tool task by task type, allowlisting off the server's
ToolCompiler.TYPE_MAPplus theworker case, and resolve the name from
inputData._agent_tool_name, theninputData.method, thentaskDefName. Never from the reference name, which carries provider-controlled data.Two corrections to the above, found while implementing it:
TYPE_MAPis not the whole allowlist. It has nogenerate_pdfentry, and media tools take theirtask type from
toolType.toUpperCase()instead (ToolCompiler.java:427-436), so agenerate_pdftool compiles to
GENERATE_PDFand has to be added by hand._agent_tool_nameis set for every tool kind only on the static dispatch path(
JavaScriptBuilder.enrichToolsScript,:797). The dynamic-tools path(
enrichToolsScriptDynamic,:1607-1609) sets no_agent_tool_nameat all and sets_agent_stateonly onSIMPLEtasks, so a non-worker tool dispatched there carries no marker.Additional Notes
Verified against
origin/main@b5d7f22.AgentStatusMappingTests.cs:164covers the worker case and passes for the right reason. Its fixture(
:173-179) omitsmethodand_agent_tool_name, and its reference name (call_echo_1) lacks thefork index and loop suffix that real payloads carry, so neither name resolution nor detection is
genuinely exercised. Nothing covers
Events.Same family of defects filed against
python-sdk,javascript-sdkandjava-sdk. Thisimplementation is a port of the Java one (
Result.cs:552namesAgentHandle.extractFromTasks), itself a port of Python's.A related server-side issue is filed against
conductor-oss/conductor:AgentEventListener.isToolTaskexcludesHTTP,CALL_MCP_TOOL,SUB_WORKFLOWandHUMAN, sothose kinds emit no tool events server-side either. Fixing this SDK gets their names right in
ToolCalls.