conductor-oss / conductor-oss/csharp-sdk
`AgentResult.Events` is never assigned, and every non-worker tool is named after its task type
- Dominant language
- C#
- Stars
- 54
- Forks
- 23
- Avg merge
- 4d 21h
- Merged PRs (30d)
- 2
Description
## 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`:
```csharp
var tc = new Dictionary { ["name"] = task!["taskType"]?.GetValue() ?? "" };
```
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
```csharp
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`.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in Conductor.AI/Result.cs, especially BuildResult around lines 539-577, and review AgentStatusMappingTests.cs around lines 164-179. Run the existing tests first, then cover Events population, tool-kind detection, provider-independent selection, and inputData name resolution. Done means non-null Events and correct ToolCalls names for worker and non-worker tools across provider ID formats.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100