Summary
Expose the current tool invocation identity, including the function call ID, through the delegating-agent middleware design proposed by the maintainers in #638.
This should preserve the idiomatic FuncTool.Call(context.Context, args) API introduced by #205. The goal is not to restore the removed custom tool.Context, but to provide a supported per-invocation interception contract for policy, approval, audit, and gateway integrations.
Motivation
The automatic tool-call loop already has the originating message.FunctionCallContent and uses its CallID to correlate approval requests, function results, and OpenTelemetry spans. However, application middleware and tool wrappers do not currently have a supported public contract for that identity.
Enterprise tool gateways commonly need to bind:
- a policy decision to the exact logical tool call;
- an approval request and its resumed execution;
- normalized argument digests and consume-once records;
- audit events and function results;
- parallel calls to separate correlation records.
Passing this identity as a model-generated tool argument is not appropriate because it mixes framework metadata with model-controlled business arguments.
Existing direction
PR #638 demonstrated the need for per-function interception. It was closed with maintainer guidance that the capability should be implemented as an agent.Middleware that replaces real tools with lifecycle-aware wrappers, similar to the .NET delegating-agent design.
This proposal follows that direction.
Proposed contract
A delegating-agent middleware should be able to observe a per-invocation context containing at least:
- the invoked tool;
- the original function-call content or an explicit
CallID;
- the normalized invocation arguments;
- the invocation result or error;
- the current
context.Context.
The exact API shape can follow the wrapper approach preferred in #638. Two possible non-exclusive surfaces are:
- a public function-invocation context passed to the wrapper callback;
- a typed accessor such as
tool.InvocationFromContext(ctx) when the wrapped FuncTool itself needs the metadata.
The second option should keep using standard context.Context; it should not reintroduce a custom context parameter.
Semantics to document
- The call ID identifies one logical tool invocation.
- The same approved invocation should expose the same call ID when execution resumes.
- Parallel invocations must expose distinct IDs.
- Provider behavior when no call ID is supplied should be documented, including whether the framework creates a synthetic ID.
- The call ID is a correlation identifier, not a cross-run idempotency key.
- Authorization must not rely on the call ID alone.
Suggested acceptance tests
- A delegating middleware observes the call ID before invoking a normal tool.
- An approval-required call exposes the same call ID before approval and during approved execution.
- Two parallel calls to the same tool expose distinct call IDs.
- A value added to
context.Context by the wrapper reaches FuncTool.Call.
- With no delegating middleware configured, current tool-call behavior remains unchanged.
- Function results retain the same call ID observed by the middleware.
I would be happy to contribute a focused implementation and tests after the API shape is confirmed.
Summary
Expose the current tool invocation identity, including the function call ID, through the delegating-agent middleware design proposed by the maintainers in #638.
This should preserve the idiomatic
FuncTool.Call(context.Context, args)API introduced by #205. The goal is not to restore the removed customtool.Context, but to provide a supported per-invocation interception contract for policy, approval, audit, and gateway integrations.Motivation
The automatic tool-call loop already has the originating
message.FunctionCallContentand uses itsCallIDto correlate approval requests, function results, and OpenTelemetry spans. However, application middleware and tool wrappers do not currently have a supported public contract for that identity.Enterprise tool gateways commonly need to bind:
Passing this identity as a model-generated tool argument is not appropriate because it mixes framework metadata with model-controlled business arguments.
Existing direction
PR #638 demonstrated the need for per-function interception. It was closed with maintainer guidance that the capability should be implemented as an
agent.Middlewarethat replaces real tools with lifecycle-aware wrappers, similar to the .NET delegating-agent design.This proposal follows that direction.
Proposed contract
A delegating-agent middleware should be able to observe a per-invocation context containing at least:
CallID;context.Context.The exact API shape can follow the wrapper approach preferred in #638. Two possible non-exclusive surfaces are:
tool.InvocationFromContext(ctx)when the wrappedFuncToolitself needs the metadata.The second option should keep using standard
context.Context; it should not reintroduce a custom context parameter.Semantics to document
Suggested acceptance tests
context.Contextby the wrapper reachesFuncTool.Call.I would be happy to contribute a focused implementation and tests after the API shape is confirmed.