Align Go agent and workflow contracts with .NET - #950
Conversation
Align provider options, A2A lifecycle, message injection, telemetry, and tool auto-calling with the audited .NET contracts. Bring workflow execution, request routing, checkpointing, and aggregation behavior into parity, and update tests, examples, and the comparison matrix.
There was a problem hiding this comment.
Copilot review overview
Review tier: Lite
Findings: 2
New issues introduced by this change (2)
| Severity | Finding |
|---|---|
tool/tool.go — RequireTool validates blank names using TrimSpace, but it does not normalize the stored tool name.… |
|
provider/a2aprovider/executor.go — yieldCompletedResponse ignores the boolean return from yield when emitting the final Completed… |
What changed in this PR
Aligns Go agent/provider/workflow runtime contracts with the .NET implementation, covering tool selection/autocall configuration, message routing/declared-vs-runtime typing, lifecycle/telemetry identity, A2A hosting semantics, and workflow execution/checkpoint behavior.
Changes:
- Updates workflow routing/execution to better preserve declared vs runtime types (including portable values) and adjusts run/stream lifecycle behavior.
- Introduces session-backed message injection (
agent.MessageInjector) and updates providers/tests/examples to use the new model. - Adds new workflow utilities/APIs (
NewAggregatingExecutor,checkpoint.Manager.LatestCheckpoint) and expands parity/regression tests.
| File | Description |
|---|---|
| workflow/route.go | Adjust portable value unwrapping during routing. |
| workflow/route_test.go | Adds regression test for catch-all routing with unknown portable type. |
| workflow/internal/execution/step.go | Preserve declared vs concrete types through checkpoint envelope round-trip. |
| workflow/internal/execution/step_test.go | Adds tests for declared-type vs concrete-type checkpoint behavior. |
| workflow/internal/execution/run.go | Adds untyped enqueue API with declared type; improves close cancellation handling. |
| workflow/internal/execution/execution.go | Updates SuperStepRunner interface to new enqueue/validation signatures. |
| workflow/internal/execution/eventstream.go | Ensures workflow run span ends on early stop; comment/behavior alignment. |
| workflow/internal/execution/eventstream_test.go | Adds tests for early stop span ending; tests for EnqueueMessageUntyped behavior. |
| workflow/internal/execution/edgerunner.go | Routes/drops based on runtime type inference for portable messages. |
| workflow/inproc/subworkflow.go | Uses active runner input types; improves response qualification erroring. |
| workflow/inproc/subworkflow_test.go | Adds tests for active runner input types and unqualified response rejection; updates send APIs. |
| workflow/inproc/state_test.go | Updates to OpenStreaming/TrySendMessage APIs. |
| workflow/inproc/runner.go | Changes input validation to return (bool, error); untyped enqueue; concurrent subworkflow stepping. |
| workflow/inproc/runner_test.go | Adds enqueue path test around ExternalResponse declared as any. |
| workflow/inproc/run.go | NewEvents becomes snapshot-based; introduces TrySendMessage; updates Resume path. |
| workflow/inproc/routing_test.go | Adds polymorphic external input routing coverage; fan-in runtime routing coverage. |
| workflow/inproc/external_request_test.go | Updates ExternalResponse handler to interface route; OpenStreaming usage. |
| workflow/inproc/environment.go | Adds OpenStreaming; hardens nil-message behavior; closes handles on error. |
| workflow/inproc/context.go | Switches join IDs to UUID strings (with hyphens). |
| workflow/inproc/concurrent_test.go | Updates tests to OpenStreaming. |
| workflow/inproc/checkpoint_test.go | Updates tests to TrySendMessage. |
| workflow/inproc/binding_test.go | Output tag assertion changes; improves halted-run test cleanup/timing. |
| workflow/info.go | Checkpoint IDs now use UUID strings (with hyphens). |
| workflow/executor.go | Eager protocol init in Initialize; adds NewAggregatingExecutor helper. |
| workflow/executor_test.go | Adds tests for NewAggregatingExecutor and updates streaming entrypoints. |
| workflow/errors.go | Removes ErrInvalidInputType sentinel error. |
| workflow/checkpoint/manager.go | Adds LatestCheckpoint API to Manager implementations. |
| workflow/checkpoint/manager_test.go | Adds tests for LatestCheckpoint behavior. |
| workflow/checkpoint/jsonstore.go | Deduplicates persisted index entries during load. |
| workflow/checkpoint/jsonstore_test.go | Adds test ensuring persisted index deduplication. |
| workflow/agentworkflow/workflow.go | Updates hosted workflow agent behavior (IDs, injection handling, turn handling). |
| workflow/agentworkflow/workflow_test.go | Expands coverage for empty-first-turn behavior and close error propagation; removes DisableFuncAutoCall usage. |
| workflow/agentworkflow/session.go | Loads/starts state with initial messages; session IDs use newMessageID; returns “initial messages sent” flag. |
| workflow/agentworkflow/inprocess_execution_test.go | Updates tag assertions and streaming entrypoints. |
| workflow/agentworkflow/hosting.go | newMessageID now uses UUID string (with hyphens). |
| workflow/agentworkflow/hosting_test.go | Updates streaming send API; removes DisableFuncAutoCall usage in configs. |
| workflow/agentworkflow/groupchat_test.go | Updates streaming entrypoints and send API; removes DisableFuncAutoCall usage. |
| workflow/agentworkflow/concurrent_test.go | Fixes deterministic assertion ordering; updates OpenStreaming usage. |
| workflow/agentworkflow/builders_test.go | Updates OpenStreaming/TrySendMessage usage; removes DisableFuncAutoCall usage. |
| tool/tool.go | Replaces RequireTools/Required with RequireTool/RequiredTool semantics. |
| tool/tool_test.go | Updates tests for new RequireTool/RequiredTool behavior, including blank-name panic. |
| tool/shelltool/shelltool_test.go | Removes t.Parallel to avoid test interaction. |
| tool/agenttool/agenttool_test.go | Changes empty args behavior to reject blank query; validates provider not invoked. |
| provider/otelprovider/otel.go | Records gen_ai.response.id attribute from updates when available. |
| provider/otelprovider/otel_test.go | Adds early-stop-safe yield usage; validates response ID attribute. |
| provider/openaiprovider/responses.go | Provider-owned autocall config; preserves caller slice backings; ProviderName override; RequiredTool support. |
| provider/openaiprovider/responses_test.go | Adds immutability/tool_choice tests; updates required-tool test expectations; config updates. |
| provider/openaiprovider/chat.go | Provider-owned autocall config; preserves caller slice backings; sets RawRepresentation; ProviderName override; RequiredTool support. |
| provider/openaiprovider/chat_test.go | Adds immutability/tool_choice tests; adds concurrent tool invocation + injection tests; validates RawRepresentation. |
| provider/geminiprovider/agent.go | Provider-owned autocall config; tool mode applies consistently; tool call IDs use UUID strings. |
| provider/geminiprovider/agent_test.go | Updates config expectations; rejects empty message; tool mode required uses RequireTool; adds native-tool ToolModeNone test. |
| provider/foundryprovider/servedmodel.go | Ensures served-model box updated consistently (no early return). |
| provider/foundryprovider/servedmodel_test.go | Adds test ensuring served-model metadata doesn’t leak across calls. |
| provider/foundryprovider/clientheaders.go | Normalizes x-client-* names to lowercase; detects duplicates case-insensitively; avoids maps.Copy. |
| provider/foundryprovider/clientheaders_test.go | Updates agent configs; adds case-insensitive upsert test. |
| provider/foundryprovider/agent.go | ProviderName set; OpenAIOptions precedence hardened; ToolAutoCall plumbed through. |
| provider/foundryprovider/agent_test.go | Validates ProviderName; adds test ensuring Foundry-owned routing overrides hostile OpenAI options. |
| provider/copilotprovider/copilot.go | Prevents mutating caller RunOptions backing by cloning before appending instructions. |
| provider/anthropicprovider/agent.go | Provider-owned autocall config; RequiredTool support (single tool vs any). |
| provider/anthropicprovider/agent_test.go | Updates configs; adds RequiredTool tool_choice assertion; test harness config updates. |
| provider/aguiprovider/agui.go | Provider-owned autocall config; clones RunOptions before appending instructions. |
| provider/a2aprovider/session.go | Stores a single current task ID instead of a growing list; renames session keys. |
| provider/a2aprovider/hosting_test.go | Adds context-id/service-id separation tests; adds background continuation polling tests; updates expected status sequences. |
| provider/a2aprovider/hosting_convert.go | Avoids emitting empty metadata maps by cloning only when non-empty. |
| provider/a2aprovider/hosting_convert_test.go | Adds executor lifecycle tests (cancellation/failure); updates empty-metadata expectation. |
| provider/a2aprovider/executor.go | Adds background polling loop; improves cancellation semantics; forwards metadata; normalizes status sequencing and failure messaging. |
| internal/telemetry/telemetry.go | Makes user-agent detection case-insensitive and segment-aware. |
| internal/telemetry/telemetry_test.go | Adds mixed-case user-agent recognition test. |
| examples/03-workflows/concurrent/concurrent_custom_aggregator/main.go | Uses TrySendMessage for turn tokens. |
| examples/03-workflows/agents/group_chat_tool_approval/main.go | Uses TrySendMessage for turn tokens. |
| examples/03-workflows/01-start-here/08_sequential_chain_only_responses/main.go | Uses TrySendMessage; removes DisableFuncAutoCall usage in example agent config. |
| examples/03-workflows/01-start-here/04_multi_model_service/main.go | Uses TrySendMessage for turn tokens. |
| examples/03-workflows/01-start-here/03_agent_workflow_patterns/main.go | Uses TrySendMessage for turn tokens. |
| examples/03-workflows/01-start-here/02_agents_in_workflows/main.go | Uses TrySendMessage for turn tokens. |
| examples/02-agents/agui/step03_frontend_tools/server/main.go | Shows ToolAutoCall configuration instead of disabling autocall globally. |
| examples/02-agents/agents/message-injection/main.go | Updates message-injection example to use session-backed agent.MessageInjector. |
| agent/response.go | Adds response-level RawRepresentation aggregation; centralizes append behavior. |
| agent/response_test.go | Extends RawRepresentation tests to include response-level aggregation. |
| agent/messageinjection.go | Adds new session-backed MessageInjector implementation. |
| agent/harness/toolautocall/inject.go | Removes old context-based injector implementation. |
| agent/harness/toolautocall/doc.go | Updates docs to reflect provider-default autocall + Config customization. |
| agent/harness/toolautocall/autocall_test.go | Updates tests for new RequiredTool semantics, iteration config pointers, and message injection integration. |
| agent/harness/toolautocall/autocall_log_test.go | Updates iteration config to pointer form. |
| agent/harness/toolautocall/autocall_inject_test.go | Removes old injection tests (replaced by new injector integration tests). |
| agent/agent.go | Removes DisableFuncAutoCall; adds MessageInjector to config; rejects blank RunText and nil RunMessage; adjusts early-stop handling. |
| agent/agent_test.go | Adds tests for injection middleware placement and new input validation; updates early-stop context-provider semantics. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This comment has been minimized.
This comment has been minimized.
Co-authored-by: qmuntal <3747816+qmuntal@users.noreply.github.com>
Co-authored-by: qmuntal <3747816+qmuntal@users.noreply.github.com>
Co-authored-by: qmuntal <3747816+qmuntal@users.noreply.github.com>
Addressed both code review comments in |
This comment has been minimized.
This comment has been minimized.
|
Copilot fix merge conflicts |
# Conflicts: # provider/foundryprovider/agent.go Co-authored-by: qmuntal <3747816+qmuntal@users.noreply.github.com>
Co-authored-by: qmuntal <3747816+qmuntal@users.noreply.github.com>
Resolved the merge conflicts by merging |
Go API Consistency Review — PR #950Scope: public API, user-visible behavior, examples Changed Go contract:
Upstream evidence reviewed:
Result: aligned — all new and changed public Go APIs map to upstream .NET equivalents with compatible semantics. The
|

Summary
MessageInjectorsupport inside provider auto-call loops and update the message-injection exampleNewAggregatingExecutor,checkpoint.Manager.LatestCheckpoint, and ordered checkpoint-index deduplicationReference
microsoft/agent-framework@5996105a1bf2726918101adc6e9c9857b7f68b98microsoft/agent-framework@6a0773ba2180e8036d138dbb9794ae64ec2d978b; no later workflow code or test changes were presentmessage.UsageContent, provider-specific request metadata, and A2A continuation state in task metadata.NET StreamingAggregators.Unionbehavior, whose documentation promises a distinct union while its implementation appends duplicatesValidation
go test ./... -count=1 -p=2 -timeout=180sgo vet ./...git diff HEAD^ --check