Go SDK
syntic-go is the planned official Go client for the Syntic API. It is generated from the OpenAPI description, so every endpoint and field is available, with hand-written helpers for streaming, tool loops, pagination and batches. It is one of the first two clients after Python and TypeScript; see Other languages for the release order.
Today, call the API with net/http as shown in Quickstart: Go. That code keeps working after the SDK ships.
Install
go get github.com/syntic-ai/syntic-go| Requirement | Value |
|---|---|
| Go | 1.22 or newer |
| Module | github.com/syntic-ai/syntic-go |
| Dependencies | Standard library only |
Create a client
import syntic "github.com/syntic-ai/syntic-go"
client := syntic.NewClient() // reads SYNTIC_API_KEY and SYNTIC_BASE_URLOptions are passed as functional options:
| Option | Default | Notes |
|---|---|---|
syntic.WithAPIKey(key) | $SYNTIC_API_KEY | A private sk_live_ key or a workload identity sat_ token. |
syntic.WithBaseURL(url) | $SYNTIC_BASE_URL, else https://app.syntic.ai/v1 | |
syntic.WithVersion(v) | The version the release was built for | Sent as syntic-version. |
syntic.WithBetas(flags...) | none | Sent as syntic-beta. Methods that need a flag add it themselves. |
syntic.WithMaxRetries(n) | 2 | Retries rate_limit, overloaded, api_error and network errors with back-off, honouring retry-after. |
syntic.WithHTTPClient(c) | A client with a 10-minute timeout | Bring your own transport, proxy or tracing. |
Every method takes a context.Context first; cancel it to abort a request or a stream.
A first request
package main
import (
"context"
"fmt"
"log"
syntic "github.com/syntic-ai/syntic-go"
)
func main() {
client := syntic.NewClient()
reply, err := client.Chat.Completions.Create(context.Background(), syntic.ChatCompletionParams{
Model: "Amara S1.2",
MaxTokens: syntic.Int(200),
Messages: []syntic.Message{
syntic.SystemMessage("Answer in one sentence."),
syntic.UserMessage("Why is the sky blue?"),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(reply.Choices[0].Message.Content)
fmt.Println(reply.Usage.TotalTokens, reply.RequestID)
}The SDK always sends stream explicitly: Create returns one completion, Stream returns a stream.
Streaming
stream := client.Chat.Completions.Stream(ctx, syntic.ChatCompletionParams{
Model: "Amara Quick",
Messages: []syntic.Message{syntic.UserMessage("Write a haiku about rain.")},
})
defer stream.Close()
for stream.Next() {
fmt.Print(stream.Current().TextDelta())
}
if err := stream.Err(); err != nil { // includes a stream_error event, as a typed error
log.Fatal(err)
}
final := stream.Completion() // assembled message, tool calls and usage
fmt.Println("\n", final.Usage.TotalTokens)Tool loop
type OrderArgs struct {
OrderID string `json:"order_id" jsonschema:"description=Order id such as 88123"`
}
getOrder := syntic.NewTool("get_order", "Look up an order by its id.",
func(ctx context.Context, a OrderArgs) (any, error) {
return map[string]string{"order_id": a.OrderID, "status": "shipped"}, nil
})
result, err := client.Tools.Run(ctx, syntic.ToolRunParams{
Model: "Amara S1.2",
Messages: []syntic.Message{syntic.UserMessage("Where is order 88123?")},
Tools: []syntic.Tool{getOrder},
MaxRounds: 8,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(result.FinalMessage.Content)The JSON Schema is generated from the argument struct. A function that returns an error has the error sent back to the model as a tool result.
Errors
API errors are returned as *syntic.Error:
var apiErr *syntic.Error
if errors.As(err, &apiErr) {
switch apiErr.Type {
case syntic.ErrQuotaExhausted:
fmt.Println("paused until", apiErr.Details["resets_at"])
case syntic.ErrInvalidRequest:
fmt.Println(apiErr.Code, apiErr.Param, apiErr.RequestID)
}
}| Field | Meaning |
|---|---|
StatusCode | HTTP status. |
Type | One of the eight envelope types, as typed constants. |
Code, Message, Param, Details | From the envelope. |
RequestID | Quote it to support. |
Network failures and timeouts are returned as ordinary Go errors wrapping context or net errors.
Pagination
iter := client.Agents.ListAutoPaging(ctx, syntic.AgentListParams{Limit: syntic.Int(50)})
for iter.Next() {
a := iter.Current()
fmt.Println(a.ID, a.Name)
}
if err := iter.Err(); err != nil {
log.Fatal(err)
}List (without AutoPaging) returns one page with HasMore, FirstID and LastID.
Files, batches, agents and admin
f, _ := client.Files.Upload(ctx, syntic.FileUploadParams{Path: "contract.pdf", Purpose: "document"})
batch, _ := client.Batches.Create(ctx, syntic.BatchCreateParams{InputFileID: syntic.String(f.ID)})
batch, _ = client.Batches.Wait(ctx, batch.ID, 30*time.Second)
session, _ := client.Sessions.Create(ctx, syntic.SessionCreateParams{AgentID: "agt_01JC4R8W6Q2N9X3T5V7Y"})
events := client.Sessions.Stream(ctx, session.ID)
for events.Next() {
if e := events.Current(); e.Type == "message.completed" {
fmt.Println(e.Content)
}
}
admin := syntic.NewAdminClient() // reads SYNTIC_ADMIN_KEY
users := admin.Users.ListAutoPaging(ctx, syntic.UserListParams{})Raw responses
reply, raw, err := client.Chat.Completions.CreateWithResponse(ctx, params)
fmt.Println(raw.Header.Get("x-syntic-billing-source"))Versioning
The module follows semantic versioning with Go module major-version paths (/v2 and so on) for breaking changes, which come with a new default syntic-version. Each release lists the API version it was tested against.