Authorization and model tool projection come from the same definition
The policy implementation follows.
ts
export function defineTool<Input, Output, App, const Id extends string = string>(
definition: ToolDefinition<Input, Output, App> & { readonly id: Id },
): ExecutableTool<Input, Output, App, Id> {
const { id, kind, description } = definition;
if (!id?.trim() || !kind?.trim() || !description?.trim())
throw new TypeError('Invalid tool identity');
if (
typeof definition.authorize !== 'function' ||
typeof definition.execute !== 'function' ||
typeof definition.parseOutput !== 'function'
)
throw new TypeError('Missing tool handler');
const inputSchema = defineSchema(definition.inputSchema);
const authorize = definition.authorize.bind(definition);
if (
definition.active !== undefined &&
typeof definition.active !== 'boolean' &&
typeof definition.active !== 'function'
)
throw new TypeError('Invalid tool active condition');
const active =
typeof definition.active === 'function'
? definition.active.bind(definition)
: definition.active;
const asIntent = bindIntent(
snapshotIntent(
typeof definition.asIntent === 'function'
? definition.asIntent.bind(definition)
: definition.asIntent,
),
definition,
);
return Object.freeze({
id,
kind,
description,
inputSchema,
active,
asIntent,
resolve: definition.resolve?.bind(definition) ?? ((input: Input) => ({ toolId: id, input })),
authorize(input: Input, context: OperationContext<App>) {
return maybeAssertion(
authorize(input, context),
'Authorization must return void; rejection must throw',
);
},
execute: definition.execute.bind(definition),
debugSteps: definition.debugSteps?.bind(definition),
parseOutput: definition.parseOutput.bind(definition),
});
}
export function defineToolCatalog<
const Definitions extends readonly ToolDefinition<any, any, any>[],
>(
definitions: Definitions,
): ToolCatalog<
DefinitionApp<Definitions[number]>,
CompiledTool<DefinitionApp<Definitions[number]>, Definitions[number]>
>;