Sparsi provides a comprehensive toolkit for building efficient, reliable agentic tools. This catalog of deterministic and AI operators is designed to minimize model dependencies—maximizing pre-written logic to reduce cost and eliminate hallucinations in your production workflows.
operators are deterministic; the AI operators are the small, scoped set you reach for only where genuine judgment is required.Every operator available, organized by category. Deterministic ops run as pure Go functions, testable without a model. AI ops call Claude or Gemini and support structured retries. The library also ships a retrieval layer (Retriever + RetrieveOp + citation validation), a repair wrapper (WithRepair) for AI-assisted recovery of deterministic ops, and pluggable factories for AI / embedding credentials.
These operators call Claude and return structured outputs with retries. Each accepts a natural-language operation or predicate param and produces a typed Result. Model reasoning is captured via WithReasoningLog when needed.
AIClassifyMultiLabelOp
AI
Classifies text into zero or more categories from a fixed label set.
AIScoreOp
AI
Scores text against a criterion on a 0–1 scale.
AIBoolOp
AI
Answers a yes/no question about text. Returns true or false.
AIBestMatchOp
AI
Selects the single best-matching candidate for a query.
AIRerankOp
AI
Reranks a list of candidates by relevance. Returns a permutation of indices.
AIExtractStringSliceOp
AI
Extracts a list of items from unstructured text as a string slice.
AIExtractMapOp
AI
Extracts structured key-value pairs from unstructured text.
AIParseNumberOp
AI
Converts natural-language or informal number text to a float64.
AISummarizeOp
AI
Summarizes a list of strings into a single output string.
AIComputeStringToStringOp
AI
General-purpose string→string AI transformation.
AIComputeMathOperandsToFloat64Op
AI
AI-powered fallback for binary float64 math operations.
ModeSelectOp
AI
Single-label classifier — always returns exactly one category.
AddFloatOpA + B (float64)
SubFloatOpA − B (float64)
MulFloatOpA × B (float64)
DivFloatOpA ÷ B (float64, errors on zero)
PowFloatOpA ^ B (float64)
ModFloatOpFloating-point remainder of A / B
AddIntOpA + B (int)
SubIntOpA − B (int)
MulIntOpA × B (int)
DivIntOpA ÷ B (int, truncates, errors on zero)
PowIntOpA ^ B (int, errors on negative exponent)
ModIntOpInteger remainder of A / B
ClampFloatOpClamp float64 to [Min, Max]
ClampIntOpClamp int to [Min, Max]
SumFloatOpSum all elements of a float64 slice
SumIntOpSum all elements of an int slice
MinFloatOpMinimum value in a float64 slice
MinIntOpMinimum value in an int slice
MaxFloatOpMaximum value in a float64 slice
MaxIntOpMaximum value in an int slice
RoundOpRound float64 to nearest integer
IntToFloat64OpWiden int wire to float64
Float64ToIntOpTruncate float64 wire to int
PackMathOperandsOpPack two float64 inputs into a MathOperands struct
StringConcatOpConcatenate two strings — A + B
StringToLowerOpConvert string to lower case
StringSplitOpSplit string by separator into a slice
StringLookupOpStatic key→value string lookup table
RegexMatchOpTest if string matches a Go regex pattern
RegexExtractOpExtract first match or capture group
IfFloatGtOpA > B
IfFloatLtOpA < B
IfFloatEqOpA == B
IfFloatGeOpA ≥ B
IfFloatLeOpA ≤ B
BetweenFloatOpMin ≤ Value ≤ Max (inclusive range)
IfStringEqOpA == B (exact match)
IfStringContainsOpA contains B as substring
IfStringHasPrefixOpA starts with B
IfStringHasSuffixOpA ends with B
IfStringRegexMatchOpInput matches a Go regex pattern
SelectStringOpTernary select: Cond ? IfTrue : IfFalse (string)
SelectFloat64OpTernary select: Cond ? IfTrue : IfFalse (float64)
SelectIntOpTernary select: Cond ? IfTrue : IfFalse (int)
SelectBoolOpTernary select: Cond ? IfTrue : IfFalse (bool)
SwitchStringOpMap a key to a value using a case table
DefaultStringOpValue if non-empty, otherwise Default
DefaultFloat64OpValue if non-nil, otherwise Default (float64)
DefaultIntOpValue if non-nil, otherwise Default (int)
SliceLenOpNumber of elements in a string slice
SliceAtOpElement at a fixed index
SliceFirstOpFirst element (errors if empty)
SliceLastOpLast element (errors if empty)
SliceContainsOpTest if slice contains a value
SliceJoinOpJoin slice elements with a separator
SliceFilterEqOpKeep only elements equal to a value
SliceTopKOpIndices of top-K scores, descending
These operators turn Model Context Protocol servers into first-class workflow steps. They speak the standard MCP wire protocol over either stdio (a local subprocess like npx @playwright/mcp or uvx-launched servers) or streamable http (a remote endpoint such as https://docs.mcp.cloudflare.com/mcp) — so any MCP-compliant server, local or remote, public or private, drops into a Sparsi graph without custom glue code.
Because these ops use the protocol's own tools/list and tools/call verbs, any reference material that documents an existing MCP server and its tools is directly usable when wiring Sparsi. Hand the server's tool catalog (names, JSON-Schema arg shapes, return types) to your editor or to Claude alongside the Sparsi graph and it has everything needed to bind a tool call to a vertex — no SDK adapter to write, no per-server client to vendor.
A built-in warm-replenish session pool (pool_size, stdio only in v1) keeps cold-start off the critical path when many vertices share the same server spec. Pair with library.ShutdownMCPPool from main() so pre-started subprocesses drain at exit.
MCPCallOp[In, Out]
Integration
Invoke a single MCP tool as one workflow step. Each Run opens a fresh session, completes the handshake, calls one tool, and tears the session down. Default dispatch decodes string, float64, int, bool, slice and map shapes, and any JSON-decodable struct (structured content preferred when the server emits it). Implement MCPArgsFormatter / MCPResponseParser for full control.
Params: transport, command/args/env (stdio) or url/headers (http), tool_name, init_timeout_ms, call_timeout_ms, max_retries, pool_size, pool_prewarm.
MCPScriptOp[In, Out]
Integration
Orchestrate a sequence of MCP tool calls against a single, long-lived session. Use this when one workflow step needs multiple calls that share server-side state — a browser session navigating then typing then snapshotting, a database cursor, an open file handle. The user-supplied Script closure runs exactly once per Run, receives a live MCPSession, and is free to CallTool any number of times in any order.
Same params as MCPCallOp, minus tool_name (the script chooses tools at call time). Only session-start failures are retried; Script runs at most once per Run.
Two operators wire a registered library.Retriever into a graph; one filters LLM-emitted citations against an allow-list. The Retriever interface itself is backend-agnostic — implement it once over BM25, a vector store, or a hosted search service, then any of these ops works. Vertices that embed (vector-store retrievers) call library.ResolveEmbeddingClient instead of reading env vars directly, so a registered EmbeddingClientFactory controls where the credential actually comes from.
See the retrieval concept guide for the full data flow, security guidance, and citation-validation pattern.
RetrieveOp
Retrieval
Top-k retrieval from a registered Retriever. Emits Documents []Document and Texts []string in parallel.
Params: k, retriever_id, credential_ref, client_factory_id, api_factory_timeout_ms, embed_timeout_ms.
RetrieveWithFiltersOp
Retrieval
Same as RetrieveOp plus a Filters *map[string]string input wire and a static_filters param. Runtime wins on key collision. Filters install on ctx via library.WithRetrievalFilters.
Use when tenant id / locale / category come from upstream auth, classifier, or planner ops.
ValidateCitationsOp
Security
Filters LLM-emitted citations against an allow-list. Partitions into Accepted (membership-tested, deduped) and Rejected (likely hallucinations).
Build the allow-list from retrieved documents, not the full loaded corpus — otherwise a model that hallucinates the name of a real-but-unretrieved file slips past.
library.WithRepair turns a deterministic op into an LLM-assisted-recovery op. When the inner op returns *library.ErrRepairable carrying a self-contained prompt, the wrapper forwards the prompt to an LLM, parses the response back into the named input field's element type via UnmarshalRepair, writes it back, and re-runs the inner op. Bounded by max_attempts; non-repairable errors propagate unchanged.
See the repair concept guide for the inner-op contract, when (and when not) to use it, and the canonical wiring pattern.
library.RegisterWithRepair[Inner]
Registration
Generic constructor. Pass the registered name, a factory that returns a fresh inner op, and a RepairConfig (InputField, MaxAttempts, PromptPrefix, PromptSuffix, Provider, Model, MaxTokens).
Vertex-level params override: max_attempts, provider, model, max_tokens, credential_ref, client_factory_id.
*library.ErrRepairable
Inner contract
Typed error inner ops return to opt in to repair. Carries a Prompt string (the self-contained instruction for the LLM) and an underlying Cause error for logging and errors.Unwrap.
The input type implements library.RepairableInput: UnmarshalRepair(string) error.
Every AI op resolves its provider SDK client through an AIClientFactory; every vector-store retriever resolves its embedding client through an EmbeddingClientFactory. Both interfaces let you source credentials from Vault, AWS Secrets Manager, workload identity, an egress proxy, or per-tenant vaults without changing graph code.
See the credential-routing guide for wiring patterns (process default vs registered-by-id vs per-vertex ref) and security guidance.
library.AIClientFactory
AI clients
Two methods: Anthropic(ctx, ref) (*anthropic.Client, error) and Gemini(ctx, ref) (*genai.Client, error). The bundled EnvAIClientFactory reads CLAUDE_API_KEY / GEMINI_API_KEY from the environment.
Wire via SetDefaultAIClientFactory, RegisterAIClientFactory(id, f), and the per-vertex client_factory_id + credential_ref params.
library.EmbeddingClientFactory
Embeddings
One method: Embedder(ctx, provider, model, ref) (EmbeddingClient, error). The bundled EnvEmbeddingClientFactory only supports provider="gemini" — register a custom factory for Voyage, OpenAI, Cohere, Vertex, or in-house embedders.
Retrievers call library.ResolveEmbeddingClient(ctx, provider, model); the framework hands them the right client based on ctx + the registry.
builtin.ContextValFactory[T](key) creates a typed operator factory that reads a value of type T from context.Context at graph execution time. This is the standard pattern for injecting per-run inputs — ticket text, API responses, weights — into a workflow without baking values into the graph at build time.
builtin.ContextValFactory[T](key)
Generic factory. Register once under a name in init(); inject the value via context.WithValue before each run. Supports any type: string, float64, int, bool, []string.
type ticketBodyKey struct{}
// Register in init()
operator.RegisterOpFactory("body_const",
builtin.ContextValFactory[string](ticketBodyKey{}))
// Wire into graph — no Params needed
Vertex("body_const").Op("body_const").
Output("Result", "ticket_body")
// Inject value at run time
ctx := context.WithValue(ctx, ticketBodyKey{}, ticketBody)
.Condition() to gate a ContextVal vertex so only the matching branch emits its valuestring, float64, int, bool, []stringThe graph stays immutable and reusable across calls. Different inputs are injected each run via context — the compiled graph is never rebuilt.