Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ After Phase 3 is resolved, implement in this order.
- [X] 4.3 — Implement schema and coercion internals ([#1841](https://github.com/github/copilot-sdk/issues/1841))
- [X] 4.4 — Unit tests for API behavior and validation ([#1842](https://github.com/github/copilot-sdk/issues/1842))
- [X] 4.5 — E2E integration test ([#1843](https://github.com/github/copilot-sdk/issues/1843))
- [ ] 4.6 — Documentation updates ([#1844](https://github.com/github/copilot-sdk/issues/1844))
- [X] 4.6 — Documentation updates ([#1844](https://github.com/github/copilot-sdk/issues/1844))

### 4.1 — Add public API types

Expand Down
67 changes: 67 additions & 0 deletions java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,73 @@ public String onlyContext(ToolInvocation invocation) { ... }
public String report(@CopilotToolParam("Phase") String phase, ToolInvocation invocation, @CopilotToolParam("Limit") int limit) { ... }
```

## Inline lambda tool definitions (experimental)

For inline tool authoring at the session construction site, use `ToolDefinition.from(...)` with explicit parameter metadata:

```java
import com.github.copilot.rpc.ToolDefinition;
import com.github.copilot.rpc.ToolDefer;
import com.github.copilot.tool.Param;

ToolDefinition search = ToolDefinition
.from(
"search_items",
"Searches indexed items by keyword",
Param.of(String.class, "keyword", "Search keyword"),
keyword -> "Searching for: " + keyword)
.skipPermission(true)
.defer(ToolDefer.AUTO);
```

### Parameter metadata with `Param.of(...)`

`Param.of(type, name, description)` creates a required parameter. For optional parameters with defaults:

```java
Param<Integer> limit = Param.of(Integer.class, "limit", "Max results", false, "10");
```

### Async handlers

Use `fromAsync` for asynchronous tool handlers:

```java
import java.util.concurrent.CompletableFuture;

ToolDefinition fetchData = ToolDefinition.fromAsync(
"fetch_data",
"Fetches data from remote source",
Param.of(String.class, "url", "Data source URL"),
url -> CompletableFuture.supplyAsync(() -> fetchRemote(url))
Comment thread
edburns marked this conversation as resolved.
);
```

### ToolInvocation context injection

Inline tools can access `ToolInvocation` runtime context using `fromWithToolInvocation`:

```java
ToolDefinition reportPhase = ToolDefinition.fromWithToolInvocation(
"report_phase",
"Reports the current phase with invocation context",
Param.of(String.class, "phase", "The current phase"),
(phase, invocation) -> "phase=" + phase + ", toolCallId=" + invocation.getToolCallId()
);
```

For async with `ToolInvocation`, use `fromAsyncWithToolInvocation`.

### Fluent option modifiers

Chain fluent modifiers to set tool options:

- `.skipPermission(boolean)` — bypass permission prompts
- `.defer(ToolDefer)` — control deferred execution (`AUTO`, `NEVER`)
- `.overridesBuiltInTool(boolean)` — shadow built-in tools

For design context and decision rationale, see [ADR-006](docs/adr/adr-006-tool-definition-inline.md).

## Memory

Sessions can opt into persistent memory, allowing the agent to read and write memory across turns. Memory is configured per session and applies to both `createSession` and `resumeSession`.
Expand Down
19 changes: 14 additions & 5 deletions java/docs/adr/adr-006-tool-definition-inline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Context and problem statement

ADR-005 introduced an ergonomic Java tools API based on `@CopilotTool` and `ToolDefinition.fromObject(...)`. That model works well when teams define tools as methods on a class.
[ADR-005](adr-005-tool-definition.md) introduced an ergonomic Java tools API based on `@CopilotTool` method annotations, `@CopilotToolParam` parameter annotations, and `ToolDefinition.fromObject(...)` for reflection-based tool registration. That model works well when teams define tools as methods on a class.

The next ergonomics goal is an inline style comparable to C# `CopilotTool.DefineTool(...)`, where developers can define a tool at the call site without creating a separate tool container class.

Expand Down Expand Up @@ -45,14 +45,14 @@ Example:
ToolDefinition setPhase = ToolDefinition.from(
"set_current_phase",
"Sets the current phase of the agent",
Params.of(ParamDef.string("phase", "The phase to transition to")),
Param.of(String.class, "phase", "The phase to transition to"),
(String phase) -> {
currentPhase = phase;
return "Phase set to " + phase;
});
```

In this model, handler logic is inline, and metadata is provided explicitly through a small parameter-definition DSL.
In this model, handler logic is inline, and metadata is provided explicitly through `Param.of(...)` parameter definitions.

Advantages:

Expand Down Expand Up @@ -98,9 +98,18 @@ Non-goals for this ADR:

## Consequences

If implemented, the SDK gains an explicit inline path for developers who prefer to keep tool declarations at session creation while preserving high-quality schema metadata.
The SDK now provides an explicit inline path for developers who prefer to keep tool declarations at session creation while preserving high-quality schema metadata. Implemented API families include:

The annotation-driven API from ADR-005 remains the recommended path for larger tool surfaces where co-locating metadata with method implementations improves maintainability.
- `ToolDefinition.from(name, description, [params...], handler)` — sync handlers
- `ToolDefinition.fromAsync(name, description, [params...], asyncHandler)` — async handlers returning `CompletableFuture<R>`
- `ToolDefinition.fromWithToolInvocation(...)` — sync with `ToolInvocation` context injection
- `ToolDefinition.fromAsyncWithToolInvocation(...)` — async with `ToolInvocation` context injection

Parameter metadata is defined using `Param.of(type, name, description)` for required parameters and `Param.of(type, name, description, required, defaultValue)` for optional parameters with defaults.

Fluent option modifiers (`.skipPermission(boolean)`, `.defer(ToolDefer)`, `.overridesBuiltInTool(boolean)`) allow post-construction customization.

The annotation-driven API from [ADR-005](adr-005-tool-definition.md) remains the recommended path for larger tool surfaces where co-locating metadata with method implementations improves maintainability. For usage examples and complete API coverage, see the Java SDK README.

## Related work items

Expand Down
Loading