Skip to content

Assembly

An assembly is the one toolkit a model is given for a turn, made of the tools of every source a workspace has. toolkit names each tool by its source and its own name, leaves out the tools a decision blocks, and marks the tools a decision asks about before they run. The model calls a tool by that name, and the call reaches the source that owns the tool by the name that source knows it by.

Which of a tool’s decisions is the right one is the host’s to say, from what it has stored. A source’s hints are its own claims, so no decision is made from them here.

Since v0.1.0

Builds the toolkit of members. The tools of a member that decide blocks are left out, and the names of the others must be distinct, or the assembly fails with the names that are not.

A model knows a tool by its source’s name and its own, as github__create_issue, and a tool that decide asks to approve needs approval before it runs. Building contacts none of the sources.

Example (The toolkit of a turn, from a workspace’s sources and its policy)

import { Assembly, type ToolSource } from "@amends-dev/toolkit"
import { Effect } from "effect"
declare const github: ToolSource.ToolSource
declare const linear: ToolSource.ToolSource
// What the host stored of each source: a decision for a tool, and the one for the others.
declare const policy: ReadonlyMap<
string,
{ readonly tools: ReadonlyMap<string, Assembly.Decision>; readonly others: Assembly.Decision }
>
const program = Effect.gen(function* () {
// The definitions come from the host's catalog, filled from `discover` when it refreshed.
const members = yield* Effect.forEach([github, linear], (source) =>
Effect.map(source.discover, (definitions) => ({ source, definitions }))
)
const toolkit = yield* Assembly.toolkit(members, (source, definition) => {
const stored = policy.get(source)
return stored?.tools.get(definition.name) ?? stored?.others ?? "block"
})
// The model knows the tools as `github__create_issue`, and a call reaches its source.
return toolkit
})

Signature

declare const toolkit: (
members: ReadonlyArray<Member>,
decide: (source: string, definition: ToolDefinition.ToolDefinition) => Decision,
options?: Options | undefined
) => Effect.Effect<
WithHandler<{
readonly [x: string]: 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
>
}>,
NameClash,
never
>

Source

Since v0.1.0

More than one tool has the same name, so the model could not tell which one it calls. toolkit fails with it, holding every clash.

Signature

declare class NameClash

Source

Since v0.1.0

A source, with the definitions of the tools of it that the workspace has, from which toolkit builds the model’s tools without asking the source.

Signature

export interface Member {
readonly source: ToolSource.ToolSource
/** The definitions of the source's tools that the host holds in its catalog. */
readonly definitions: ReadonlyArray<ToolDefinition.ToolDefinition>
}

Source

Since v0.1.0

What toolkit takes besides its members and the decision for each tool.

Signature

export interface Options {
/**
* The longest name a tool may have, for an agent that adds to the names it is given and so takes
* fewer than the model APIs' 64 characters, such as an agent's `maxToolNameLength`. At least 16.
*/
readonly maxNameLength?: number
}

Source

Since v0.1.0

Tools the model would know by one name, as NameClash reports them.

Signature

declare const Clash: Schema.Struct<{
readonly name: Schema.String
readonly tools: Schema.$Array<Schema.Struct<{ readonly source: Schema.String; readonly tool: Schema.String }>>
}>

Source

Since v0.1.0

Signature

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

Source

Since v0.1.0

What the model may do with a tool: call it, call it once the person has approved the call, or not be given it. A schema, so that a host can store its policy.

Signature

declare const Decision: Schema.Literals<readonly ["allow", "approve", "block"]>

Source

Since v0.1.0

Signature

type Decision = typeof Decision.Type

Source

Since v0.1.0