Skip to content

Add E2E integration test for ergonomic @CopilotTool + ToolDefinition.fromObject() API#1787

Merged
edburns merged 9 commits into
edburns/1682-java-tool-ergonomicsfrom
copilot/edburns1682-java-tool-ergonomics
Jun 24, 2026
Merged

Add E2E integration test for ergonomic @CopilotTool + ToolDefinition.fromObject() API#1787
edburns merged 9 commits into
edburns/1682-java-tool-ergonomicsfrom
copilot/edburns1682-java-tool-ergonomics

Conversation

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Proves the ergonomic @CopilotTool annotation API produces byte-for-byte identical wire behavior to the low-level ToolDefinition.create() API against the replay proxy.

Changes

  • test/snapshots/tools/ergonomic_tool_definition.yaml — Reuses the same snapshot as low_level_tool_definition.yaml (wire format is identical by design)
  • java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools.java — Tool fixture exercising all three annotation patterns:
    • Default snake_case name derivation (setCurrentPhaseset_current_phase)
    • Simple parameter tool (searchItemssearch_items)
    • Explicit name + override (name = "grep", overridesBuiltInTool = true)
  • java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools$$CopilotToolMeta.java — Hand-written processor companion (same pattern as rpc/fixtures/*$$CopilotToolMeta.java)
  • java/src/test/java/com/github/copilot/e2e/ErgonomicToolDefinitionIT.java — Failsafe IT that calls ToolDefinition.fromObject(tools), sends a prompt triggering all three tools, and asserts invocation args + state mutation

Wire equivalence

The meta class produces schemas with identical tool names, parameter names, types, and overridesBuiltInTool flags as LowLevelToolDefinitionIT — allowing the same replay snapshot to serve both tests.

ErgonomicTestTools tools = new ErgonomicTestTools();
List<ToolDefinition> toolDefs = ToolDefinition.fromObject(tools);
// → [set_current_phase, search_items, grep] with identical JSON schemas

@edburns edburns force-pushed the edburns/1682-java-tool-ergonomics branch from 96ede86 to 1aae0df Compare June 24, 2026 18:08
Copilot AI changed the title [WIP] Add E2E integration test for @CopilotTool ergonomics Add E2E integration test for ergonomic @CopilotTool + ToolDefinition.fromObject() API Jun 24, 2026
Copilot AI requested a review from edburns June 24, 2026 18:16
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@edburns edburns marked this pull request as ready for review June 24, 2026 18:48
@edburns edburns requested a review from a team as a code owner June 24, 2026 18:48
Copilot AI review requested due to automatic review settings June 24, 2026 18:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new ergonomic, annotation-driven tool-definition API to the Java SDK (@CopilotTool, @Param, and ToolDefinition.fromObject/fromClass) backed by a JSR-269 annotation processor that generates $$CopilotToolMeta companion classes. It also introduces new unit/compilation tests and a Java E2E integration test plus snapshot intended to prove wire-level equivalence with the existing low-level ToolDefinition.create() approach.

Changes:

  • Add com.github.copilot.tool public API: annotations, metadata-provider interface, schema generator, and annotation processor.
  • Add ToolDefinition.fromObject/fromClass to load generated metadata and produce ToolDefinition lists with working handlers.
  • Add tests (compiler-based processor/schema tests, fromObject unit tests, and an E2E failsafe IT + snapshot).
Show a summary per file
File Description
test/snapshots/tools/ergonomic_tool_definition.yaml Replay snapshot for the new ergonomic Java E2E tool-definition test.
java/src/test/java/com/github/copilot/tool/SchemaGeneratorTest.java Compilation-testing unit tests for SchemaGenerator type→schema mapping.
java/src/test/java/com/github/copilot/tool/CopilotToolProcessorTest.java Compilation-based tests asserting generated code shape and diagnostics for CopilotToolProcessor.
java/src/test/java/com/github/copilot/tool/CopilotToolAnnotationTest.java Unit tests validating annotation retention/targets/defaults and presence of @CopilotExperimental.
java/src/test/java/com/github/copilot/rpc/ToolDefinitionFromObjectTest.java Unit tests for ToolDefinition.fromObject/fromClass behavior and handler invocation.
java/src/test/java/com/github/copilot/rpc/fixtures/SimpleTools$$CopilotToolMeta.java Hand-written fixture mimicking generated metadata for SimpleTools.
java/src/test/java/com/github/copilot/rpc/fixtures/SimpleTools.java @CopilotTool fixture class for fromObject tests.
java/src/test/java/com/github/copilot/rpc/fixtures/OverrideTools$$CopilotToolMeta.java Hand-written fixture metadata for override tool behavior.
java/src/test/java/com/github/copilot/rpc/fixtures/OverrideTools.java @CopilotTool fixture exercising overridesBuiltInTool.
java/src/test/java/com/github/copilot/rpc/fixtures/MultiReturnTools$$CopilotToolMeta.java Hand-written fixture metadata for return-type handling.
java/src/test/java/com/github/copilot/rpc/fixtures/MultiReturnTools.java Fixture with multiple return shapes (String/void/CompletableFuture).
java/src/test/java/com/github/copilot/rpc/fixtures/DefaultValueTools$$CopilotToolMeta.java Hand-written fixture metadata exercising default-argument behavior.
java/src/test/java/com/github/copilot/rpc/fixtures/DefaultValueTools.java Fixture with @Param(defaultValue=...) on a primitive parameter.
java/src/test/java/com/github/copilot/rpc/fixtures/DateTimeTools$$CopilotToolMeta.java Hand-written fixture metadata for java.time arg coercion using mapper.
java/src/test/java/com/github/copilot/rpc/fixtures/DateTimeTools.java Fixture using LocalDateTime tool parameter.
java/src/test/java/com/github/copilot/rpc/fixtures/ArgCoercionTools$$CopilotToolMeta.java Hand-written fixture metadata for primitive/enum coercion.
java/src/test/java/com/github/copilot/rpc/fixtures/ArgCoercionTools.java Fixture class for mixed arg coercion.
java/src/test/java/com/github/copilot/e2e/ErgonomicToolDefinitionIT.java New Java failsafe IT that uses ToolDefinition.fromObject(...) against the replay proxy.
java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools$$CopilotToolMeta.java Hand-written $$CopilotToolMeta fixture for the E2E test.
java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools.java Tool fixture class exercising annotation patterns for the E2E test.
java/src/main/resources/META-INF/services/javax.annotation.processing.Processor Registers the new processor via SPI alongside CopilotExperimentalProcessor.
java/src/main/java/module-info.java Exports new com.github.copilot.tool package and registers the processor in JPMS provides.
java/src/main/java/com/github/copilot/tool/SchemaGenerator.java Compile-time JSON schema generator from TypeMirror / javax.lang.model types.
java/src/main/java/com/github/copilot/tool/Param.java New @Param annotation (description/name/required/defaultValue).
java/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java JSR-269 processor generating $$CopilotToolMeta classes + schema + invocation lambdas.
java/src/main/java/com/github/copilot/tool/CopilotToolMetadataProvider.java SPI-style interface implemented by generated meta classes to return ToolDefinitions.
java/src/main/java/com/github/copilot/tool/CopilotTool.java New @CopilotTool annotation (name/override/skipPermission/defer).
java/src/main/java/com/github/copilot/rpc/ToolDefinition.java Adds fromObject/fromClass runtime bridge for loading generated metadata.
java/src/main/java/com/github/copilot/rpc/ToolDefer.java Adds NONE sentinel and adjusts JSON value handling to support omission semantics.
java/mvnw Adds a Maven wrapper script under java/.
1682-java-tool-ergonomics-prompts-remove-before-merge/dd3021192/src/main/java/module-info.java JPMS spike module for experimentation (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/dd3021192/src/main/java/com/github/dd3021192/MyTools$$CopilotToolMeta.java JPMS spike meta-class example (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/dd3021192/src/main/java/com/github/dd3021192/MyTools.java JPMS spike tool class (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/dd3021192/src/main/java/com/github/dd3021192/Main.java JPMS spike main program (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/dd3021192/pom.xml Spike Maven project (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/dd3021192/dependency-reduced-pom.xml Generated Shade artifact (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md Internal implementation-plan notes (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/add-tests-that-use-low_level_tool_definition.yaml.md Internal prompt/instructions doc (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/20260618-prompts.md Internal prompt transcript (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/20260617-prompts.md Internal prompt transcript (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/20260616-prompts.md Internal prompt transcript (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/20260615-prompts.md Internal prompt transcript (staging content).
1682-java-tool-ergonomics-prompts-remove-before-merge/1682-low-level-tool-definition.md Internal plan doc (staging content).

Copilot's findings

  • Files reviewed: 44/46 changed files
  • Comments generated: 7

Comment thread java/src/main/java/com/github/copilot/tool/CopilotToolProcessor.java Outdated
Copilot AI and others added 9 commits June 24, 2026 16:20
…fromObject() API

Create ErgonomicToolDefinitionIT that proves the ergonomic annotation-based
API produces identical wire behavior to the low-level ToolDefinition.create()
API, tested against the replay proxy.

Files added:
- test/snapshots/tools/ergonomic_tool_definition.yaml (identical to
  low_level_tool_definition.yaml since wire format is the same)
- java/src/test/java/com/github/copilot/e2e/ErgonomicToolDefinitionIT.java
- java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools.java
- java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools$$CopilotToolMeta.java

Closes #1762
The single-record-parameter shortcut in CopilotToolProcessor generated
invocation.getArgumentsAs() which uses an unconfigured ObjectMapper
internally (no JavaTimeModule, no SDK settings). Switch to
mapper.convertValue(args, RecordType.class) which uses the
SDK-configured mapper passed to the definitions() method.

Addresses review comment r3469523760.
CopilotToolProcessor.generateSchemaWithParamMetadata() now checks if
a parameter type is Optional/OptionalInt/OptionalLong/OptionalDouble
before adding it to the JSON Schema required list. This aligns with
SchemaGenerator which already treats these types as optional.

Addresses review comment r3469523801.
The class-level Javadoc incorrectly stated that the annotation processor
generates $$CopilotToolMeta fixtures during test compilation. In reality,
the module has <proc>none</proc> and these fixtures are hand-written
classes under com.github.copilot.rpc.fixtures.

Addresses review comment r3469523833.
The ErgonomicToolDefinitionIT snapshot only exercises set_current_phase
and search_items. The grep tool (with overridesBuiltInTool=true) was
never invoked, making it dead code that contradicted the PR description.

Addresses review comment r3469523851.
@edburns edburns force-pushed the copilot/edburns1682-java-tool-ergonomics branch from 3b89229 to a423f7c Compare June 24, 2026 20:21
@github-actions

Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review ✅

This PR is scoped entirely to the Java SDK — E2E test for the ergonomic @CopilotTool annotation API and a bug fix in CopilotToolProcessor. No cross-SDK consistency issues are introduced.

Ergonomic tool-definition API — consistent across all SDKs

The ToolDefinition.fromObject() / @CopilotTool pattern being tested here is the Java idiom for a feature that already exists in language-appropriate form across every SDK:

SDK Ergonomic API
Java @CopilotTool + ToolDefinition.fromObject()
Python @define_tool decorator
Go DefineTool[T]() generic helper
.NET CopilotTool.DefineTool()
Rust define_tool() / ToolHandler trait
Node.js Manual ToolDefinition construction (by design)

Optional-type fix — Java-specific, no cross-SDK action needed

The fix to mark Optional / OptionalInt / OptionalLong / OptionalDouble parameters as non-required in the generated JSON schema is a Java annotation-processor concern. All other SDKs already handle this correctly through their own type systems:

  • Python: Pydantic excludes Optional[T] fields from required automatically
  • Go: pointer types (*T) are treated as optional by jsonschema-go
  • .NET: nullable types (T?) are excluded from required by AIFunctionFactory
  • Rust: Option<T> is excluded from required by schemars

Minor observation (not a blocker)

The PR description lists three annotation patterns under test — including name = "grep", overridesBuiltInTool = true — but ErgonomicTestTools.java and its $$CopilotToolMeta companion only implement two tools (set_current_phase, search_items). The override/named tool pattern is not exercised in this iteration. Worth noting in case that coverage is planned for a follow-up.

Generated by SDK Consistency Review Agent for issue #1787 · sonnet46 1M ·

@edburns edburns merged commit 3afb2fe into edburns/1682-java-tool-ergonomics Jun 24, 2026
31 checks passed
@edburns edburns deleted the copilot/edburns1682-java-tool-ergonomics branch June 24, 2026 20:36
edburns added a commit that referenced this pull request Jun 24, 2026
…fromObject() API (#1787)

* Initial plan

* Initial plan

* Initial plan

* Add E2E integration test for ergonomic @copilotTool + ToolDefinition.fromObject() API

Create ErgonomicToolDefinitionIT that proves the ergonomic annotation-based
API produces identical wire behavior to the low-level ToolDefinition.create()
API, tested against the replay proxy.

Files added:
- test/snapshots/tools/ergonomic_tool_definition.yaml (identical to
  low_level_tool_definition.yaml since wire format is the same)
- java/src/test/java/com/github/copilot/e2e/ErgonomicToolDefinitionIT.java
- java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools.java
- java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools$$CopilotToolMeta.java

Closes #1762

* spotless

* fix: use passed ObjectMapper for record-parameter conversion

The single-record-parameter shortcut in CopilotToolProcessor generated
invocation.getArgumentsAs() which uses an unconfigured ObjectMapper
internally (no JavaTimeModule, no SDK settings). Switch to
mapper.convertValue(args, RecordType.class) which uses the
SDK-configured mapper passed to the definitions() method.

Addresses review comment r3469523760.

* fix: exclude Optional types from required list in generated schema

CopilotToolProcessor.generateSchemaWithParamMetadata() now checks if
a parameter type is Optional/OptionalInt/OptionalLong/OptionalDouble
before adding it to the JSON Schema required list. This aligns with
SchemaGenerator which already treats these types as optional.

Addresses review comment r3469523801.

* fix: correct misleading Javadoc in ToolDefinitionFromObjectTest

The class-level Javadoc incorrectly stated that the annotation processor
generates $$CopilotToolMeta fixtures during test compilation. In reality,
the module has <proc>none</proc> and these fixtures are hand-written
classes under com.github.copilot.rpc.fixtures.

Addresses review comment r3469523833.

* fix: remove unused grep override tool from E2E test

The ErgonomicToolDefinitionIT snapshot only exercises set_current_phase
and search_items. The grep tool (with overridesBuiltInTool=true) was
never invoked, making it dead code that contradicted the PR description.

Addresses review comment r3469523851.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Ed Burns <edburns@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Java] @CopilotTool ergonomics 4.5: E2E integration test with replay proxy

3 participants