feat!: sync with Python SDK v2.3.0 — workflow registration model + remove workers
Add CodeDefinition, SignalDefinition, QueryDefinition, UpdateDefinition types for workflow interface metadata. Update Registration struct with DeploymentID, Definition, and CompatibleWithChatAssistant fields. Deprecate TaskQueue in favor of DeploymentID. BREAKING CHANGE: Remove GetWorkflowWorkerInfo and workflow.WorkerInfo — the /v1/workflows/workers/whoami endpoint was removed upstream.
This commit is contained in:
31
CHANGELOG.md
31
CHANGELOG.md
@@ -1,3 +1,34 @@
|
||||
## 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
|
||||
|
||||
@@ -11,7 +11,7 @@ The most complete Go client for the [Mistral AI API](https://docs.mistral.ai/).
|
||||
|
||||
**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.
|
||||
|
||||
**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.
|
||||
**Full API coverage.** 165 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.
|
||||
|
||||
**Typed streaming.** A generic pull-based `Stream[T]` iterator — no channels, no goroutines, no leaks. Just `Next()` / `Current()` / `Err()` / `Close()`.
|
||||
|
||||
@@ -132,7 +132,7 @@ for stream.Next() {
|
||||
|
||||
## API Coverage
|
||||
|
||||
166 public methods on `Client`, grouped by domain:
|
||||
165 public methods on `Client`, grouped by domain:
|
||||
|
||||
| Domain | Methods |
|
||||
|--------|---------|
|
||||
@@ -167,7 +167,6 @@ for stream.Next() {
|
||||
| **Workflows (metrics)** | `GetWorkflowMetrics` |
|
||||
| **Workflows (runs)** | `ListWorkflowRuns`, `GetWorkflowRun`, `GetWorkflowRunHistory` |
|
||||
| **Workflows (schedules)** | `ListWorkflowSchedules`, `ScheduleWorkflow`, `UnscheduleWorkflow` |
|
||||
| **Workflows (workers)** | `GetWorkflowWorkerInfo` |
|
||||
|
||||
## Comparison
|
||||
|
||||
@@ -241,6 +240,7 @@ as its upstream reference for API surface and type definitions.
|
||||
|
||||
| SDK Version | Upstream Python SDK |
|
||||
|-------------|---------------------|
|
||||
| v1.3.0 | v2.3.0 |
|
||||
| v1.2.1 | v2.2.0 |
|
||||
| v1.2.0 | v2.2.0 |
|
||||
| v1.1.0 | v2.1.3 |
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// Version is the SDK version string.
|
||||
const Version = "1.2.1"
|
||||
const Version = "1.3.0"
|
||||
|
||||
const (
|
||||
defaultBaseURL = "https://api.mistral.ai"
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package mistral
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/VikingOwl91/mistral-go-sdk/workflow"
|
||||
)
|
||||
|
||||
// GetWorkflowWorkerInfo retrieves information about the current worker.
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package mistral
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"scheduler_url": "https://scheduler.mistral.ai",
|
||||
"namespace": "default",
|
||||
"tls": true,
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient("key", WithBaseURL(server.URL))
|
||||
info, err := client.GetWorkflowWorkerInfo(context.Background())
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user