fix(agents): name tool calls from the payload, and populate AgentResult.Events - #174
Open
ambiorix2099 wants to merge 3 commits into
Open
fix(agents): name tool calls from the payload, and populate AgentResult.Events#174ambiorix2099 wants to merge 3 commits into
ambiorix2099 wants to merge 3 commits into
Conversation
…lt.Events `ToolCalls` named every tool after its Conductor task type. That is correct only for a worker tool, because Conductor sets an executed SIMPLE task's `taskType` to the task's own name; every other kind carries its system task type there, so an HTTP tool was named "HTTP", an MCP tool "CALL_MCP_TOOL", an agent used as a tool "SUB_WORKFLOW". Resolve the name from `inputData._agent_tool_name`, then `inputData.method`, then `taskDefName`. Detection required a `call_` reference-name prefix. The server seeds the reference from the provider's tool-call id, so that prefix is OpenAI's format and an Anthropic-backed agent recorded no tool calls at all. Identify a tool task by task type instead, allowlisted off the server's `ToolCompiler.TYPE_MAP`. Two cases need corroborating evidence that the LLM dispatched the task, and take a dispatch marker (`_agent_tool_name` or `_agent_state`) as well: the worker kind, whose task type is the tool's own name and so cannot be allowlisted, and `SUB_WORKFLOW`/`HUMAN`, which the agent layer emits for sub-agents, strategy workflows, routers and plan approval steps far more often than for a tool. Without that second requirement every multi-agent handoff would be reported as a tool call that never happened. `AgentResult.Events` was never assigned, so enumerating it threw. Build it from the same task walk: a `ToolCall`/`ToolResult` pair per tool call, closed by a terminal `Done`, or `Error` for a run that did not complete. It is a reconstruction from the finished execution's tasks and is narrower than the live stream, which is documented rather than implied. Also read a tool's result from the whole task output when there is no `result` key, since an HTTP tool answers under `response`, and include `GENERATE_PDF`, which `TYPE_MAP` omits although the server compiles a `generate_pdf` tool to it. The existing tool-call test passed for the right reason but on a fixture that omitted `method` and `_agent_tool_name` and carried a reference name without the fork index and loop suffix real payloads have, so it exercised neither name resolution nor detection. Its fixture now has the shape a real payload does.
ambiorix2099
force-pushed
the
agentspan-evals
branch
from
September 8, 2026 22:46
ff91ba4 to
85b1cc0
Compare
Contributor
Author
|
Fixing that isn't a one-liner: the same fallback runs after a mid-stream reconnect failure, so a replay would have to skip events already sent. No issue open. |
The comment layer added with the tool-call fix explained how the code works where the code already shows it, and ran well past what this file does elsewhere: its 25 existing doc blocks average 2.5 lines, 17 of them are one-liners, and its section banners carry no prose at all. Docs now state what each member is, and why it exists only where that is not evident from the code: GENERATE_PDF is absent from the server's TYPE_MAP, the dispatch marker is what keeps the agent's own structure out of ToolCalls, and an HTTP tool answers under `response`. The fallback order, the return shape and the per-kind task type lists are left to the code. Test comments come down to the 5-6% of lines the sibling suites carry; the fixtures already show the payload shapes the prose was restating. Nothing executable changed.
Review follow-ups on the tool-extraction change. ExtractToolActivity skipped any task without outputData before deciding whether it was a tool task at all, so a tool the LLM dispatched that failed or never finished left no ToolCalls entry and no ToolCall event. The call demonstrably happened; it is now reported with its name and arguments and no result. Servers send outputData as an empty object rather than omitting it, so this is a narrow path, but the ordering hid it rather than handling it. AmbiguousToolTaskTypes named the ambiguity rather than the rule it encodes and becomes MarkerRequiredToolTaskTypes, which is what the call site asks. The internal-input-key list joins the two dispatch markers as a named set. Test fixtures built by positional Replace over JSON, which would rewrite any later occurrence of TYPE or NAME, become interpolated raw strings. Docs: the new concepts section leads with its example, per docs/documentation-standard.md rule 1, and the reference entry links rather than repeating the gloss, per rule 5.
ambiorix2099
force-pushed
the
agentspan-evals
branch
from
September 9, 2026 06:00
85b1cc0 to
c9b0da1
Compare
ambiorix2099
marked this pull request as ready for review
September 9, 2026 17:03
ambiorix2099
requested review from
NicholasDCole,
dfont-orkes,
kowser-orkes and
ling-senpeng13
September 10, 2026 21:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AgentResult.Eventswas null afterWaitAsync, so enumerating it threw.ToolCallsnamed every tool after its task type, and came back empty on any non-OpenAI provider.BuildResultnever assignedEvents;ExtractToolCallsnamed tools fromtaskType(the tool's own name only for a worker task, perSimpleTaskMapper) and selected them by acall_prefix on the reference name, which is the provider's tool-call id.ToolCompiler.TYPE_MAP, name frominputData._agent_tool_name, thenmethod, thentaskDefName.Eventscomes from the same walk.User impact
Same agent and call, an HTTP tool and a worker tool, run on conductor-oss 3.32.1 with
openai/gpt-4o-minieach side of the change:ToolCallsEvents[{name="HTTP"}, {name="get_weather"}], neither with a resultnull,foreachthrew[{name="lookup_order", result=…}, {name="get_weather", result=…}]ToolCall, ToolResult, ToolCall, ToolResult, DoneScope is the polled result path;
StreamAsyncis unchanged.Not fixed: the server's dynamic dispatch script sets no
_agent_tool_name, so on that path an agent-as-tool is missed and a media tool still reports its task type.Changes
Conductor.AI/Result.cs:IsToolTask/ResolveToolNamereplace the reference-name check; results fall back to the whole task output when there is noresultkey;Eventsbuilt alongsideToolCallsConductor.AI.Tests/AgentToolCallExtractionTests.cs,StubAgentServer.cs: new. Naming per tool kind, Anthropic reference names, agent structure excluded,EventsshapeConductor.AI.Tests/AgentStatusMappingTests.cs: fixture gains the dispatch markers and a realistic reference namedocs/agents/concepts/streaming-hitl.md,docs/agents/reference/api.md:Eventson a result is a reconstruction from completed tasksFixes #173