Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 5 additions & 46 deletions src/test/java/com/github/copilot/sdk/ToolsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -377,10 +374,6 @@ void testShouldExecuteMultipleCustomToolsInParallelSingleTurn() throws Exception

var toolACalled = new CompletableFuture<String>();
var toolBCalled = new CompletableFuture<String>();
var handlersStarted = new CountDownLatch(2);
var releaseHandlers = new CountDownLatch(1);
var activeHandlers = new AtomicInteger();
var handlersOverlapped = new AtomicBoolean(false);

Map<String, Object> cityParams = Map.of("type", "object", "properties",
Map.of("city", Map.of("type", "string", "description", "City name")), "required", List.of("city"));
Expand All @@ -392,36 +385,28 @@ void testShouldExecuteMultipleCustomToolsInParallelSingleTurn() throws Exception
(invocation) -> {
String city = (String) invocation.getArguments().get("city");
toolACalled.complete(city);
return executeParallelHandler(city, "CITY_", handlersStarted, releaseHandlers, activeHandlers,
handlersOverlapped);
return CompletableFuture.completedFuture("CITY_" + city.toUpperCase());
});

ToolDefinition lookupCountry = ToolDefinition.create("lookup_country", "Looks up country information",
countryParams, (invocation) -> {
String country = (String) invocation.getArguments().get("country");
toolBCalled.complete(country);
return executeParallelHandler(country, "COUNTRY_", handlersStarted, releaseHandlers, activeHandlers,
handlersOverlapped);
return CompletableFuture.completedFuture("COUNTRY_" + country.toUpperCase());
});

try (CopilotClient client = ctx.createClient()) {
CopilotSession session = client.createSession(new SessionConfig()
.setTools(List.of(lookupCity, lookupCountry)).setOnPermissionRequest(PermissionHandler.APPROVE_ALL))
.get();

CompletableFuture<AssistantMessageEvent> responseFuture = session
.sendAndWait(new MessageOptions().setPrompt(
"Use lookup_city with 'Paris' and lookup_country with 'France' at the same time, then combine both results in your reply."));

assertTrue(handlersStarted.await(10, TimeUnit.SECONDS), "Both tool handlers should start");
releaseHandlers.countDown();

AssistantMessageEvent response = responseFuture.get(60, TimeUnit.SECONDS);
AssistantMessageEvent response = session.sendAndWait(new MessageOptions().setPrompt(
"Use lookup_city with 'Paris' and lookup_country with 'France' at the same time, then combine both results in your reply."))
.get(60, TimeUnit.SECONDS);

// Both tools should have been called
assertEquals("Paris", toolACalled.get(10, TimeUnit.SECONDS));
assertEquals("France", toolBCalled.get(10, TimeUnit.SECONDS));
Comment thread
edburns marked this conversation as resolved.
assertTrue(handlersOverlapped.get(), "Tool handlers should overlap in execution");

assertNotNull(response);
String content = response.getData().content();
Expand All @@ -432,32 +417,6 @@ void testShouldExecuteMultipleCustomToolsInParallelSingleTurn() throws Exception
}
}

private CompletableFuture<Object> executeParallelHandler(String value, String prefix,
CountDownLatch handlersStarted, CountDownLatch releaseHandlers, AtomicInteger activeHandlers,
AtomicBoolean handlersOverlapped) {
int currentActive = activeHandlers.incrementAndGet();
if (currentActive > 1) {
handlersOverlapped.set(true);
}

handlersStarted.countDown();
try {
if (!handlersStarted.await(10, TimeUnit.SECONDS)) {
return CompletableFuture.failedFuture(new IllegalStateException("Tool handlers did not overlap"));
}
if (!releaseHandlers.await(10, TimeUnit.SECONDS)) {
return CompletableFuture
.failedFuture(new IllegalStateException("Timed out waiting to release handlers"));
}
return CompletableFuture.completedFuture(prefix + value.toUpperCase());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return CompletableFuture.failedFuture(e);
} finally {
activeHandlers.decrementAndGet();
}
}

/**
* Verifies that excludedTools are respected even when also listed in
* availableTools.
Expand Down
Loading