# How to Elicit User Input During Agent Execution in the Copilot SDK

> Learn how to elicit user input during agent execution with the Copilot SDK. Use the Session class and UI helpers like ui.input and ui.confirm for seamless interaction.

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

---

**The Copilot SDK provides a structured elicitation flow through the `Session` class that lets agents request information from users mid-execution by registering a handler with `registerUserInputHandler` and calling UI helpers like `ui.input`, `ui.confirm`, or `ui.select`.**

The Copilot SDK supports interactive agent workflows that pause execution to request user input. According to the github/copilot-sdk source code, the SDK exposes a three-part elicitation architecture that negotiates capabilities, registers handlers, and provides high-level UI helpers to bridge the gap between agent logic and human interaction.

## Understanding the Elicitation Architecture

The elicitation system in the Copilot SDK operates through three coordinated mechanisms defined across the codebase.

First, **capability negotiation** occurs when a session initializes. The host reports whether it supports UI-based elicitation via `session.capabilities.ui?.elicitation`, a boolean flag defined in [`src/types.ts`](https://github.com/github/copilot-sdk/blob/main/src/types.ts) at lines 755-756. Agents should verify this flag before attempting to request input.

Second, **handler registration** happens through the `Session` class method `registerUserInputHandler`, implemented in [`src/session.ts`](https://github.com/github/copilot-sdk/blob/main/src/session.ts) at lines 1759-1769. This method accepts a callback that receives a `UserInputRequest` and must return a `UserInputResponse`, establishing the communication channel between the runtime and your application.

Third, **UI helper methods** wrap the raw RPC calls to provide typed interfaces. The `ui.confirm`, `ui.select`, and `ui.input` methods in [`src/session.ts`](https://github.com/github/copilot-sdk/blob/main/src/session.ts) (lines 78-102) handle the complexity of building JSON Schema requests and parsing responses.

## Registering a User Input Handler

Before requesting input, you must register a handler that processes elicitation requests. The `registerUserInputHandler` method on the `Session` instance stores your callback and invokes it whenever the runtime broadcasts an `elicitation.requested` event.

According to [`src/generated/session-events.ts`](https://github.com/github/copilot-sdk/blob/main/src/generated/session-events.ts) (lines 7550-7577), these events carry the `UserInputRequest` payload containing the prompt and schema definition. Your handler must return a `UserInputResponse` object with the `answer` property populated.

```typescript
import { createSession } from "copilot-sdk";

async function main() {
    const session = await createSession({ /* session options */ });

    // Register handler for all user input requests
    session.registerUserInputHandler(async (request) => {
        console.log("Agent asks:", request.prompt);
        // Return the user's answer
        return { answer: "blue" };
    });

    // Now safe to request input
    const color = await session.ui.input("What is your favorite color?");
    console.log("Received:", color);
}

```

## Using UI Helper Methods

The SDK abstracts the raw `rpc.ui.elicitation` call (defined in [`src/generated/rpc.ts`](https://github.com/github/copilot-sdk/blob/main/src/generated/rpc.ts) at lines 134-135) through convenient helper methods on the `session.ui` namespace.

### session.ui.input()

Requests free-form text input with optional defaults and descriptions:

```typescript
const color = await session.ui.input(
    "What is your favorite color?",
    { default: "red", description: "Pick a color" }
);

```

### session.ui.confirm()

Displays a binary accept/reject dialog, returning `true` only when the user accepts:

```typescript
const confirmed = await session.ui.confirm("Do you want to continue?");
if (!confirmed) return;

```

### session.ui.select()

Presents a dropdown selection and returns the chosen string or `null` if cancelled:

```typescript
const choice = await session.ui.select(
    "Pick a fruit:",
    ["Apple", "Banana", "Cherry"]
);
console.log("Picked:", choice);

```

These helpers automatically check `session.capabilities.ui?.elicitation` and throw an error if the host does not support interactive elicitation.

## Enabling the Built-in ask_user Tool

For agents that invoke tools rather than direct UI methods, the SDK provides the `ask_user` built-in tool defined in [`src/toolSet.ts`](https://github.com/github/copilot-sdk/blob/main/src/toolSet.ts) at lines 129-130. Enable it via `session.useTools()` and reference it in prompts:

```typescript
import { BuiltInTools } from "copilot-sdk";

// Optional: explicitly enable the tool
await session.useTools([BuiltInTools.Isolated.ask_user]);

// The model will invoke ask_user when it needs clarification
const response = await session.run({
    prompt: "Ask me a question using the ask_user tool."
});
// Response routes through your registered user input handler

```

## Handling Capability Negotiation

Always guard elicitation calls with capability checks to prevent runtime errors. The `elicitation` capability flag in [`src/types.ts`](https://github.com/github/copilot-sdk/blob/main/src/types.ts) (lines 755-756) indicates host support:

```typescript
if (!session.capabilities.ui?.elicitation) {
    console.warn("Host does not support interactive input");
    return;
}
const answer = await session.ui.input("Your question here?");

```

When the capability is absent, the SDK cannot translate UI helper calls into `elicitation.requested` events, and the CLI host cannot display dialogs.

## Summary

- **Capability Check**: Verify `session.capabilities.ui?.elicitation` (defined in [`src/types.ts`](https://github.com/github/copilot-sdk/blob/main/src/types.ts) lines 755-756) before requesting input.
- **Handler Registration**: Use `session.registerUserInputHandler()` (implemented in [`src/session.ts`](https://github.com/github/copilot-sdk/blob/main/src/session.ts) lines 1759-1769) to define how your application responds to input requests.
- **UI Helpers**: Leverage `session.ui.input()`, `session.ui.confirm()`, and `session.ui.select()` (defined in [`src/session.ts`](https://github.com/github/copilot-sdk/blob/main/src/session.ts) lines 78-102) for typed, high-level interfaces.
- **RPC Layer**: The helpers internally call `rpc.ui.elicitation` (defined in [`src/generated/rpc.ts`](https://github.com/github/copilot-sdk/blob/main/src/generated/rpc.ts) lines 134-135) to communicate with the host.
- **Built-in Tool**: Enable `BuiltInTools.Isolated.ask_user` (from [`src/toolSet.ts`](https://github.com/github/copilot-sdk/blob/main/src/toolSet.ts) lines 129-130) for agent-driven input requests via tool calling.

## Frequently Asked Questions

### What happens if the host does not support elicitation?

If the host does not advertise the `elicitation` capability in `session.capabilities.ui`, calling any `session.ui` helper method throws an error. According to the source code in [`src/session.ts`](https://github.com/github/copilot-sdk/blob/main/src/session.ts), these methods perform a guard check before invoking the underlying RPC call, ensuring fail-fast behavior when the host cannot display dialogs.

### Can I use custom JSON Schema for input validation?

Yes. While the UI helpers provide convenient defaults, you can construct custom `UserInputRequest` objects with JSON Schema definitions for validation. The `UserInputRequest` and `UserInputResponse` types are defined in [`src/types.ts`](https://github.com/github/copilot-sdk/blob/main/src/types.ts) at lines 1170-1172, allowing you to pass structured schemas through the `registerUserInputHandler` callback for complex input validation beyond simple strings or selections.

### How does the elicitation flow work internally?

When you call a UI helper or the `ask_user` tool is invoked, the SDK sends an `elicitation.requested` event through the RPC layer ([`src/generated/rpc.ts`](https://github.com/github/copilot-sdk/blob/main/src/generated/rpc.ts) lines 134-135). The host displays the dialog, collects the response, and sends an `elicitation.completed` event back to the SDK. Your registered handler receives the `UserInputRequest`, and the SDK replies with the `UserInputResponse`, completing the synchronous flow from the agent's perspective.

### Where are the elicitation events defined?

The typed definitions for `elicitation.requested` and `elicitation.completed` events reside in [`src/generated/session-events.ts`](https://github.com/github/copilot-sdk/blob/main/src/generated/session-events.ts) at lines 7550-7577. These generated types ensure type safety when handling low-level session events directly, though most developers interact with the higher-level `registerUserInputHandler` API instead.