9 Commits
v1.2.0 ... main

Author SHA1 Message Date
fc4bc249b6 docs: refocus README on agentic stack
Some checks failed
Watch Mistral OpenAPI Spec / check-spec (push) Has been cancelled
Lead with workflows, conversations, and connectors — the differentiated
surface no other Go SDK covers — and acknowledge that the OpenAI-wire-
compatible /v1/chat/completions endpoint is the easier path for plain
chat use cases.

Reorders sections so the workflow-execute-with-connector-bindings
example is first, conversations second, chat completions third (and
explicitly signposted as 'when that's all you need'). API coverage
table moved below configuration and error handling — it's reference,
not a hook.
2026-04-28 13:36:27 +02:00
8d1c839093 feat: sync to upstream OpenAPI v1.0.0 / Python SDK v2.4.3
Group A — gap fills:
- restore Client.GetWorkflowWorkerInfo (regression from v1.3.0;
  /v1/workflows/workers/whoami is still in the spec and is needed by
  callers running custom workers)
- add Client.GetChatCompletionFields, GetChatCompletionFieldOptions,
  GetChatCompletionFieldOptionsCounts (previously-missing observability
  fields API)

Group B — Python SDK v2.3.0..v2.4.3 sync:
- workflow.EncodedPayloadOption typed enum (offloaded / encrypted /
  encrypted-partial); replaces []string on NetworkEncodedInput.EncodingOptions.
  Wire-compatible refinement; source-incompatible for callers that built the
  slice as []string literals.
- workflow-connector integration: ConnectorSlot, ConnectorBindings,
  ConnectorExtensions, WorkflowExtensions, BuildConnectorExtensions(...)
  helper, ConnectorAuthTaskState, ConnectorAuthStatus constants.
  New Extensions map[string]any field on workflow.ExecutionRequest.
- HITL confirmation constants: conversation.Confirmation enum
  (ConfirmationAllow/Deny) and ConfirmationStatusPending/Allowed/Denied
  alongside the pre-existing ToolCallConfirmation type and
  tool_confirmations field.

No-op verification:
- ChatCompletionChoice.message remains singular per spec v1.0.0;
  Python's 'messages[]' rename was internal SDK shape, not wire format.

Tests: 297 (was 284), all green. go vet clean.
2026-04-28 13:04:04 +02:00
c5bb663bc7 chore: sync openapi spec to upstream v1.0.0; fix watcher
Upstream OpenAPI spec moved from v0.1.104 (7c0bb6af) to v1.0.0 (ff8a7389).
Only delta is removal of OCR confidence-score fields/types, which the SDK
never wrapped — no code changes required.

The watcher previously tried to commit hash/spec updates to main, but the
gitea→github mirror reverts them on every sync, leaving issue #1 with
stale hashes across multiple upstream releases. Watcher now skips the
push and instead refreshes the open tracking issue's body on each run,
posting a comment when upstream moves again while the issue is still open.
2026-04-28 12:37:56 +02:00
fc61bc42ad docs: update upstream reference to OpenAPI spec as primary source 2026-04-10 01:52:16 +02:00
9b7488183d ci: bump actions/checkout to v5 for Node.js 24 compat 2026-04-10 01:48:34 +02:00
78f7c745a7 ci: add OpenAPI spec change watcher workflow
Monitors upstream Mistral OpenAPI spec daily, opens a GitHub issue
with a unified diff when changes are detected. Includes curl failure
handling and explicit workflow permissions.
2026-04-10 01:45:39 +02:00
c028dfb0ed feat!: sync with Python SDK v2.3.0 — workflow registration model + remove workers
Add CodeDefinition, SignalDefinition, QueryDefinition, UpdateDefinition
types for workflow interface metadata. Update Registration struct with
DeploymentID, Definition, and CompatibleWithChatAssistant fields.
Deprecate TaskQueue in favor of DeploymentID.

BREAKING CHANGE: Remove GetWorkflowWorkerInfo and workflow.WorkerInfo —
the /v1/workflows/workers/whoami endpoint was removed upstream.
2026-04-03 18:53:15 +02:00
214fd02b3b docs: add v1.2.1 to upstream version table 2026-04-03 12:02:19 +02:00
3167966b98 chore: move module path to github.com/VikingOwl91/mistral-go-sdk
Public discoverability on pkg.go.dev. Also fixes stream tool call
test fixture to match real Mistral API responses (finish_reason, usage).
2026-04-03 12:01:11 +02:00
84 changed files with 20837 additions and 248 deletions

132
.github/workflows/watch-openapi.yml vendored Normal file
View File

@@ -0,0 +1,132 @@
name: Watch Mistral OpenAPI Spec
on:
schedule:
# Runs daily at 06:00 UTC
- cron: "0 6 * * *"
workflow_dispatch: # manual trigger for testing
permissions:
contents: read
issues: write
jobs:
check-spec:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Fetch and compare spec
id: check
run: |
if ! curl --fail -sL https://raw.githubusercontent.com/mistralai/platform-docs-public/main/openapi.yaml -o new-spec.yaml; then
echo "::error::Failed to download OpenAPI spec"
exit 1
fi
NEW_HASH=$(sha256sum new-spec.yaml | cut -d' ' -f1)
if [ -f .openapi-hash ]; then
OLD_HASH=$(cat .openapi-hash)
else
OLD_HASH="none"
fi
echo "old=$OLD_HASH" >> "$GITHUB_OUTPUT"
echo "new=$NEW_HASH" >> "$GITHUB_OUTPUT"
if [ "$NEW_HASH" != "$OLD_HASH" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
# Diff against the in-tree baseline (.openapi-spec.yaml).
# Maintainer commits a fresh baseline when addressing the issue.
if [ -f .openapi-spec.yaml ]; then
diff -u .openapi-spec.yaml new-spec.yaml > /tmp/spec-diff.txt || true
else
echo "No baseline .openapi-spec.yaml in repo - commit one to enable diffs." > /tmp/spec-diff.txt
fi
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
- name: Open or refresh tracking issue
if: steps.check.outputs.changed == 'true'
uses: actions/github-script@v7
env:
OLD_HASH: ${{ steps.check.outputs.old }}
NEW_HASH: ${{ steps.check.outputs.new }}
with:
script: |
const fs = require('fs');
let diff = fs.readFileSync('/tmp/spec-diff.txt', 'utf8');
// Truncate if too long for issue body (GitHub issue body limit is 65536 chars)
if (diff.length > 50000) {
diff = diff.substring(0, 50000) + '\n\n... (truncated - view full spec for details)';
}
const oldHash = process.env.OLD_HASH;
const newHash = process.env.NEW_HASH;
const body =
`The upstream OpenAPI spec has changed and the SDK is out of sync.\n\n` +
`**Stored hash (.openapi-hash):** \`${oldHash}\`\n` +
`**Current upstream hash:** \`${newHash}\`\n` +
`_Last refreshed: ${new Date().toISOString()}_\n\n` +
`[View upstream spec](https://github.com/mistralai/platform-docs-public/blob/main/openapi.yaml)\n\n` +
`### Diff vs in-tree baseline\n\`\`\`diff\n${diff}\n\`\`\`\n\n` +
`### TODO\n` +
`- [ ] Review spec changes\n` +
`- [ ] Update SDK types if needed\n` +
`- [ ] Run tests\n` +
`- [ ] Bump \`.openapi-hash\` and refresh \`.openapi-spec.yaml\` in same commit\n` +
`- [ ] Close this issue\n\n` +
`<sub>This issue body is rewritten by the watcher each run, so the diff and hashes always reflect the latest upstream state.</sub>`;
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'openapi-update',
state: 'open'
});
if (issues.data.length === 0) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Mistral OpenAPI spec has changed',
body,
labels: ['openapi-update']
});
return;
}
// Refresh the existing open issue so the diff/hashes never go stale.
const issue = issues.data[0];
// Detect whether upstream moved *again* since the last refresh by
// parsing the previous "Current upstream hash" out of the issue body.
const marker = /\*\*Current upstream hash:\*\* `([a-f0-9]{64})`/;
const prev = (issue.body || '').match(marker);
const movedAgain = prev && prev[1] !== newHash;
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body
});
if (movedAgain) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body:
`Upstream spec moved again since this issue was last refreshed.\n\n` +
`Previous upstream hash: \`${prev[1]}\`\n` +
`New upstream hash: \`${newHash}\`\n\n` +
`Issue body has been updated to the latest diff.`
});
}

1
.openapi-hash Normal file
View File

@@ -0,0 +1 @@
ff8a7389b7a4e61145561361537aae37c49f7e2dcf7c4f79f41e80a30b484cc3

19660
.openapi-spec.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,118 @@
## v1.4.0 — 2026-04-28
Spec/SDK alignment pass after upstream OpenAPI moved to v1.0.0 and
Python SDK shipped v2.3.0..v2.4.3. RAG ingestion-pipeline beta surface
(Python v2.4.3) intentionally deferred until the dust settles upstream.
### Added
- **`Client.GetWorkflowWorkerInfo`** — restores the
`GET /v1/workflows/workers/whoami` endpoint that was removed in v1.3.0.
The endpoint is still in the spec and is needed by callers running
custom workers that connect their own scheduler.
(`workflow.WorkerInfo` type.)
- **Observability fields API** — three GETs missing since the
observability surface was first added:
- `Client.GetChatCompletionFields` (`/v1/observability/chat-completion-fields`)
- `Client.GetChatCompletionFieldOptions` (`…/{field}/options?operator=…`)
- `Client.GetChatCompletionFieldOptionsCounts` (`…/{field}/options-counts`)
- new types: `observability.BaseFieldDefinition`, `FieldGroup`,
`ChatCompletionFields`, `ChatCompletionFieldOptions`,
`FieldOptionCountsRequest`, `FieldOptionCounts`, `FieldOptionCountItem`,
plus `FieldType` and `FieldOperator` typed enums.
- **Workflow payload encoding constants** — `workflow.EncodedPayloadOption`
with `EncodedPayloadOffloaded`, `EncodedPayloadEncrypted`,
`EncodedPayloadEncryptedPartial`. Wire-compatible refinement of the
pre-existing `[]string` field on `NetworkEncodedInput`.
(Mirrors Python SDK v2.4.0.)
- **Workflow ↔ connector integration** (Python SDK v2.4.2):
- `workflow.ConnectorSlot`, `ConnectorBindings`, `ConnectorExtensions`,
`WorkflowExtensions` types.
- `workflow.BuildConnectorExtensions(slots …)` helper that produces the
nested map expected at `ExecutionRequest.Extensions["mistralai"]`.
- `workflow.ConnectorAuthTaskState` + `ConnectorAuthStatus` constants
for parsing payloads emitted by the `connector-auth` custom task event.
- New `Extensions map[string]any` field on `workflow.ExecutionRequest`.
- **HITL (human-in-the-loop) confirmation constants** — typed values
alongside the pre-existing `conversation.ToolCallConfirmation` and
`tool_confirmations` field:
- `conversation.Confirmation` with `ConfirmationAllow` / `ConfirmationDeny`
for the reply side.
- `ConfirmationStatusPending` / `ConfirmationStatusAllowed` /
`ConfirmationStatusDenied` for `FunctionCallEvent.ConfirmationStatus`
and `FunctionCallEntry.ConfirmationStatus` (already present as
untyped strings).
### Changed
- `workflow.NetworkEncodedInput.EncodingOptions` is now
`[]EncodedPayloadOption` (string-typed alias). JSON wire format
unchanged; existing call sites that passed `[]string{"offloaded"}`
need to switch to `[]workflow.EncodedPayloadOption{workflow.EncodedPayloadOffloaded}`
or the typed constants directly.
- Tracking upstream Mistral OpenAPI spec **v1.0.0** (was v0.1.104).
Only spec delta in this window was the removal of OCR confidence-score
fields (`OCRPageObject.confidence_scores`,
`OCRRequest.confidence_scores_granularity`,
`OCRTableObject.word_confidence_scores`, plus the `OCRConfidenceScore`
and `OCRPageConfidenceScores` schemas), none of which this SDK exposed.
### Fixed (CI)
- `watch-openapi.yml` no longer attempts to commit `.openapi-hash` /
`.openapi-spec.yaml` to `main`. The push was being silently reverted
by an upstream mirror, leaving the tracking issue stale across
multiple upstream releases. The watcher now refreshes the open
tracking issue's body on each run so the diff and hashes always
reflect the current upstream state, and posts a comment when the
spec moves again while the issue is still open.
## v1.3.0 — 2026-04-03
Upstream sync with Python SDK v2.3.0. Updates workflow registration model
to reflect the managed deployment architecture and removes the deprecated
workers endpoint.
### Added
- **`workflow.CodeDefinition`** — workflow interface metadata type with
input/output schemas, signal/query/update handler definitions,
determinism flag, and execution timeout.
- **`workflow.SignalDefinition`**, **`QueryDefinition`**,
**`UpdateDefinition`** — handler descriptor types.
- **`Registration.Definition`** — code definition field on workflow
registrations.
- **`Registration.DeploymentID`** — replaces the worker/task-queue model
with managed deployment references.
- **`Registration.CompatibleWithChatAssistant`** — flag for chat assistant
compatibility.
### Deprecated
- **`Registration.TaskQueue`** — use `DeploymentID` instead. Will be
removed in a future release.
### Removed (breaking)
- **`GetWorkflowWorkerInfo`** — the `/v1/workflows/workers/whoami` endpoint
was removed upstream.
- **`workflow.WorkerInfo`** — type no longer exists in the API.
## v1.2.1 — 2026-04-03
Move module path to `github.com/VikingOwl91/mistral-go-sdk` for public
discoverability on pkg.go.dev.
### Changed
- Module path changed from `somegit.dev/vikingowl/mistral-go-sdk` to
`github.com/VikingOwl91/mistral-go-sdk`.
### Fixed
- `TestChatCompleteStream_WithToolCalls` fixture now includes `finish_reason`
and `usage` to match real Mistral API responses.
## v1.2.0 — 2026-04-02
Upstream sync with Python SDK v2.2.0. Adds Workflows API and DeleteBatchJob.

View File

@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project
Idiomatic Go SDK for the Mistral AI API. Module path: `somegit.dev/vikingowl/mistral-go-sdk`. Requires Go 1.26+. Zero external dependencies (stdlib only). Tracks the upstream [Mistral Python SDK](https://github.com/mistralai/client-python) as reference for API surface and type definitions.
Idiomatic Go SDK for the Mistral AI API. Module path: `github.com/VikingOwl91/mistral-go-sdk`. Requires Go 1.26+. Zero external dependencies (stdlib only). Tracks the [official Mistral OpenAPI spec](https://github.com/mistralai/platform-docs-public/blob/main/openapi.yaml) as primary reference for API surface and type definitions, with the [Mistral Python SDK](https://github.com/mistralai/client-python) as secondary reference for implementation patterns. A daily GitHub Action monitors the OpenAPI spec for changes.
## Repository layout

278
README.md
View File

@@ -1,72 +1,93 @@
# mistral-go-sdk
The most complete Go client for the [Mistral AI API](https://docs.mistral.ai/).
Go SDK for Mistral's agentic stack — Workflows, Conversations, Connectors — with full coverage of the rest of the Mistral AI API.
<!-- Badges -->
[![Go Reference](https://pkg.go.dev/badge/somegit.dev/vikingowl/mistral-go-sdk.svg)](https://pkg.go.dev/somegit.dev/vikingowl/mistral-go-sdk)
[![Go Reference](https://pkg.go.dev/badge/github.com/VikingOwl91/mistral-go-sdk.svg)](https://pkg.go.dev/github.com/VikingOwl91/mistral-go-sdk)
![Go Version](https://img.shields.io/badge/go-1.26-blue)
![License](https://img.shields.io/badge/license-MIT-green)
## Why This SDK?
## What this is for
**Zero dependencies.** The entire SDK — including tests — uses only the Go standard library. No `go.sum`, no transitive dependency tree to audit, no version conflicts, no supply chain risk.
Mistral's `/v1/chat/completions` endpoint is OpenAI-wire-compatible, so if all you need is plain chat or tool calling, pointing any OpenAI Go client at `https://api.mistral.ai/v1` already works. **This SDK exists for the rest of Mistral's surface** — the parts no other Go client covers:
**Full API coverage.** 166 methods across every Mistral endpoint — including Workflows, Connectors, Audio Speech/Voices, Conversations, Agents CRUD, Libraries, OCR, Observability, Fine-tuning, and Batch Jobs. No other Go SDK covers Workflows, Conversations, Connectors, or Observability.
- **Workflows** — durable, long-running executions with signals, queries, updates, and full event streaming.
- **Conversations API** — server-stored multi-turn state with streaming events, agent handoffs, and human-in-the-loop tool confirmations.
- **Connectors / MCP** — manage MCP connectors and bind them to workflow executions.
- **Agents CRUD** — create, version, and alias agents (not just `agents/completions`).
- **Libraries / Documents** — RAG document stores with reprocess, status, and signed-URL retrieval.
- **OCR, Audio (transcription + TTS + voices), Fine-tuning, Batch, Observability, Moderation, Classification.**
**Typed streaming.** A generic pull-based `Stream[T]` iterator — no channels, no goroutines, no leaks. Just `Next()` / `Current()` / `Err()` / `Close()`.
If your use case is "Go program calls Mistral and gets a response back," any OpenAI-compatible client is the easier path. If you need agentic workflows or stateful conversations from Go, this is the only option.
**Forward-compatible.** Unknown types (`UnknownEntry`, `UnknownEvent`, `UnknownMessage`, `UnknownChunk`, `UnknownAgentTool`, workflow `UnknownEvent`) capture raw JSON instead of returning errors. When Mistral ships a new message role or event type, your code keeps running — it doesn't panic.
## Why this SDK
**Hand-written, not generated.** Idiomatic Go with sealed interfaces, discriminated unions, and functional options — not a Speakeasy/OpenAPI auto-gen dump with `any` everywhere.
**Test-driven.** 284 tests with race detection clean. Every endpoint tested against mock servers; integration tests against the real API.
- **Zero dependencies.** Stdlib-only. No `go.sum`, no transitive tree, no supply chain.
- **Hand-written, not generated.** Idiomatic Go with sealed interfaces, discriminated unions, and functional options — not a Speakeasy/OpenAPI dump with `any` everywhere.
- **Forward-compatible types.** `UnknownEntry`, `UnknownEvent`, `UnknownMessage`, `UnknownChunk`, `UnknownAgentTool` capture raw JSON instead of returning errors — when Mistral ships a new event type, your code keeps running.
- **Typed streaming.** Generic pull-based `Stream[T]` iterator — no channels, no goroutines, no leaks. Just `Next()` / `Current()` / `Err()` / `Close()`.
- **Test-driven.** 297 tests, race-clean. Every endpoint has a mock-server unit test; integration tests run against the real API behind a build tag.
## Install
```sh
go get somegit.dev/vikingowl/mistral-go-sdk
go get github.com/VikingOwl91/mistral-go-sdk
```
## Quick Start
### Chat Completion
### Execute a workflow with connector bindings
The most differentiated thing this SDK does. Run a registered workflow, hand it the MCP connectors it needs, and block until completion:
```go
package main
import (
"context"
"encoding/json"
"fmt"
"log"
mistral "somegit.dev/vikingowl/mistral-go-sdk"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
mistral "github.com/VikingOwl91/mistral-go-sdk"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func main() {
client := mistral.NewClient("sk-your-api-key")
resp, err := client.ChatComplete(context.Background(), &chat.CompletionRequest{
Model: "mistral-small-latest",
Messages: []chat.Message{
&chat.UserMessage{Content: chat.TextContent("What is the capital of France?")},
creds := "work-account"
resp, err := client.ExecuteWorkflowAndWait(context.Background(), "my-workflow", &workflow.ExecutionRequest{
Input: map[string]any{
"topic": "Q3 earnings",
},
Extensions: workflow.BuildConnectorExtensions(
workflow.ConnectorSlot{ConnectorName: "gmail"},
workflow.ConnectorSlot{ConnectorName: "notion", CredentialsName: &creds},
),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Choices[0].Message.Content)
fmt.Printf("execution %s finished with status %s\n", resp.ExecutionID, resp.Status)
if resp.Status == workflow.ExecutionCompleted {
result, _ := json.MarshalIndent(resp.Result, "", " ")
fmt.Println(string(result))
}
}
```
### Streaming
### Stream a conversation with tool-call confirmation
Conversations keep server-side state across turns. Stream events, accept or deny pending tool calls, and continue:
```go
stream, err := client.ChatCompleteStream(ctx, &chat.CompletionRequest{
Model: "mistral-small-latest",
Messages: []chat.Message{
&chat.UserMessage{Content: chat.TextContent("Tell me a joke.")},
},
import "github.com/VikingOwl91/mistral-go-sdk/conversation"
stream, err := client.StartConversationStream(ctx, &conversation.StartRequest{
AgentID: "ag-your-agent-id",
Inputs: conversation.TextInputs("Summarize today's incident review and email it to the on-call channel."),
})
if err != nil {
log.Fatal(err)
@@ -74,9 +95,20 @@ if err != nil {
defer stream.Close()
for stream.Next() {
chunk := stream.Current()
if len(chunk.Choices) > 0 {
fmt.Print(chunk.Choices[0].Delta.Content)
event := stream.Current()
switch e := event.(type) {
case *conversation.FunctionCallEvent:
if e.ConfirmationStatus != nil && *e.ConfirmationStatus == conversation.ConfirmationStatusPending {
// Hand the user a confirmation prompt; reply on the next AppendConversation.
confirmations := []conversation.ToolCallConfirmation{
{ToolCallID: e.ToolCallID, Confirmation: string(conversation.ConfirmationAllow)},
}
_, _ = client.AppendConversation(ctx, /* conversationID */ "conv-...", &conversation.AppendRequest{
ToolConfirmations: confirmations,
})
}
case *conversation.MessageOutputEntry:
// assistant tokens
}
}
if err := stream.Err(); err != nil {
@@ -84,115 +116,24 @@ if err := stream.Err(); err != nil {
}
```
### Tool Calling
### Chat completion (when that's all you need)
```go
import "github.com/VikingOwl91/mistral-go-sdk/chat"
resp, err := client.ChatComplete(ctx, &chat.CompletionRequest{
Model: "mistral-small-latest",
Messages: []chat.Message{
&chat.UserMessage{Content: chat.TextContent("What's the weather in Paris?")},
&chat.UserMessage{Content: chat.TextContent("What is the capital of France?")},
},
Tools: []chat.Tool{{
Type: "function",
Function: chat.Function{
Name: "get_weather",
Description: "Get weather for a city",
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"city": map[string]any{"type": "string"},
},
"required": []string{"city"},
},
},
}},
})
```
### Conversations
```go
import "somegit.dev/vikingowl/mistral-go-sdk/conversation"
resp, err := client.StartConversation(ctx, &conversation.StartRequest{
AgentID: "ag-your-agent-id",
Inputs: conversation.TextInputs("Hello, agent!"),
})
// Stream events
stream, err := client.AppendConversationStream(ctx, resp.ConversationID, &conversation.AppendRequest{
Inputs: conversation.TextInputs("Follow-up question"),
})
defer stream.Close()
for stream.Next() {
event := stream.Current()
// handle typed events
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Choices[0].Message.Content)
```
## API Coverage
166 public methods on `Client`, grouped by domain:
| Domain | Methods |
|--------|---------|
| **Chat** | `ChatComplete`, `ChatCompleteStream` |
| **FIM** | `FIMComplete`, `FIMCompleteStream` |
| **Agents (completions)** | `AgentsComplete`, `AgentsCompleteStream` |
| **Agents (CRUD)** | `CreateAgent`, `ListAgents`, `GetAgent`, `UpdateAgent`, `DeleteAgent`, `UpdateAgentVersion`, `ListAgentVersions`, `GetAgentVersion`, `SetAgentAlias`, `ListAgentAliases`, `DeleteAgentAlias` |
| **Connectors** | `CreateConnector`, `ListConnectors`, `GetConnector`, `UpdateConnector`, `DeleteConnector`, `GetConnectorAuthURL`, `ListConnectorTools`, `CallConnectorTool` |
| **Conversations** | `StartConversation`, `StartConversationStream`, `AppendConversation`, `AppendConversationStream`, `RestartConversation`, `RestartConversationStream`, `GetConversation`, `ListConversations`, `DeleteConversation`, `GetConversationHistory`, `GetConversationMessages` |
| **Models** | `ListModels`, `GetModel`, `DeleteModel` |
| **Files** | `UploadFile`, `ListFiles`, `GetFile`, `DeleteFile`, `GetFileContent`, `GetFileURL` |
| **Embeddings** | `CreateEmbeddings` |
| **Fine-tuning** | `CreateFineTuningJob`, `ListFineTuningJobs`, `GetFineTuningJob`, `CancelFineTuningJob`, `StartFineTuningJob`, `UpdateFineTunedModel`, `ArchiveFineTunedModel`, `UnarchiveFineTunedModel` |
| **Batch** | `CreateBatchJob`, `ListBatchJobs`, `GetBatchJob`, `CancelBatchJob`, `DeleteBatchJob` |
| **OCR** | `OCR` |
| **Audio (transcription)** | `Transcribe`, `TranscribeStream` |
| **Audio (speech)** | `Speech`, `SpeechStream` |
| **Audio (voices)** | `ListVoices`, `CreateVoice`, `GetVoice`, `UpdateVoice`, `DeleteVoice`, `GetVoiceSampleAudio` |
| **Libraries** | `CreateLibrary`, `ListLibraries`, `GetLibrary`, `UpdateLibrary`, `DeleteLibrary`, `UploadDocument`, `ListDocuments`, `GetDocument`, `UpdateDocument`, `DeleteDocument`, `GetDocumentTextContent`, `GetDocumentStatus`, `GetDocumentSignedURL`, `GetDocumentExtractedTextSignedURL`, `ReprocessDocument`, `ListLibrarySharing`, `ShareLibrary`, `UnshareLibrary` |
| **Moderation** | `Moderate`, `ModerateChat` |
| **Classification** | `Classify`, `ClassifyChat` |
| **Observability (campaigns)** | `CreateCampaign`, `ListCampaigns`, `GetCampaign`, `DeleteCampaign`, `GetCampaignStatus`, `ListCampaignEvents` |
| **Observability (events)** | `SearchChatCompletionEvents`, `SearchChatCompletionEventIDs`, `GetChatCompletionEvent`, `GetSimilarChatCompletionEvents`, `JudgeChatCompletionEvent` |
| **Observability (judges)** | `CreateJudge`, `ListJudges`, `GetJudge`, `UpdateJudge`, `DeleteJudge`, `JudgeConversation` |
| **Observability (datasets)** | `CreateDataset`, `ListDatasets`, `GetDataset`, `UpdateDataset`, `DeleteDataset`, `ExportDatasetToJSONL`, `ListDatasetRecords`, `CreateDatasetRecord`, `GetDatasetRecord`, `UpdateDatasetRecordPayload`, `UpdateDatasetRecordProperties`, `DeleteDatasetRecord`, `BulkDeleteDatasetRecords`, `JudgeDatasetRecord`, `ImportDatasetFromCampaign`, `ImportDatasetFromExplorer`, `ImportDatasetFromFile`, `ImportDatasetFromPlayground`, `ImportDatasetFromDataset`, `ListDatasetTasks`, `GetDatasetTask` |
| **Workflows (CRUD)** | `ListWorkflows`, `GetWorkflow`, `UpdateWorkflow`, `ArchiveWorkflow`, `UnarchiveWorkflow`, `ExecuteWorkflow`, `ExecuteWorkflowAndWait` |
| **Workflows (registrations)** | `ListWorkflowRegistrations`, `GetWorkflowRegistration`, `ExecuteWorkflowRegistration` |
| **Workflows (executions)** | `GetWorkflowExecution`, `GetWorkflowExecutionHistory`, `StreamWorkflowExecution`, `SignalWorkflowExecution`, `QueryWorkflowExecution`, `UpdateWorkflowExecution`, `TerminateWorkflowExecution`, `CancelWorkflowExecution`, `ResetWorkflowExecution`, `BatchCancelWorkflowExecutions`, `BatchTerminateWorkflowExecutions` |
| **Workflows (trace)** | `GetWorkflowExecutionTraceOTel`, `GetWorkflowExecutionTraceSummary`, `GetWorkflowExecutionTraceEvents` |
| **Workflows (events)** | `StreamWorkflowEvents`, `ListWorkflowEvents` |
| **Workflows (deployments)** | `ListWorkflowDeployments`, `GetWorkflowDeployment` |
| **Workflows (metrics)** | `GetWorkflowMetrics` |
| **Workflows (runs)** | `ListWorkflowRuns`, `GetWorkflowRun`, `GetWorkflowRunHistory` |
| **Workflows (schedules)** | `ListWorkflowSchedules`, `ScheduleWorkflow`, `UnscheduleWorkflow` |
| **Workflows (workers)** | `GetWorkflowWorkerInfo` |
## Comparison
There is no official Go SDK from Mistral AI (only Python and TypeScript). The main community options:
| Feature | mistral-go-sdk | [Gage-Technologies](https://github.com/Gage-Technologies/mistral-go) | [robertjkeck2](https://github.com/robertjkeck2/mistral-go) | [AuxData-ai](https://github.com/AuxData-ai/mistral-go) |
|---------|:-:|:-:|:-:|:-:|
| Chat / Streaming | Yes | Yes | Yes | Yes |
| FIM | Yes | Yes | No | Yes |
| Embeddings | Yes | Yes | Yes | Yes |
| Tool calling | Yes | No | No | No |
| Agents (completions + CRUD) | Yes | No | No | No |
| Connectors (MCP) | Yes | No | No | No |
| Conversations API | Yes | No | No | No |
| Libraries / Documents | Yes | No | No | No |
| Fine-tuning / Batch | Yes | No | No | No |
| OCR | Yes | No | No | Yes |
| Audio (transcription + TTS + voices) | Yes | No | No | No |
| Workflows API | Yes | No | No | No |
| Observability (beta) | Yes | No | No | No |
| Moderation / Classification | Yes | No | No | No |
| Vision (multimodal) | Yes | No | No | Yes |
| Zero dependencies | Yes | test-only (testify) | test-only (testify) | test-only (testify) |
| Forward-compatible types | Yes | No | No | No |
| Last updated | 2026 | Jun 2024 | Jan 2024 | ~2025 (fork of Gage) |
If this is your whole use case, the OpenAI-wire-compatible endpoint is also a valid path — point any `openai-go` client at `https://api.mistral.ai/v1` and it works. The rest of this SDK is for what the OpenAI shape doesn't cover.
## Configuration
@@ -234,16 +175,85 @@ if err != nil {
}
```
## API Coverage
169 public methods on `Client`, grouped by domain:
| Domain | Methods |
|--------|---------|
| **Chat** | `ChatComplete`, `ChatCompleteStream` |
| **FIM** | `FIMComplete`, `FIMCompleteStream` |
| **Agents (completions)** | `AgentsComplete`, `AgentsCompleteStream` |
| **Agents (CRUD)** | `CreateAgent`, `ListAgents`, `GetAgent`, `UpdateAgent`, `DeleteAgent`, `UpdateAgentVersion`, `ListAgentVersions`, `GetAgentVersion`, `SetAgentAlias`, `ListAgentAliases`, `DeleteAgentAlias` |
| **Connectors** | `CreateConnector`, `ListConnectors`, `GetConnector`, `UpdateConnector`, `DeleteConnector`, `GetConnectorAuthURL`, `ListConnectorTools`, `CallConnectorTool` |
| **Conversations** | `StartConversation`, `StartConversationStream`, `AppendConversation`, `AppendConversationStream`, `RestartConversation`, `RestartConversationStream`, `GetConversation`, `ListConversations`, `DeleteConversation`, `GetConversationHistory`, `GetConversationMessages` |
| **Models** | `ListModels`, `GetModel`, `DeleteModel` |
| **Files** | `UploadFile`, `ListFiles`, `GetFile`, `DeleteFile`, `GetFileContent`, `GetFileURL` |
| **Embeddings** | `CreateEmbeddings` |
| **Fine-tuning** | `CreateFineTuningJob`, `ListFineTuningJobs`, `GetFineTuningJob`, `CancelFineTuningJob`, `StartFineTuningJob`, `UpdateFineTunedModel`, `ArchiveFineTunedModel`, `UnarchiveFineTunedModel` |
| **Batch** | `CreateBatchJob`, `ListBatchJobs`, `GetBatchJob`, `CancelBatchJob`, `DeleteBatchJob` |
| **OCR** | `OCR` |
| **Audio (transcription)** | `Transcribe`, `TranscribeStream` |
| **Audio (speech)** | `Speech`, `SpeechStream` |
| **Audio (voices)** | `ListVoices`, `CreateVoice`, `GetVoice`, `UpdateVoice`, `DeleteVoice`, `GetVoiceSampleAudio` |
| **Libraries** | `CreateLibrary`, `ListLibraries`, `GetLibrary`, `UpdateLibrary`, `DeleteLibrary`, `UploadDocument`, `ListDocuments`, `GetDocument`, `UpdateDocument`, `DeleteDocument`, `GetDocumentTextContent`, `GetDocumentStatus`, `GetDocumentSignedURL`, `GetDocumentExtractedTextSignedURL`, `ReprocessDocument`, `ListLibrarySharing`, `ShareLibrary`, `UnshareLibrary` |
| **Moderation** | `Moderate`, `ModerateChat` |
| **Classification** | `Classify`, `ClassifyChat` |
| **Observability (campaigns)** | `CreateCampaign`, `ListCampaigns`, `GetCampaign`, `DeleteCampaign`, `GetCampaignStatus`, `ListCampaignEvents` |
| **Observability (events)** | `SearchChatCompletionEvents`, `SearchChatCompletionEventIDs`, `GetChatCompletionEvent`, `GetSimilarChatCompletionEvents`, `JudgeChatCompletionEvent` |
| **Observability (fields)** | `GetChatCompletionFields`, `GetChatCompletionFieldOptions`, `GetChatCompletionFieldOptionsCounts` |
| **Observability (judges)** | `CreateJudge`, `ListJudges`, `GetJudge`, `UpdateJudge`, `DeleteJudge`, `JudgeConversation` |
| **Observability (datasets)** | `CreateDataset`, `ListDatasets`, `GetDataset`, `UpdateDataset`, `DeleteDataset`, `ExportDatasetToJSONL`, `ListDatasetRecords`, `CreateDatasetRecord`, `GetDatasetRecord`, `UpdateDatasetRecordPayload`, `UpdateDatasetRecordProperties`, `DeleteDatasetRecord`, `BulkDeleteDatasetRecords`, `JudgeDatasetRecord`, `ImportDatasetFromCampaign`, `ImportDatasetFromExplorer`, `ImportDatasetFromFile`, `ImportDatasetFromPlayground`, `ImportDatasetFromDataset`, `ListDatasetTasks`, `GetDatasetTask` |
| **Workflows (CRUD)** | `ListWorkflows`, `GetWorkflow`, `UpdateWorkflow`, `ArchiveWorkflow`, `UnarchiveWorkflow`, `ExecuteWorkflow`, `ExecuteWorkflowAndWait` |
| **Workflows (registrations)** | `ListWorkflowRegistrations`, `GetWorkflowRegistration`, `ExecuteWorkflowRegistration` |
| **Workflows (executions)** | `GetWorkflowExecution`, `GetWorkflowExecutionHistory`, `StreamWorkflowExecution`, `SignalWorkflowExecution`, `QueryWorkflowExecution`, `UpdateWorkflowExecution`, `TerminateWorkflowExecution`, `CancelWorkflowExecution`, `ResetWorkflowExecution`, `BatchCancelWorkflowExecutions`, `BatchTerminateWorkflowExecutions` |
| **Workflows (trace)** | `GetWorkflowExecutionTraceOTel`, `GetWorkflowExecutionTraceSummary`, `GetWorkflowExecutionTraceEvents` |
| **Workflows (events)** | `StreamWorkflowEvents`, `ListWorkflowEvents` |
| **Workflows (deployments)** | `ListWorkflowDeployments`, `GetWorkflowDeployment` |
| **Workflows (metrics)** | `GetWorkflowMetrics` |
| **Workflows (runs)** | `ListWorkflowRuns`, `GetWorkflowRun`, `GetWorkflowRunHistory` |
| **Workflows (schedules)** | `ListWorkflowSchedules`, `ScheduleWorkflow`, `UnscheduleWorkflow` |
| **Workflows (workers)** | `GetWorkflowWorkerInfo` |
## Comparison
There is no official Go SDK from Mistral AI (only Python and TypeScript). The main community options:
| Feature | mistral-go-sdk | [Gage-Technologies](https://github.com/Gage-Technologies/mistral-go) | [robertjkeck2](https://github.com/robertjkeck2/mistral-go) | [AuxData-ai](https://github.com/AuxData-ai/mistral-go) |
|---------|:-:|:-:|:-:|:-:|
| Chat / Streaming | Yes | Yes | Yes | Yes |
| FIM | Yes | Yes | No | Yes |
| Embeddings | Yes | Yes | Yes | Yes |
| Tool calling | Yes | No | No | No |
| Agents (completions + CRUD) | Yes | No | No | No |
| Connectors (MCP) | Yes | No | No | No |
| Conversations API | Yes | No | No | No |
| Libraries / Documents | Yes | No | No | No |
| Fine-tuning / Batch | Yes | No | No | No |
| OCR | Yes | No | No | Yes |
| Audio (transcription + TTS + voices) | Yes | No | No | No |
| Workflows API | Yes | No | No | No |
| Observability (beta) | Yes | No | No | No |
| Moderation / Classification | Yes | No | No | No |
| Vision (multimodal) | Yes | No | No | Yes |
| Zero dependencies | Yes | test-only (testify) | test-only (testify) | test-only (testify) |
| Forward-compatible types | Yes | No | No | No |
| Last updated | 2026 | Jun 2024 | Jan 2024 | ~2025 (fork of Gage) |
## Upstream Reference
This SDK tracks the [official Mistral Python SDK](https://github.com/mistralai/client-python)
as its upstream reference for API surface and type definitions.
This SDK tracks the [official Mistral OpenAPI spec](https://github.com/mistralai/platform-docs-public/blob/main/openapi.yaml) as its primary reference for API surface and type definitions. A daily GitHub Action monitors the spec for changes and refreshes a tracking issue when updates are detected.
| SDK Version | Upstream Python SDK |
|-------------|---------------------|
| v1.2.0 | v2.2.0 |
| v1.1.0 | v2.1.3 |
| v1.0.0 | v2.0.4 |
The [Mistral Python SDK](https://github.com/mistralai/client-python) is used as a secondary reference for implementation patterns.
| SDK Version | Upstream Python SDK | Upstream OpenAPI |
|-------------|---------------------|------------------|
| v1.4.0 | v2.4.3 (excl. RAG ingestion-pipeline beta) | v1.0.0 |
| v1.3.0 | v2.3.0 | v0.1.104 |
| v1.2.1 | v2.2.0 | — |
| v1.2.0 | v2.2.0 | — |
| v1.1.0 | v2.1.3 | — |
| v1.0.0 | v2.0.4 | — |
## License

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// AgentTool is a sealed interface for agent tool types.

View File

@@ -3,7 +3,7 @@ package agents
import (
"encoding/json"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// CompletionRequest represents an agents completion request.

View File

@@ -3,8 +3,8 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/agents"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/agents"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// AgentsComplete sends an agents completion request.

View File

@@ -8,8 +8,8 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/agents"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/agents"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
func TestAgentsComplete_Success(t *testing.T) {

View File

@@ -6,7 +6,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/agents"
"github.com/VikingOwl91/mistral-go-sdk/agents"
)
// CreateAgent creates a new agent.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/agents"
"github.com/VikingOwl91/mistral-go-sdk/agents"
)
func TestCreateAgent_Success(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"io"
"net/http"
"somegit.dev/vikingowl/mistral-go-sdk/audio"
"github.com/VikingOwl91/mistral-go-sdk/audio"
)
// Transcribe sends an audio file for transcription.

View File

@@ -8,7 +8,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/audio"
"github.com/VikingOwl91/mistral-go-sdk/audio"
)
func TestSpeech_Success(t *testing.T) {

View File

@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/audio"
"github.com/VikingOwl91/mistral-go-sdk/audio"
)
func TestTranscribe_WithFileURL(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
"somegit.dev/vikingowl/mistral-go-sdk/batch"
"github.com/VikingOwl91/mistral-go-sdk/batch"
)
// CreateBatchJob creates a new batch inference job.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/batch"
"github.com/VikingOwl91/mistral-go-sdk/batch"
)
func TestCreateBatchJob_Success(t *testing.T) {

View File

@@ -3,7 +3,7 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// ChatComplete sends a chat completion request and returns the full response.

View File

@@ -8,7 +8,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
func TestChatComplete_Success(t *testing.T) {

View File

@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
func TestChatCompleteStream_Success(t *testing.T) {
@@ -165,6 +165,7 @@ func TestChatCompleteStream_WithToolCalls(t *testing.T) {
w.Header().Set("Content-Type", "text/event-stream")
flusher, _ := w.(http.Flusher)
toolCalls := chat.FinishReasonToolCalls
chunk := chat.CompletionChunk{
ID: "c",
Model: "m",
@@ -177,7 +178,9 @@ func TestChatCompleteStream_WithToolCalls(t *testing.T) {
Function: chat.FunctionCall{Name: "get_weather", Arguments: `{"city":"Paris"}`},
}},
},
FinishReason: &toolCalls,
}},
Usage: &chat.UsageInfo{PromptTokens: 10, CompletionTokens: 5, TotalTokens: 15},
}
data, _ := json.Marshal(chunk)
fmt.Fprintf(w, "data: %s\n\n", data)
@@ -199,10 +202,17 @@ func TestChatCompleteStream_WithToolCalls(t *testing.T) {
if !stream.Next() {
t.Fatalf("expected chunk, err: %v", stream.Err())
}
tc := stream.Current().Choices[0].Delta.ToolCalls
cur := stream.Current()
tc := cur.Choices[0].Delta.ToolCalls
if len(tc) != 1 || tc[0].Function.Name != "get_weather" {
t.Errorf("got tool calls %+v", tc)
}
if cur.Choices[0].FinishReason == nil || *cur.Choices[0].FinishReason != chat.FinishReasonToolCalls {
t.Errorf("expected finish_reason tool_calls, got %v", cur.Choices[0].FinishReason)
}
if cur.Usage == nil || cur.Usage.TotalTokens != 15 {
t.Errorf("expected usage with total_tokens=15, got %+v", cur.Usage)
}
}
func TestChatCompleteStream_APIError(t *testing.T) {

View File

@@ -1,6 +1,6 @@
package classification
import "somegit.dev/vikingowl/mistral-go-sdk/chat"
import "github.com/VikingOwl91/mistral-go-sdk/chat"
// Request represents a text classification request (/v1/classifications).
type Request struct {

View File

@@ -6,7 +6,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/connector"
"github.com/VikingOwl91/mistral-go-sdk/connector"
)
// CreateConnector registers a new MCP connector.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/connector"
"github.com/VikingOwl91/mistral-go-sdk/connector"
)
func TestCreateConnector_Success(t *testing.T) {

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// HandoffExecution controls tool call execution.
@@ -44,10 +44,30 @@ type CompletionArgs struct {
ToolChoice *chat.ToolChoiceMode `json:"tool_choice,omitempty"`
}
// Confirmation is a client decision on a pending tool call.
type Confirmation string
const (
ConfirmationAllow Confirmation = "allow"
ConfirmationDeny Confirmation = "deny"
)
// ConfirmationStatus values appear on FunctionCallEvent.ConfirmationStatus
// and FunctionCallEntry.ConfirmationStatus, reporting where in the
// human-in-the-loop flow a tool call currently sits.
const (
ConfirmationStatusPending = "pending"
ConfirmationStatusAllowed = "allowed"
ConfirmationStatusDenied = "denied"
)
// ToolCallConfirmation confirms or denies a pending tool call.
//
// Send a slice of these on AppendRequest.ToolConfirmations after receiving
// a function call event whose ConfirmationStatus is "pending".
type ToolCallConfirmation struct {
ToolCallID string `json:"tool_call_id"`
Confirmation string `json:"confirmation"` // "allow" or "deny"
Confirmation string `json:"confirmation"` // use ConfirmationAllow / ConfirmationDeny
}
// Inputs represents conversation inputs (text string or entry array).

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// Entry is a sealed interface for conversation history entries.

View File

@@ -3,7 +3,7 @@ package conversation
import (
"encoding/json"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
// StartRequest starts a new conversation.

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/conversation"
"github.com/VikingOwl91/mistral-go-sdk/conversation"
)
// StartConversation creates and starts a new conversation.

View File

@@ -8,7 +8,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/conversation"
"github.com/VikingOwl91/mistral-go-sdk/conversation"
)
func TestStartConversation_Success(t *testing.T) {

View File

@@ -1144,7 +1144,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestListWorkflows_Success(t *testing.T) {
@@ -1387,7 +1387,7 @@ import (
"strconv"
"time"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflows lists workflows.
@@ -1616,7 +1616,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestGetWorkflowExecution_Success(t *testing.T) {
@@ -1849,7 +1849,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// GetWorkflowExecution retrieves a workflow execution by ID.
@@ -2099,7 +2099,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestListWorkflowEvents_Success(t *testing.T) {
@@ -2241,7 +2241,7 @@ func TestGetWorkflowMetrics_Success(t *testing.T) {
}
```
Add `"somegit.dev/vikingowl/mistral-go-sdk/workflow"` import to `workflows_metrics_test.go`.
Add `"github.com/VikingOwl91/mistral-go-sdk/workflow"` import to `workflows_metrics_test.go`.
- [ ] **Step 2: Run tests to verify they fail**
@@ -2262,7 +2262,7 @@ import (
"strconv"
"strings"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// StreamWorkflowEvents streams workflow events via SSE.
@@ -2365,7 +2365,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflowDeployments lists workflow deployments.
@@ -2410,7 +2410,7 @@ import (
"fmt"
"net/url"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// GetWorkflowMetrics retrieves performance metrics for a workflow.
@@ -2534,7 +2534,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestScheduleWorkflow_Success(t *testing.T) {
@@ -2675,7 +2675,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflowRuns lists workflow runs.
@@ -2737,7 +2737,7 @@ import (
"context"
"fmt"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflowSchedules lists workflow schedules.
@@ -2780,7 +2780,7 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// GetWorkflowWorkerInfo retrieves information about the current worker.

View File

@@ -1,6 +1,6 @@
package embedding
import "somegit.dev/vikingowl/mistral-go-sdk/chat"
import "github.com/VikingOwl91/mistral-go-sdk/chat"
// Dtype specifies the data type of output embeddings.
type Dtype string

View File

@@ -3,7 +3,7 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/embedding"
"github.com/VikingOwl91/mistral-go-sdk/embedding"
)
// CreateEmbeddings sends an embedding request and returns the response.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/embedding"
"github.com/VikingOwl91/mistral-go-sdk/embedding"
)
func TestCreateEmbeddings_Success(t *testing.T) {

View File

@@ -5,9 +5,9 @@ import (
"fmt"
"log"
mistral "somegit.dev/vikingowl/mistral-go-sdk"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"somegit.dev/vikingowl/mistral-go-sdk/embedding"
mistral "github.com/VikingOwl91/mistral-go-sdk"
"github.com/VikingOwl91/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/embedding"
)
func ExampleNewClient() {

View File

@@ -8,7 +8,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/file"
"github.com/VikingOwl91/mistral-go-sdk/file"
)
// UploadFile uploads a file for use with fine-tuning, batch, or OCR.

View File

@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/file"
"github.com/VikingOwl91/mistral-go-sdk/file"
)
func TestUploadFile_Success(t *testing.T) {

View File

@@ -3,8 +3,8 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"somegit.dev/vikingowl/mistral-go-sdk/fim"
"github.com/VikingOwl91/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/fim"
)
// FIMComplete sends a Fill-In-the-Middle completion request.

View File

@@ -8,8 +8,8 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"somegit.dev/vikingowl/mistral-go-sdk/fim"
"github.com/VikingOwl91/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/fim"
)
func TestFIMComplete_Success(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/finetune"
"github.com/VikingOwl91/mistral-go-sdk/finetune"
)
// CreateFineTuningJob creates a new fine-tuning job.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/finetune"
"github.com/VikingOwl91/mistral-go-sdk/finetune"
)
func TestCreateFineTuningJob_Success(t *testing.T) {

2
go.mod
View File

@@ -1,3 +1,3 @@
module somegit.dev/vikingowl/mistral-go-sdk
module github.com/VikingOwl91/mistral-go-sdk
go 1.26

View File

@@ -8,8 +8,8 @@ import (
"strings"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"somegit.dev/vikingowl/mistral-go-sdk/embedding"
"github.com/VikingOwl91/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/embedding"
)
func integrationClient(t *testing.T) *Client {

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/library"
"github.com/VikingOwl91/mistral-go-sdk/library"
)
// CreateLibrary creates a new document library.

View File

@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/library"
"github.com/VikingOwl91/mistral-go-sdk/library"
)
func newLibraryJSON() map[string]any {

View File

@@ -6,7 +6,7 @@ import (
)
// Version is the SDK version string.
const Version = "1.2.0"
const Version = "1.3.0"
const (
defaultBaseURL = "https://api.mistral.ai"

View File

@@ -4,7 +4,7 @@ import (
"context"
"net/url"
"somegit.dev/vikingowl/mistral-go-sdk/model"
"github.com/VikingOwl91/mistral-go-sdk/model"
)
// ListModels returns a list of available models.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/model"
"github.com/VikingOwl91/mistral-go-sdk/model"
)
func TestListModels_Success(t *testing.T) {

View File

@@ -1,6 +1,6 @@
package moderation
import "somegit.dev/vikingowl/mistral-go-sdk/chat"
import "github.com/VikingOwl91/mistral-go-sdk/chat"
// Request represents a text moderation request (/v1/moderations).
type Request struct {

View File

@@ -3,8 +3,8 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/classification"
"somegit.dev/vikingowl/mistral-go-sdk/moderation"
"github.com/VikingOwl91/mistral-go-sdk/classification"
"github.com/VikingOwl91/mistral-go-sdk/moderation"
)
// Moderate sends a text moderation request.

View File

@@ -7,8 +7,8 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/classification"
"somegit.dev/vikingowl/mistral-go-sdk/moderation"
"github.com/VikingOwl91/mistral-go-sdk/classification"
"github.com/VikingOwl91/mistral-go-sdk/moderation"
)
func TestModerate_Success(t *testing.T) {

84
observability/field.go Normal file
View File

@@ -0,0 +1,84 @@
package observability
// FieldType identifies the data type of a chat-completion-event field.
type FieldType string
const (
FieldTypeEnum FieldType = "ENUM"
FieldTypeText FieldType = "TEXT"
FieldTypeInt FieldType = "INT"
FieldTypeFloat FieldType = "FLOAT"
FieldTypeBool FieldType = "BOOL"
FieldTypeTimestamp FieldType = "TIMESTAMP"
FieldTypeArray FieldType = "ARRAY"
)
// FieldOperator is a filter operator supported on observability fields.
type FieldOperator string
const (
FieldOperatorLT FieldOperator = "lt"
FieldOperatorLTE FieldOperator = "lte"
FieldOperatorGT FieldOperator = "gt"
FieldOperatorGTE FieldOperator = "gte"
FieldOperatorStartsWith FieldOperator = "startswith"
FieldOperatorIStartsWith FieldOperator = "istartswith"
FieldOperatorEndsWith FieldOperator = "endswith"
FieldOperatorIEndsWith FieldOperator = "iendswith"
FieldOperatorContains FieldOperator = "contains"
FieldOperatorIContains FieldOperator = "icontains"
FieldOperatorMatches FieldOperator = "matches"
FieldOperatorNotContains FieldOperator = "notcontains"
FieldOperatorINotContain FieldOperator = "inotcontains"
FieldOperatorEq FieldOperator = "eq"
FieldOperatorNeq FieldOperator = "neq"
FieldOperatorIsNull FieldOperator = "isnull"
FieldOperatorIncludes FieldOperator = "includes"
FieldOperatorExcludes FieldOperator = "excludes"
FieldOperatorLenEq FieldOperator = "len_eq"
)
// BaseFieldDefinition describes a searchable chat-completion-event field.
type BaseFieldDefinition struct {
Name string `json:"name"`
Label string `json:"label"`
Type FieldType `json:"type"`
Group *string `json:"group,omitempty"`
SupportedOperators []FieldOperator `json:"supported_operators"`
}
// FieldGroup groups related field definitions for UI display.
type FieldGroup struct {
Name string `json:"name"`
Label string `json:"label"`
}
// ChatCompletionFields is the response of GET /v1/observability/chat-completion-fields.
type ChatCompletionFields struct {
FieldDefinitions []BaseFieldDefinition `json:"field_definitions"`
FieldGroups []FieldGroup `json:"field_groups"`
}
// ChatCompletionFieldOptions is the response of
// GET /v1/observability/chat-completion-fields/{field_name}/options.
//
// Each option may be a string, bool, or null — preserved as raw any.
type ChatCompletionFieldOptions struct {
Options []any `json:"options"`
}
// FieldOptionCountsRequest is the body of POST options-counts.
type FieldOptionCountsRequest struct {
FilterParams *FilterPayload `json:"filter_params,omitempty"`
}
// FieldOptionCountItem pairs a field value with how many events have it.
type FieldOptionCountItem struct {
Value string `json:"value"`
Count int `json:"count"`
}
// FieldOptionCounts is the response of POST options-counts.
type FieldOptionCounts struct {
Counts []FieldOptionCountItem `json:"counts"`
}

View File

@@ -6,7 +6,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
// CreateCampaign creates a new observability campaign.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
func TestCreateCampaign_Success(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
// CreateDataset creates a new observability dataset.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
func datasetJSON() map[string]any {

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
// SearchChatCompletionEvents searches for chat completion events.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
func TestSearchChatCompletionEvents_Success(t *testing.T) {

46
observability_fields.go Normal file
View File

@@ -0,0 +1,46 @@
package mistral
import (
"context"
"fmt"
"net/url"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
// GetChatCompletionFields returns the searchable field definitions and groups
// for chat-completion observability events.
func (c *Client) GetChatCompletionFields(ctx context.Context) (*observability.ChatCompletionFields, error) {
var resp observability.ChatCompletionFields
if err := c.doJSON(ctx, "GET", "/v1/observability/chat-completion-fields", nil, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// GetChatCompletionFieldOptions returns the distinct values seen for the given
// field, filtered by the requested operator.
func (c *Client) GetChatCompletionFieldOptions(ctx context.Context, fieldName string, operator observability.FieldOperator) (*observability.ChatCompletionFieldOptions, error) {
q := url.Values{}
q.Set("operator", string(operator))
path := fmt.Sprintf("/v1/observability/chat-completion-fields/%s/options?%s", url.PathEscape(fieldName), q.Encode())
var resp observability.ChatCompletionFieldOptions
if err := c.doJSON(ctx, "GET", path, nil, &resp); err != nil {
return nil, err
}
return &resp, nil
}
// GetChatCompletionFieldOptionsCounts returns per-value event counts for the
// given field, optionally filtered by the supplied filter payload.
func (c *Client) GetChatCompletionFieldOptionsCounts(ctx context.Context, fieldName string, req *observability.FieldOptionCountsRequest) (*observability.FieldOptionCounts, error) {
if req == nil {
req = &observability.FieldOptionCountsRequest{}
}
path := fmt.Sprintf("/v1/observability/chat-completion-fields/%s/options-counts", url.PathEscape(fieldName))
var resp observability.FieldOptionCounts
if err := c.doJSON(ctx, "POST", path, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}

View File

@@ -0,0 +1,100 @@
package mistral
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
func TestGetChatCompletionFields_Success(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" || r.URL.Path != "/v1/observability/chat-completion-fields" {
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"field_definitions": []map[string]any{
{
"name": "model",
"label": "Model",
"type": "ENUM",
"supported_operators": []string{"eq", "neq", "includes"},
},
},
"field_groups": []map[string]any{
{"name": "request", "label": "Request"},
},
})
}))
defer server.Close()
client := NewClient("key", WithBaseURL(server.URL))
resp, err := client.GetChatCompletionFields(context.Background())
if err != nil {
t.Fatal(err)
}
if len(resp.FieldDefinitions) != 1 {
t.Fatalf("got %d field definitions", len(resp.FieldDefinitions))
}
def := resp.FieldDefinitions[0]
if def.Name != "model" || def.Type != observability.FieldTypeEnum {
t.Errorf("unexpected field def: %+v", def)
}
if len(def.SupportedOperators) != 3 {
t.Errorf("got %d operators", len(def.SupportedOperators))
}
if len(resp.FieldGroups) != 1 || resp.FieldGroups[0].Name != "request" {
t.Errorf("unexpected groups: %+v", resp.FieldGroups)
}
}
func TestGetChatCompletionFieldOptions_Success(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v1/observability/chat-completion-fields/model/options" {
t.Errorf("got path %s", r.URL.Path)
}
if got := r.URL.Query().Get("operator"); got != "eq" {
t.Errorf("got operator=%q want eq", got)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"options": []any{"mistral-small-latest", "mistral-large-latest", nil, true},
})
}))
defer server.Close()
client := NewClient("key", WithBaseURL(server.URL))
resp, err := client.GetChatCompletionFieldOptions(context.Background(), "model", observability.FieldOperatorEq)
if err != nil {
t.Fatal(err)
}
if len(resp.Options) != 4 {
t.Fatalf("got %d options", len(resp.Options))
}
}
func TestGetChatCompletionFieldOptionsCounts_Success(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" || r.URL.Path != "/v1/observability/chat-completion-fields/model/options-counts" {
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"counts": []map[string]any{
{"value": "mistral-small-latest", "count": 42},
{"value": "mistral-large-latest", "count": 17},
},
})
}))
defer server.Close()
client := NewClient("key", WithBaseURL(server.URL))
resp, err := client.GetChatCompletionFieldOptionsCounts(context.Background(), "model", &observability.FieldOptionCountsRequest{})
if err != nil {
t.Fatal(err)
}
if len(resp.Counts) != 2 || resp.Counts[0].Count != 42 {
t.Errorf("unexpected counts: %+v", resp.Counts)
}
}

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
// CreateJudge creates a new observability judge.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/observability"
"github.com/VikingOwl91/mistral-go-sdk/observability"
)
func judgeJSON() map[string]any {

View File

@@ -3,7 +3,7 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/ocr"
"github.com/VikingOwl91/mistral-go-sdk/ocr"
)
// OCR performs optical character recognition on a document.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/ocr"
"github.com/VikingOwl91/mistral-go-sdk/ocr"
)
func TestOCR_Success(t *testing.T) {

View File

@@ -9,7 +9,7 @@ import (
"testing"
"time"
"somegit.dev/vikingowl/mistral-go-sdk/chat"
"github.com/VikingOwl91/mistral-go-sdk/chat"
)
func TestRetry_429ThenSuccess(t *testing.T) {

61
workflow/connectors.go Normal file
View File

@@ -0,0 +1,61 @@
package workflow
// ConnectorSlot declares a connector dependency for a workflow execution.
//
// Pass a slice of slots to BuildConnectorExtensions to produce the
// nested map expected on ExecutionRequest.Extensions.
type ConnectorSlot struct {
ConnectorName string `json:"connector_name"`
CredentialsName *string `json:"credentials_name,omitempty"`
}
// ConnectorBindings is the bindings list inside ConnectorExtensions.
type ConnectorBindings struct {
Bindings []ConnectorSlot `json:"bindings"`
}
// ConnectorExtensions is the value of the "mistralai" key in workflow extensions.
type ConnectorExtensions struct {
Connectors ConnectorBindings `json:"connectors"`
}
// WorkflowExtensions is the top-level shape of the extensions field
// expected by the workflow execute endpoint when binding connectors.
type WorkflowExtensions struct {
Mistralai ConnectorExtensions `json:"mistralai"`
}
// BuildConnectorExtensions returns the value to set on
// ExecutionRequest.Extensions for the given connector slots.
//
// The result is a map[string]any so callers can merge in additional
// extension keys without colliding with the connector wire shape.
func BuildConnectorExtensions(slots ...ConnectorSlot) map[string]any {
return map[string]any{
"mistralai": ConnectorExtensions{
Connectors: ConnectorBindings{Bindings: slots},
},
}
}
// ConnectorAuthStatus is the state of an OAuth flow emitted by a
// connector-auth custom task event.
type ConnectorAuthStatus string
const (
ConnectorAuthWaitingForAuth ConnectorAuthStatus = "waiting_for_auth"
ConnectorAuthConnected ConnectorAuthStatus = "connected"
ConnectorAuthAccessDenied ConnectorAuthStatus = "access_denied"
ConnectorAuthTimedOut ConnectorAuthStatus = "timed_out"
ConnectorAuthError ConnectorAuthStatus = "error"
)
// ConnectorAuthTaskState is the payload of a custom task event of type
// "connector-auth", emitted while a workflow waits for OAuth completion.
type ConnectorAuthTaskState struct {
ConnectorName string `json:"connector_name"`
ConnectorID string `json:"connector_id"`
Status ConnectorAuthStatus `json:"status"`
AuthURL *string `json:"auth_url,omitempty"`
Message *string `json:"message,omitempty"`
}

36
workflow/definition.go Normal file
View File

@@ -0,0 +1,36 @@
package workflow
// CodeDefinition describes a workflow's code-level interface: its input/output
// schemas, signal/query/update handlers, and execution constraints.
type CodeDefinition struct {
InputSchema map[string]any `json:"input_schema"`
OutputSchema map[string]any `json:"output_schema,omitempty"`
Signals []SignalDefinition `json:"signals,omitempty"`
Queries []QueryDefinition `json:"queries,omitempty"`
Updates []UpdateDefinition `json:"updates,omitempty"`
EnforceDeterminism bool `json:"enforce_determinism,omitempty"`
ExecutionTimeout *float64 `json:"execution_timeout,omitempty"`
}
// SignalDefinition describes a signal handler on a workflow.
type SignalDefinition struct {
Name string `json:"name"`
InputSchema map[string]any `json:"input_schema"`
Description *string `json:"description,omitempty"`
}
// QueryDefinition describes a query handler on a workflow.
type QueryDefinition struct {
Name string `json:"name"`
InputSchema map[string]any `json:"input_schema"`
Description *string `json:"description,omitempty"`
OutputSchema map[string]any `json:"output_schema,omitempty"`
}
// UpdateDefinition describes an update handler on a workflow.
type UpdateDefinition struct {
Name string `json:"name"`
InputSchema map[string]any `json:"input_schema"`
Description *string `json:"description,omitempty"`
OutputSchema map[string]any `json:"output_schema,omitempty"`
}

166
workflow/definition_test.go Normal file
View File

@@ -0,0 +1,166 @@
package workflow
import (
"encoding/json"
"testing"
)
func TestCodeDefinition_RoundTrip(t *testing.T) {
raw := `{
"input_schema": {"type": "object", "properties": {"prompt": {"type": "string"}}},
"output_schema": {"type": "object", "properties": {"result": {"type": "string"}}},
"signals": [
{"name": "cancel", "input_schema": {"type": "object"}, "description": "Cancel the workflow"}
],
"queries": [
{"name": "status", "input_schema": {"type": "object"}, "description": "Get status", "output_schema": {"type": "string"}}
],
"updates": [
{"name": "set_priority", "input_schema": {"type": "object", "properties": {"level": {"type": "integer"}}}, "description": "Set priority", "output_schema": null}
],
"enforce_determinism": true,
"execution_timeout": 3600.5
}`
var def CodeDefinition
if err := json.Unmarshal([]byte(raw), &def); err != nil {
t.Fatal(err)
}
if def.InputSchema == nil {
t.Fatal("InputSchema is nil")
}
if def.OutputSchema == nil {
t.Fatal("OutputSchema is nil")
}
if len(def.Signals) != 1 {
t.Fatalf("expected 1 signal, got %d", len(def.Signals))
}
if def.Signals[0].Name != "cancel" {
t.Errorf("signal name = %q, want cancel", def.Signals[0].Name)
}
if def.Signals[0].Description == nil || *def.Signals[0].Description != "Cancel the workflow" {
t.Errorf("signal description wrong")
}
if len(def.Queries) != 1 {
t.Fatalf("expected 1 query, got %d", len(def.Queries))
}
if def.Queries[0].Name != "status" {
t.Errorf("query name = %q, want status", def.Queries[0].Name)
}
if def.Queries[0].OutputSchema == nil {
t.Error("query OutputSchema is nil, expected non-nil")
}
if len(def.Updates) != 1 {
t.Fatalf("expected 1 update, got %d", len(def.Updates))
}
if def.Updates[0].Name != "set_priority" {
t.Errorf("update name = %q, want set_priority", def.Updates[0].Name)
}
if def.EnforceDeterminism != true {
t.Error("EnforceDeterminism should be true")
}
if def.ExecutionTimeout == nil || *def.ExecutionTimeout != 3600.5 {
t.Errorf("ExecutionTimeout = %v, want 3600.5", def.ExecutionTimeout)
}
// Re-marshal and verify round-trip
out, err := json.Marshal(def)
if err != nil {
t.Fatal(err)
}
var def2 CodeDefinition
if err := json.Unmarshal(out, &def2); err != nil {
t.Fatal(err)
}
if len(def2.Signals) != 1 || def2.Signals[0].Name != "cancel" {
t.Error("round-trip failed for signals")
}
if def2.EnforceDeterminism != true {
t.Error("round-trip failed for enforce_determinism")
}
}
func TestCodeDefinition_MinimalFields(t *testing.T) {
raw := `{"input_schema": {"type": "object"}}`
var def CodeDefinition
if err := json.Unmarshal([]byte(raw), &def); err != nil {
t.Fatal(err)
}
if def.InputSchema == nil {
t.Fatal("InputSchema is nil")
}
if def.OutputSchema != nil {
t.Errorf("OutputSchema should be nil, got %v", def.OutputSchema)
}
if def.Signals != nil {
t.Errorf("Signals should be nil, got %v", def.Signals)
}
if def.EnforceDeterminism != false {
t.Error("EnforceDeterminism should default to false")
}
if def.ExecutionTimeout != nil {
t.Errorf("ExecutionTimeout should be nil, got %v", def.ExecutionTimeout)
}
}
func TestRegistration_NewFields(t *testing.T) {
raw := `{
"id": "reg-1",
"workflow_id": "wf-1",
"task_queue": "legacy-queue",
"deployment_id": "dep-abc",
"compatible_with_chat_assistant": true,
"definition": {
"input_schema": {"type": "object"},
"enforce_determinism": false
},
"created_at": "2026-04-01T00:00:00Z",
"updated_at": "2026-04-02T00:00:00Z"
}`
var reg Registration
if err := json.Unmarshal([]byte(raw), &reg); err != nil {
t.Fatal(err)
}
if reg.ID != "reg-1" {
t.Errorf("ID = %q", reg.ID)
}
if reg.DeploymentID == nil || *reg.DeploymentID != "dep-abc" {
t.Errorf("DeploymentID = %v, want dep-abc", reg.DeploymentID)
}
if reg.CompatibleWithChatAssistant != true {
t.Error("CompatibleWithChatAssistant should be true")
}
if reg.Definition == nil {
t.Fatal("Definition is nil")
}
if reg.Definition.InputSchema == nil {
t.Error("Definition.InputSchema is nil")
}
// TaskQueue still works for backward compat
if reg.TaskQueue != "legacy-queue" {
t.Errorf("TaskQueue = %q, want legacy-queue", reg.TaskQueue)
}
}
func TestRegistration_NullDeploymentID(t *testing.T) {
raw := `{
"id": "reg-2",
"workflow_id": "wf-2",
"task_queue": "q",
"definition": {"input_schema": {"type": "object"}}
}`
var reg Registration
if err := json.Unmarshal([]byte(raw), &reg); err != nil {
t.Fatal(err)
}
if reg.DeploymentID != nil {
t.Errorf("DeploymentID should be nil, got %v", reg.DeploymentID)
}
if reg.CompatibleWithChatAssistant != false {
t.Error("CompatibleWithChatAssistant should default to false")
}
}

View File

@@ -25,6 +25,9 @@ type ExecutionRequest struct {
TimeoutSeconds *float64 `json:"timeout_seconds,omitempty"`
CustomTracingAttributes map[string]string `json:"custom_tracing_attributes,omitempty"`
DeploymentName *string `json:"deployment_name,omitempty"`
// Extensions carries plugin-specific data such as connector bindings.
// Use BuildConnectorExtensions to construct the standard connector shape.
Extensions map[string]any `json:"extensions,omitempty"`
}
// ExecutionResponse is the response from a workflow execution.
@@ -40,11 +43,20 @@ type ExecutionResponse struct {
TotalDurationMs *int `json:"total_duration_ms,omitempty"`
}
// EncodedPayloadOption identifies how a workflow payload was encoded.
type EncodedPayloadOption string
const (
EncodedPayloadOffloaded EncodedPayloadOption = "offloaded"
EncodedPayloadEncrypted EncodedPayloadOption = "encrypted"
EncodedPayloadEncryptedPartial EncodedPayloadOption = "encrypted-partial"
)
// NetworkEncodedInput holds a base64-encoded payload for workflow input.
type NetworkEncodedInput struct {
B64Payload string `json:"b64payload"`
EncodingOptions []string `json:"encoding_options,omitempty"`
Empty bool `json:"empty,omitempty"`
B64Payload string `json:"b64payload"`
EncodingOptions []EncodedPayloadOption `json:"encoding_options,omitempty"`
Empty bool `json:"empty,omitempty"`
}
// SignalInvocationBody is the request body for signaling a workflow execution.

View File

@@ -2,8 +2,12 @@ package workflow
// Registration represents a workflow registration.
type Registration struct {
ID string `json:"id"`
WorkflowID string `json:"workflow_id"`
ID string `json:"id"`
WorkflowID string `json:"workflow_id"`
Definition *CodeDefinition `json:"definition,omitempty"`
DeploymentID *string `json:"deployment_id,omitempty"`
CompatibleWithChatAssistant bool `json:"compatible_with_chat_assistant,omitempty"`
// Deprecated: use DeploymentID instead. Will be removed in a future release.
TaskQueue string `json:"task_queue"`
Workflow *Workflow `json:"workflow,omitempty"`
CreatedAt string `json:"created_at"`
@@ -35,10 +39,3 @@ type RegistrationGetParams struct {
WithWorkflow *bool
IncludeShared *bool
}
// WorkerInfo holds information about the current worker.
type WorkerInfo struct {
SchedulerURL string `json:"scheduler_url"`
Namespace string `json:"namespace"`
TLS bool `json:"tls"`
}

12
workflow/worker.go Normal file
View File

@@ -0,0 +1,12 @@
package workflow
// WorkerInfo describes the worker scheduler the SDK is connected to.
//
// Returned by GET /v1/workflows/workers/whoami. Useful when running custom
// workers that need to know which scheduler / namespace to connect to.
// For managed deployments, prefer Registration.DeploymentID.
type WorkerInfo struct {
SchedulerURL string `json:"scheduler_url"`
Namespace string `json:"namespace"`
TLS bool `json:"tls"`
}

View File

@@ -6,7 +6,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflows lists workflows.

View File

@@ -6,7 +6,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflowDeployments lists workflow deployments.

View File

@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// StreamWorkflowEvents streams workflow events via SSE.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestListWorkflowEvents_Success(t *testing.T) {

View File

@@ -8,7 +8,7 @@ import (
"strconv"
"time"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// GetWorkflowExecution retrieves a workflow execution by ID.

View File

@@ -8,7 +8,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestGetWorkflowExecution_Success(t *testing.T) {

View File

@@ -0,0 +1,106 @@
package mistral
import (
"encoding/json"
"testing"
"github.com/VikingOwl91/mistral-go-sdk/conversation"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestNetworkEncodedInput_EncodingOptions(t *testing.T) {
in := workflow.NetworkEncodedInput{
B64Payload: "eyJrIjoidiJ9",
EncodingOptions: []workflow.EncodedPayloadOption{workflow.EncodedPayloadOffloaded, workflow.EncodedPayloadEncrypted},
}
b, err := json.Marshal(in)
if err != nil {
t.Fatal(err)
}
var got map[string]any
if err := json.Unmarshal(b, &got); err != nil {
t.Fatal(err)
}
opts, ok := got["encoding_options"].([]any)
if !ok || len(opts) != 2 {
t.Fatalf("unexpected encoding_options: %v", got["encoding_options"])
}
if opts[0] != "offloaded" || opts[1] != "encrypted" {
t.Errorf("got %v, want [offloaded encrypted]", opts)
}
}
func TestBuildConnectorExtensions_WireShape(t *testing.T) {
creds := "work-account"
ext := workflow.BuildConnectorExtensions(
workflow.ConnectorSlot{ConnectorName: "gmail"},
workflow.ConnectorSlot{ConnectorName: "notion", CredentialsName: &creds},
)
b, err := json.Marshal(ext)
if err != nil {
t.Fatal(err)
}
want := `{"mistralai":{"connectors":{"bindings":[{"connector_name":"gmail"},{"connector_name":"notion","credentials_name":"work-account"}]}}}`
if string(b) != want {
t.Errorf("\nwant %s\ngot %s", want, string(b))
}
}
func TestExecutionRequest_Extensions(t *testing.T) {
req := workflow.ExecutionRequest{
Extensions: workflow.BuildConnectorExtensions(workflow.ConnectorSlot{ConnectorName: "gmail"}),
}
b, err := json.Marshal(req)
if err != nil {
t.Fatal(err)
}
var got map[string]any
if err := json.Unmarshal(b, &got); err != nil {
t.Fatal(err)
}
if _, ok := got["extensions"]; !ok {
t.Fatalf("expected extensions key in marshalled request: %s", string(b))
}
}
func TestConnectorAuthTaskState_Roundtrip(t *testing.T) {
authURL := "https://oauth.example.com/authorize"
in := workflow.ConnectorAuthTaskState{
ConnectorName: "gmail",
ConnectorID: "conn-1",
Status: workflow.ConnectorAuthWaitingForAuth,
AuthURL: &authURL,
}
b, err := json.Marshal(in)
if err != nil {
t.Fatal(err)
}
var out workflow.ConnectorAuthTaskState
if err := json.Unmarshal(b, &out); err != nil {
t.Fatal(err)
}
if out.Status != workflow.ConnectorAuthWaitingForAuth {
t.Errorf("got status %q", out.Status)
}
if out.AuthURL == nil || *out.AuthURL != authURL {
t.Errorf("auth_url roundtrip failed")
}
}
func TestConfirmationConstants_WireValues(t *testing.T) {
// Reply constants.
c := conversation.ToolCallConfirmation{
ToolCallID: "call_1",
Confirmation: string(conversation.ConfirmationAllow),
}
b, _ := json.Marshal(c)
if string(b) != `{"tool_call_id":"call_1","confirmation":"allow"}` {
t.Errorf("got %s", string(b))
}
// Inbound status constants.
if conversation.ConfirmationStatusPending != "pending" ||
conversation.ConfirmationStatusAllowed != "allowed" ||
conversation.ConfirmationStatusDenied != "denied" {
t.Errorf("unexpected confirmation status constants")
}
}

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"net/url"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// GetWorkflowMetrics retrieves performance metrics for a workflow.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestGetWorkflowMetrics_Success(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"net/url"
"strconv"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflowRuns lists workflow runs.

View File

@@ -4,7 +4,7 @@ import (
"context"
"fmt"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// ListWorkflowSchedules lists workflow schedules.

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestScheduleWorkflow_Success(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
func TestListWorkflows_Success(t *testing.T) {

View File

@@ -3,10 +3,14 @@ package mistral
import (
"context"
"somegit.dev/vikingowl/mistral-go-sdk/workflow"
"github.com/VikingOwl91/mistral-go-sdk/workflow"
)
// GetWorkflowWorkerInfo retrieves information about the current worker.
// GetWorkflowWorkerInfo returns the scheduler URL, namespace, and TLS setting
// the API expects custom workers to connect with.
//
// Most callers using managed deployments do not need this — see
// Registration.DeploymentID. It is exposed for users running custom workers.
func (c *Client) GetWorkflowWorkerInfo(ctx context.Context) (*workflow.WorkerInfo, error) {
var resp workflow.WorkerInfo
if err := c.doJSON(ctx, "GET", "/v1/workflows/workers/whoami", nil, &resp); err != nil {

View File

@@ -10,12 +10,12 @@ import (
func TestGetWorkflowWorkerInfo_Success(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v1/workflows/workers/whoami" {
t.Errorf("got path %s", r.URL.Path)
if r.Method != "GET" || r.URL.Path != "/v1/workflows/workers/whoami" {
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
}
json.NewEncoder(w).Encode(map[string]any{
"scheduler_url": "https://scheduler.mistral.ai",
"namespace": "default",
_ = json.NewEncoder(w).Encode(map[string]any{
"scheduler_url": "scheduler.example.com:7233",
"namespace": "tenant-2",
"tls": true,
})
}))
@@ -26,10 +26,27 @@ func TestGetWorkflowWorkerInfo_Success(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if info.Namespace != "default" {
t.Errorf("got namespace %q", info.Namespace)
}
if !info.TLS {
t.Error("expected tls=true")
if info.SchedulerURL != "scheduler.example.com:7233" || info.Namespace != "tenant-2" || !info.TLS {
t.Errorf("unexpected info: %+v", info)
}
}
func TestGetWorkflowWorkerInfo_TLSDefault(t *testing.T) {
// Server omits the tls field; the SDK should default it to false.
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = json.NewEncoder(w).Encode(map[string]any{
"scheduler_url": "s",
"namespace": "n",
})
}))
defer server.Close()
client := NewClient("key", WithBaseURL(server.URL))
info, err := client.GetWorkflowWorkerInfo(context.Background())
if err != nil {
t.Fatal(err)
}
if info.TLS {
t.Errorf("expected default tls=false, got true")
}
}