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
| Scenario | Use deferred? |
|---|---|
Tools used in every message (e.g. navigate_to) | No |
Heavy/specialized tools (e.g. run_sql_query) | Yes |
| Tools with large input schemas | Yes |
| You have 10+ tools registered | Consider 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
}