Current section

Files

Jump to
copilot_sdk_supercharged lib copilot define_tool.ex
Raw

lib/copilot/define_tool.ex

defmodule Copilot.DefineTool do
@moduledoc """
Helper for defining tools to expose to the Copilot CLI.
Provides a convenient function for creating `Copilot.Types.Tool` structs
with proper JSON schema parameters.
## Examples
### Simple tool (no parameters)
tool = Copilot.DefineTool.define("get_time",
description: "Returns the current UTC time",
handler: fn _args, _inv -> DateTime.utc_now() |> DateTime.to_iso8601() end
)
### Tool with JSON schema parameters
tool = Copilot.DefineTool.define("lookup_fact",
description: "Returns a fun fact about a given topic.",
parameters: %{
"type" => "object",
"properties" => %{
"topic" => %{
"type" => "string",
"description" => "Topic to look up (e.g. 'javascript', 'node')"
}
},
"required" => ["topic"]
},
handler: fn %{"topic" => topic}, _invocation ->
facts = %{
"javascript" => "JavaScript was created in 10 days by Brendan Eich.",
"node" => "Node.js uses the V8 engine."
}
Map.get(facts, String.downcase(topic), "No fact stored for \#{topic}.")
end
)
### Using the macro for cleaner syntax
use Copilot.DefineTool
deftool :weather, "Get weather for a city",
parameters: %{
"type" => "object",
"properties" => %{
"city" => %{"type" => "string", "description" => "City name"}
},
"required" => ["city"]
} do
fn %{"city" => city}, _inv ->
"The weather in \#{city} is sunny, 72F."
end
end
"""
alias Copilot.Types.Tool
@doc """
Define a tool with the given name and options.
## Options
* `:description` - Description shown to the LLM (required).
* `:parameters` - JSON schema map for tool parameters (optional).
* `:handler` - A 2-arity function `(args, invocation) -> result`.
The result can be:
- A string (wrapped as success)
- A `Copilot.Types.ToolResult` struct
- Any term (JSON-encoded as success)
"""
@spec define(String.t(), keyword()) :: Tool.t()
def define(name, opts) when is_binary(name) do
description = Keyword.get(opts, :description)
parameters = Keyword.get(opts, :parameters)
handler = Keyword.fetch!(opts, :handler)
%Tool{
name: name,
description: description,
parameters: parameters,
handler: handler
}
end
@doc """
Convenience for defining a tool from a keyword list that includes `:name`.
"""
@spec define(keyword()) :: Tool.t()
def define(opts) when is_list(opts) do
name = Keyword.fetch!(opts, :name)
define(name, opts)
end
@doc false
defmacro __using__(_opts) do
quote do
import Copilot.DefineTool, only: [deftool: 4]
end
end
@doc """
Macro for defining a tool inline.
## Example
use Copilot.DefineTool
deftool :echo, "Echoes back the input",
parameters: %{
"type" => "object",
"properties" => %{
"text" => %{"type" => "string"}
},
"required" => ["text"]
} do
fn %{"text" => text}, _inv -> text end
end
Returns a `Copilot.Types.Tool` struct bound to a variable with the tool name.
"""
defmacro deftool(name, description, opts, do: handler_block) do
var_name = name
quote do
unquote(Macro.var(var_name, nil)) =
Copilot.DefineTool.define(to_string(unquote(name)),
description: unquote(description),
parameters: Keyword.get(unquote(opts), :parameters),
handler: unquote(handler_block)
)
end
end
end