{"id":50732681,"url":"https://github.com/kaatinga/mistralai-go","last_synced_at":"2026-06-10T10:30:36.785Z","repository":{"id":361119516,"uuid":"1245916649","full_name":"kaatinga/mistralai-go","owner":"kaatinga","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-29T09:56:06.000Z","size":39,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T10:04:43.412Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kaatinga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T17:28:18.000Z","updated_at":"2026-05-29T09:56:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kaatinga/mistralai-go","commit_stats":null,"previous_names":["kaatinga/mistralai-go"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/kaatinga/mistralai-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaatinga%2Fmistralai-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaatinga%2Fmistralai-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaatinga%2Fmistralai-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaatinga%2Fmistralai-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kaatinga","download_url":"https://codeload.github.com/kaatinga/mistralai-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaatinga%2Fmistralai-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34149132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-10T10:30:35.958Z","updated_at":"2026-06-10T10:30:36.780Z","avatar_url":"https://github.com/kaatinga.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mistralai-go\n\nSynchronous Go client for the [Mistral API](https://docs.mistral.ai/api). Each call blocks until Mistral returns HTTP 200 with the full JSON body (no job polling or background workers).\n\n## API surface\n\n| Method | HTTP | Use when |\n|--------|------|----------|\n| `OCR` | `POST /v1/files`, then `POST /v1/ocr` | Document OCR via file upload |\n| `Chat` | `POST /v1/chat/completions` | Single user turn with optional system prompt and output format helpers |\n| `ChatCompletion` | `POST /v1/chat/completions` | Full control: message list, temperature, `response_format`, etc. |\n| `Embeddings` | `POST /v1/embeddings` | Text embeddings (`mistral-embed`, batch input, optional dimensions/dtype) |\n| `ListModels` | `GET /v1/models` | List models available to your API key |\n| `UploadFile` | `POST /v1/files` | Upload a file; returns file id |\n| `ListFiles` | `GET /v1/files` | List uploaded files (optional pagination and filters) |\n| `DeleteFile` | `DELETE /v1/files/{file_id}` | Remove an uploaded file |\n| `DownloadFile` | `GET /v1/files/{file_id}/content` | Download raw file content (e.g. batch results) |\n| `UploadBatchInput` | `POST /v1/files` | Build a JSONL input file from typed entries and upload it (`purpose=batch`) |\n| `CreateBatchJob` | `POST /v1/batch/jobs` | Create an async batch job over an uploaded input file |\n| `ListBatchJobs` | `GET /v1/batch/jobs` | List batch jobs (optional pagination, `created_by_me`) |\n| `GetBatchJob` | `GET /v1/batch/jobs/{job_id}` | Fetch one batch job |\n| `CancelBatchJob` | `POST /v1/batch/jobs/{job_id}/cancel` | Request cancellation of a batch job |\n\nJSON API calls (`Chat`, `ChatCompletion`, `Embeddings`, `ListModels`, `ListFiles`, `DeleteFile`, `DownloadFile`, the batch job calls, OCR after upload) retry on **429** and **5xx** with exponential backoff (default **5** attempts, context-aware). Configure with `WithMaxRetries`.\n\n## Install\n\n```bash\ngo get github.com/kaatinga/mistralai-go\n```\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"bytes\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n\n\tmistralai \"github.com/kaatinga/mistralai-go\"\n)\n\nfunc main() {\n\tcl, err := mistralai.NewClient(\n\t\tos.Getenv(\"MISTRAL_API_KEY\"),\n\t\tmistralai.WithHTTPClient(\u0026http.Client{Timeout: 120 * time.Second}),\n\t)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer cl.Close()\n\n\tctx := context.Background()\n\n\t// OCR: POST /v1/files, then POST /v1/ocr\n\tpdf, _ := os.ReadFile(\"document.pdf\")\n\tocr, err := cl.OCR(ctx, mistralai.OCRRequest{\n\t\tFilename:    \"document.pdf\",\n\t\tContent:     bytes.NewReader(pdf),\n\t\tContentType: \"application/pdf\",\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tlog.Println(ocr.Pages[0].Markdown)\n\n\t// Chat — one system + one user message; optional markdown/json formatting\n\tchat, err := cl.Chat(ctx, mistralai.ChatRequest{\n\t\tInput:  \"Summarize the document in one sentence.\",\n\t\tFormat: mistralai.OutputText,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tlog.Println(chat.Content)\n\n\t// ChatCompletion — multi-turn or custom parameters\n\tresp, err := cl.ChatCompletion(ctx, mistralai.ChatCompletionRequest{\n\t\tModel: \"mistral-small-latest\",\n\t\tMessages: []mistralai.ChatMessage{\n\t\t\t{Role: \"system\", Content: \"You are concise.\"},\n\t\t\t{Role: \"user\", Content: \"Hello\"},\n\t\t},\n\t\tTemperature: new(0.7), // pointer so temperature 0 is distinguishable from unset\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tlog.Println(resp.FirstChoiceContent())\n\n\t// ListModels\n\tmodels, err := cl.ListModels(ctx)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfor _, m := range models.Data {\n\t\tlog.Println(m.ID)\n\t}\n}\n```\n\n### High-level `Chat` vs `ChatCompletion`\n\n- **`Chat`** builds a short message list from `Input` and optional `System`, and can request text, markdown, or JSON output via `Format` / `ResponseFormat`.\n- **`ChatCompletion`** maps directly to the REST request body: any number of messages, `temperature`, `max_tokens`, `top_p`, `response_format`, and **tool calling** (`tools`, `tool_choice`, `parallel_tool_calls`). Use this for conversation history or app-specific control.\n\n`Chat` is implemented on top of `ChatCompletion` internally.\n\n### Tool calling\n\nExpose functions to the model via `tools` on `ChatCompletionRequest`. When the model needs data, it returns `tool_calls` on the assistant message; run your handlers and send `role: \"tool\"` messages back, then call `ChatCompletion` again (or use `ChatCompletionWithTools` to run that loop).\n\n`parallel_tool_calls` defaults to `true` on the Mistral API when omitted, so the model may request multiple functions in one assistant turn.\n\nDo not combine `response_format: json_schema` with `tools` on the same request.\n\n```go\nparamsSchema := map[string]any{\n\t\"type\": \"object\",\n\t\"properties\": map[string]any{\n\t\t\"building_id\": map[string]any{\"type\": \"integer\"},\n\t},\n}\ntools := []mistralai.Tool{\n\tmistralai.FunctionTool(\"count_apartments\", \"Count apartments in confirmed project data\", paramsSchema),\n}\n\nhandler := func(ctx context.Context, call mistralai.ToolCall) (string, error) {\n\t// Parse call.Function.Arguments (JSON string), run your Go logic, return JSON text.\n\treturn `{\"count\":8}`, nil\n}\n\nresp, err := mistralai.ChatCompletionWithTools(ctx, cl, mistralai.ChatCompletionRequest{\n\tModel: mistralai.DefaultChatModel,\n\tMessages: []mistralai.ChatMessage{\n\t\tmistralai.TextMessage(mistralai.RoleUser, \"How many apartments?\"),\n\t},\n\tTools:      tools,\n\tToolChoice: mistralai.ToolChoiceAuto,\n}, handler, 3)\nif err != nil {\n\tlog.Fatal(err)\n}\nanswer, err := resp.FirstChoiceContent()\n```\n\nManual loop: check `choice, _ := resp.FirstChoice()` and `choice.HasToolCalls()`, append `choice.Message` plus `mistralai.ToolMessage(call.ID, call.Function.Name, result)` for each call, then call `ChatCompletion` again with the extended `Messages` slice.\n\n### Embeddings\n\n```go\nresp, err := cl.Embeddings(ctx, mistralai.EmbeddingRequest{\n\tModel: mistralai.EmbeddingModelMistralEmbed,\n\tInput: mistralai.EmbeddingInputStrings(\n\t\t\"Embed this sentence.\",\n\t\t\"As well as this one.\",\n\t),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nvecs, err := resp.Float64Vectors()\nif err != nil {\n\tlog.Fatal(err)\n}\nlog.Println(len(vecs), len(vecs[0]))\n```\n\nOptional request fields: `encoding_format` (`float` or `base64`), `output_dimension`, `output_dtype` (`float`, `int8`, `uint8`, `binary`, `ubinary`), and `metadata`. Decode each vector with `EmbeddingData.Float64s()` or `Float32s()` (handles JSON float arrays and base64-encoded float32 payloads).\n\nFor batch jobs on `/v1/embeddings`, use `EmbeddingEntry` and `ParseBatchResults[mistralai.EmbeddingResponse]`.\n\n### Client options\n\n- `WithHTTPClient` — custom `http.Client` (default timeout **10 minutes**, suitable for OCR).\n- `WithMaxRetries` — retries for retryable status codes (default **5**).\n- `WithBaseURL` — override API origin (tests or proxies).\n\n### JSON output with `Chat`\n\n```go\nresp, err := cl.Chat(ctx, mistralai.ChatRequest{\n\tInput:  `{\"task\":\"translate\",\"text\":\"hello\"}`,\n\tFormat: mistralai.OutputJSON,\n})\nvar out map[string]string\nif err = resp.JSON(\u0026out); err != nil {\n\tlog.Fatal(err)\n}\n```\n\nFor `json_schema`, set `ResponseFormat` on `ChatRequest`, `ChatCompletionRequest`, or `OCRRequest.DocumentAnnotationFormat`. Unmarshal OCR output with `OCRStructured[T]` or `DocumentAnnotationInto[T](resp)`.\n\n### Ergonomic helpers\n\n- `new(v)` (Go 1.26 built-in) — set optional pointer fields (`Temperature`, `TopP`, `ExtractHeader`, `IncludeImageBase64`, …) inline; `new(0.0)` is an explicit zero, a nil pointer is \"unset\".\n- `JSONSchemaFormat(name, schema)` — build a strict `json_schema` `*ResponseFormat` without hand-writing the `ResponseFormat`/`JSONSchema` nesting.\n- `TextMessage(role, text)` / `MultipartMessage(role, parts...)` and `TextPart`, `FilePart`, `ImageURLPart`, `DocumentURLPart` — build messages and multimodal content without magic strings.\n- `FunctionTool(name, description, parameters)` / `ToolMessage(toolCallID, name, content)` / `ChatCompletionWithTools` — function calling on chat completions.\n- `RoleSystem`, `RoleUser`, `RoleAssistant`, `RoleTool` and `ResponseFormatText`, `ResponseFormatJSONObject`, `ResponseFormatJSONSchema` constants for the role and `response_format` type fields.\n\n```go\nreq := mistralai.ChatCompletionRequest{\n\tModel: mistralai.ChatModelPixtralLargeLatest,\n\tMessages: []mistralai.ChatMessage{\n\t\tmistralai.TextMessage(mistralai.RoleSystem, \"Classify the document.\"),\n\t\tmistralai.MultipartMessage(mistralai.RoleUser,\n\t\t\tmistralai.TextPart(\"What kind of document is this?\"),\n\t\t\tmistralai.FilePart(fileID), // from cl.UploadFile\n\t\t),\n\t},\n\tTemperature:    new(0.0),\n\tResponseFormat: mistralai.JSONSchemaFormat(\"doc_type\", schema),\n}\n```\n\n### Batch API\n\nThe Batch API runs one endpoint over many requests asynchronously (roughly half\nthe per-token cost, no per-request rate limits) and returns results as a JSONL\nfile. It is **not** for latency-sensitive calls — a job completes within its\n`timeout_hours` (default 24), not immediately.\n\nBuild the input from the same typed request values you already use:\n`ChatCompletionEntry` for `/v1/chat/completions`, `EmbeddingEntry` for\n`/v1/embeddings`, `OCREntry` for `/v1/ocr` (referencing an already-uploaded\n`file_id`), or `Entry(customID, body)` for any other endpoint. Parse results\nback into the matching typed response with `ParseBatchResults[T]`.\n\n```go\nentries := []mistralai.BatchEntry{\n\tmistralai.ChatCompletionEntry(\"0\", mistralai.ChatCompletionRequest{\n\t\tModel:    mistralai.ChatModelMistralSmallLatest,\n\t\tMessages: []mistralai.ChatMessage{mistralai.TextMessage(mistralai.RoleUser, \"Hello\")},\n\t}),\n\tmistralai.ChatCompletionEntry(\"1\", mistralai.ChatCompletionRequest{\n\t\tModel:    mistralai.ChatModelMistralSmallLatest,\n\t\tMessages: []mistralai.ChatMessage{mistralai.TextMessage(mistralai.RoleUser, \"Bonjour\")},\n\t}),\n}\n\ninputFileID, err := cl.UploadBatchInput(ctx, \"batch.jsonl\", entries)\nif err != nil {\n\tlog.Fatal(err)\n}\n\njob, err := cl.CreateBatchJob(ctx, mistralai.CreateBatchJobRequest{\n\tEndpoint:   mistralai.BatchEndpointChatCompletions,\n\tModel:      mistralai.ChatModelMistralSmallLatest, // required at job level; defaults per endpoint if omitted\n\tInputFiles: []string{inputFileID},\n})\nif err != nil {\n\tlog.Fatal(err)\n}\n\n// Poll until terminal (SUCCESS / FAILED / TIMEOUT_EXCEEDED / CANCELLED).\nwaitCtx, cancel := mistralai.WithTimeout(ctx, time.Hour)\ndefer cancel()\njob, err = mistralai.WaitForBatchJob(waitCtx, cl, job.ID, 10*time.Second)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nif job.Status == mistralai.BatchStatusSuccess \u0026\u0026 job.OutputFile != nil {\n\traw, err := cl.DownloadFile(ctx, *job.OutputFile)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tresults, err := mistralai.ParseBatchResults[mistralai.ChatCompletionResponse](raw)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfor _, r := range results {\n\t\tif r.StatusCode == 200 {\n\t\t\tcontent, _ := r.Body.FirstChoiceContent()\n\t\t\tlog.Println(r.CustomID, content)\n\t\t}\n\t}\n}\n```\n\n`WaitForBatchJob` returns terminal-but-failed jobs **without** a Go error — inspect\n`job.Errors` and download `job.ErrorFile` (also JSONL, parse with\n`ParseBatchResults[T]`) to see per-request failures. The input file is not\ndeleted automatically; use `DeleteFile` when you no longer need it.\n\n### Error handling\n\nNon-200 responses return a typed `*APIError`. Inspect it with `errors.As` to\nbranch on the HTTP status, error type, or whether the client already retried it:\n\n```go\nresp, err := cl.Chat(ctx, req)\nvar apiErr *mistralai.APIError\nif errors.As(err, \u0026apiErr) {\n\tswitch apiErr.StatusCode {\n\tcase http.StatusUnauthorized:\n\t\tlog.Fatal(\"bad API key\")\n\tcase http.StatusTooManyRequests:\n\t\t// apiErr.Retryable() == true; the client already exhausted WithMaxRetries\n\t}\n}\n```\n\n## Comparison with other Go Mistral clients\n\nThere is no official Go SDK for Mistral. The table below compares `mistralai-go`\nwith the three most widely used community clients (state as of May 2026):\n\n- [`gage-technologies/mistral-go`](https://github.com/Gage-Technologies/mistral-go) — the most popular and most-referenced client (e.g. used by `langchaingo`); MIT, last release v1.1.0 (Jun 2024).\n- [`robertjkeck2/mistral-go`](https://github.com/robertjkeck2/mistral-go) — an early, minimal client; MIT, last release v0.1.1 (Jan 2024).\n- [`onkyou/go-mistral`](https://pkg.go.dev/github.com/onkyou/go-mistral/mistral) — a newer, broad client with a service-oriented API; MIT, untagged.\n\n| Capability | **mistralai-go** | gage-technologies | robertjkeck2 | onkyou/go-mistral |\n|---|:---:|:---:|:---:|:---:|\n| Chat completions | ✅ | ✅ | ✅ | ✅ |\n| Streaming chat | ❌ | ✅ | ✅ | ✅ |\n| Embeddings | ✅ | ✅ | ✅ | ✅ |\n| FIM / code completion | ❌ | ✅ | ❌ | ❌ |\n| Function / tool calling | ✅ | ✅ | ❌ | ✅ |\n| Moderation / classification | ❌ | ❌ | ❌ | ✅ |\n| **OCR + document annotation** | ✅ | ❌ | ❌ | ❌ |\n| **File API (upload / list / delete / download)** | ✅ | ❌ | ❌ | ❌ |\n| **Batch API** (typed entries + typed results) | ✅ | ❌ | ❌ | ❌ |\n| List models | ✅ | ✅ | ✅ | ❌ |\n| `response_format: json_object` | ✅ | ✅ | ❌ | ✅ |\n| `response_format: json_schema` (strict) | ✅ | ❌ | ❌ | ✅ |\n| Typed structured-output helpers (generics) | ✅ | ❌ | ❌ | partial |\n| Multimodal content parts (file / image / document URL) | ✅ | ❌ | ❌ | ❌ |\n| Built-in retries (429 / 5xx, backoff) | ✅ | ✅ | ❌ | ❌ |\n| Typed API error (`errors.As`) | ✅ | partial | partial | ✅ |\n\n### What `mistralai-go` does that the others do not\n\n- **OCR** (`mistral-ocr-latest`) with the upload→OCR→cleanup flow handled for you, plus **document annotation** (`json_schema`-driven structured extraction) — no other client implements the OCR endpoint.\n- A first-class **Files API** (`UploadFile`, `ListFiles` with pagination/filters, `DeleteFile`, `DownloadFile`).\n- The **Batch API** with an ergonomic typed contract: build input from `ChatCompletionRequest`/OCR/arbitrary bodies (`UploadBatchInput`), create/poll/cancel jobs (`WaitForBatchJob`), and parse results straight into `ChatCompletionResponse`/`OCRResponse` (`ParseBatchResults[T]`) — no hand-rolled JSONL.\n- Strict **`json_schema`** structured output with generic helpers (`OCRStructured[T]`, `ChatStructured[T]`, `DocumentAnnotationInto[T]`).\n- **Multimodal** message parts (`FilePart`, `ImageURLPart`, `DocumentURLPart`) for vision/document chat.\n\n### What `mistralai-go` does NOT do (yet)\n\nIf you need any of the following, one of the clients above will serve you better today:\n\n- **Streaming responses** — `mistralai-go` is fully synchronous (blocks until the complete JSON body returns). All three other clients support streamed chat. The OCR-first design assumes a single blocking call.\n- **FIM / code completion** (Codestral) — available in `gage-technologies`.\n- **Moderation and classification** — available only in `onkyou/go-mistral`.\n- **Agents and fine-tuning** — not implemented by any of these clients, including this one.\n\nIn short: choose `mistralai-go` for **OCR, document/file workflows, tool calling, and strict structured output**; reach for `gage-technologies/mistral-go` for streaming and FIM, and `onkyou/go-mistral` if you specifically need moderation/classification.\n\n## Testing\n\n```bash\ngo test ./...\n```\n\n### Live OCR test\n\n```bash\nMISTRAL_API_KEY=... go test -tags=mistral_test ./...\n```\n\n## License\n\nSee repository for license terms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaatinga%2Fmistralai-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaatinga%2Fmistralai-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaatinga%2Fmistralai-go/lists"}