> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blink.so/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Structure

> Understanding the architecture of a Blink agent.

## Overview

This is a small, functional Blink agent:

```ts theme={null}
import { convertToModelMessages, streamText, tool } from "ai";
import * as blink from "blink";
import { z } from "zod";

const agent = new blink.Agent();

agent.on("chat", async ({ messages }) => {
  return streamText({
    model: "anthropic/claude-sonnet-4.5",
    system: "You are a helpful assistant.",
    messages: convertToModelMessages(messages),
    tools: {
      get_favorite_number: tool({
        inputSchema: z.object({}),
        execute() {
          return 42;
        },
      }),
    },
  });
});

agent.serve();
```

**Conversations are organized into chats.** When you send a message, the Blink platform invokes the `chat` handler - your message and its response become part of the chat's history. Subsequent invocations access the history via the `messages` parameter.

## Chat Loop

The `chat` handler is called in a loop, continuing as long as:

* The agent's last response contains tool calls
* All tool calls have completed (output available or errored)
* No tool calls are pending approval

The loop stops when there are no tool calls, a tool is awaiting approval, or an error occurs.

## Chat Handler

```ts theme={null}
agent.on("chat", async ({ messages, id, abortSignal }) => {
  return streamText({
    // ... configuration
  });
});
```

The `chat` handler is invoked whenever:

* A user sends a message
* The model makes tool calls (automatically loops)
* External services trigger a chat via webhooks

**Parameters:**

* `messages` - Array of all messages in the conversation
* `id` - Unique chat identifier
* `abortSignal` - For cancellation support

The `chat` handler can return responses using the `ai` SDK, the OpenAI SDK, the Anthropic SDK, the xAI SDK, or the Google SDK.

## Chat Management

Blink automatically manages chat state when you use it via the web UI, but for more advanced use cases, you can manage chats manually.

### Creating Chats

```ts theme={null}
// Create or get existing chat with a unique key
const chat = await agent.chat.upsert("unique-key");

// Or use structured keys
const chat = await agent.chat.upsert(["slack", teamId, channelId, threadTs]);
```

**Chat keys** should be:

* Unique for each conversation context
* JSON-serializable

### Sending Messages

```ts theme={null}
await agent.chat.sendMessages(
  chat.id,
  [
    {
      role: "user",
      parts: [{ type: "text", text: "Hello!" }],
    },
  ],
  {
    behavior: "interrupt", // or "enqueue" or "append"
  }
);
```

**Behaviors:**

* **interrupt** - Stop current processing, handle immediately
* **enqueue** - Queue message, process after current chat finishes
* **append** - Add to history without triggering processing

## Webhooks

Blink agents can handle webhooks from external services by defining a `request` event handler:

```ts theme={null}
agent.on("request", async (request) => {
  return new Response("Hello, world!", { status: 200 });
});
```

You may use it to trigger actions in your agent, such as sending a message to a chat.

```ts theme={null}
agent.on("request", async (request) => {
  const { chatName, message } = await request.json();
  const chat = await agent.chat.upsert([chatName]);
  await agent.chat.sendMessages(chat.id, [
    {
      role: "user",
      parts: [{ type: "text", text: message }],
    },
  ]);
  return new Response("Message sent", { status: 200 });
});
```

## Storage API

Blink agents can persist data across invocations using the key-value storage `agent.store` API:

```ts theme={null}
// Store data
await agent.store.set("user-preferences", {
  theme: "dark",
  notifications: true,
});

// Retrieve data
const prefs = await agent.store.get("user-preferences");

// Delete data
await agent.store.delete("user-preferences");

// List keys by prefix
const keys = await agent.store.list("user-", { limit: 100 });
```

**Use cases:**

* OAuth tokens
* User preferences
* Cache data
* Chat associations
* Rate limiting counters

***

## Tool Approvals

Blink agents can require manual approval for destructive operations using the `agent.tools.withApproval` API:

```ts theme={null}
tools: {
  // Safe tools - no approval needed
  read_file: tool({ /* ... */ }),

  // Destructive tools - require approval
  ...blink.tools.withApproval({
    messages,
    tools: {
      delete_file: tool({ /* ... */ }),
      run_command: tool({ /* ... */ }),
    },
  }),
}
```
