-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add E2E integration test for ergonomic @CopilotTool + ToolDefinition.fromObject() API #1787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
edburns
merged 9 commits into
edburns/1682-java-tool-ergonomics
from
copilot/edburns1682-java-tool-ergonomics
Jun 24, 2026
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
f1c0897
Initial plan
Copilot aeb9f24
Initial plan
Copilot ccb2a33
Initial plan
Copilot 9906986
Add E2E integration test for ergonomic @CopilotTool + ToolDefinition.…
Copilot 141b5ac
spotless
edburns 1a919f2
fix: use passed ObjectMapper for record-parameter conversion
edburns bdc3c69
fix: exclude Optional types from required list in generated schema
edburns a277021
fix: correct misleading Javadoc in ToolDefinitionFromObjectTest
edburns a423f7c
fix: remove unused grep override tool from E2E test
edburns File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools$$CopilotToolMeta.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| // Hand-written test fixture mimicking CopilotToolProcessor output. | ||
| package com.github.copilot.e2e; | ||
|
|
||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.github.copilot.rpc.ToolDefinition; | ||
| import com.github.copilot.tool.CopilotToolMetadataProvider; | ||
|
|
||
| import java.util.*; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| public final class ErgonomicTestTools$$CopilotToolMeta implements CopilotToolMetadataProvider<ErgonomicTestTools> { | ||
|
|
||
| private static Map<String, Object> withMeta(Map<String, Object> base, String description, Object defaultValue) { | ||
| var result = new LinkedHashMap<String, Object>(base); | ||
| if (description != null) | ||
| result.put("description", description); | ||
| if (defaultValue != null) | ||
| result.put("default", defaultValue); | ||
| return Collections.unmodifiableMap(result); | ||
| } | ||
|
|
||
| @Override | ||
| @SuppressWarnings({"unchecked", "rawtypes"}) | ||
| public List<ToolDefinition> definitions(ErgonomicTestTools instance, ObjectMapper mapper) { | ||
| return List.of(new ToolDefinition("set_current_phase", "Sets the current phase of the agent", | ||
| Map.of("type", "object", "properties", | ||
| Map.ofEntries(Map.entry("phase", | ||
| (Map<String, Object>) (Map) withMeta(Map.of("type", "string"), | ||
| "The phase to transition to", null))), | ||
| "required", List.of("phase")), | ||
| invocation -> { | ||
| Map<String, Object> args = invocation.getArguments(); | ||
| String phase = (String) args.get("phase"); | ||
| return CompletableFuture.completedFuture(instance.setCurrentPhase(phase)); | ||
| }, null, null, null), | ||
| new ToolDefinition( | ||
| "search_items", "Search for items by keyword", Map | ||
| .of("type", "object", "properties", | ||
| Map.ofEntries(Map.entry("keyword", | ||
| (Map<String, Object>) (Map) withMeta(Map.of("type", "string"), | ||
| "Search keyword", null))), | ||
| "required", List.of("keyword")), | ||
| invocation -> { | ||
| Map<String, Object> args = invocation.getArguments(); | ||
| String keyword = (String) args.get("keyword"); | ||
| return CompletableFuture.completedFuture(instance.searchItems(keyword)); | ||
| }, null, null, null)); | ||
| } | ||
| } |
32 changes: 32 additions & 0 deletions
32
java/src/test/java/com/github/copilot/e2e/ErgonomicTestTools.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| package com.github.copilot.e2e; | ||
|
|
||
| import com.github.copilot.tool.CopilotTool; | ||
| import com.github.copilot.tool.Param; | ||
|
|
||
| /** | ||
| * Tool fixture for the ergonomic {@code @CopilotTool} E2E integration test. | ||
| * | ||
| * <p> | ||
| * This class exercises the annotation-based tool definition API, producing | ||
| * identical wire-level tool schemas to the low-level | ||
| * {@code ToolDefinition.create()} API. | ||
| */ | ||
| class ErgonomicTestTools { | ||
|
|
||
| String currentPhase; | ||
|
|
||
| @CopilotTool("Sets the current phase of the agent") | ||
| public String setCurrentPhase(@Param("The phase to transition to") String phase) { | ||
| currentPhase = phase; | ||
| return "Phase set to " + phase; | ||
| } | ||
|
|
||
| @CopilotTool("Search for items by keyword") | ||
| public String searchItems(@Param("Search keyword") String keyword) { | ||
| return "Found: item_alpha, item_beta"; | ||
| } | ||
| } |
85 changes: 85 additions & 0 deletions
85
java/src/test/java/com/github/copilot/e2e/ErgonomicToolDefinitionIT.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| package com.github.copilot.e2e; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
|
||
| import java.util.List; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| import org.junit.jupiter.api.AfterAll; | ||
| import org.junit.jupiter.api.BeforeAll; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import com.github.copilot.CopilotClient; | ||
| import com.github.copilot.CopilotSession; | ||
| import com.github.copilot.E2ETestContext; | ||
| import com.github.copilot.generated.AssistantMessageEvent; | ||
| import com.github.copilot.rpc.MessageOptions; | ||
| import com.github.copilot.rpc.PermissionHandler; | ||
| import com.github.copilot.rpc.SessionConfig; | ||
| import com.github.copilot.rpc.ToolDefinition; | ||
| import com.github.copilot.rpc.ToolSet; | ||
|
|
||
| /** | ||
| * Failsafe integration test for the ergonomic {@code @CopilotTool} + | ||
| * {@code ToolDefinition.fromObject()} API. | ||
| * | ||
| * <p> | ||
| * This test proves that the ergonomic annotation-based API produces identical | ||
| * wire behavior to the low-level {@code ToolDefinition.create()} API tested in | ||
| * {@code LowLevelToolDefinitionIT}. | ||
| * | ||
| * @see Snapshot: tools/ergonomic_tool_definition | ||
| */ | ||
| class ErgonomicToolDefinitionIT { | ||
|
|
||
| private static E2ETestContext ctx; | ||
|
|
||
| @BeforeAll | ||
| static void setup() throws Exception { | ||
| ctx = E2ETestContext.create(); | ||
| } | ||
|
|
||
| @AfterAll | ||
| static void teardown() throws Exception { | ||
| if (ctx != null) { | ||
| ctx.close(); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| void ergonomicToolDefinition() throws Exception { | ||
| ctx.configureForTest("tools", "ergonomic_tool_definition"); | ||
|
|
||
| ErgonomicTestTools tools = new ErgonomicTestTools(); | ||
| List<ToolDefinition> toolDefs = ToolDefinition.fromObject(tools); | ||
|
|
||
| try (CopilotClient client = ctx.createClient()) { | ||
| CopilotSession session = client | ||
| .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) | ||
| .setAvailableTools(new ToolSet().addCustom("*").addBuiltIn("web_fetch")).setTools(toolDefs)) | ||
| .get(30, TimeUnit.SECONDS); | ||
|
|
||
| try { | ||
| AssistantMessageEvent response = session.sendAndWait(new MessageOptions().setPrompt( | ||
| "First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and search results."), | ||
| 60_000).get(90, TimeUnit.SECONDS); | ||
|
|
||
| assertNotNull(response, "Expected a response from the assistant"); | ||
| String content = response.getData().content().toLowerCase(); | ||
| assertTrue(content.contains("analyzing"), | ||
| "Response should contain the updated phase: " + response.getData().content()); | ||
| assertTrue(content.contains("item_alpha") || content.contains("item_beta"), | ||
| "Response should contain search results: " + response.getData().content()); | ||
| assertTrue("analyzing".equals(tools.currentPhase), | ||
| "Expected currentPhase to be 'analyzing' but was: " + tools.currentPhase); | ||
| } finally { | ||
| session.close(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| models: | ||
| - claude-sonnet-4.5 | ||
| conversations: | ||
| - messages: | ||
| - role: system | ||
| content: ${system} | ||
| - role: user | ||
| content: First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and | ||
| search results. | ||
| - role: assistant | ||
| content: I'll set the phase and run the search now. | ||
| tool_calls: | ||
| - id: toolcall_0 | ||
| type: function | ||
| function: | ||
| name: set_current_phase | ||
| arguments: '{"phase":"analyzing"}' | ||
| - id: toolcall_1 | ||
| type: function | ||
| function: | ||
| name: search_items | ||
| arguments: '{"keyword":"copilot"}' | ||
| - role: tool | ||
| tool_call_id: toolcall_0 | ||
| content: Phase set to analyzing | ||
| - role: tool | ||
| tool_call_id: toolcall_1 | ||
| content: "Found: item_alpha, item_beta" | ||
| - role: assistant | ||
| content: |- | ||
| Current phase: analyzing | ||
| Search results: item_alpha, item_beta |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.