Skip to content

ToolSource

A tool source is a system that tells which tools it has and runs them, such as an MCP server or an HTTP API. Each kind implements ToolSource, and toolkit builds from it the Effect AI toolkit a model calls: a dynamic tool for each definition, whose handler checks the model’s input against the tool’s parameters, asks the source to run the tool, and turns whatever happens into a tool result.

Building a toolkit contacts nothing. The definitions come from the caller, who has them from a catalog, and the source is reached only when the model calls a tool. discover is for the catalog, which asks the source what it has now and decides what its tools may do before any of them is built into a toolkit.

A call that fails is a result the model reads, so the turn goes on and the model can try something else. Only interrupting the call ends it in any other way.

Since v0.1.0

Builds the toolkit for exactly these definitions, which must have distinct names, as a catalog keyed by them has. Its tools are named as the definitions name them. A tool that needsApproval names is one the session asks about before it runs the tool.

Building contacts nothing: the source is reached only when the model calls a tool.

Example (The tools of a source, given to a model)

import { ToolSource } from "@amends-dev/toolkit"
import { Effect } from "effect"
import { LanguageModel } from "effect/ai"
declare const github: ToolSource.ToolSource // from Mcp.http or Http.make
const program = Effect.gen(function* () {
// The definitions come from the host's catalog, which `discover` fills when it refreshes.
const definitions = yield* github.discover
const toolkit = yield* ToolSource.toolkit(github, definitions, {
needsApproval: (definition) => definition.annotations.readOnly !== true
})
// The model calls a tool by the name the source gave it, and reads a failure as a result.
const response = yield* LanguageModel.generateText({
prompt: "Which issues of amends-dev/amends are open?",
toolkit
})
return response.text
})

Signature

declare const toolkit: (
source: ToolSource,
definitions: ReadonlyArray<ToolDefinition.ToolDefinition>,
options?: { readonly needsApproval?: (definition: ToolDefinition.ToolDefinition) => boolean } | undefined
) => Effect.Effect<
Toolkit.WithHandler<{
readonly [x: string]: Tool.Tool<
string,
{
readonly parameters: Schema.Unknown
readonly success: Schema.Codec<Schema.Json, Schema.Json, never, never>
readonly failure: Schema.Struct<{
readonly code: Schema.String
readonly message: Schema.String
readonly retryable: Schema.Boolean
}>
readonly failureMode: "return"
},
never
>
}>,
never,
never
>

Source

Since v0.1.0

What every kind of tool source implements: its name, the tools it has now, and how to run one. Mcp.http and Http.make make one, and toolkit builds from one the toolkit a model calls.

Signature

export interface ToolSource {
/**
* Names the source, such as `github`. Its failures carry the name, and the toolkit of a set of
* sources is told apart by it.
*/
readonly name: string
/** Asks the source which tools it has now. */
readonly discover: Effect.Effect<ReadonlyArray<ToolDefinition.ToolDefinition>, ToolSourceError.ToolSourceError>
/**
* Runs the tool of this name, as `discover` names it, with `input`, an object that matches the
* tool's parameters, and returns what the tool answers.
*/
readonly call: (tool: string, input: Schema.JsonObject) => Effect.Effect<Schema.Json, ToolSourceError.ToolSourceError>
}

Source

Since v0.1.0

What a model reads of a call that failed: the failure’s reason, what the model is told of it, and whether trying again may help. Presentation, ToolSearch, and CodeMode give their own failures in this shape too.

Signature

declare const Failure: Schema.Struct<{
readonly code: Schema.String
readonly message: Schema.String
readonly retryable: Schema.Boolean
}>

Source

Since v0.1.0

Signature

export interface Failure extends Schema.Schema.Type<typeof Failure> {}

Source

Since v0.1.0