synapcores

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2026 License: MIT Imports: 14 Imported by: 0

README

synapcores-go — Go SDK for SynapCores AIDB

Go Reference License

Official Go SDK for SynapCores — the AI-native database that runs SQL, vectors, RAG, and the in-database agentic runtime from a single engine.

Zero third-party dependencies. Pure stdlib. Idiomatic context propagation throughout.

Requirements

  • Go 1.18+
  • A running SynapCores engine (free CE: docker run -d -p 28080:8080 ghcr.io/synapcores/community:latest)

Install

go get github.com/SynapCores/synapcores-go@latest
import sc "github.com/SynapCores/synapcores-go"

Quickstart — 30 seconds

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    sc "github.com/SynapCores/synapcores-go"
)

func main() {
    client, err := sc.New(sc.Config{
        Host:   "localhost",
        Port:   8080,
        APIKey: os.Getenv("AIDB_API_KEY"),  // aidb_… or ak_…
    })
    if err != nil { log.Fatal(err) }

    ctx := context.Background()
    result, err := client.SQL(ctx, "SELECT name FROM users WHERE id = :id",
        map[string]any{"id": 42})
    if err != nil { log.Fatal(err) }

    for _, row := range result.Rows {
        fmt.Println(row["name"])
    }
}

What's in the box

Method What it does
client.SQL(ctx, sql, params) Run SQL via /v1/query/execute. :name placeholders inlined client-side. Returns *QueryResult.
client.Embed(ctx, text) SELECT EMBED(...) — returns []float64.
client.RAGSearch(ctx, query, opts) Top-K similar rows from a table with a VECTOR column.
client.AgentRun(ctx, persona, task, opts) Fire AGENT_RUN() — in-DB agentic runtime.
client.ImportRecipe(ctx, url) Import a recipe from a URL.
client.ExecRecipe(ctx, id, params) Execute an imported recipe.
client.KNNSearch(ctx, table, vec, k, opts) KNN over a VECTOR column with a literal query vector.
client.Login(ctx, user, pass) Exchange credentials for a JWT (only needed without APIKey).

Errors

Every error is one of *AuthError, *QueryError, *NetworkError, or *EnvelopeError — all unwrapping to ErrSynapCores for catch-all.

result, err := client.SQL(ctx, sql, params)
if err != nil {
    var qe *sc.QueryError
    if errors.As(err, &qe) {
        log.Printf("engine rejected at %s (status %d): %s",
            qe.Endpoint, qe.StatusCode, err)
    }
    return err
}

Parameter binding — how it actually works

The engine's /v1/query/execute route does NOT parse :name, ?, or $1 placeholders server-side. The SDK substitutes :name placeholders client-side with proper SQL escaping (single-quote doubling, backslash escape, NULL/TRUE/FALSE literals, [1,2,3] array literals for []float32 / []float64 / []int).

What goes over the wire is fully inlined SQL. The request body never contains a params field. This means:

  • map[string]any is the supported params shape.
  • Untrusted user input is safe if passed through params — the SDK escapes it. Never string-concatenate user input into the SQL.
  • A :name in the SQL with no matching key returns *QueryError — fail-fast.
// SAFE — single quotes in the value get doubled correctly:
client.SQL(ctx, "SELECT * FROM users WHERE name = :n", map[string]any{
    "n": "O'Brien",
})

// SAFE — vector literal becomes [0.1,0.2,0.3]:
client.SQL(ctx, "INSERT INTO docs (id, embedding) VALUES (:id, :v)", map[string]any{
    "id": 1,
    "v":  []float32{0.1, 0.2, 0.3},
})

Context + cancellation

Every method takes context.Context as the first arg. Per-call deadlines work as expected:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
result, err := client.SQL(ctx, "SELECT pg_sleep(10)", nil)
// → err is *NetworkError (context deadline exceeded)

Configuration reference

sc.Config{
    Host:      "localhost",          // default
    Port:      8080,                 // default
    UseHTTPS:  false,                // set true in prod
    APIKey:    "aidb_…",             // OR (Username + Password)
    Token:     "",                   // pre-obtained JWT (skip Login)
    Username:  "",
    Password:  "",
    Timeout:   30 * time.Second,     // default
    Database:  "",                   // sets X-Database header
    Tenant:    "",                   // sets X-Tenant header
    UserAgent: "",                   // default: synapcores-go/<Version>
    Transport: nil,                  // swap-in your own Transport impl
}

Engine compatibility

Tested live against SynapCores AIDB v1.7.0.2.1-ce (image ghcr.io/synapcores/community:latest). The SDK targets the stable /v1/* REST surface — minor engine releases should not break it.

Running tests

go test ./...                                                 # unit tests
go test -tags=integration ./...                               # also run live tests
# integration suite reads SYNAPCORES_HOST/PORT/USER/PASSWORD

License

MIT — see LICENSE.

Documentation

Overview

Package synapcores is the official Go SDK for SynapCores AIDB — the AI-native database that runs SQL, vectors, RAG, and an in-database agentic runtime from a single engine.

Quick start

import (
    "context"
    "fmt"
    sc "github.com/SynapCores/synapcores-go"
)

func main() {
    client, err := sc.New(sc.Config{
        Host:   "localhost",
        Port:   8080,
        APIKey: "aidb_…",
    })
    if err != nil { panic(err) }

    ctx := context.Background()
    result, err := client.SQL(ctx, "SELECT 1 + 1 AS sum", nil)
    if err != nil { panic(err) }
    fmt.Println(result.Scalar())  // 2
}

Two auth paths

Either set Config.APIKey to a Bearer key (recommended for service-to-service), OR set Config.Username + Config.Password and call client.Login(ctx) before any other method.

Parameter binding — how it actually works

The engine's /v1/query/execute route does NOT parse :name / ? / $1 placeholders server-side. The SDK substitutes :name placeholders client-side with proper SQL escaping (single-quote doubling, backslash escape, NULL/TRUE/FALSE literals, [1,2,3] vector literals for []float32 / []float64).

What goes over the wire is fully inlined SQL — you'll never see a params field in the request body. This means:

  • map[string]any is the supported params shape. Keys map to :name in the SQL.
  • Untrusted user input is safe IF passed through params (the SDK escapes it). Never string-concatenate user input into the SQL itself.
  • If a :name in the SQL has no matching key, the SDK returns a QueryError.

Errors

Every error is one of AuthError, QueryError, NetworkError, or EnvelopeError — all unwrapping to ErrSynapCores for the catch-all case. Use errors.As to branch on the specific type.

var qe *sc.QueryError
if errors.As(err, &qe) {
    fmt.Println(qe.StatusCode, qe.Endpoint)
}

Engine compatibility

Tested live against SynapCores AIDB v1.7.0.2.1-ce (current :latest, image ghcr.io/synapcores/community:latest).

Index

Constants

View Source
const Version = "1.0.0"

Version is the SDK version, surfaced in the User-Agent header.

Variables

View Source
var ErrSynapCores = errors.New("synapcores: error")

ErrSynapCores is the sentinel error every typed SDK error unwraps to. Use errors.Is(err, ErrSynapCores) to catch ANY SDK error in one shot; use errors.As with a specific *AuthError / *QueryError / etc. to branch.

Functions

func InlineParams

func InlineParams(sql string, params map[string]any) (string, error)

InlineParams substitutes :name placeholders in sql with the corresponding values from params, quoting each value with proper SQL escaping. Exported so wrappers (e.g. a Gin middleware) can reuse the exact same encoding.

The engine's /v1/query/execute route does NOT parse placeholders server-side; this is how the SDK keeps a parameter-binding-shaped API while still producing wire-compatible SQL.

Returns a QueryError if a :name in sql has no matching key in params, or if any value is of an unsupported type.

Types

type AgentRunOptions

type AgentRunOptions struct {
	Model         string   `json:"model,omitempty"`
	Tools         []string `json:"tools,omitempty"`
	MaxIterations int      `json:"max_iterations,omitempty"`
}

AgentRunOptions tunes an AgentRun call. Marshalled to JSON and passed as the third argument to AGENT_RUN().

type AgentRunResult

type AgentRunResult struct {
	Answer      string
	Persona     string
	Task        string
	TookMs      int
	QueryResult *QueryResult
}

AgentRunResult is the outcome of an AGENT_RUN SQL function call. The engine returns a TEXT cell with the agent's final answer; this wrapper preserves both the answer and the underlying QueryResult.

func (*AgentRunResult) String

func (a *AgentRunResult) String() string

String returns the agent's answer — lets the result satisfy fmt.Stringer so `fmt.Println(agent)` Just Works.

type AuthError

type AuthError struct {
	// contains filtered or unexported fields
}

AuthError — login failed, JWT expired, missing/invalid API key.

func (*AuthError) Error

func (e *AuthError) Error() string

func (*AuthError) Unwrap

func (e *AuthError) Unwrap() error

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the main SDK entry point. Construct with New(); methods are safe for concurrent use across goroutines.

func New

func New(cfg Config) (*Client, error)

New builds a Client from the given config. Validates auth fields up front.

func (*Client) AgentRun

func (c *Client) AgentRun(ctx context.Context, persona, task string, opts *AgentRunOptions) (*AgentRunResult, error)

AgentRun fires the in-DB agentic runtime via the AGENT_RUN SQL function. Pass a nil opts pointer to use engine defaults.

func (*Client) Config

func (c *Client) Config() Config

Config returns the resolved Config (after applying defaults). Useful for debugging — never mutate the returned struct, treat it as read-only.

func (*Client) Embed

func (c *Client) Embed(ctx context.Context, text string) ([]float64, error)

Embed generates an embedding for the given text by running `SELECT EMBED(:t)`. Returns the raw float vector as []float64 (JSON numbers decode to float64 in Go).

func (*Client) ExecRecipe

func (c *Client) ExecRecipe(ctx context.Context, recipeID string, params map[string]any) (*RecipeExecResult, error)

ExecRecipe executes a saved recipe by id (the value returned from ImportRecipe).

func (*Client) ImportRecipe

func (c *Client) ImportRecipe(ctx context.Context, url string) (*RecipeImportResult, error)

ImportRecipe imports a recipe from a URL (e.g. https://synapcores.com/recipes/foo.md).

func (*Client) KNNSearch

func (c *Client) KNNSearch(ctx context.Context, table string, vector []float64, k int, opts KNNOptions) (*QueryResult, error)

KNNSearch runs a top-K cosine-similarity search against a VECTOR column using a literal query vector. Useful when you've already computed the embedding yourself (e.g. cached or batch-precomputed).

func (*Client) Login

func (c *Client) Login(ctx context.Context, username, password string) (string, error)

Login exchanges username + password for a JWT and caches it on the Client. Subsequent calls send the JWT as Bearer. Pass empty strings to use the Username + Password from Config.

func (*Client) Query

func (c *Client) Query(ctx context.Context, sql string, params map[string]any) (*QueryResult, error)

Query is an alias for SQL — mirrors the Node SDK ergonomic surface.

func (*Client) RAGSearch

func (c *Client) RAGSearch(ctx context.Context, query string, opts RAGOptions) (*QueryResult, error)

RAGSearch returns the top-K most-similar rows from a table with a VECTOR column. Builds and runs `SELECT *, COSINE_SIMILARITY(<vec_col>, EMBED(:q)) AS _score FROM <table> [WHERE …] ORDER BY _score DESC LIMIT k`.

For more control build the SQL yourself and call SQL().

func (*Client) SQL

func (c *Client) SQL(ctx context.Context, sql string, params map[string]any) (*QueryResult, error)

SQL executes a SQL statement against /v1/query/execute. :name placeholders in sql are substituted client-side via InlineParams — see the package doc for the why.

func (*Client) Token

func (c *Client) Token() string

Token returns the current Bearer token — either the APIKey or a JWT obtained from Login(). Empty string if neither is set.

type Config

type Config struct {
	// Host is the gateway hostname. Default: "localhost".
	Host string
	// Port is the gateway port. Default: 8080.
	Port int
	// UseHTTPS flips the URL scheme. Default: false (plain HTTP).
	UseHTTPS bool

	// APIKey is the Bearer key (must start with "aidb_" or "ak_"). Either set
	// APIKey OR (Username + Password) — APIKey wins if both are present.
	APIKey string
	// Token is a pre-obtained JWT (skips Login()).
	Token string
	// Username + Password drive the Login() flow.
	Username string
	Password string

	// Timeout is the per-request HTTP timeout. Default: 30s.
	// Per-call deadlines via context.WithTimeout(ctx, …) ALSO apply and win
	// whichever expires first.
	Timeout time.Duration

	// Database sets the X-Database header (optional).
	Database string
	// Tenant sets the X-Tenant header (optional).
	Tenant string

	// UserAgent is the request User-Agent. Default: "synapcores-go/<Version>".
	UserAgent string

	// Transport lets callers swap the HTTP impl — pass nil for the default
	// net/http-backed Transport.
	Transport Transport
}

Config carries every knob the Client honors. Fields are read once at New() time; mutating Config afterwards has no effect.

type EnvelopeError

type EnvelopeError struct {
	// contains filtered or unexported fields
}

EnvelopeError — 2xx response but the {data, meta} envelope was malformed. Usually means we're talking to an unexpected gateway version.

func (*EnvelopeError) Error

func (e *EnvelopeError) Error() string

func (*EnvelopeError) Unwrap

func (e *EnvelopeError) Unwrap() error

type KNNOptions

type KNNOptions struct {
	VecCol string
	Where  string
	Params map[string]any
}

KNNOptions tunes a KNNSearch call.

type NetworkError

type NetworkError struct {
	// contains filtered or unexported fields
}

NetworkError — connection refused, timeout, DNS, TLS handshake error.

func (*NetworkError) Error

func (e *NetworkError) Error() string

func (*NetworkError) Unwrap

func (e *NetworkError) Unwrap() error

type QueryError

type QueryError struct {
	// contains filtered or unexported fields
}

QueryError — engine accepted the request but the query failed (parse / plan / execute / 4xx with structured error body).

func (*QueryError) Error

func (e *QueryError) Error() string

func (*QueryError) Unwrap

func (e *QueryError) Unwrap() error

type QueryResult

type QueryResult struct {
	Rows     []map[string]any
	Columns  []string
	RowCount int
	TookMs   int
	Raw      map[string]any
}

QueryResult is the outcome of a /v1/query/execute call. Rows are zipped into map[string]any keyed by column name.

func (*QueryResult) First

func (q *QueryResult) First() map[string]any

First returns the first row, or nil if the result is empty.

func (*QueryResult) Scalar

func (q *QueryResult) Scalar() any

Scalar returns the first column of the first row — handy for SELECT COUNT(*) or SELECT 1 + 1 style queries. Returns nil for an empty result.

type RAGOptions

type RAGOptions struct {
	Table  string
	VecCol string
	K      int
	Where  string         // raw SQL fragment, e.g. "lang = 'en'"
	Params map[string]any // additional :name bindings for Where
}

RAGOptions tunes a RAGSearch call. Zero value uses sensible defaults (table="documents", vec_col="embedding", k=5).

type RecipeExecResult

type RecipeExecResult struct {
	Steps          []any
	TotalSteps     int
	SucceededSteps int
	TookMs         int
	Raw            map[string]any
}

RecipeExecResult is the outcome of POST /v1/recipes/{id}/execute. A recipe is a multi-step SQL program; the engine returns one entry per step plus aggregate timings.

func (*RecipeExecResult) OK

func (r *RecipeExecResult) OK() bool

OK reports whether every step succeeded.

type RecipeImportResult

type RecipeImportResult struct {
	RecipeID string
	Name     string
	Version  string
	Raw      map[string]any
}

RecipeImportResult is the outcome of POST /v1/recipes/import.

type Request

type Request struct {
	Method  string
	URL     string
	Body    map[string]any // nil → empty body
	Headers map[string]string
	Timeout time.Duration
}

Request is the transport-agnostic outbound payload.

type Response

type Response struct {
	Status int
	Body   map[string]any
	Raw    []byte
}

Response carries the decoded body. Body is nil for empty responses.

type Transport

type Transport interface {
	Do(ctx context.Context, req *Request) (*Response, error)
}

Transport is the HTTP contract the Client depends on. Implement this to swap net/http for a custom client (PSR-style, mock for tests, etc.).

Directories

Path Synopsis
examples
agentrun command
AgentRun — fire the in-DB agentic runtime via AGENT_RUN().
AgentRun — fire the in-DB agentic runtime via AGENT_RUN().
quickstart command
Quickstart — login, run a scalar query, print the result.
Quickstart — login, run a scalar query, print the result.
ragsearch command
RAG search — top-K cosine-similarity over a table with a VECTOR column.
RAG search — top-K cosine-similarity over a table with a VECTOR column.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL