Deferred Tools

Keep large tool registries lean by loading tools only when semantically relevant

Experimental — This feature is under active development. APIs may change before stable release.

Large tool registries bloat the LLM request payload and consume valuable context tokens. Mark tools with deferLoading: true to exclude them from the default request — they are auto-injected only when the user's query semantically matches the tool.


Usage

import { useTool } from "@yourgpt/copilot-sdk/react";
import { z } from "zod";

useTool({
  name: "run_sql_query",
  description: "Execute a SQL query against the database",
  deferLoading: true,                              // Not sent on every request
  searchKeywords: ["sql", "query", "database", "table"],
  inputSchema: z.object({ query: z.string() }),
  handler: async ({ query }) => db.execute(query),
});

Auto-detection uses description + searchKeywords to score relevance against the current message. No configuration required.


useTools (ToolSet pattern)

Register multiple tools at once:

import { useTools, tool } from "@yourgpt/copilot-sdk/react";

function MyApp() {
  useTools({
    get_weather: tool({
      description: "Get weather for a location",
      inputSchema: {
        type: "object",
        properties: { location: { type: "string" } },
        required: ["location"],
      },
      handler: async ({ location }) => fetchWeather(location),
    }),
    run_sql_query: tool({
      description: "Execute a SQL query",
      deferLoading: true,
      searchKeywords: ["sql", "query", "database"],
      inputSchema: z.object({ query: z.string() }),
      handler: async ({ query }) => db.execute(query),
    }),
  });
}

UseToolConfig — Deferred Fields

interface UseToolConfig<TParams> {
  // ...other fields...

  // Loading strategy
  deferLoading?: boolean;       // Exclude from default request payload
  searchKeywords?: string[];    // Extra keywords for relevance matching
  group?: string;               // Logical group for batch deferred loading
  category?: string;            // Category tag
  profiles?: string[];          // Named profiles for conditional activation
}

When to Use

ScenarioUse deferred?
Tools used in every message (e.g. navigate_to)No
Heavy/specialized tools (e.g. run_sql_query)Yes
Tools with large input schemasYes
You have 10+ tools registeredConsider it

Deferred tools are still available to the AI — they're just not included in the initial request payload. When the user's message matches, they're injected automatically before the request is sent.


Tool Profiles

Experimental — APIs may change before stable release.

Group tools into named profiles and activate only the relevant set per use case. Useful when different parts of your app need different tool subsets.

Tag tools with the profiles they belong to:

useTool({
  name: "run_migration",
  description: "Run a database migration",
  profiles: ["admin"],        // Only active when "admin" profile is selected
  inputSchema: z.object({ migrationId: z.string() }),
  handler: async ({ migrationId }) => runMigration(migrationId),
});

useTool({
  name: "search_docs",
  description: "Search documentation",
  profiles: ["support", "default"],
  inputSchema: z.object({ query: z.string() }),
  handler: async ({ query }) => searchDocs(query),
});

Configure profiles on <CopilotProvider>:

<CopilotProvider
  optimization={{
    toolProfiles: {
      enabled: true,
      defaultProfile: "default",
      includeUnprofiled: true,      // Tools with no profiles[] are always included
      profiles: {
        admin: {
          include: ["run_migration", "manage_users"],
        },
        support: {
          include: ["search_docs", "get_ticket"],
          exclude: ["run_migration"],
        },
      },
    },
  }}
>

Switch the active profile at runtime:

// Switch to admin tools when user elevates privileges
chat.setOptimizationConfig({
  toolProfiles: { defaultProfile: "admin" },
});

ToolProfileConfig reference

interface ToolProfileConfig {
  enabled?: boolean;
  defaultProfile?: string;
  profiles?: Record<string, {
    include?: string[];    // Tool names to include
    exclude?: string[];    // Tool names to exclude
  }>;
  includeUnprofiled?: boolean;   // default: true — tools with no profiles[] always load
}

On this page