Plumb EnableMessageInjection through provider AgentConfig so the message-injector loop is reachable - #652
Conversation
69d726d to
4b79ee6
Compare
This comment has been minimized.
This comment has been minimized.
4b79ee6 to
36251f3
Compare
This comment has been minimized.
This comment has been minimized.
The toolautocall harness fully implements Config.EnableMessageInjection and its MessageInjector loop, but no provider wired the flag: every provider built toolautocall.Config with only Logger/LogSensitiveData, so the message-injector loop was unreachable through the normal agent API. Add EnableMessageInjection to agent.Config beside DisableFuncAutoCall and pass it into each provider's guarded toolautocall.New literal (openai chat and responses, anthropic, gemini, agui). The value threads through the embedded agent.Config on every provider AgentConfig. Behavior is unchanged when the field is false (the default).
36251f3 to
5e31a1a
Compare
This comment has been minimized.
This comment has been minimized.
# Conflicts: # provider/openaiprovider/chat_test.go
Go API Consistency Review — Parity Approved ✅SummaryThis PR plumbs Upstream Alignment
Semantic equivalence is preserved. All three SDKs gate the feature with an opt-in flag and keep baseline behavior identical when the flag is absent.
Minor Observation — Example Coverage GapBoth upstream SDKs ship a runnable message-injection sample:
Go Label Status
|
There was a problem hiding this comment.
Pull request overview
This PR makes the existing toolautocall message-injection loop reachable through the normal provider agent constructors by plumbing an EnableMessageInjection flag through agent.Config and into each provider’s toolautocall.Config.
Changes:
- Added
EnableMessageInjection booltoagent.Configso providers can expose message injection via their embeddedagent.Config. - Threaded
EnableMessageInjectioninto the provider-installedtoolautocall.New(toolautocall.Config{...})middleware across OpenAI (chat + responses), Anthropic, Gemini, and AGUI providers. - Added OpenAI chat black-box tests validating injection-enabled behavior and the default disabled behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| agent/agent.go | Adds Config.EnableMessageInjection (public surface) and documents intended behavior. |
| provider/openaiprovider/chat.go | Passes EnableMessageInjection into the OpenAI chat agent’s toolautocall middleware config. |
| provider/openaiprovider/responses.go | Passes EnableMessageInjection into the OpenAI responses agent’s toolautocall middleware config. |
| provider/openaiprovider/chat_test.go | Adds end-to-end tests proving injected messages are forwarded on the next provider call (and nil injector when disabled). |
| provider/anthropicprovider/agent.go | Threads EnableMessageInjection into Anthropic provider toolautocall config. |
| provider/geminiprovider/agent.go | Threads EnableMessageInjection into Gemini provider toolautocall config. |
| provider/aguiprovider/agui.go | Threads EnableMessageInjection into AGUI provider toolautocall config. |
| // EnableMessageInjection lets tool implementations enqueue additional messages into the | ||
| // automatic function-call loop via the injector returned by | ||
| // [github.com/microsoft/agent-framework-go/agent/harness/toolautocall.MessageInjectorFromContext]. | ||
| // It is threaded into the provider-installed toolautocall middleware and has no effect when | ||
| // DisableFuncAutoCall is true. |
What
The
toolautocallharness already fully implementsConfig.EnableMessageInjectionand itsMessageInjectorloop (inject.go, wired inautocall.go, tested inautocall_inject_test.go, ported from .NET'sMessageInjectingChatClient). However, no provider ever wired the flag: every provider builttoolautocall.Configwith onlyLogger/LogSensitiveData, so the message-injector loop was unreachable through the normal agent API.This PR:
EnableMessageInjection booltoagent.Config(inagent/agent.go), beside the existingDisableFuncAutoCall.EnableMessageInjection: config.EnableMessageInjectioninto each provider's guardedtoolautocall.New(toolautocall.Config{...})literal:openaiprovider(chat + responses),anthropicprovider,geminiprovider, andaguiprovider.Because each provider
AgentConfigembedsagent.Configand forwardsconfig.Configtoagent.New, the new field flows to all providers uniformly. Previously the only way to enable injection wasDisableFuncAutoCall=trueplus hand-rebuilding the middleware, which loses provider defaults.Why (parity)
This mirrors the .NET
MessageInjectingChatClient/EnqueueMessagessurface, which is composable into the standard function-invocation pipeline. Exposing the flag onAgentConfigkeeps the Go SDK aligned: tools can enqueue follow-up messages into the auto-call loop without opting out of the provider-managed middleware.Behavior change
None when the field is false (the default). The value is zero-valued for all existing callers, so the installed middleware behaves exactly as before.
Tests
Added two black-box tests in the canonical
provider/openaiprovider/chat_test.go:TestChatMessageInjection_ToolInjectsMessage: builds an agent withAgentConfig.EnableMessageInjection=trueand a tool that callsMessageInjectorFromContext(ctx).EnqueueMessages(...); asserts the injected message is forwarded to the provider on the following service round and the final answer is produced. This test fails before the wiring change and passes after.TestChatMessageInjection_DisabledReturnsNilInjector: negative case with the field false, assertingMessageInjectorFromContextreturns nil and nothing is injected.go build ./...,go vet, andgo test(incl.-raceon the new tests) pass for the changed packages.Open design questions
EnableMessageInjectionsits onagent.ConfigalongsideDisableFuncAutoCall. Is that the desired home, or should message injection be surfaced as part of a broader composable-middleware config (cf. Add composable function-invocation middleware to the tool autocall loop #638)?toolautocall.Configknobs (e.g.AllowConcurrentInvocations,MaximumIterationsPerRequest) remain provider-internal. Happy to plumb those in a follow-up if that is the direction.