Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion nodejs/test/e2e/session_lifecycle.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe("Session Lifecycle", async () => {

// Sessions must have activity to be persisted to disk
await session1.sendAndWait({ prompt: "Say hello" });
await session2.sendAndWait({ prompt: "Say world" });
await session2.sendAndWait({ prompt: "Say hi" });

// Poll until both sessions are visible on disk instead of a hard 500ms wait.
await waitFor(async () => {
Expand Down
48 changes: 47 additions & 1 deletion nodejs/test/e2e/tools.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { writeFile } from "fs/promises";
import { join } from "path";
import { assert, describe, expect, it } from "vitest";
import { z } from "zod";
import { defineTool, approveAll } from "../../src/index.js";
import { defineTool, approveAll, ToolSet } from "../../src/index.js";
import type { PermissionRequest } from "../../src/index.js";
import { createSdkTestContext } from "./harness/sdkTestContext";

Expand Down Expand Up @@ -45,6 +45,52 @@ describe("Custom tools", async () => {
expect(assistantMessage?.data.content).toContain("HELLO");
});

it("low_level_tool_definition", async () => {
let currentPhase = "";
const session = await client.createSession({
onPermissionRequest: approveAll,
availableTools: new ToolSet().addCustom("*").addBuiltIn("web_fetch"),
tools: [
defineTool("set_current_phase", {
description: "Sets the current phase of the agent",
parameters: z.object({
phase: z.enum(["searching", "analyzing", "done"]),
}),
handler: ({ phase }) => {
currentPhase = phase;
return `Phase set to ${phase}`;
},
}),
defineTool("search_items", {
description: "Search for items by keyword",
parameters: z.object({
keyword: z.string(),
}),
handler: (_args, invocation) => {
const args = invocation.arguments as Record<string, unknown>;
if (args.keyword !== "copilot") {
throw new Error(`Expected keyword to be 'copilot', got: ${String(args.keyword)}`);
}
return "Found: item_alpha, item_beta";
},
}),
],
});

const assistantMessage = await session.sendAndWait({
prompt: "First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and search results.",
});

const content = assistantMessage?.data.content ?? "";
expect(content.length).toBeGreaterThan(0);
expect(content.toLowerCase()).toContain("analyzing");
expect(
content.toLowerCase().includes("item_alpha") ||
content.toLowerCase().includes("item_beta")
).toBe(true);
expect(currentPhase).toBe("analyzing");
});

it("handles tool calling errors", async () => {
const session = await client.createSession({
onPermissionRequest: approveAll,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ conversations:
- role: system
content: ${system}
- role: user
content: Say world
content: Say hi
- role: assistant
content: world
content: Hi! I'm GitHub Copilot CLI, ready to help with your software engineering tasks. What would you like to work on?
Loading