Overview
Add support for hidden ToolInvocation parameter injection in the annotation-based Java tools API so a @CopilotTool method can opt in to receiving invocation context without exposing that parameter in the tool schema.
Example target usage:
@CopilotTool("Reports progress for the current tool call")
public String reportProgress(
@Param("Current phase") String phase,
ToolInvocation invocation) {
return "phase=" + phase + ", session=" + invocation.getSessionId();
}
ToolInvocation must be treated as runtime context, not as an LLM-visible parameter.
Parent Epic: #1682
Parent Follow-up: #1809
Motivation
The current annotation-based Java API generates a ToolDefinition handler that receives a ToolInvocation, but @CopilotTool methods themselves cannot declare ToolInvocation as a hidden injected parameter. Every declared method parameter is currently treated as schema/input data.
This is a capability gap relative to:
- the low-level Java
ToolHandler API, which already exposes ToolInvocation
- the .NET API, which supports hidden
ToolInvocation binding in CopilotTool.DefineTool(...)
Some advanced tools need access to invocation context such as:
sessionId
toolCallId
toolName
- raw arguments for logging, auditing, or custom handling
Without this feature, users must drop down to the low-level ToolDefinition.create(...) API just to access invocation context.
Deliverables
Files to modify
java/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java
java/src/test/java/com/github/copilot/rpc/ToolDefinitionFromObjectTest.java
java/src/test/java/com/github/copilot/rpc/fixtures/* — add or update fixtures that exercise ToolInvocation injection
java/README.md and/or the relevant Java tools documentation if annotation-based examples are documented there
Implementation specification
1. Treat ToolInvocation as a hidden special parameter
If a @CopilotTool method declares a parameter of type com.github.copilot.rpc.ToolInvocation, the annotation processor must:
- exclude that parameter from generated JSON Schema
- exclude that parameter from
required
- not read that parameter from
invocation.getArguments()
- pass the current
invocation object directly when generating the method call
This is opt-in by signature only. Methods that do not declare ToolInvocation must behave exactly as they do today.
2. Schema generation changes
In generateSchemaWithParamMetadata(...), skip parameters whose erased/qualified type is com.github.copilot.rpc.ToolInvocation.
That means this method:
@CopilotTool("Reports progress")
public String reportProgress(@Param("Current phase") String phase,
ToolInvocation invocation) {
return "ok";
}
must produce a schema equivalent to a single-parameter tool with only phase.
3. Invocation lambda generation changes
In generateLambdaBody(...) and argument-list generation, treat ToolInvocation specially:
- normal parameters are still extracted from
Map<String, Object> args = invocation.getArguments();
ToolInvocation parameters are bound directly to the in-scope invocation variable
Generated code should conceptually behave like:
invocation -> {
Map<String, Object> args = invocation.getArguments();
String phase = (String) args.get("phase");
return CompletableFuture.completedFuture(instance.reportProgress(phase, invocation));
}
4. Validation rules
The processor should reject ambiguous or unsupported forms with compile-time errors.
At minimum:
- More than one
ToolInvocation parameter on the same method is an error.
ToolInvocation must not be annotated with @Param.
ToolInvocation must not be used as the single-record wrapper parameter shortcut.
The error messages should clearly explain that ToolInvocation is injected runtime context and not part of the tool schema.
5. Static methods
This feature must work for both instance and static @CopilotTool methods.
6. Return-type behavior remains unchanged
This issue is only about parameter binding. Existing return handling must continue to work unchanged for:
String
void
- non-
String sync return values
CompletableFuture<T>
Gating tests and criteria
All of the following must pass:
Unit/integration tests
- Instance method injection:
@CopilotTool instance method with one normal argument plus ToolInvocation receives both values correctly.
- Static method injection: static
@CopilotTool method with ToolInvocation works correctly.
- Schema exclusion: generated tool schema does not include
ToolInvocation as a property or required parameter.
- No-regression path: existing annotation-based tools without
ToolInvocation continue to behave unchanged.
- Async method compatibility: a
@CopilotTool method returning CompletableFuture<String> can also declare ToolInvocation.
- Compile error on duplicate context params: two
ToolInvocation parameters produce a processor error.
- Compile error on
@Param ToolInvocation: annotating a ToolInvocation parameter with @Param produces a processor error.
Full build
cd java && mvn verify passes with no regressions.
Design decisions
- Opt-in by signature. Users only receive
ToolInvocation if they explicitly declare it.
- Hidden runtime context.
ToolInvocation is never part of the LLM-visible schema.
- Annotation API parity improvement. This closes a gap between
@CopilotTool and the low-level ToolHandler/ToolDefinition.create(...) path.
- No CDI or JSR-330 dependency. This feature is simple generated-parameter binding, not container-managed injection.
Example usage
class ProgressTools {
@CopilotTool("Reports the current phase and session")
public String reportProgress(
@Param("Current phase") String phase,
ToolInvocation invocation) {
return "phase=" + phase
+ ", sessionId=" + invocation.getSessionId()
+ ", toolCallId=" + invocation.getToolCallId();
}
}
Branch and PR conventions
- Branch: create from
main on upstream
- PR target:
main
- Run
cd java && mvn verify before merging
- Follow existing Javadoc conventions for any public API/documentation updates
Overview
Add support for hidden
ToolInvocationparameter injection in the annotation-based Java tools API so a@CopilotToolmethod can opt in to receiving invocation context without exposing that parameter in the tool schema.Example target usage:
ToolInvocationmust be treated as runtime context, not as an LLM-visible parameter.Parent Epic: #1682
Parent Follow-up: #1809
Motivation
The current annotation-based Java API generates a
ToolDefinitionhandler that receives aToolInvocation, but@CopilotToolmethods themselves cannot declareToolInvocationas a hidden injected parameter. Every declared method parameter is currently treated as schema/input data.This is a capability gap relative to:
ToolHandlerAPI, which already exposesToolInvocationToolInvocationbinding inCopilotTool.DefineTool(...)Some advanced tools need access to invocation context such as:
sessionIdtoolCallIdtoolNameWithout this feature, users must drop down to the low-level
ToolDefinition.create(...)API just to access invocation context.Deliverables
Files to modify
java/src/main/java/com/github/copilot/tool/CopilotToolProcessor.javajava/src/test/java/com/github/copilot/rpc/ToolDefinitionFromObjectTest.javajava/src/test/java/com/github/copilot/rpc/fixtures/*— add or update fixtures that exerciseToolInvocationinjectionjava/README.mdand/or the relevant Java tools documentation if annotation-based examples are documented thereImplementation specification
1. Treat
ToolInvocationas a hidden special parameterIf a
@CopilotToolmethod declares a parameter of typecom.github.copilot.rpc.ToolInvocation, the annotation processor must:requiredinvocation.getArguments()invocationobject directly when generating the method callThis is opt-in by signature only. Methods that do not declare
ToolInvocationmust behave exactly as they do today.2. Schema generation changes
In
generateSchemaWithParamMetadata(...), skip parameters whose erased/qualified type iscom.github.copilot.rpc.ToolInvocation.That means this method:
must produce a schema equivalent to a single-parameter tool with only
phase.3. Invocation lambda generation changes
In
generateLambdaBody(...)and argument-list generation, treatToolInvocationspecially:Map<String, Object> args = invocation.getArguments();ToolInvocationparameters are bound directly to the in-scopeinvocationvariableGenerated code should conceptually behave like:
4. Validation rules
The processor should reject ambiguous or unsupported forms with compile-time errors.
At minimum:
ToolInvocationparameter on the same method is an error.ToolInvocationmust not be annotated with@Param.ToolInvocationmust not be used as the single-record wrapper parameter shortcut.The error messages should clearly explain that
ToolInvocationis injected runtime context and not part of the tool schema.5. Static methods
This feature must work for both instance and static
@CopilotToolmethods.6. Return-type behavior remains unchanged
This issue is only about parameter binding. Existing return handling must continue to work unchanged for:
StringvoidStringsync return valuesCompletableFuture<T>Gating tests and criteria
All of the following must pass:
Unit/integration tests
@CopilotToolinstance method with one normal argument plusToolInvocationreceives both values correctly.@CopilotToolmethod withToolInvocationworks correctly.ToolInvocationas a property or required parameter.ToolInvocationcontinue to behave unchanged.@CopilotToolmethod returningCompletableFuture<String>can also declareToolInvocation.ToolInvocationparameters produce a processor error.@Param ToolInvocation: annotating aToolInvocationparameter with@Paramproduces a processor error.Full build
cd java && mvn verifypasses with no regressions.Design decisions
ToolInvocationif they explicitly declare it.ToolInvocationis never part of the LLM-visible schema.@CopilotTooland the low-levelToolHandler/ToolDefinition.create(...)path.Example usage
Branch and PR conventions
mainonupstreammaincd java && mvn verifybefore merging