Skip to content

feat(java): Add ToolDefinition.fromObject() and fromClass() registration API#1779

Draft
Copilot wants to merge 2 commits into
edburns/1682-java-tool-ergonomicsfrom
copilot/edburns1682-java-tool-ergonomics
Draft

feat(java): Add ToolDefinition.fromObject() and fromClass() registration API#1779
Copilot wants to merge 2 commits into
edburns/1682-java-tool-ergonomicsfrom
copilot/edburns1682-java-tool-ergonomics

Conversation

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Adds the runtime registration API that loads processor-generated $$CopilotToolMeta companion classes and returns List<ToolDefinition> with fully working handlers. This is task 4.4 in the tool ergonomics epic.

Changes

  • ToolDefinition.java — two new @CopilotExperimental static methods:

    • fromObject(Object) — for instance methods annotated with @CopilotTool
    • fromClass(Class<?>) — for static @CopilotTool methods (passes null instance)
    • Private loadDefinitions() uses Class.forName with the target classloader, setAccessible(true), and passes a configured ObjectMapper
    • ConfiguredMapperHolder — lazy-init mapper matching JsonRpcClient.createObjectMapper() (JavaTimeModule, lenient unknown-props, ISO dates, NON_NULL)
    • Throws IllegalStateException with actionable message if $$CopilotToolMeta not found — no reflection fallback
  • ToolDefinitionFromObjectTest.java — 13 gating tests with hand-written meta fixtures covering: tool discovery, schema validation, handler invocation (String/void/CompletableFuture), argument coercion (primitives + enum), default values, missing-class error, java.time deserialization via ObjectMapper contract, override flag, and ToolDefer.NONEnull JSON omission

Usage

class MyTools {
    @CopilotTool("Get weather for a city")
    public String getWeather(@Param("City name") String city) {
        return fetchWeather(city);
    }
}

// At runtime — processor must have run at compile time
List<ToolDefinition> tools = ToolDefinition.fromObject(new MyTools());
session.setTools(tools);

…thods

Adds static methods that load processor-generated $$CopilotToolMeta
classes and return List<ToolDefinition> with fully working tool
definitions (schema + invocation handlers).

- fromObject(Object): discovers tools from an instance with @copilotTool methods
- fromClass(Class<?>): discovers tools from a class with static @copilotTool methods
- Private getConfiguredMapper(): provides ObjectMapper matching JsonRpcClient config
- Throws IllegalStateException with helpful message if generated class not found
- Both methods annotated with @CopilotExperimental

Includes comprehensive test suite (ToolDefinitionFromObjectTest) covering:
- Basic discovery and schema verification
- Handler invocation for String, void, and CompletableFuture returns
- Argument coercion with primitives, String, boolean, and enums
- Default value handling when arguments are omitted
- Error case for missing generated class
- java.time argument deserialization (validates JavaTimeModule contract)
- Override tool flag propagation
- ToolDefer.NONE → null mapping (defer absent from JSON output)

Closes #1761

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Copilot AI changed the title [WIP] Add ToolDefinition registration API methods feat(java): Add ToolDefinition.fromObject() and fromClass() registration API Jun 24, 2026
Copilot AI requested a review from edburns June 24, 2026 03:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Java] @CopilotTool ergonomics 4.4: ToolDefinition.fromObject(Object) registration API

2 participants