@agentproto/tool 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -0
- package/dist/index.mjs +8 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -151,6 +151,14 @@ interface PaginatedOptions<TItem> {
|
|
|
151
151
|
* envelope; set this to reproduce that wrapper (default `"items"`).
|
|
152
152
|
*/
|
|
153
153
|
itemKey?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Row cap for the NON-paginated (no `limit`/`cursor`) call. Unset = the
|
|
156
|
+
* legacy unbounded `{ [itemKey]: [...] }`. When set and the list is longer,
|
|
157
|
+
* the wrapper carries the first `defaultLimit` rows plus
|
|
158
|
+
* `{ total, truncated: true, nextCursor }` so the caller can page on —
|
|
159
|
+
* keeps a tool whose rows pile up (terminals) under the MCP output cap.
|
|
160
|
+
*/
|
|
161
|
+
defaultLimit?: number;
|
|
154
162
|
}
|
|
155
163
|
/**
|
|
156
164
|
* Pagination transformer — adds {@link pageParamsShape} to the input shape
|
package/dist/index.mjs
CHANGED
|
@@ -132,7 +132,7 @@ function textResult(text) {
|
|
|
132
132
|
return { content: [{ type: "text", text }] };
|
|
133
133
|
}
|
|
134
134
|
function paginated(opts) {
|
|
135
|
-
const { project, keyOf, maxLimit = 200, itemKey = "items" } = opts;
|
|
135
|
+
const { project, keyOf, maxLimit = 200, itemKey = "items", defaultLimit } = opts;
|
|
136
136
|
return {
|
|
137
137
|
name: "paginated",
|
|
138
138
|
wrapShape: (shape) => ({ ...shape, ...pageParamsShape }),
|
|
@@ -146,6 +146,13 @@ function paginated(opts) {
|
|
|
146
146
|
const projectRows = compact && (params.fields === void 0 || params.compact === true);
|
|
147
147
|
return projectRows ? textResult(toolText({ ...page, items: page.items.map(project) }, params)) : textResult(toolText(page, params));
|
|
148
148
|
}
|
|
149
|
+
if (defaultLimit !== void 0 && items.length > defaultLimit) {
|
|
150
|
+
const page = paginate(items, { limit: defaultLimit }, { maxLimit: Math.max(maxLimit, defaultLimit), keyOf });
|
|
151
|
+
const rows2 = compact ? page.items.map(project) : page.items;
|
|
152
|
+
return textResult(
|
|
153
|
+
JSON.stringify({ [itemKey]: rows2, total: page.total, truncated: true, nextCursor: page.nextCursor })
|
|
154
|
+
);
|
|
155
|
+
}
|
|
149
156
|
const rows = compact ? items.map(project) : items;
|
|
150
157
|
return textResult(JSON.stringify({ [itemKey]: rows }));
|
|
151
158
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/create-tool.ts","../src/spec.ts","../src/envelope.ts","../src/transformers.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * `createTool(params, opts)` — write a TOOL.md to disk.\n *\n * Symmetric to `parseToolManifest` (.md → handle) and `defineTool`\n * (params → handle): this takes params, validates via defineTool\n * (single source of truth — same zod schema, same cross-AIP\n * invariants), then serialises the validated frontmatter to YAML\n * and writes it under `<dir>/<id>/TOOL.md`.\n *\n * The author's body markdown is preserved verbatim in `opts.body`.\n * Pass `dryRun: true` to get the rendered string without touching\n * disk — useful for tests, the MCP server's preview, and CI lints.\n *\n * Non-frontmatter values that can't appear in YAML (zod schemas,\n * function bodies) are filtered out by `filterSerializable` from\n * `@agentproto/define-doctype`; the resulting frontmatter matches\n * what `parseToolManifest` would consume on the way back in.\n */\n\nimport { filterSerializable } from \"@agentproto/define-doctype\"\nimport matter from \"gray-matter\"\nimport { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\nimport { defineTool } from \"./define-tool.js\"\nimport type { ToolContext, ToolDefinition, ToolHandle } from \"./types.js\"\n\nfunction toSnakeCaseKeys(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([k, v]) => [k.replace(/([A-Z])/g, \"_$1\").toLowerCase(), v]),\n )\n}\n\nexport interface CreateToolOptions {\n /** Workspace-relative or absolute directory under which to write `<id>/TOOL.md`. */\n dir: string\n /** Body markdown after the frontmatter. Defaults to a one-line stub. */\n body?: string\n /** Render only — don't write. Returns the rendered string. */\n dryRun?: boolean\n}\n\nexport interface CreateToolResult<\n TInput,\n TOutput,\n TContext extends ToolContext,\n> {\n /** The path where the file was (or would be) written. */\n path: string\n /** The validated handle returned by defineTool. */\n handle: ToolHandle<TInput, TOutput, TContext>\n /** The full rendered file contents (frontmatter + body). */\n rendered: string\n}\n\nexport async function createTool<\n TInput,\n TOutput,\n TContext extends ToolContext = ToolContext,\n>(\n params: ToolDefinition<TInput, TOutput, TContext>,\n opts: CreateToolOptions,\n): Promise<CreateToolResult<TInput, TOutput, TContext>> {\n const handle = defineTool<TInput, TOutput, TContext>(params)\n const path = join(opts.dir, handle.id, \"TOOL.md\")\n const frontmatter = filterSerializable({\n schema: \"agentproto/tool/v1\",\n ...toSnakeCaseKeys(params as unknown as Record<string, unknown>),\n }) as Record<string, unknown>\n const rendered = matter.stringify(\n opts.body ?? `# ${handle.name}\\n\\n${handle.description}\\n`,\n frontmatter,\n )\n if (!opts.dryRun) {\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, rendered, \"utf8\")\n }\n return { path, handle, rendered }\n}\n","/**\n * AIP-14 doctype spec — fed to `@agentproto/manifest.createVerbs`\n * to derive create / load / list / update / resolve / delete in one\n * place. Keeping the spec separate from `define-tool.ts` lets the\n * manifest layer (and the future MCP server) iterate over a uniform\n * descriptor without each package re-implementing the wiring.\n */\n\nimport { createVerbs, type DoctypeSpec } from \"@agentproto/manifest\"\nimport { defineTool } from \"./define-tool.js\"\nimport { parseToolManifest } from \"./manifest/index.js\"\nimport type { ToolDefinition, ToolHandle } from \"./types.js\"\n\nexport const toolSpec: DoctypeSpec<\n ToolDefinition<unknown, unknown>,\n ToolHandle<unknown, unknown>\n> = {\n name: \"tool\",\n aip: 14,\n schemaLiteral: \"agentproto/tool/v1\",\n pathOf: (h) => `${h.id}/TOOL.md`,\n define: (params) =>\n defineTool(params) as ToolHandle<unknown, unknown>,\n parse: (source) => {\n const m = parseToolManifest(source)\n const fm = m.frontmatter\n // `createVerbs.load` feeds this frontmatter straight to `define`\n // (= `defineTool`), which reads camelCase keys. The manifest uses\n // snake_case for multi-word fields, so they must be renamed here or\n // `defineTool` silently falls back to its defaults. Single-word fields\n // (mutates, approval, idempotent, tags, metadata, requires) share the\n // same key in both conventions and pass through unchanged.\n const frontmatter: Record<string, unknown> = {\n id: fm.id,\n name: fm.name,\n description: fm.description,\n version: fm.version,\n ...(fm.mutates !== undefined && { mutates: fm.mutates }),\n ...(fm.requires !== undefined && { requires: fm.requires }),\n ...(fm.approval !== undefined && { approval: fm.approval }),\n ...(fm.risk_level !== undefined && { riskLevel: fm.risk_level }),\n ...(fm.cost_class !== undefined && { costClass: fm.cost_class }),\n ...(fm.timeout_ms !== undefined && { timeoutMs: fm.timeout_ms }),\n ...(fm.idempotent !== undefined && { idempotent: fm.idempotent }),\n ...(fm.tags !== undefined && { tags: fm.tags }),\n ...(fm.metadata !== undefined && { metadata: fm.metadata }),\n // AIP-16 IO blocks pass through under the same keys.\n ...(fm.inputs !== undefined && { inputs: fm.inputs }),\n ...(fm.outputs !== undefined && { outputs: fm.outputs }),\n }\n return { frontmatter, body: m.body }\n },\n}\n\nexport const toolVerbs = createVerbs(toolSpec)\n","import { z } from \"zod\"\n\n/**\n * Shared pagination primitives (moved here from `@agentproto/runtime`'s\n * `tool-envelope.ts` so the `paginated()` ToolTransformer can reuse the\n * exact cursor/limit semantics the daemon's list tools already depend on).\n * `@agentproto/runtime` re-exports this module verbatim, so existing\n * imports are unchanged.\n */\n\n/** Shared pagination params, spread into every list tool's input schema. */\nexport interface PageParams {\n limit?: number\n cursor?: string\n since?: number\n compact?: boolean\n full?: boolean\n fields?: string[]\n}\n\nexport interface Page<T> {\n items: T[]\n nextCursor?: string\n total?: number\n truncated?: boolean\n}\n\n/** Opaque cursor: base64(JSON `{ k: keysetValue, i: index }`). */\nexport interface CursorPayload {\n k: string | number | null\n i: number\n}\n\nexport function encodeCursor(payload: CursorPayload): string {\n return Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64url\")\n}\n\nconst cursorPayloadSchema = z.object({\n k: z.union([z.string(), z.number(), z.null()]),\n i: z.number().int().min(0),\n})\n\n/** No `unknown`/`as`: the JSON boundary is typed by zod's safeParse/parse. */\nexport function decodeCursor(token: string): CursorPayload | null {\n let text: string\n try {\n text = Buffer.from(token, \"base64url\").toString(\"utf8\")\n } catch {\n return null\n }\n try {\n return cursorPayloadSchema.parse(JSON.parse(text))\n } catch {\n return null\n }\n}\n\nexport interface PaginateOpts<T> {\n maxLimit: number\n keyOf?: (item: T) => string | number | null\n}\n\nexport function paginate<T>(items: readonly T[], params: PageParams, opts: PaginateOpts<T>): Page<T> {\n const limit = Math.min(Math.max(params.limit ?? 50, 1), opts.maxLimit)\n let start = 0\n if (params.cursor) {\n const decoded = decodeCursor(params.cursor)\n if (decoded && decoded.i >= 0 && decoded.i <= items.length) start = decoded.i\n }\n const end = start + limit\n const slice = items.slice(start, end)\n const keyAt = (idx: number): string | number | null => {\n const item = items[idx]\n return opts.keyOf && item !== undefined ? opts.keyOf(item) : null\n }\n return {\n items: slice,\n ...(end < items.length ? { nextCursor: encodeCursor({ k: keyAt(end), i: end }) } : {}),\n total: items.length,\n }\n}\n\n/**\n * Compact serializer — replaces every `JSON.stringify(x, null, 2)` in list handlers.\n *\n * When `params.fields` is supplied, an explicit allowlist is applied to every\n * item (mechanically, across all call sites): items keep only the named keys.\n * Absent `fields`, the output is byte-identical to `JSON.stringify(page)`.\n */\nexport function toolText<T extends object>(page: Page<T>, params?: Pick<PageParams, \"fields\">): string {\n const fields = params?.fields\n const items =\n fields === undefined\n ? page.items\n : page.items.map(item =>\n Object.fromEntries(\n Object.entries(item).filter(([key]) => fields.includes(key)),\n ),\n )\n return JSON.stringify({ ...page, items })\n}\n\n/** Zod fragment to spread into each list tool's input schema. */\nexport const pageParamsShape = {\n limit: z.number().int().min(1).max(200).optional().describe(\"Max items per page. Default 50.\"),\n cursor: z.string().optional().describe(\"Opaque token from a prior call's `nextCursor`.\"),\n compact: z\n .boolean()\n .optional()\n .describe(\n \"Compact projection (fewer fields per item). Default true on tools \" +\n \"that define a compact projection (session_list); a no-op elsewhere.\",\n ),\n full: z\n .boolean()\n .optional()\n .describe(\n \"Escape hatch — full, unprojected records (opts out of compact). \" +\n \"Default false.\",\n ),\n fields: z.array(z.string()).optional().describe(\"Keep only these fields per item.\"),\n} as const\n","import type { ZodRawShape } from \"zod\"\nimport {\n paginate,\n pageParamsShape,\n toolText,\n type PageParams,\n} from \"./envelope.js\"\nimport type { ToolTransformer } from \"./types.js\"\n\n/**\n * Concrete {@link ToolTransformer}s — cross-cutting concerns composed by\n * MCP-facing adapters (`toMcpTool`) around a tool's handler pipeline.\n */\n\n/** The MCP text-result shape transformers terminate the pipeline into. */\nexport interface McpTextResult {\n content: Array<{ type: \"text\"; text: string }>\n isError?: boolean\n}\n\nfunction textResult(text: string): McpTextResult {\n return { content: [{ type: \"text\", text }] }\n}\n\nexport interface PaginatedOptions<TItem> {\n /**\n * REQUIRED per-item compact projection. Requiring it is the point: there\n * is no code path that accepts the `compact` param without an actual\n * compact projection behind it, killing the \"declared but dead param\"\n * bug class. Pass the identity function only if you truly want\n * `compact` to be a no-op.\n */\n project: (item: TItem) => object\n /** Key function for the opaque pagination cursor. */\n keyOf?: (item: TItem) => string | number | null\n /** Hard ceiling on `limit` (default 200 — matches the daemon tools). */\n maxLimit?: number\n /**\n * Wrapper key for the NON-paginated output. With no `limit`/`cursor`,\n * legacy list tools returned `{ sessions: [...] }` rather than the page\n * envelope; set this to reproduce that wrapper (default `\"items\"`).\n */\n itemKey?: string\n}\n\n/**\n * Pagination transformer — adds {@link pageParamsShape} to the input shape\n * and wraps the handler (which must return the FULL, unprojected item\n * array) with the shared cursor/limit semantics:\n *\n * - `limit`/`cursor` present → the `{ items, nextCursor?, total }` page\n * envelope via `paginate` + `toolText` (cursor/limit semantics are the\n * exact ones the daemon's list tools already depend on).\n * - neither present → the legacy `{ [itemKey]: [...] }` wrapper, no\n * envelope fields.\n *\n * Rows are COMPACT by default (`project`); `full: true` / `compact: false`\n * returns the unprojected records. `fields` is a per-item allowlist\n * applied on the paginated envelope branch (matching existing behavior).\n * An explicit `fields` list is itself a projection, bounded by what the\n * caller names, so on that branch it is applied to the FULL record and the\n * compact projection is skipped (unless `compact: true` is explicit) —\n * otherwise a requested field outside the compact set is silently dropped.\n */\nexport function paginated<TItem extends object>(\n opts: PaginatedOptions<TItem>,\n): ToolTransformer<unknown, readonly TItem[], McpTextResult> {\n const { project, keyOf, maxLimit = 200, itemKey = \"items\" } = opts\n return {\n name: \"paginated\",\n wrapShape: (shape: ZodRawShape): ZodRawShape => ({ ...shape, ...pageParamsShape }),\n wrapHandler: handler => async input => {\n const params = (input ?? {}) as PageParams\n const items = (await handler(input)) as readonly TItem[]\n const full = params.full === true\n const compact = full ? false : params.compact !== false\n if (params.limit !== undefined || params.cursor !== undefined) {\n const page = paginate(items, params, { maxLimit, keyOf })\n const projectRows = compact && (params.fields === undefined || params.compact === true)\n return projectRows\n ? textResult(toolText({ ...page, items: page.items.map(project) }, params))\n : textResult(toolText(page, params))\n }\n const rows = compact ? items.map(project) : items\n return textResult(JSON.stringify({ [itemKey]: rows }))\n },\n }\n}\n\n/**\n * Error-normalization transformer — wraps the handler so ANY thrown error\n * becomes the single canonical MCP error result\n * `{ content: [{ type: \"text\", text: <message> }], isError: true }`,\n * replacing the ~150 copy-pasted inline catch blocks.\n */\nexport function catchErrors(): ToolTransformer<unknown, unknown, McpTextResult> {\n return {\n name: \"catchErrors\",\n wrapHandler: handler => async input => {\n try {\n return (await handler(input)) as McpTextResult\n } catch (err) {\n const text = err instanceof Error ? err.message : String(err)\n return { content: [{ type: \"text\", text }], isError: true }\n }\n },\n }\n}\n","/**\n * @agentproto/tool — AIP-14 TOOL.md `defineTool` reference impl.\n *\n * Vendor-neutral tool **contract** registration: an author writes\n * `defineTool({...})` and the runtime returns a `ToolHandle` carrying\n * identity, schemas, side-effect profile, approval class, and\n * provider routing hints. Bodies live on AIP-30 PROVIDER manifests;\n * invocation goes through `@agentproto/driver`.\n *\n * Spec: https://agentproto.sh/docs/aip-14\n */\n\nexport const SPEC_NAME = \"agenttool/v1\" as const\nexport const SPEC_VERSION = \"1.0.0-alpha\" as const\n\nexport {\n defineTool,\n validateInput,\n validateContext,\n validateOutput,\n} from \"./define-tool.js\"\n// Standalone create-tool kept for back-compat; new code should import\n// the unified verb surface (`toolVerbs.create`, `.load`, `.list`,\n// `.update`, `.resolve`, `.delete`) from `./spec.js`.\nexport {\n createTool,\n type CreateToolOptions,\n type CreateToolResult,\n} from \"./create-tool.js\"\nexport { toolSpec, toolVerbs } from \"./spec.js\"\nexport {\n parseToolManifest,\n toolFromManifest,\n toolFromManifestOnly,\n type ToolManifest,\n type ToolManifestFrontmatter,\n} from \"./manifest/index.js\"\nexport {\n checkMinimalJsonSchema,\n validateManifestIOBlocks,\n type MinimalJsonSchemaIssue,\n} from \"./json-schema.js\"\nexport {\n ToolError,\n toToolError,\n toToolResult,\n type ToolErrorCode,\n type ToolErrorPayload,\n} from \"./errors.js\"\nexport {\n paginated,\n catchErrors,\n type McpTextResult,\n type PaginatedOptions,\n} from \"./transformers.js\"\nexport {\n paginate,\n toolText,\n encodeCursor,\n decodeCursor,\n pageParamsShape,\n type Page,\n type PageParams,\n type PaginateOpts,\n type CursorPayload,\n} from \"./envelope.js\"\nexport type {\n ToolDefinition,\n ToolHandle,\n ToolTransformer,\n ToolContext,\n ToolCapabilities,\n ApprovalClass,\n DriverConstraints,\n DriverKind,\n RetryPolicy,\n ToolResult,\n ValidationResult,\n ValidationFailure,\n ValidationSuccess,\n} from \"./types.js\"\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/create-tool.ts","../src/spec.ts","../src/envelope.ts","../src/transformers.ts","../src/index.ts"],"names":["rows"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * `createTool(params, opts)` — write a TOOL.md to disk.\n *\n * Symmetric to `parseToolManifest` (.md → handle) and `defineTool`\n * (params → handle): this takes params, validates via defineTool\n * (single source of truth — same zod schema, same cross-AIP\n * invariants), then serialises the validated frontmatter to YAML\n * and writes it under `<dir>/<id>/TOOL.md`.\n *\n * The author's body markdown is preserved verbatim in `opts.body`.\n * Pass `dryRun: true` to get the rendered string without touching\n * disk — useful for tests, the MCP server's preview, and CI lints.\n *\n * Non-frontmatter values that can't appear in YAML (zod schemas,\n * function bodies) are filtered out by `filterSerializable` from\n * `@agentproto/define-doctype`; the resulting frontmatter matches\n * what `parseToolManifest` would consume on the way back in.\n */\n\nimport { filterSerializable } from \"@agentproto/define-doctype\"\nimport matter from \"gray-matter\"\nimport { mkdir, writeFile } from \"node:fs/promises\"\nimport { dirname, join } from \"node:path\"\nimport { defineTool } from \"./define-tool.js\"\nimport type { ToolContext, ToolDefinition, ToolHandle } from \"./types.js\"\n\nfunction toSnakeCaseKeys(obj: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(obj).map(([k, v]) => [k.replace(/([A-Z])/g, \"_$1\").toLowerCase(), v]),\n )\n}\n\nexport interface CreateToolOptions {\n /** Workspace-relative or absolute directory under which to write `<id>/TOOL.md`. */\n dir: string\n /** Body markdown after the frontmatter. Defaults to a one-line stub. */\n body?: string\n /** Render only — don't write. Returns the rendered string. */\n dryRun?: boolean\n}\n\nexport interface CreateToolResult<\n TInput,\n TOutput,\n TContext extends ToolContext,\n> {\n /** The path where the file was (or would be) written. */\n path: string\n /** The validated handle returned by defineTool. */\n handle: ToolHandle<TInput, TOutput, TContext>\n /** The full rendered file contents (frontmatter + body). */\n rendered: string\n}\n\nexport async function createTool<\n TInput,\n TOutput,\n TContext extends ToolContext = ToolContext,\n>(\n params: ToolDefinition<TInput, TOutput, TContext>,\n opts: CreateToolOptions,\n): Promise<CreateToolResult<TInput, TOutput, TContext>> {\n const handle = defineTool<TInput, TOutput, TContext>(params)\n const path = join(opts.dir, handle.id, \"TOOL.md\")\n const frontmatter = filterSerializable({\n schema: \"agentproto/tool/v1\",\n ...toSnakeCaseKeys(params as unknown as Record<string, unknown>),\n }) as Record<string, unknown>\n const rendered = matter.stringify(\n opts.body ?? `# ${handle.name}\\n\\n${handle.description}\\n`,\n frontmatter,\n )\n if (!opts.dryRun) {\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, rendered, \"utf8\")\n }\n return { path, handle, rendered }\n}\n","/**\n * AIP-14 doctype spec — fed to `@agentproto/manifest.createVerbs`\n * to derive create / load / list / update / resolve / delete in one\n * place. Keeping the spec separate from `define-tool.ts` lets the\n * manifest layer (and the future MCP server) iterate over a uniform\n * descriptor without each package re-implementing the wiring.\n */\n\nimport { createVerbs, type DoctypeSpec } from \"@agentproto/manifest\"\nimport { defineTool } from \"./define-tool.js\"\nimport { parseToolManifest } from \"./manifest/index.js\"\nimport type { ToolDefinition, ToolHandle } from \"./types.js\"\n\nexport const toolSpec: DoctypeSpec<\n ToolDefinition<unknown, unknown>,\n ToolHandle<unknown, unknown>\n> = {\n name: \"tool\",\n aip: 14,\n schemaLiteral: \"agentproto/tool/v1\",\n pathOf: (h) => `${h.id}/TOOL.md`,\n define: (params) =>\n defineTool(params) as ToolHandle<unknown, unknown>,\n parse: (source) => {\n const m = parseToolManifest(source)\n const fm = m.frontmatter\n // `createVerbs.load` feeds this frontmatter straight to `define`\n // (= `defineTool`), which reads camelCase keys. The manifest uses\n // snake_case for multi-word fields, so they must be renamed here or\n // `defineTool` silently falls back to its defaults. Single-word fields\n // (mutates, approval, idempotent, tags, metadata, requires) share the\n // same key in both conventions and pass through unchanged.\n const frontmatter: Record<string, unknown> = {\n id: fm.id,\n name: fm.name,\n description: fm.description,\n version: fm.version,\n ...(fm.mutates !== undefined && { mutates: fm.mutates }),\n ...(fm.requires !== undefined && { requires: fm.requires }),\n ...(fm.approval !== undefined && { approval: fm.approval }),\n ...(fm.risk_level !== undefined && { riskLevel: fm.risk_level }),\n ...(fm.cost_class !== undefined && { costClass: fm.cost_class }),\n ...(fm.timeout_ms !== undefined && { timeoutMs: fm.timeout_ms }),\n ...(fm.idempotent !== undefined && { idempotent: fm.idempotent }),\n ...(fm.tags !== undefined && { tags: fm.tags }),\n ...(fm.metadata !== undefined && { metadata: fm.metadata }),\n // AIP-16 IO blocks pass through under the same keys.\n ...(fm.inputs !== undefined && { inputs: fm.inputs }),\n ...(fm.outputs !== undefined && { outputs: fm.outputs }),\n }\n return { frontmatter, body: m.body }\n },\n}\n\nexport const toolVerbs = createVerbs(toolSpec)\n","import { z } from \"zod\"\n\n/**\n * Shared pagination primitives (moved here from `@agentproto/runtime`'s\n * `tool-envelope.ts` so the `paginated()` ToolTransformer can reuse the\n * exact cursor/limit semantics the daemon's list tools already depend on).\n * `@agentproto/runtime` re-exports this module verbatim, so existing\n * imports are unchanged.\n */\n\n/** Shared pagination params, spread into every list tool's input schema. */\nexport interface PageParams {\n limit?: number\n cursor?: string\n since?: number\n compact?: boolean\n full?: boolean\n fields?: string[]\n}\n\nexport interface Page<T> {\n items: T[]\n nextCursor?: string\n total?: number\n truncated?: boolean\n}\n\n/** Opaque cursor: base64(JSON `{ k: keysetValue, i: index }`). */\nexport interface CursorPayload {\n k: string | number | null\n i: number\n}\n\nexport function encodeCursor(payload: CursorPayload): string {\n return Buffer.from(JSON.stringify(payload), \"utf8\").toString(\"base64url\")\n}\n\nconst cursorPayloadSchema = z.object({\n k: z.union([z.string(), z.number(), z.null()]),\n i: z.number().int().min(0),\n})\n\n/** No `unknown`/`as`: the JSON boundary is typed by zod's safeParse/parse. */\nexport function decodeCursor(token: string): CursorPayload | null {\n let text: string\n try {\n text = Buffer.from(token, \"base64url\").toString(\"utf8\")\n } catch {\n return null\n }\n try {\n return cursorPayloadSchema.parse(JSON.parse(text))\n } catch {\n return null\n }\n}\n\nexport interface PaginateOpts<T> {\n maxLimit: number\n keyOf?: (item: T) => string | number | null\n}\n\nexport function paginate<T>(items: readonly T[], params: PageParams, opts: PaginateOpts<T>): Page<T> {\n const limit = Math.min(Math.max(params.limit ?? 50, 1), opts.maxLimit)\n let start = 0\n if (params.cursor) {\n const decoded = decodeCursor(params.cursor)\n if (decoded && decoded.i >= 0 && decoded.i <= items.length) start = decoded.i\n }\n const end = start + limit\n const slice = items.slice(start, end)\n const keyAt = (idx: number): string | number | null => {\n const item = items[idx]\n return opts.keyOf && item !== undefined ? opts.keyOf(item) : null\n }\n return {\n items: slice,\n ...(end < items.length ? { nextCursor: encodeCursor({ k: keyAt(end), i: end }) } : {}),\n total: items.length,\n }\n}\n\n/**\n * Compact serializer — replaces every `JSON.stringify(x, null, 2)` in list handlers.\n *\n * When `params.fields` is supplied, an explicit allowlist is applied to every\n * item (mechanically, across all call sites): items keep only the named keys.\n * Absent `fields`, the output is byte-identical to `JSON.stringify(page)`.\n */\nexport function toolText<T extends object>(page: Page<T>, params?: Pick<PageParams, \"fields\">): string {\n const fields = params?.fields\n const items =\n fields === undefined\n ? page.items\n : page.items.map(item =>\n Object.fromEntries(\n Object.entries(item).filter(([key]) => fields.includes(key)),\n ),\n )\n return JSON.stringify({ ...page, items })\n}\n\n/** Zod fragment to spread into each list tool's input schema. */\nexport const pageParamsShape = {\n limit: z.number().int().min(1).max(200).optional().describe(\"Max items per page. Default 50.\"),\n cursor: z.string().optional().describe(\"Opaque token from a prior call's `nextCursor`.\"),\n compact: z\n .boolean()\n .optional()\n .describe(\n \"Compact projection (fewer fields per item). Default true on tools \" +\n \"that define a compact projection (session_list); a no-op elsewhere.\",\n ),\n full: z\n .boolean()\n .optional()\n .describe(\n \"Escape hatch — full, unprojected records (opts out of compact). \" +\n \"Default false.\",\n ),\n fields: z.array(z.string()).optional().describe(\"Keep only these fields per item.\"),\n} as const\n","import type { ZodRawShape } from \"zod\"\nimport {\n paginate,\n pageParamsShape,\n toolText,\n type PageParams,\n} from \"./envelope.js\"\nimport type { ToolTransformer } from \"./types.js\"\n\n/**\n * Concrete {@link ToolTransformer}s — cross-cutting concerns composed by\n * MCP-facing adapters (`toMcpTool`) around a tool's handler pipeline.\n */\n\n/** The MCP text-result shape transformers terminate the pipeline into. */\nexport interface McpTextResult {\n content: Array<{ type: \"text\"; text: string }>\n isError?: boolean\n}\n\nfunction textResult(text: string): McpTextResult {\n return { content: [{ type: \"text\", text }] }\n}\n\nexport interface PaginatedOptions<TItem> {\n /**\n * REQUIRED per-item compact projection. Requiring it is the point: there\n * is no code path that accepts the `compact` param without an actual\n * compact projection behind it, killing the \"declared but dead param\"\n * bug class. Pass the identity function only if you truly want\n * `compact` to be a no-op.\n */\n project: (item: TItem) => object\n /** Key function for the opaque pagination cursor. */\n keyOf?: (item: TItem) => string | number | null\n /** Hard ceiling on `limit` (default 200 — matches the daemon tools). */\n maxLimit?: number\n /**\n * Wrapper key for the NON-paginated output. With no `limit`/`cursor`,\n * legacy list tools returned `{ sessions: [...] }` rather than the page\n * envelope; set this to reproduce that wrapper (default `\"items\"`).\n */\n itemKey?: string\n /**\n * Row cap for the NON-paginated (no `limit`/`cursor`) call. Unset = the\n * legacy unbounded `{ [itemKey]: [...] }`. When set and the list is longer,\n * the wrapper carries the first `defaultLimit` rows plus\n * `{ total, truncated: true, nextCursor }` so the caller can page on —\n * keeps a tool whose rows pile up (terminals) under the MCP output cap.\n */\n defaultLimit?: number\n}\n\n/**\n * Pagination transformer — adds {@link pageParamsShape} to the input shape\n * and wraps the handler (which must return the FULL, unprojected item\n * array) with the shared cursor/limit semantics:\n *\n * - `limit`/`cursor` present → the `{ items, nextCursor?, total }` page\n * envelope via `paginate` + `toolText` (cursor/limit semantics are the\n * exact ones the daemon's list tools already depend on).\n * - neither present → the legacy `{ [itemKey]: [...] }` wrapper, no\n * envelope fields.\n *\n * Rows are COMPACT by default (`project`); `full: true` / `compact: false`\n * returns the unprojected records. `fields` is a per-item allowlist\n * applied on the paginated envelope branch (matching existing behavior).\n * An explicit `fields` list is itself a projection, bounded by what the\n * caller names, so on that branch it is applied to the FULL record and the\n * compact projection is skipped (unless `compact: true` is explicit) —\n * otherwise a requested field outside the compact set is silently dropped.\n */\nexport function paginated<TItem extends object>(\n opts: PaginatedOptions<TItem>,\n): ToolTransformer<unknown, readonly TItem[], McpTextResult> {\n const { project, keyOf, maxLimit = 200, itemKey = \"items\", defaultLimit } = opts\n return {\n name: \"paginated\",\n wrapShape: (shape: ZodRawShape): ZodRawShape => ({ ...shape, ...pageParamsShape }),\n wrapHandler: handler => async input => {\n const params = (input ?? {}) as PageParams\n const items = (await handler(input)) as readonly TItem[]\n const full = params.full === true\n const compact = full ? false : params.compact !== false\n if (params.limit !== undefined || params.cursor !== undefined) {\n const page = paginate(items, params, { maxLimit, keyOf })\n const projectRows = compact && (params.fields === undefined || params.compact === true)\n return projectRows\n ? textResult(toolText({ ...page, items: page.items.map(project) }, params))\n : textResult(toolText(page, params))\n }\n if (defaultLimit !== undefined && items.length > defaultLimit) {\n const page = paginate(items, { limit: defaultLimit }, { maxLimit: Math.max(maxLimit, defaultLimit), keyOf })\n const rows = compact ? page.items.map(project) : page.items\n return textResult(\n JSON.stringify({ [itemKey]: rows, total: page.total, truncated: true, nextCursor: page.nextCursor }),\n )\n }\n const rows = compact ? items.map(project) : items\n return textResult(JSON.stringify({ [itemKey]: rows }))\n },\n }\n}\n\n/**\n * Error-normalization transformer — wraps the handler so ANY thrown error\n * becomes the single canonical MCP error result\n * `{ content: [{ type: \"text\", text: <message> }], isError: true }`,\n * replacing the ~150 copy-pasted inline catch blocks.\n */\nexport function catchErrors(): ToolTransformer<unknown, unknown, McpTextResult> {\n return {\n name: \"catchErrors\",\n wrapHandler: handler => async input => {\n try {\n return (await handler(input)) as McpTextResult\n } catch (err) {\n const text = err instanceof Error ? err.message : String(err)\n return { content: [{ type: \"text\", text }], isError: true }\n }\n },\n }\n}\n","/**\n * @agentproto/tool — AIP-14 TOOL.md `defineTool` reference impl.\n *\n * Vendor-neutral tool **contract** registration: an author writes\n * `defineTool({...})` and the runtime returns a `ToolHandle` carrying\n * identity, schemas, side-effect profile, approval class, and\n * provider routing hints. Bodies live on AIP-30 PROVIDER manifests;\n * invocation goes through `@agentproto/driver`.\n *\n * Spec: https://agentproto.sh/docs/aip-14\n */\n\nexport const SPEC_NAME = \"agenttool/v1\" as const\nexport const SPEC_VERSION = \"1.0.0-alpha\" as const\n\nexport {\n defineTool,\n validateInput,\n validateContext,\n validateOutput,\n} from \"./define-tool.js\"\n// Standalone create-tool kept for back-compat; new code should import\n// the unified verb surface (`toolVerbs.create`, `.load`, `.list`,\n// `.update`, `.resolve`, `.delete`) from `./spec.js`.\nexport {\n createTool,\n type CreateToolOptions,\n type CreateToolResult,\n} from \"./create-tool.js\"\nexport { toolSpec, toolVerbs } from \"./spec.js\"\nexport {\n parseToolManifest,\n toolFromManifest,\n toolFromManifestOnly,\n type ToolManifest,\n type ToolManifestFrontmatter,\n} from \"./manifest/index.js\"\nexport {\n checkMinimalJsonSchema,\n validateManifestIOBlocks,\n type MinimalJsonSchemaIssue,\n} from \"./json-schema.js\"\nexport {\n ToolError,\n toToolError,\n toToolResult,\n type ToolErrorCode,\n type ToolErrorPayload,\n} from \"./errors.js\"\nexport {\n paginated,\n catchErrors,\n type McpTextResult,\n type PaginatedOptions,\n} from \"./transformers.js\"\nexport {\n paginate,\n toolText,\n encodeCursor,\n decodeCursor,\n pageParamsShape,\n type Page,\n type PageParams,\n type PaginateOpts,\n type CursorPayload,\n} from \"./envelope.js\"\nexport type {\n ToolDefinition,\n ToolHandle,\n ToolTransformer,\n ToolContext,\n ToolCapabilities,\n ApprovalClass,\n DriverConstraints,\n DriverKind,\n RetryPolicy,\n ToolResult,\n ValidationResult,\n ValidationFailure,\n ValidationSuccess,\n} from \"./types.js\"\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/tool",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "agentproto/tool-runtime — reference implementation of AIP-14 TOOL.md `defineTool` contract. Vendor-neutral tool registration with validated input/output schemas, structured error envelopes, and side-effect declarations. Per-framework adapters (Mastra, LangChain, A2A) consume the produced ToolHandle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentproto",
|