Skip to content

Custom Tools ​

Seepient ships with built-in tools and provides explicit extension points for custom capabilities. Custom tools are registered with explicit trust models rather than ambient host authority.

The Honesty Ladder ​

Naming a tool prepared does not make it safe; the label declares what the platform governs. Analyzer code is trusted computing base; connector code does not exist; host code is sudo. Pick the lowest rung that fits.

Decision Table ​

Your tool…UseWhy
Needs arbitrary application logic (DB queries, internal APIs, household-scoped work)trustedHostToolThe effect cannot be described as a supported operation; ambient authority is the honest label. Approval says "host tool"; every call is audit-labelled and allowlist-gated in server roots.
Performs an effect the platform understands (write/commit files, other supported operations) and you want approvals that describe the real effectpreparedToolYour analyzer returns a draft (operation, effects, risk, display); the platform stamps identity and digests; the user approves the operation, not "unknown JavaScript"; audit carries digests and risk.
Just maps tool arguments into an existing broker (search, sends, future brokers)brokerConnectorZero of your code runs. Lowest rung; the risk is your mapping, not your code.

Chooser Questions ​

  1. Can the tool's whole effect be expressed as one existing broker operation?
    → brokerConnector.
  2. Can it be expressed as one supported operation kind that your code prepares (digests, display, effects)?
    → preparedTool.
  3. Otherwise
    → trustedHostTool, and expect host-authority approval and audit labels.

Compliance Burden per Rung ​

  • brokerConnector: write a correct mapping (pointer targets, no constant/binding collisions, secretRefs only for real secrets).
  • preparedTool: meet the authoring checklist — a complete, honest draft; the platform does the rest.
  • trustedHostTool: none at registration; all of it in your execute (args validation, household scoping, injection defense — the model can be tricked into calling you with hostile args, and your code is the only defense).

Deprecation: legacy tool() factory

The legacy tool({ execute }) factory is deprecated and fails closed at runtime. Migrate existing tools to an explicit trust model (trustedHostTool, preparedTool, or brokerConnector).

Per-Agent Tool Isolation

All custom tools are scoped to the agent instance where they are supplied via tools: [...]. Global mutable tool registries and legacy global mutators have been deleted. For multi-tenant environments and migration details, see the Multi-Tenant Isolation Guide.


1. brokerConnector (Data-Only Mapping) ​

brokerConnector registers a declarative mapping from tool arguments directly to a platform-supported broker. No embedder code executes during preparation or execution.

typescript
import { createSeepient, brokerConnector } from "seepient";

const searchTool = brokerConnector({
  definition: {
    type: "function",
    function: {
      name: "search_docs",
      description: "Search technical documentation",
      parameters: {
        type: "object",
        properties: {
          searchQuery: { type: "string", description: "Search query" },
        },
        required: ["searchQuery"],
      },
    },
  },
  connector: "web-search",
  mapping: {
    version: 1,
    operation: "search",
    argumentBindings: { query: "/searchQuery" }, // JSON Pointer into tool args
    constants: { limit: 5 },
    secretRefs: ["tavilyApiKey"], // resolved at execution time
  },
});

Mapping Rules ​

  • version must be 1.
  • argumentBindings values are JSON Pointers (RFC 6901) into tool args.
  • constants merge into the connector request. A constant colliding with a bound argument is rejected.
  • secretRefs reference credential entries or environment variables (e.g. tavilyApiKey resolving TAVILY_API_KEY, smtpPass resolving SMTP_PASS, or generic environment variable names). If any declared secret cannot be resolved, execution fails closed with CONNECTOR_SECRET_UNRESOLVED. Secret values are never exposed in prompt displays, tool results, or audit rows.

2. preparedTool (Policy-Governed Preparation) ​

preparedTool registers an analyzer that prepares a serializable operation draft (operation, effects, risk, display). The platform stamps identity and computes digests, then routes the operation through the policy engine and execution boundary.

typescript
import { createSeepient, preparedTool } from "seepient";
import { join } from "node:path";

const reportTool = preparedTool({
  definition: {
    type: "function",
    function: {
      name: "generate_report",
      description: "Generate and save a weekly status report",
      parameters: {
        type: "object",
        properties: {
          title: { type: "string" },
          content: { type: "string" },
        },
        required: ["title", "content"],
      },
    },
  },
  allowedOperationKinds: ["commit-files"],
  analyze: async (args, context) => {
    const { title, content } = (args ?? {}) as { title: string; content: string };
    const artifact = await context.artifacts.put(
      Buffer.from(`Report: ${title}\n${content}`),
      "text/plain",
    );
    const fullPath = join(context.workspace.canonicalRoot, "reports", `${title}.txt`);
    const target = {
      canonicalPath: fullPath,
      canonicalParent: join(context.workspace.canonicalRoot, "reports"),
      basename: `${title}.txt`,
      exists: false,
      finalSymlink: false,
    };

    return {
      operation: {
        kind: "commit-files",
        commits: [{ destination: target, content: artifact }],
      },
      effects: [
        {
          kind: "filesystem-write",
          targets: [{ target, mode: "create" }],
        },
      ],
      risk: "edit",
      display: {
        title: `Generate Report ${title}`,
        summary: `Writes report to reports/${title}.txt`,
        canonicalTargets: [target.canonicalPath],
        effects: ["filesystem-write"],
      },
    };
  },
});

What the Platform Guarantees ​

  • The analyzer runs once per tool call at analysis time with the real ToolAnalysisContext.
  • Identity fields (runId, toolCallId, toolName, principalId) and digests (argsDigest, actionDigest) are stamped platform-side.
  • The returned operation executes via the configured boundary (e.g. FileCommitBroker), never arbitrary JavaScript.

Non-Guarantees (Honesty Section) ​

  • No sandboxing of analyzer code: Analyzer JavaScript runs in-process as application TCB.
  • No new operation kinds in v1: The closed v1 set is commit-files, read-file, process, broker, and none.
  • No dynamic re-registration after composition: setTools() cannot add custom tool registrations dynamically.

3. trustedHostTool (Ambient Host Authority) ​

trustedHostTool registers an arbitrary JavaScript function with ambient in-process authority.

typescript
import { createSeepient, trustedHostTool, type HostToolContext } from "seepient";

const queryBankTool = trustedHostTool({
  definition: {
    type: "function",
    function: {
      name: "query_bank_balance",
      description: "Query bank account balance",
      parameters: {
        type: "object",
        properties: {
          accountId: { type: "string", description: "Account identifier" },
        },
        required: ["accountId"],
      },
    },
  },
  declaration: {
    risk: "high",
    effects: [
      { kind: "network-egress", destinations: ["api.bank.com"] },
      { kind: "secret-use", secretRefs: ["BANK_API_KEY"] },
    ],
  },
  execute: async (args: unknown, _context: HostToolContext) => {
    const { accountId } = (args ?? {}) as { accountId: string };
    return JSON.stringify({ accountId, balance: 4200 });
  },
});

Host Tool Rules ​

  1. Governed Execution by Default: Custom host tools execute governed within the unified permission pipeline and execution boundary.
  2. Automatic Allowlist Registration: Passing a trustedHostTool in the tools array automatically binds the callback to the agent execution boundary.
  3. Multi-Tenant Gating: Server roots enforce permissions.trustedHostAllowlist.

Mixed-Rung Composition Example ​

You can combine built-in tool groups and custom tools across any trust model:

typescript
import { createSeepient, CORE_TOOLS } from "seepient";

const agent = await createSeepient({
  tools: [
    ...CORE_TOOLS,
    searchTool,     // brokerConnector
    reportTool,     // preparedTool
    queryBankTool,  // trustedHostTool
  ],
});

Released under the Business Source License 1.1.