import * as Effect from "effect/Effect";import * as Schema from "effect/Schema"; import { createDiscoveryPrimitivesFromToolCatalog } from "./discovery";import { toTool } from "./tool-map";import type { DiscoveryPrimitives, ToolCatalog, ToolMap, ToolPath,} from "./types"; const asToolPath = (value: string): ToolPath => value as ToolPath; const catalogNamespacesInputSchema = Schema.standardSchemaV1( Schema.Struct({ limit: Schema.optional(Schema.Number), }),); const catalogNamespacesOutputSchema = Schema.standardSchemaV1( Schema.Struct({ namespaces: Schema.Array( Schema.Struct({ namespace: Schema.String, displayName: Schema.optional(Schema.String), toolCount: Schema.optional(Schema.Number), }), ), }),); const catalogToolsInputSchema = Schema.standardSchemaV1( Schema.Struct({ namespace: Schema.optional(Schema.String), query: Schema.optional(Schema.String), limit: Schema.optional(Schema.Number), includeSchemas: Schema.optional(Schema.Boolean), }),); const catalogToolsOutputSchema = Schema.standardSchemaV1( Schema.Struct({ results: Schema.Array( Schema.Struct({ path: Schema.String, sourceKey: Schema.String, description: Schema.optional(Schema.String), interaction: Schema.optional(Schema.String), inputType: Schema.optional(Schema.String), outputType: Schema.optional(Schema.String), inputSchemaJson: Schema.optional(Schema.String), outputSchemaJson: Schema.optional(Schema.String), exampleInputJson: Schema.optional(Schema.String), exampleOutputJson: Schema.optional(Schema.String), providerKind: Schema.optional(Schema.String), providerDataJson: Schema.optional(Schema.String), }), ), }),); const describeToolInputSchema = Schema.standardSchemaV1( Schema.Struct({ path: Schema.String, includeSchemas: Schema.optional(Schema.Boolean), }),); const describeToolOutputSchema = Schema.standardSchemaV1( Schema.NullOr(Schema.Unknown),); const discoverInputSchema = Schema.standardSchemaV1( Schema.Struct({ query: Schema.String, limit: Schema.optional(Schema.Number), includeSchemas: Schema.optional(Schema.Boolean), }),); const discoverResultItemSchema = Schema.Struct({ path: Schema.String, score: Schema.Number, description: Schema.optional(Schema.String), interaction: Schema.optional(Schema.String), inputType: Schema.optional(Schema.String), outputType: Schema.optional(Schema.String), inputSchemaJson: Schema.optional(Schema.String), outputSchemaJson: Schema.optional(Schema.String),}); const discoverOutputSchema = Schema.standardSchemaV1( Schema.Struct({ bestPath: Schema.NullOr(Schema.String), results: Schema.Array(discoverResultItemSchema), total: Schema.Number, }),); export type CreateSystemToolMapInput = { catalog: ToolCatalog; sourceKey?: string;}; export const createSystemToolMap = ( input: CreateSystemToolMapInput,): ToolMap => { const sourceKey = input.sourceKey ?? "system"; const primitives: DiscoveryPrimitives = createDiscoveryPrimitivesFromToolCatalog({ catalog: input.catalog, }); const tools: ToolMap = {}; if (primitives.catalog) { tools["catalog.namespaces"] = toTool({ tool: { description: "List available namespaces with display names and tool counts", inputSchema: catalogNamespacesInputSchema, outputSchema: catalogNamespacesOutputSchema, execute: ({ limit }: { limit?: number }) => Effect.runPromise( primitives.catalog!.namespaces({ ...(limit !== undefined ? { limit } : {}), }), ), }, metadata: { sourceKey, interaction: "auto", }, }); tools["catalog.tools"] = toTool({ tool: { description: "List tools with optional namespace and query filters", inputSchema: catalogToolsInputSchema, outputSchema: catalogToolsOutputSchema, execute: ( input: { namespace?: string; query?: string; limit?: number; includeSchemas?: boolean; }, ) => Effect.runPromise( primitives.catalog!.tools({ ...(input.namespace !== undefined ? { namespace: input.namespace } : {}), ...(input.query !== undefined ? { query: input.query } : {}), ...(input.limit !== undefined ? { limit: input.limit } : {}), ...(input.includeSchemas !== undefined ? { includeSchemas: input.includeSchemas } : {}), }), ), }, metadata: { sourceKey, interaction: "auto", }, }); } if (primitives.describe) { tools["describe.tool"] = toTool({ tool: { description: "Get metadata and optional schemas for a tool path", inputSchema: describeToolInputSchema, outputSchema: describeToolOutputSchema, execute: ({ path, includeSchemas }: { path: string; includeSchemas?: boolean }) => Effect.runPromise( primitives.describe!.tool({ path: asToolPath(path), ...(includeSchemas !== undefined ? { includeSchemas } : {}), }), ), }, metadata: { sourceKey, interaction: "auto", }, }); } if (primitives.discover) { tools.discover = toTool({ tool: { description: "Search tools by intent and return ranked matches", inputSchema: discoverInputSchema, outputSchema: discoverOutputSchema, execute: ( input: { query: string; limit?: number; includeSchemas?: boolean; }, ) => Effect.runPromise( primitives.discover!({ query: input.query, ...(input.limit !== undefined ? { limit: input.limit } : {}), ...(input.includeSchemas !== undefined ? { includeSchemas: input.includeSchemas } : {}), }), ), }, metadata: { sourceKey, interaction: "auto", }, }); } return tools;}; export type MergeToolMapsOptions = { conflictMode?: "throw" | "override";}; export const mergeToolMaps = ( maps: ReadonlyArray<ToolMap>, options: MergeToolMapsOptions = {},): ToolMap => { const conflictMode = options.conflictMode ?? "throw"; const merged: ToolMap = {}; for (const map of maps) { for (const [path, tool] of Object.entries(map)) { if (conflictMode === "throw" && path in merged) { throw new Error(`Tool path conflict: ${path}`); } merged[path] = tool; } } return merged;};
import * as Effect from "effect/Effect";
import * as Schema from "effect/Schema";
import { createDiscoveryPrimitivesFromToolCatalog } from "./discovery";
import { toTool } from "./tool-map";
import type {
DiscoveryPrimitives,
ToolCatalog,
ToolMap,
ToolPath,
} from "./types";
const asToolPath = (value: string): ToolPath => value as ToolPath;
const catalogNamespacesInputSchema = Schema.standardSchemaV1(
Schema.Struct({
limit: Schema.optional(Schema.Number),
}),
);
const catalogNamespacesOutputSchema = Schema.standardSchemaV1(
Schema.Struct({
namespaces: Schema.Array(
Schema.Struct({
namespace: Schema.String,
displayName: Schema.optional(Schema.String),
toolCount: Schema.optional(Schema.Number),
}),
),
}),
);
const catalogToolsInputSchema = Schema.standardSchemaV1(
Schema.Struct({
namespace: Schema.optional(Schema.String),
query: Schema.optional(Schema.String),
limit: Schema.optional(Schema.Number),
includeSchemas: Schema.optional(Schema.Boolean),
}),
);
const catalogToolsOutputSchema = Schema.standardSchemaV1(
Schema.Struct({
results: Schema.Array(
Schema.Struct({
path: Schema.String,
sourceKey: Schema.String,
description: Schema.optional(Schema.String),
interaction: Schema.optional(Schema.String),
inputType: Schema.optional(Schema.String),
outputType: Schema.optional(Schema.String),
inputSchemaJson: Schema.optional(Schema.String),
outputSchemaJson: Schema.optional(Schema.String),
exampleInputJson: Schema.optional(Schema.String),
exampleOutputJson: Schema.optional(Schema.String),
providerKind: Schema.optional(Schema.String),
providerDataJson: Schema.optional(Schema.String),
}),
),
}),
);
const describeToolInputSchema = Schema.standardSchemaV1(
Schema.Struct({
path: Schema.String,
includeSchemas: Schema.optional(Schema.Boolean),
}),
);
const describeToolOutputSchema = Schema.standardSchemaV1(
Schema.NullOr(Schema.Unknown),
);
const discoverInputSchema = Schema.standardSchemaV1(
Schema.Struct({
query: Schema.String,
limit: Schema.optional(Schema.Number),
includeSchemas: Schema.optional(Schema.Boolean),
}),
);
const discoverResultItemSchema = Schema.Struct({
path: Schema.String,
score: Schema.Number,
description: Schema.optional(Schema.String),
interaction: Schema.optional(Schema.String),
inputType: Schema.optional(Schema.String),
outputType: Schema.optional(Schema.String),
inputSchemaJson: Schema.optional(Schema.String),
outputSchemaJson: Schema.optional(Schema.String),
});
const discoverOutputSchema = Schema.standardSchemaV1(
Schema.Struct({
bestPath: Schema.NullOr(Schema.String),
results: Schema.Array(discoverResultItemSchema),
total: Schema.Number,
}),
);
export type CreateSystemToolMapInput = {
catalog: ToolCatalog;
sourceKey?: string;
};
export const createSystemToolMap = (
input: CreateSystemToolMapInput,
): ToolMap => {
const sourceKey = input.sourceKey ?? "system";
const primitives: DiscoveryPrimitives = createDiscoveryPrimitivesFromToolCatalog({
catalog: input.catalog,
});
const tools: ToolMap = {};
if (primitives.catalog) {
tools["catalog.namespaces"] = toTool({
tool: {
description: "List available namespaces with display names and tool counts",
inputSchema: catalogNamespacesInputSchema,
outputSchema: catalogNamespacesOutputSchema,
execute: ({ limit }: { limit?: number }) =>
Effect.runPromise(
primitives.catalog!.namespaces({
...(limit !== undefined ? { limit } : {}),
}),
),
},
metadata: {
sourceKey,
interaction: "auto",
},
});
tools["catalog.tools"] = toTool({
tool: {
description: "List tools with optional namespace and query filters",
inputSchema: catalogToolsInputSchema,
outputSchema: catalogToolsOutputSchema,
execute: (
input: {
namespace?: string;
query?: string;
limit?: number;
includeSchemas?: boolean;
},
) =>
Effect.runPromise(
primitives.catalog!.tools({
...(input.namespace !== undefined ? { namespace: input.namespace } : {}),
...(input.query !== undefined ? { query: input.query } : {}),
...(input.limit !== undefined ? { limit: input.limit } : {}),
...(input.includeSchemas !== undefined
? { includeSchemas: input.includeSchemas }
: {}),
}),
),
},
metadata: {
sourceKey,
interaction: "auto",
},
});
}
if (primitives.describe) {
tools["describe.tool"] = toTool({
tool: {
description: "Get metadata and optional schemas for a tool path",
inputSchema: describeToolInputSchema,
outputSchema: describeToolOutputSchema,
execute: ({ path, includeSchemas }: { path: string; includeSchemas?: boolean }) =>
Effect.runPromise(
primitives.describe!.tool({
path: asToolPath(path),
...(includeSchemas !== undefined ? { includeSchemas } : {}),
}),
),
},
metadata: {
sourceKey,
interaction: "auto",
},
});
}
if (primitives.discover) {
tools.discover = toTool({
tool: {
description: "Search tools by intent and return ranked matches",
inputSchema: discoverInputSchema,
outputSchema: discoverOutputSchema,
execute: (
input: {
query: string;
limit?: number;
includeSchemas?: boolean;
},
) =>
Effect.runPromise(
primitives.discover!({
query: input.query,
...(input.limit !== undefined ? { limit: input.limit } : {}),
...(input.includeSchemas !== undefined
? { includeSchemas: input.includeSchemas }
: {}),
}),
),
},
metadata: {
sourceKey,
interaction: "auto",
},
});
}
return tools;
};
export type MergeToolMapsOptions = {
conflictMode?: "throw" | "override";
};
export const mergeToolMaps = (
maps: ReadonlyArray<ToolMap>,
options: MergeToolMapsOptions = {},
): ToolMap => {
const conflictMode = options.conflictMode ?? "throw";
const merged: ToolMap = {};
for (const map of maps) {
for (const [path, tool] of Object.entries(map)) {
if (conflictMode === "throw" && path in merged) {
throw new Error(`Tool path conflict: ${path}`);
}
merged[path] = tool;
}
}
return merged;
};