# Custom Agent Inference Control and Tool Scoping in the Copilot SDK

> Master custom agent inference control and tool scoping in the Copilot SDK. Learn to orchestrate agent participation and define exposed capabilities for precise LLM interaction.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: deep-dive
- Published: 2026-08-02

---

**The Copilot SDK enables precise control over custom agent selection through the `infer` flag while restricting LLM tool access via `tools` and `tool_choice` parameters, allowing developers to orchestrate when agents participate in inference and what capabilities they expose.**

The github/copilot-sdk repository provides a flexible framework for extending GitHub Copilot with custom agents that can execute specialized logic and interact with language models. Mastering **custom agent inference control and tool scoping** is essential for building secure, predictable AI workflows that only invoke specific agents when intended and limit their operational surface area to predefined tools.

## Understanding Inference Control with the `infer` Flag

The `infer` property in `AgentConfig` determines whether the Copilot runtime may automatically select a custom agent for a given turn or requires explicit invocation.

### How the Runtime Evaluates Agent Selection

When a user prompt arrives, the runtime builds a **session turn** containing the user message, system context, and evaluation criteria for registered agents. According to the source code in [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts), the runtime checks the `infer` boolean on each `AgentConfig` during the selection phase:

- **`infer: true`** (default): The runtime may automatically select the agent when user prompts match the agent's trigger regex or when the model decides the agent should handle the request.
- **`infer: false`**: Disables auto-selection. The agent can only be invoked explicitly through tool calls or user-directed requests.

This logic is implemented in the session helper's `runInference` method, which reads the agent's configuration before constructing the inference request.

### Configuration in AgentConfig

The `AgentConfig` interface is defined in [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) for TypeScript and mirrored in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go) for Go implementations. The configuration includes:

```typescript
interface AgentConfig {
  name: string;
  infer?: boolean;        // Defaults to true
  trigger?: string;       // Optional regex for auto-selection
  tools?: ToolDefinition[];
  tool_choice?: "auto" | "none" | { type: "function"; name: string };
}

```

When `infer` is set to `false`, optional triggers like `trigger: "search"` are ignored by the auto-selection logic, effectively making the agent available only through explicit tool invocations.

## Implementing Tool Scoping with `tools` and `tool_choice`

Custom agents can expose restricted tool sets that limit what functions the LLM may call during inference, preventing unauthorized access to capabilities outside the agent's scope.

### Defining Tool Sets for Custom Agents

The `tools` array contains JSON-schema definitions for each function the agent makes available. In [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts), these are defined as `ToolDefinition` objects. The SDK automatically serializes Zod-like schemas from [`nodejs/src/toolSet.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/toolSet.ts) into the proper format for the LLM provider.

A typical agent configuration restricts the available tools like this:

```json
{
  "name": "knowledge-base-agent",
  "description": "Agent that searches internal documentation",
  "infer": false,
  "tools": [
    {
      "name": "searchKB",
      "description": "Search the internal knowledge base",
      "parameters": {
        "type": "object",
        "properties": {
          "query": { "type": "string" }
        },
        "required": ["query"]
      }
    }
  ]
}

```

The file is parsed by the SDK loader in [`nodejs/src/extension.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/extension.ts) and converted into an `AgentConfig` object at runtime.

### Controlling Tool Selection Behavior

The `tool_choice` parameter dictates the model's willingness to invoke tools, passed directly to the provider following the OpenAI/Anthropic tool-calling contract:

- **`"auto"`**: The model may select any tool from the provided list.
- **`"none"`**: The model is forbidden from calling any tools.
- **`{ type: "function", name: "searchKB" }`**: Forces the model to use the specific named tool.

The response adapter in [`test/harness/responsesApiAdapter.ts`](https://github.com/github/copilot-sdk/blob/main/test/harness/responsesApiAdapter.ts) (lines 23-55) normalizes these parameters through the `convertResponsesTools` and `convertResponsesToolChoice` functions, ensuring the provider's response is mapped back to the session's internal message format.

## Architecture of the Inference Pipeline

Understanding how the SDK wires configuration into RPC calls reveals how inference control and tool scoping enforce boundaries at the network level.

### Session Helper and Request Construction

The `runInference` method in [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts) serves as the orchestration layer. When processing a turn, it:

1. Evaluates agent selection criteria based on the `infer` flag.
2. Merges the selected agent's `tools` and `tool_choice` into the request payload.
3. Hands the constructed request to the RPC client.

This ensures that tool scoping is enforced immediately before the network request, preventing tool leakage across agent boundaries.

### RPC Payload Generation

The actual inference request follows the `CreateMessageRequest` schema defined in [`nodejs/src/generated/rpc.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/generated/rpc.ts) (lines 11531-11598). The relevant fields include:

- `modelName`: The target LLM identifier.
- `tools`: Array of tool specifications (only present when the active agent declares tools).
- `tool_choice`: The restriction hint passed to the model.

The payload construction logic in [`responsesApiAdapter.ts`](https://github.com/github/copilot-sdk/blob/main/responsesApiAdapter.ts) demonstrates how the SDK injects these fields into the JSON-RPC request sent to the Copilot backend, ensuring that providers receive exactly the tool set and constraints defined by the active agent.

## Practical Implementation Examples

### Defining a TypeScript Custom Agent

Create an agent descriptor file that disables auto-inference and scopes tools to a single search function:

```json
// plugins/agents/kb-agent.md
{
  "name": "kb-agent",
  "description": "Knowledge base search agent",
  "infer": false,
  "tools": [
    {
      "name": "searchKB",
      "description": "Search internal documentation",
      "parameters": {
        "type": "object",
        "properties": {
          "query": { "type": "string", "description": "Search terms" }
        },
        "required": ["query"]
      }
    }
  ],
  "tool_choice": { "type": "function", "name": "searchKB" }
}

```

### Invoking the Agent from Application Code

Since `infer` is disabled, explicitly call the agent via tool syntax:

```typescript
import { createSession } from '@github/copilot-sdk';

const session = await createSession({ pluginDir: './plugins' });

const result = await session.run(`
  <tool name="searchKB">
    {"query": "Custom agent inference control"}
  </tool>
`);

console.log(result);

```

The request payload automatically includes only the `searchKB` tool definition and forces the model to use it via the `tool_choice` parameter.

### Handling Tool Calls in Agent Logic

Implement the handler that executes when the LLM invokes the scoped tool:

```typescript
// plugins/agents/kb-agent.handler.ts
export async function handleToolCall(name: string, args: any) {
  if (name === 'searchKB') {
    const results = await documentationIndex.search(args.query);
    return { result: results.slice(0, 5) };
  }
  throw new Error(`Tool ${name} not in agent scope`);
}

```

The SDK registers this handler automatically when loading the plugin directory.

### Runtime Configuration in Go

The Go SDK mirrors the TypeScript behavior, allowing dynamic configuration of inference control:

```go
import "github.com/github/copilot-sdk/go/copilot"

cfg := copilot.NewSessionConfig().
    WithCustomAgent(&copilot.AgentConfig{
        Name:  "kb-agent",
        Infer: false,
        Tools: searchToolSet,
    })

session, _ := copilot.NewSession(cfg)
resp, _ := session.RunPrompt(`
  <tool name="searchKB">
    {"query": "tool scoping semantics"}
  </tool>
`)

```

The `AgentConfig` struct in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go) and tool serialization in [`go/toolset.go`](https://github.com/github/copilot-sdk/blob/main/go/toolset.go) ensure parity with the Node.js implementation.

## Summary

- **Inference control** via the `infer` flag in `AgentConfig` determines whether the Copilot runtime auto-selects custom agents or requires explicit invocation, defined in [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) and [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go).
- **Tool scoping** restricts LLM capabilities through the `tools` array and `tool_choice` parameter, preventing unauthorized tool access beyond the agent's defined surface area.
- The **session helper** in [`nodejs/src/session.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts) merges these configurations into `CreateMessageRequest` payloads defined in [`nodejs/src/generated/rpc.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/generated/rpc.ts).
- **Response adapters** normalize tool schemas and choices between the SDK's internal format and provider-specific JSON-RPC formats.

## Frequently Asked Questions

### What is the difference between infer true and false in Copilot SDK custom agents?

When `infer` is `true` (the default), the Copilot runtime may automatically select the agent for a turn if the user prompt matches the agent's trigger regex or if the model determines the agent should handle the request. When set to `false`, auto-selection is disabled and the agent can only be invoked explicitly through tool calls or direct user commands, providing strict control over agent activation.

### How does tool_choice restrict LLM behavior in Copilot SDK?

The `tool_choice` parameter controls the model's tool-calling freedom by accepting `"auto"` (model may choose any provided tool), `"none"` (model cannot call tools), or a specific function object like `{ type: "function", name: "searchKB" }` which forces the model to use that exact tool. This is enforced in the RPC payload generated by [`test/harness/responsesApiAdapter.ts`](https://github.com/github/copilot-sdk/blob/main/test/harness/responsesApiAdapter.ts) before transmission to the LLM provider.

### Where is the AgentConfig interface defined in the Copilot SDK source code?

The `AgentConfig` interface is defined in [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) for TypeScript implementations and mirrored in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go) for Go implementations. These files specify the shape of agent configuration including the `infer` boolean, `tools` array, and `tool_choice` union type.

### Can I change inference control settings at runtime in the Copilot SDK?

Yes, inference control settings are configured when constructing session objects. In TypeScript, pass the configuration when calling `createSession()`. In Go, use `copilot.NewSessionConfig().WithCustomAgent()` to specify `AgentConfig` with `Infer: false` before instantiating the session. Once a session is active, the configuration remains fixed for that session's lifecycle.