Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fc4bc249b6 | |||
| 8d1c839093 | |||
| c5bb663bc7 | |||
| fc61bc42ad | |||
| 9b7488183d | |||
| 78f7c745a7 | |||
| c028dfb0ed | |||
| 214fd02b3b | |||
| 3167966b98 |
132
.github/workflows/watch-openapi.yml
vendored
Normal file
132
.github/workflows/watch-openapi.yml
vendored
Normal 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
1
.openapi-hash
Normal file
@@ -0,0 +1 @@
|
||||
ff8a7389b7a4e61145561361537aae37c49f7e2dcf7c4f79f41e80a30b484cc3
|
||||
19660
.openapi-spec.yaml
Normal file
19660
.openapi-spec.yaml
Normal file
File diff suppressed because it is too large
Load Diff
115
CHANGELOG.md
115
CHANGELOG.md
@@ -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.
|
||||
|
||||
@@ -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
278
README.md
@@ -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 -->
|
||||
[](https://pkg.go.dev/somegit.dev/vikingowl/mistral-go-sdk)
|
||||
[](https://pkg.go.dev/github.com/VikingOwl91/mistral-go-sdk)
|
||||

|
||||

|
||||
|
||||
## 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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
2
files.go
2
files.go
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
2
go.mod
@@ -1,3 +1,3 @@
|
||||
module somegit.dev/vikingowl/mistral-go-sdk
|
||||
module github.com/VikingOwl91/mistral-go-sdk
|
||||
|
||||
go 1.26
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
84
observability/field.go
Normal 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"`
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
46
observability_fields.go
Normal 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
|
||||
}
|
||||
100
observability_fields_test.go
Normal file
100
observability_fields_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
61
workflow/connectors.go
Normal 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
36
workflow/definition.go
Normal 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
166
workflow/definition_test.go
Normal 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), ®); 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), ®); 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")
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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
12
workflow/worker.go
Normal 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"`
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
106
workflows_extensions_test.go
Normal file
106
workflows_extensions_test.go
Normal 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")
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user