> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/agentclientprotocol/typescript-sdk/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling Prompts

> Learn how to process user prompts and send real-time updates

## Overview

The `prompt` method is the core of your agent's functionality. It handles the entire lifecycle of processing a user's request, from receiving the initial messages to executing tool calls and returning a final response.

```typescript theme={null}
async prompt(
  params: PromptRequest
): Promise<PromptResponse>
```

<ParamField path="params.sessionId" type="string" required>
  The session ID to process the prompt in
</ParamField>

<ParamField path="params.messages" type="Message[]" required>
  The user messages with optional context (files, images, etc.)
</ParamField>

<ResponseField name="stopReason" type="StopReason" required>
  The reason the prompt turn ended: "end\_turn", "cancelled", or "error"
</ResponseField>

See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)

## Prompt Lifecycle

The prompt method handles the complete lifecycle of a turn:

<Steps>
  <Step title="Receive Messages">
    The client sends user messages with optional context (files, images, etc.)
  </Step>

  <Step title="Process with Language Model">
    Send the messages to your language model and receive a response
  </Step>

  <Step title="Stream Updates to Client">
    Send real-time updates as the model generates content using `sessionUpdate`
  </Step>

  <Step title="Handle Tool Calls">
    If the model wants to use tools, request permission (if needed) and execute them
  </Step>

  <Step title="Return Stop Reason">
    Return the final stop reason indicating why the turn ended
  </Step>
</Steps>

## Sending Session Updates

Use the `sessionUpdate` method on your `AgentSideConnection` to send real-time updates during prompt processing:

### Message Chunks

Send text content as it's generated by the language model:

```typescript theme={null}
await this.connection.sessionUpdate({
  sessionId: params.sessionId,
  update: {
    sessionUpdate: "agent_message_chunk",
    content: {
      type: "text",
      text: "I'll help you with that task.",
    },
  },
});
```

### Tool Calls

Report when the model wants to execute a tool:

```typescript theme={null}
// Initial tool call
await this.connection.sessionUpdate({
  sessionId: params.sessionId,
  update: {
    sessionUpdate: "tool_call",
    toolCallId: "call_1",
    title: "Reading project files",
    kind: "read",
    status: "pending",
    locations: [{ path: "/project/README.md" }],
    rawInput: { path: "/project/README.md" },
  },
});

// Update with results
await this.connection.sessionUpdate({
  sessionId: params.sessionId,
  update: {
    sessionUpdate: "tool_call_update",
    toolCallId: "call_1",
    status: "completed",
    content: [
      {
        type: "content",
        content: {
          type: "text",
          text: "# My Project\n\nThis is a sample project...",
        },
      },
    ],
    rawOutput: { content: "# My Project\n\nThis is a sample project..." },
  },
});
```

## Tool Calls and Permission Requests

When the language model wants to execute a sensitive operation, request permission from the user:

```typescript theme={null}
// Send the tool call
await this.connection.sessionUpdate({
  sessionId: params.sessionId,
  update: {
    sessionUpdate: "tool_call",
    toolCallId: "call_2",
    title: "Modifying critical configuration file",
    kind: "edit",
    status: "pending",
    locations: [{ path: "/project/config.json" }],
    rawInput: {
      path: "/project/config.json",
      content: '{"database": {"host": "new-host"}}',
    },
  },
});

// Request permission
const permissionResponse = await this.connection.requestPermission({
  sessionId: params.sessionId,
  toolCall: {
    toolCallId: "call_2",
    title: "Modifying critical configuration file",
    kind: "edit",
    status: "pending",
    locations: [{ path: "/home/user/project/config.json" }],
    rawInput: {
      path: "/home/user/project/config.json",
      content: '{"database": {"host": "new-host"}}',
    },
  },
  options: [
    {
      kind: "allow_once",
      name: "Allow this change",
      optionId: "allow",
    },
    {
      kind: "reject_once",
      name: "Skip this change",
      optionId: "reject",
    },
  ],
});

// Handle the response
if (permissionResponse.outcome.outcome === "cancelled") {
  // User cancelled the entire prompt turn
  return { stopReason: "cancelled" };
}

switch (permissionResponse.outcome.optionId) {
  case "allow":
    // Execute the tool call
    await this.executeToolCall("call_2");
    break;
  case "reject":
    // Skip the tool call
    break;
}
```

<Warning>
  If the client cancels the prompt turn via `session/cancel`, the `requestPermission` call MUST respond with `RequestPermissionOutcome::Cancelled`.
</Warning>

## Stop Reasons

Return one of the following stop reasons when the prompt completes:

<ParamField path="end_turn" type="StopReason">
  The language model completed its turn naturally
</ParamField>

<ParamField path="cancelled" type="StopReason">
  The prompt was cancelled by the client via `session/cancel`
</ParamField>

<ParamField path="error" type="StopReason">
  An error occurred during processing
</ParamField>

## Handling Cancellation

Implement proper cancellation handling using `AbortController`:

```typescript theme={null}
interface AgentSession {
  pendingPrompt: AbortController | null;
}

async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {
  const session = this.sessions.get(params.sessionId);
  if (!session) {
    throw new Error(`Session ${params.sessionId} not found`);
  }

  // Cancel any existing prompt
  session.pendingPrompt?.abort();
  session.pendingPrompt = new AbortController();

  try {
    // Pass the abort signal to your LLM client
    await this.processWithLLM(params, session.pendingPrompt.signal);
    return { stopReason: "end_turn" };
  } catch (err) {
    if (session.pendingPrompt.signal.aborted) {
      return { stopReason: "cancelled" };
    }
    throw err;
  } finally {
    session.pendingPrompt = null;
  }
}

async cancel(params: acp.CancelNotification): Promise<void> {
  this.sessions.get(params.sessionId)?.pendingPrompt?.abort();
}
```

<Note>
  Continue accepting tool call updates even after receiving a `session/cancel` notification, as you may need to send final updates before responding with the cancelled stop reason.
</Note>

## Complete Example

Here's a complete example from the SDK's example agent:

```typescript theme={null}
async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {
  const session = this.sessions.get(params.sessionId);
  if (!session) {
    throw new Error(`Session ${params.sessionId} not found`);
  }

  session.pendingPrompt?.abort();
  session.pendingPrompt = new AbortController();

  try {
    // Send initial text chunk
    await this.connection.sessionUpdate({
      sessionId: params.sessionId,
      update: {
        sessionUpdate: "agent_message_chunk",
        content: {
          type: "text",
          text: "I'll help you with that. Let me start by reading some files.",
        },
      },
    });

    // Send a tool call
    await this.connection.sessionUpdate({
      sessionId: params.sessionId,
      update: {
        sessionUpdate: "tool_call",
        toolCallId: "call_1",
        title: "Reading project files",
        kind: "read",
        status: "pending",
        locations: [{ path: "/project/README.md" }],
        rawInput: { path: "/project/README.md" },
      },
    });

    // Execute and update
    await this.connection.sessionUpdate({
      sessionId: params.sessionId,
      update: {
        sessionUpdate: "tool_call_update",
        toolCallId: "call_1",
        status: "completed",
        content: [
          {
            type: "content",
            content: {
              type: "text",
              text: "# My Project\n\nThis is a sample project...",
            },
          },
        ],
        rawOutput: { content: "# My Project\n\nThis is a sample project..." },
      },
    });

    return { stopReason: "end_turn" };
  } catch (err) {
    if (session.pendingPrompt.signal.aborted) {
      return { stopReason: "cancelled" };
    }
    throw err;
  } finally {
    session.pendingPrompt = null;
  }
}
```

See the [full example agent](https://github.com/agentclientprotocol/typescript-sdk/blob/main/src/examples/agent.ts) for more details.
