Skip to content

Commit 721eeb4

Browse files
edburnsCopilot
andcommitted
Add low-level tool definition E2E coverage
Add a new Java failsafe integration test and replay snapshot that exercise the current explicit tool-definition APIs before ergonomic annotations are added. - add `LowLevelToolDefinitionIT` covering `create`, `createOverride`, `getArgumentsAs(record)`, `getArguments()`, and `ToolSet` available tools - add `tools/low_level_tool_definition.yaml` with multi-tool call and final response replay conversations - assert handler-driven state mutation (`currentPhase`) and expected response content Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2e25e2b commit 721eeb4

2 files changed

Lines changed: 160 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
package com.github.copilot;
6+
7+
import static org.junit.jupiter.api.Assertions.assertNotNull;
8+
import static org.junit.jupiter.api.Assertions.assertTrue;
9+
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.concurrent.CompletableFuture;
13+
import java.util.concurrent.TimeUnit;
14+
15+
import org.junit.jupiter.api.AfterAll;
16+
import org.junit.jupiter.api.BeforeAll;
17+
import org.junit.jupiter.api.Test;
18+
19+
import com.github.copilot.generated.AssistantMessageEvent;
20+
import com.github.copilot.rpc.MessageOptions;
21+
import com.github.copilot.rpc.PermissionHandler;
22+
import com.github.copilot.rpc.SessionConfig;
23+
import com.github.copilot.rpc.ToolDefinition;
24+
import com.github.copilot.rpc.ToolSet;
25+
26+
/**
27+
* Failsafe integration test for explicit (non-ergonomic) tool definition APIs.
28+
*
29+
* @see Snapshot: tools/low_level_tool_definition
30+
*/
31+
class LowLevelToolDefinitionIT {
32+
33+
private static E2ETestContext ctx;
34+
private String currentPhase;
35+
36+
record PhaseArgs(String phase) {
37+
}
38+
39+
@BeforeAll
40+
static void setup() throws Exception {
41+
ctx = E2ETestContext.create();
42+
}
43+
44+
@AfterAll
45+
static void teardown() throws Exception {
46+
if (ctx != null) {
47+
ctx.close();
48+
}
49+
}
50+
51+
@Test
52+
void lowLevelToolDefinition() throws Exception {
53+
ctx.configureForTest("tools", "low_level_tool_definition");
54+
55+
Map<String, Object> setPhaseSchema = Map.of("type", "object", "properties",
56+
Map.of("phase", Map.of("type", "string", "enum", List.of("searching", "analyzing", "done"))),
57+
"required", List.of("phase"));
58+
59+
ToolDefinition setPhaseTool = ToolDefinition.create("set_current_phase", "Sets the current phase of the agent",
60+
setPhaseSchema, invocation -> {
61+
PhaseArgs args = invocation.getArgumentsAs(PhaseArgs.class);
62+
currentPhase = args.phase();
63+
return CompletableFuture.completedFuture("Phase set to " + currentPhase);
64+
});
65+
66+
Map<String, Object> searchSchema = Map.of("type", "object", "properties",
67+
Map.of("keyword", Map.of("type", "string")), "required", List.of("keyword"));
68+
69+
ToolDefinition searchTool = ToolDefinition.create("search_items", "Search for items by keyword", searchSchema,
70+
invocation -> {
71+
Map<String, Object> args = invocation.getArguments();
72+
args.get("keyword");
73+
return CompletableFuture.completedFuture("Found: item_alpha, item_beta");
74+
});
75+
76+
Map<String, Object> grepSchema = Map.of("type", "object", "properties",
77+
Map.of("query", Map.of("type", "string")), "required", List.of("query"));
78+
79+
ToolDefinition grepOverrideTool = ToolDefinition.createOverride("grep", "Custom grep override", grepSchema,
80+
invocation -> {
81+
Map<String, Object> args = invocation.getArguments();
82+
String query = (String) args.get("query");
83+
return CompletableFuture.completedFuture("CUSTOM_GREP: " + query);
84+
});
85+
86+
try (CopilotClient client = ctx.createClient()) {
87+
CopilotSession session = client
88+
.createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
89+
.setAvailableTools(new ToolSet().addCustom("*").addBuiltIn("web_fetch"))
90+
.setTools(List.of(setPhaseTool, searchTool, grepOverrideTool)))
91+
.get(30, TimeUnit.SECONDS);
92+
93+
try {
94+
AssistantMessageEvent response = session.sendAndWait(new MessageOptions().setPrompt(
95+
"First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and search results."),
96+
60_000).get(90, TimeUnit.SECONDS);
97+
98+
assertNotNull(response, "Expected a response from the assistant");
99+
String content = response.getData().content().toLowerCase();
100+
assertTrue(content.contains("analyzing"),
101+
"Response should contain the updated phase: " + response.getData().content());
102+
assertTrue(content.contains("item_alpha") || content.contains("item_beta"),
103+
"Response should contain search results: " + response.getData().content());
104+
assertTrue("analyzing".equals(currentPhase),
105+
"Expected currentPhase to be analyzing but was: " + currentPhase);
106+
} finally {
107+
session.close();
108+
}
109+
}
110+
}
111+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
models:
2+
- claude-sonnet-4.5
3+
conversations:
4+
- messages:
5+
- role: system
6+
content: ${system}
7+
- role: user
8+
content: First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and search results.
9+
- role: assistant
10+
content: I'll set the phase and run the search now.
11+
tool_calls:
12+
- id: toolcall_0
13+
type: function
14+
function:
15+
name: set_current_phase
16+
arguments: '{"phase":"analyzing"}'
17+
- id: toolcall_1
18+
type: function
19+
function:
20+
name: search_items
21+
arguments: '{"keyword":"copilot"}'
22+
- messages:
23+
- role: system
24+
content: ${system}
25+
- role: user
26+
content: First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and search results.
27+
- role: assistant
28+
content: I'll set the phase and run the search now.
29+
tool_calls:
30+
- id: toolcall_0
31+
type: function
32+
function:
33+
name: set_current_phase
34+
arguments: '{"phase":"analyzing"}'
35+
- id: toolcall_1
36+
type: function
37+
function:
38+
name: search_items
39+
arguments: '{"keyword":"copilot"}'
40+
- role: tool
41+
tool_call_id: toolcall_0
42+
content: Phase set to analyzing
43+
- role: tool
44+
tool_call_id: toolcall_1
45+
content: "Found: item_alpha, item_beta"
46+
- role: assistant
47+
content: |-
48+
Current phase: analyzing
49+
Search results: item_alpha, item_beta

0 commit comments

Comments
 (0)