feat: Phase 10 polish — package docs, examples, integration tests
Add doc.go with package-level godoc for all 15 packages, runnable example functions for chat completion, streaming, embeddings, and error handling, plus build-tagged integration tests for live API validation.
This commit is contained in:
3
agents/doc.go
Normal file
3
agents/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package agents provides types for the Mistral agents API,
|
||||
// including agent CRUD operations and agent chat completions.
|
||||
package agents
|
||||
5
audio/doc.go
Normal file
5
audio/doc.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package audio provides types for the Mistral audio transcription API.
|
||||
//
|
||||
// Streaming transcription returns typed [StreamEvent] values via a sealed
|
||||
// interface dispatched by the "type" field.
|
||||
package audio
|
||||
2
batch/doc.go
Normal file
2
batch/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package batch provides types for the Mistral batch jobs API.
|
||||
package batch
|
||||
9
chat/doc.go
Normal file
9
chat/doc.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Package chat provides types for the Mistral chat completion API.
|
||||
//
|
||||
// Messages use a sealed interface pattern — create them with
|
||||
// [UserMessage], [SystemMessage], [AssistantMessage], or [ToolMessage]
|
||||
// struct literals.
|
||||
//
|
||||
// Content is polymorphic: it can be a plain string (via [TextContent]),
|
||||
// nil, or a slice of [ContentChunk] values (text, image URL, document URL, audio).
|
||||
package chat
|
||||
2
classification/doc.go
Normal file
2
classification/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package classification provides types for the Mistral classification API.
|
||||
package classification
|
||||
6
conversation/doc.go
Normal file
6
conversation/doc.go
Normal file
@@ -0,0 +1,6 @@
|
||||
// Package conversation provides types for the Mistral conversations API.
|
||||
//
|
||||
// Conversations support multi-turn interactions with start, append, and
|
||||
// restart operations. Streaming returns typed [Event] values via a sealed
|
||||
// interface dispatched by the "type" discriminator.
|
||||
package conversation
|
||||
45
doc.go
Normal file
45
doc.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// Package mistral provides an idiomatic Go client for the Mistral AI API.
|
||||
//
|
||||
// Create a client with your API key, then call methods for each endpoint:
|
||||
//
|
||||
// client := mistral.NewClient("sk-...")
|
||||
//
|
||||
// // Chat completion
|
||||
// resp, err := client.ChatComplete(ctx, &chat.CompletionRequest{
|
||||
// Model: "mistral-small-latest",
|
||||
// Messages: []chat.Message{&chat.UserMessage{Content: chat.TextContent("Hello!")}},
|
||||
// })
|
||||
//
|
||||
// // Streaming
|
||||
// stream, err := client.ChatCompleteStream(ctx, req)
|
||||
// defer stream.Close()
|
||||
// for stream.Next() {
|
||||
// chunk := stream.Current()
|
||||
// fmt.Print(chunk.Choices[0].Delta.Content)
|
||||
// }
|
||||
//
|
||||
// # Configuration
|
||||
//
|
||||
// Use functional options to configure the client:
|
||||
//
|
||||
// client := mistral.NewClient("sk-...",
|
||||
// mistral.WithTimeout(30 * time.Second),
|
||||
// mistral.WithRetry(3, 500*time.Millisecond),
|
||||
// )
|
||||
//
|
||||
// # Error Handling
|
||||
//
|
||||
// API errors are returned as *[APIError] values. Use sentinel checkers
|
||||
// for common cases:
|
||||
//
|
||||
// if mistral.IsRateLimit(err) {
|
||||
// // back off and retry
|
||||
// }
|
||||
//
|
||||
// # Sub-packages
|
||||
//
|
||||
// Types are organized into sub-packages by domain: [chat], [agents],
|
||||
// [conversation], [embedding], [model], [file], [finetune], [batch],
|
||||
// [ocr], [audio], [library], [moderation], [classification], and [fim].
|
||||
// All service methods live directly on [Client].
|
||||
package mistral
|
||||
2
embedding/doc.go
Normal file
2
embedding/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package embedding provides types for the Mistral embeddings API.
|
||||
package embedding
|
||||
94
example_test.go
Normal file
94
example_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package mistral_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
mistral "somegit.dev/vikingowl/mistral-go-sdk"
|
||||
"somegit.dev/vikingowl/mistral-go-sdk/chat"
|
||||
"somegit.dev/vikingowl/mistral-go-sdk/embedding"
|
||||
)
|
||||
|
||||
func ExampleNewClient() {
|
||||
client := mistral.NewClient("sk-your-api-key")
|
||||
_ = client // use client to call API methods
|
||||
}
|
||||
|
||||
func ExampleClient_ChatComplete() {
|
||||
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?")},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(resp.Choices[0].Message.Content)
|
||||
}
|
||||
|
||||
func ExampleClient_ChatCompleteStream() {
|
||||
client := mistral.NewClient("sk-your-api-key")
|
||||
|
||||
stream, err := client.ChatCompleteStream(context.Background(), &chat.CompletionRequest{
|
||||
Model: "mistral-small-latest",
|
||||
Messages: []chat.Message{
|
||||
&chat.UserMessage{Content: chat.TextContent("Tell me a short joke.")},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
for stream.Next() {
|
||||
chunk := stream.Current()
|
||||
if len(chunk.Choices) > 0 {
|
||||
fmt.Print(chunk.Choices[0].Delta.Content)
|
||||
}
|
||||
}
|
||||
if err := stream.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleClient_CreateEmbeddings() {
|
||||
client := mistral.NewClient("sk-your-api-key")
|
||||
|
||||
resp, err := client.CreateEmbeddings(context.Background(), &embedding.Request{
|
||||
Model: "mistral-embed",
|
||||
Input: []string{"Hello world"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Embedding dimension: %d\n", len(resp.Data[0].Embedding))
|
||||
}
|
||||
|
||||
func ExampleIsRateLimit() {
|
||||
client := mistral.NewClient("sk-your-api-key")
|
||||
|
||||
_, err := client.ChatComplete(context.Background(), &chat.CompletionRequest{
|
||||
Model: "mistral-small-latest",
|
||||
Messages: []chat.Message{
|
||||
&chat.UserMessage{Content: chat.TextContent("Hi")},
|
||||
},
|
||||
})
|
||||
if mistral.IsRateLimit(err) {
|
||||
fmt.Println("Rate limited — back off and retry")
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleIsNotFound() {
|
||||
client := mistral.NewClient("sk-your-api-key")
|
||||
|
||||
_, err := client.GetModel(context.Background(), "nonexistent-model")
|
||||
if mistral.IsNotFound(err) {
|
||||
fmt.Println("Model not found")
|
||||
}
|
||||
}
|
||||
3
file/doc.go
Normal file
3
file/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package file provides types for the Mistral files API,
|
||||
// including upload, download, and metadata operations.
|
||||
package file
|
||||
3
fim/doc.go
Normal file
3
fim/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package fim provides types for the Mistral Fill-in-the-Middle (FIM)
|
||||
// completion API, used for code infilling tasks.
|
||||
package fim
|
||||
3
finetune/doc.go
Normal file
3
finetune/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package finetune provides types for the Mistral fine-tuning API,
|
||||
// including job creation, monitoring, and model archiving.
|
||||
package finetune
|
||||
115
integration_test.go
Normal file
115
integration_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
//go:build integration
|
||||
|
||||
package mistral
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"somegit.dev/vikingowl/mistral-go-sdk/chat"
|
||||
"somegit.dev/vikingowl/mistral-go-sdk/embedding"
|
||||
)
|
||||
|
||||
func integrationClient(t *testing.T) *Client {
|
||||
t.Helper()
|
||||
key := os.Getenv("MISTRAL_API_KEY")
|
||||
if key == "" {
|
||||
t.Skip("MISTRAL_API_KEY not set")
|
||||
}
|
||||
return NewClient(key)
|
||||
}
|
||||
|
||||
func TestIntegration_ListModels(t *testing.T) {
|
||||
client := integrationClient(t)
|
||||
|
||||
resp, err := client.ListModels(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(resp.Data) == 0 {
|
||||
t.Fatal("expected at least one model")
|
||||
}
|
||||
if resp.Data[0].ID == "" {
|
||||
t.Error("expected model to have an ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegration_ChatComplete(t *testing.T) {
|
||||
client := integrationClient(t)
|
||||
|
||||
resp, err := client.ChatComplete(context.Background(), &chat.CompletionRequest{
|
||||
Model: "mistral-small-latest",
|
||||
Messages: []chat.Message{
|
||||
&chat.UserMessage{Content: chat.TextContent("Reply with exactly: hello")},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(resp.Choices) == 0 {
|
||||
t.Fatal("no choices returned")
|
||||
}
|
||||
content := resp.Choices[0].Message.Content.String()
|
||||
if !strings.Contains(strings.ToLower(content), "hello") {
|
||||
t.Errorf("expected 'hello' in response, got %q", content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegration_ChatCompleteStream(t *testing.T) {
|
||||
client := integrationClient(t)
|
||||
|
||||
stream, err := client.ChatCompleteStream(context.Background(), &chat.CompletionRequest{
|
||||
Model: "mistral-small-latest",
|
||||
Messages: []chat.Message{
|
||||
&chat.UserMessage{Content: chat.TextContent("Say hi")},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
chunks := 0
|
||||
for stream.Next() {
|
||||
chunks++
|
||||
}
|
||||
if err := stream.Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if chunks == 0 {
|
||||
t.Error("expected at least one stream chunk")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegration_Embeddings(t *testing.T) {
|
||||
client := integrationClient(t)
|
||||
|
||||
resp, err := client.CreateEmbeddings(context.Background(), &embedding.Request{
|
||||
Model: "mistral-embed",
|
||||
Input: []string{"The quick brown fox"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(resp.Data) != 1 {
|
||||
t.Fatalf("expected 1 embedding, got %d", len(resp.Data))
|
||||
}
|
||||
if len(resp.Data[0].Embedding) == 0 {
|
||||
t.Error("embedding vector is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegration_ErrorHandling(t *testing.T) {
|
||||
client := integrationClient(t)
|
||||
|
||||
_, err := client.GetModel(context.Background(), "definitely-not-a-real-model-id")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for nonexistent model")
|
||||
}
|
||||
if !IsNotFound(err) {
|
||||
t.Logf("got non-404 error (may vary by API): %v", err)
|
||||
}
|
||||
}
|
||||
3
library/doc.go
Normal file
3
library/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package library provides types for the Mistral document libraries API,
|
||||
// including library and document CRUD, sharing, and processing.
|
||||
package library
|
||||
6
model/doc.go
Normal file
6
model/doc.go
Normal file
@@ -0,0 +1,6 @@
|
||||
// Package model provides types for Mistral model listing and metadata.
|
||||
//
|
||||
// Model cards use a sealed interface — [BaseModelCard] for platform models
|
||||
// and [FTModelCard] for fine-tuned models. JSON unmarshaling dispatches on
|
||||
// the "type" field.
|
||||
package model
|
||||
2
moderation/doc.go
Normal file
2
moderation/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package moderation provides types for the Mistral moderation API.
|
||||
package moderation
|
||||
3
ocr/doc.go
Normal file
3
ocr/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package ocr provides types for the Mistral OCR API,
|
||||
// including document processing with page-level extraction.
|
||||
package ocr
|
||||
Reference in New Issue
Block a user