> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.meshapi.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.meshapi.ai/_mcp/server.

# RAG (Files & Search)

> Upload files, embed them, and run vector search with the Go SDK.

# RAG (Retrieval-Augmented Generation)

Upload documents, generate embeddings, and query them semantically — all through `client.RAG`.

## Quick upload

The `UploadFile` convenience method handles both the init call and the PUT to the signed URL in one step:

```go
content, _ := os.ReadFile("handbook.pdf")

upload, err := client.RAG.UploadFile(ctx, meshapi.UploadFileParams{
    FileName: "handbook.pdf",
    MimeType: "application/pdf",
    Content:  content,
})
if err != nil {
    log.Fatal(err)
}
fmt.Println("File ID:", upload.FileID)
```

## Two-step upload

Use `InitUpload` when you want to control the PUT yourself (e.g. streaming large files):

```go
embedFalse := false
upload, err := client.RAG.InitUpload(ctx, meshapi.InitUploadRequest{
    FileName: "handbook.pdf",
    MimeType: "application/pdf",
    Embed:    &embedFalse,
})

// PUT the bytes directly to the signed URL
req, _ := http.NewRequestWithContext(ctx, http.MethodPut, upload.SignedURL, bytes.NewReader(content))
req.Header.Set("Content-Type", "application/pdf")
http.DefaultClient.Do(req)
```

## Trigger embedding

```go
resp, err := client.RAG.Embed(ctx, meshapi.BulkEmbedRequest{
    FileIDs: []string{upload.FileID},
})
for _, r := range resp.Results {
    fmt.Printf("%s: %s\n", r.FileID, r.EmbeddingStatus)
}
```

## Poll until ready

```go
for {
    status, _ := client.RAG.Get(ctx, upload.FileID)
    if status.EmbeddingStatus == "ready" {
        break
    }
    if status.EmbeddingStatus == "failed" {
        log.Fatalf("embedding failed: %v", status.LastErrorCode)
    }
    time.Sleep(3 * time.Second)
}
```

## Search

```go
topK := 5
results, err := client.RAG.Search(ctx, meshapi.SearchRequest{
    Query:   "What is the refund policy?",
    TopK:    &topK,
    FileIDs: []string{upload.FileID}, // omit to search all files
})

for _, r := range results.Results {
    fmt.Printf("[%.3f] %s\n", r.Score, r.Text)
}
```

### Search options

| Field      | Type            | Notes                                       |
| ---------- | --------------- | ------------------------------------------- |
| `Query`    | string          | Plain-language question                     |
| `TopK`     | \*int           | Results to return (1–50, default 5)         |
| `FileIDs`  | \[]string       | Restrict to specific files                  |
| `Filter`   | map\[string]any | Match on metadata key-value pairs           |
| `DateFrom` | \*int64         | Unix timestamp — only chunks created after  |
| `DateTo`   | \*int64         | Unix timestamp — only chunks created before |

## List files

```go
limit := 50
list, err := client.RAG.List(ctx, meshapi.ListRagFilesParams{
    Limit: &limit,
})
fmt.Printf("%d total files\n", list.Total)
for _, f := range list.Files {
    fmt.Printf("%s  upload=%s  embed=%s\n", f.FileID, f.UploadStatus, f.EmbeddingStatus)
}
```

## RAG chat

Combine search results with a chat completion:

```go
results, _ := client.RAG.Search(ctx, meshapi.SearchRequest{
    Query: "What is the refund policy?",
    TopK:  &topK,
})

var chunks []string
for _, r := range results.Results {
    chunks = append(chunks, r.Text)
}
context := strings.Join(chunks, "\n\n")

model := "openai/gpt-4o-mini"
reply, _ := client.Chat.Completions.Create(ctx, meshapi.ChatCompletionParams{
    Model: &model,
    Messages: []meshapi.ChatMessage{
        {Role: "system", Content: "Answer using only the context below.\n\n" + context},
        {Role: "user",   Content: "What is the refund policy?"},
    },
})
fmt.Println(reply.Choices[0].Message.Content)
```