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

# Serving Agents through HTTP

Agents can be served as HTTP endpoints, allowing them to be invoked through standard HTTP requests. `hastekit.NewHTTPHandler()` returns an `http.Handler` that dispatches to any registered agent, making it compatible with Go's standard `net/http` package.

## Creating an HTTP Server

Register your agents with `hastekit.NewAgent`, then serve `hastekit.NewHTTPHandler()`:

```go theme={null}
client := hastekit.NewLLMClient([]hastekit.ProviderConfig{
    {
        ProviderName: hastekit.ProviderOpenAI,
        ApiKeys: []*hastekit.APIKeyConfig{
            {
                Name:   "Key 1",
                APIKey: os.Getenv("OPENAI_API_KEY"),
            },
        },
    },
})

// Create agents — they register into a package-global registry
hastekit.NewAgent(&hastekit.AgentConfig{
    Name:        "SampleAgent",
    Instruction: hastekit.NewPrompt("You are helpful assistant."),
    LLM:         client.Model("OpenAI/gpt-4o-mini"),
})

// Start HTTP server
http.ListenAndServe(":8070", hastekit.NewHTTPHandler())
```

## Invoking an Agent

Send a POST request to `http://localhost:8070/?agent=<agent-name>` with the request body as `agents.AgentInput`:

```bash theme={null}
curl -X POST "http://localhost:8070/?agent=SampleAgent" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": {
      "sender_id": "user",
      "messages": [
        {
          "role": "user",
          "content": "Hello!"
        }
      ]
    }
  }'
```

The `messages` key maps to `AgentInput.Message`, which is a single message **object** (not an array). It holds a `sender_id` and the actual `messages` array of input messages.

### Response: Server-Sent Events

The handler streams the run back as an event stream, not a single JSON body. It sets `Content-Type: text/event-stream` and emits one frame per chunk:

```
event: <ChunkType>
data: <json chunk>

```

The server requires the response writer to support flushing (an `http.Flusher`); if it doesn't, it responds with `500 streaming unsupported`. Clients should read the response as an SSE stream and process each `data:` payload as it arrives.

### Request Structure

The request body follows the `agents.AgentInput` structure:

```go theme={null}
type AgentInput struct {
    Namespace         string          `json:"namespace"`
    ThreadID          string          `json:"thread_id"`
    PreviousMessageID string          `json:"previous_message_id"`
    Message           history.Message `json:"messages"`
    RunContext        map[string]any  `json:"run_context"`
    StreamID          string          `json:"stream_id,omitempty"`
    SessionID         string          `json:"shared_session_id"`
}
```

Where `history.Message` (an alias of `messages.Message`) carries a sender-attributed bundle of provider messages:

```go theme={null}
type Message struct {
    ID       string                        `json:"id"`
    SenderID string                        `json:"sender_id"`
    Messages []responses.InputMessageUnion `json:"messages"`
}
```

* `namespace` - Optional. Namespace for conversation isolation
* `thread_id` - Optional. Thread to continue (or empty to start a new one)
* `previous_message_id` - Optional. Previous message ID for conversation history
* `messages` - Required. A single message bundle (`history.Message`) with a `sender_id` and the `messages` array of input messages
* `run_context` - Optional. Additional context for the execution
* `stream_id` - Optional. Broker channel id; the server generates one if empty. The HTTP handler streams chunks back as Server-Sent Events as the run progresses.
* `shared_session_id` - Optional. Conversation ID shared by a parent agent and its sub-agent

## Complete Example

```go theme={null}
package main

import (
	"net/http"
	"os"

	hastekit "github.com/hastekit/hastekit-sdk-go"
)

func main() {
	client := hastekit.NewLLMClient([]hastekit.ProviderConfig{
		{
			ProviderName: hastekit.ProviderOpenAI,
			ApiKeys: []*hastekit.APIKeyConfig{
				{
					Name:   "Key 1",
					APIKey: os.Getenv("OPENAI_API_KEY"),
				},
			},
		},
	})

	model := client.Model("OpenAI/gpt-4.1-mini")

	history := hastekit.NewFileHistory("./conversations")
	agentName := "SampleAgent"
	_ = hastekit.NewAgent(&hastekit.AgentConfig{
		Name:        agentName,
		Instruction: hastekit.NewPrompt("You are helpful assistant."),
		LLM:         model,
		History:     history,
	})

	http.ListenAndServe(":8070", hastekit.NewHTTPHandler())

	// You can then invoke by hitting POST http://localhost:8070/?agent=SampleAgent with `agents.AgentInput` as your payload
	/*
		  curl -X POST "http://localhost:8070/?agent=SampleAgent" \
		  -H "Content-Type: application/json" \
		  -d '{
			"messages": {
			  "sender_id": "user",
			  "messages": [
				{
				  "role": "user",
				  "content": "Hello!"
				}
			  ]
			}
		  }'
	*/
}
```

## Serving over AG-UI

The raw `http.Handler` above is the simplest way to expose an agent, but it speaks the SDK's own `AgentInput` shape. For a standards-based option that works with CopilotKit and other off-the-shelf clients — and a ready-made browser chat UI — serve your agents over the AG-UI protocol instead. See [Serving Agents over AG-UI](/docs/hastekit-sdk/agents/serving-agents/serving-agents-agui).
