API reference¶
Auto-generated from the source. The public surface lives in spine_core.
Agent¶
spine_core.Agent ¶
A configured agent: a provider, tools, guards, and a middleware onion.
Source code in packages/spine-core/src/spine_core/agent.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 | |
run
async
¶
run(
input: str,
*,
session_id: str | None = None,
should_cancel: Callable[[], bool] | None = None,
) -> Result
Source code in packages/spine-core/src/spine_core/agent.py
stream
async
¶
Yield trace events live as the run executes; final Result lands
on self.last_result.
Source code in packages/spine-core/src/spine_core/agent.py
resume
async
¶
Continue a paused (HITL) run with a human decision.
token is the run's session id (see :meth:_pause). Because it maps
directly to a durable checkpoint, a pause can outlive the process: a
fresh Agent sharing the same checkpoint store resumes it.
Source code in packages/spine-core/src/spine_core/agent.py
as_tool ¶
Expose this agent as a tool another agent can call (sub-agent).
Delegation depth is tracked across calls so an A->B->A cycle is bounded.
Source code in packages/spine-core/src/spine_core/agent.py
run_sync ¶
Result & stop reasons¶
spine_core.Result ¶
Bases: BaseModel
The outcome of an agent.run() / agent.resume() call.
Source code in packages/spine-core/src/spine_core/result.py
spine_core.StopReason ¶
Bases: StrEnum
Source code in packages/spine-core/src/spine_core/result.py
Guards¶
spine_core.Guards ¶
Bases: BaseModel
Declarative limits checked before each step.
Source code in packages/spine-core/src/spine_core/guards.py
check ¶
Return the tripped :class:StopReason, or None to continue.
Checked in priority order so the most specific budget wins the report.
Note: cost/token ceilings are enforced before the next step, so a run can overshoot the budget by at most one model call (the one already in flight when the limit was crossed). They are ceilings that stop runaway spend, not exact-to-the-cent caps.
Source code in packages/spine-core/src/spine_core/guards.py
Messages¶
spine_core.Message ¶
Bases: BaseModel
A single conversational turn.
content may be None on an assistant turn that only carries
tool_calls. tool_call_id links a TOOL result back to its request.
Source code in packages/spine-core/src/spine_core/messages.py
user_parts
classmethod
¶
A user turn carrying multimodal content blocks (text + images).
spine_core.ModelResponse ¶
Bases: BaseModel
What a provider returns from complete.
Source code in packages/spine-core/src/spine_core/messages.py
spine_core.Usage ¶
Bases: BaseModel
Token + cost accounting for one or more model calls.
cost_usd is set by the provider (or a cost-tracking middleware); the
kernel's guards read it directly, so cost ceilings are enforced on real
numbers rather than estimates.
Source code in packages/spine-core/src/spine_core/messages.py
spine_core.ToolCall ¶
Bases: BaseModel
A model's request to invoke a tool. Arguments are raw (unvalidated).
Source code in packages/spine-core/src/spine_core/messages.py
Tools¶
spine_core.tool ¶
tool(
func: Callable[..., Any] | None = None,
*,
name: str | None = None,
description: str | None = None,
approve: bool = False,
) -> Any
Decorator turning a typed function into a :class:Tool.
Usage::
@tool
async def search(query: str) -> str: ...
@tool(approve=True) # one flag enables HITL for this tool
async def transfer_funds(amount: int, to: str) -> str: ...
Source code in packages/spine-core/src/spine_core/tools.py
spine_core.raw_tool ¶
raw_tool(
name: str,
description: str,
parameters: dict[str, Any],
func: Callable[..., Any],
*,
approve: bool = False,
is_async: bool = True,
) -> Tool
Build a :class:Tool from a ready-made JSON schema and callable.
For adapters (MCP, A2A) that already have a tool's schema and a remote
invoker, rather than a typed Python function. Argument validation is
delegated to the remote side; the LLM still sees parameters.
Source code in packages/spine-core/src/spine_core/tools.py
spine_core.Tool
dataclass
¶
A validated, callable capability exposed to the model.
Source code in packages/spine-core/src/spine_core/tools.py
Middleware¶
spine_core.Middleware ¶
Base class with no-op hooks; subclass and override what you need.
Duck-typed objects implementing only some hooks work too — the chain calls a hook only if the middleware defines it.
Source code in packages/spine-core/src/spine_core/middleware.py
spine_core.StepContext ¶
Mutable per-step context shared across the model-call hooks.
Middleware may rewrite messages, swap the provider, or read
response after the model returns.
Source code in packages/spine-core/src/spine_core/middleware.py
spine_core.ToolContext ¶
Mutable per-tool-call context shared across the tool hooks.
Source code in packages/spine-core/src/spine_core/middleware.py
spine_core.ErrorAction ¶
Bases: StrEnum
What on_error instructs the kernel to do with a failed model call.
Source code in packages/spine-core/src/spine_core/middleware.py
spine_core.StopRun ¶
Bases: SpineError
Raised by a middleware hook to end the run with a structured reason.
message becomes the answer for non-error reasons (e.g. a guardrail
explanation) or the error text when reason is :attr:StopReason.ERROR.
Source code in packages/spine-core/src/spine_core/control.py
Providers¶
spine_core.Provider ¶
Bases: Protocol
Anything that can turn messages + tool schemas into a response.
Source code in packages/spine-core/src/spine_core/provider.py
spine_core.StreamingProvider ¶
Bases: Protocol
A provider that can stream token deltas as well as a final response.
Source code in packages/spine-core/src/spine_core/provider.py
spine_core.StreamChunk ¶
Bases: BaseModel
One streamed piece. delta is incremental text; the final chunk carries
the assembled response.
Source code in packages/spine-core/src/spine_core/provider.py
State & memory¶
spine_core.State ¶
Bases: BaseModel
The complete, resumable state of one agent run.
Source code in packages/spine-core/src/spine_core/state.py
spine_core.Memory ¶
Bases: Protocol
Persist and semantically recall snippets across sessions.
Source code in packages/spine-core/src/spine_core/memory.py
spine_core.Embedder ¶
Bases: Protocol
Turns text into a vector. Async so API-backed embedders fit too.
Source code in packages/spine-core/src/spine_core/memory.py
Registries¶
spine_core.register_provider ¶
Register a provider factory under a scheme (e.g. "anthropic").
spine_core.register_middleware ¶
spine_core.register_checkpoint ¶
spine_core.register_memory ¶
Middleware (spine_middleware)¶
spine_middleware.Retry ¶
Retry a failed model call with capped exponential backoff.
Implemented purely via the on_error hook: the kernel re-issues the call
on RETRY and gives up on FAIL. ctx.attempt is the count of
retries already performed this step.
Source code in packages/spine-middleware/src/spine_middleware/retry.py
spine_middleware.ModelFallback ¶
On a provider error, swap to the next provider and retry the call.
Providers are tried in order, per step, until one succeeds or the list is
exhausted (then the kernel fails). Accepts Provider instances or
"scheme:model" strings.
Source code in packages/spine-middleware/src/spine_middleware/fallback.py
spine_middleware.LoopGuard ¶
Detect a stuck agent that keeps calling the same tool with the same args.
Hashes each step's (tool, args) set; if the same signature appears
max_repeats times within the trailing window, the run stops with
:attr:StopReason.LOOP instead of burning the whole step budget.
Source code in packages/spine-middleware/src/spine_middleware/loopguard.py
spine_middleware.CircuitBreaker ¶
Open the circuit after repeated provider failures; fail fast while open.
Counts failures via on_error; once threshold consecutive failures is
reached the breaker opens for cooldown_s, during which before_model
short-circuits the run with a guardrail-style error. A successful model call
resets the count.
Source code in packages/spine-middleware/src/spine_middleware/reliability.py
spine_middleware.RateLimit ¶
Token-bucket rate limit on model calls (per-process).
max_calls per per_s seconds; refills continuously. When empty,
before_model waits for a token. For cross-worker limiting back this with
a shared store (e.g. Redis) — that is a separate distributed backend.
Source code in packages/spine-middleware/src/spine_middleware/reliability.py
spine_middleware.CostTracking ¶
Compute cost_usd from token counts and a per-1M-token price.
Runs in after_model (before the kernel banks usage), so the computed
cost feeds straight into the cost guard. By default it only fills a cost the
provider left at zero; set overwrite=True to always recompute.
Source code in packages/spine-middleware/src/spine_middleware/cost.py
spine_middleware.Cache ¶
In-memory prompt/response cache with optional TTL and size bound.
A hit returns a deep copy (so downstream mutation can't corrupt the entry)
and, by default, zeroes usage — a cached response is free, which lets cost
guards and reports reflect the saving. Pass a dict-like store to share a
cache across agents.
Source code in packages/spine-middleware/src/spine_middleware/cache.py
spine_middleware.Compaction ¶
Trim long histories before each model call, non-destructively.
When the message count exceeds max_messages, system messages plus the
last keep_last turns are kept and the middle is replaced by one synthetic
note. ctx.messages is reassigned (not mutated), so the full history stays
in durable state and is re-compacted fresh each step. A leading orphan tool
result is dropped to keep the trimmed window valid for providers.
Source code in packages/spine-middleware/src/spine_middleware/compaction.py
spine_middleware.StructuredOutput ¶
Validate the final answer against a Pydantic schema, repairing on failure.
On an invalid final answer it feeds the validation error back as a new turn
(capped at max_repairs) via force_continue; on success the parsed
object is stashed in state.scratch[key]; when repairs are exhausted the
run fails loud with :attr:StopReason.ERROR.
Source code in packages/spine-middleware/src/spine_middleware/structured.py
spine_middleware.ToolTimeout ¶
Apply a wall-clock timeout to tool execution.
Sets ctx.timeout_s in before_tool; the kernel cancels the tool with
anyio.fail_after and surfaces the timeout as a tool error to the model.
Restrict to specific tools with tools=[...].
Source code in packages/spine-middleware/src/spine_middleware/tooling.py
spine_middleware.ToolOutputTruncation ¶
Cap huge tool outputs before they re-enter the context window.
Source code in packages/spine-middleware/src/spine_middleware/tooling.py
spine_middleware.Idempotency ¶
De-duplicate side-effecting tool calls by an idempotency key.
On a repeated (tool, args) the cached result is replayed and the tool is
not executed again (ctx.skip). Restrict to side-effecting tools with
tools=[...] and share store across processes for cross-worker safety.
Source code in packages/spine-middleware/src/spine_middleware/reliability.py
spine_middleware.Sandbox ¶
Run sync tools in a resource-limited child process.
Restrict to specific tools with tools=[...] (default: all sync tools).
Source code in packages/spine-middleware/src/spine_middleware/sandbox.py
spine_middleware.PIIRedaction ¶
Redact PII from tool outputs (and so from traces) and the final answer.
Order matters: redacting in after_tool happens before the kernel records
the tool result in the trace, so secrets never reach the trace either.
Source code in packages/spine-middleware/src/spine_middleware/guardrails.py
spine_middleware.PromptInjectionScreen ¶
Screen untrusted tool output for prompt-injection attempts.
action="annotate" (default) prepends a caution banner so the model treats
the output as data; action="block" stops the run with a guardrail reason.
Source code in packages/spine-middleware/src/spine_middleware/guardrails.py
spine_middleware.ContentPolicy ¶
Block a run on banned content in the user input or the final answer.
Provide banned substrings/patterns and/or a validate(text) -> bool
predicate (return False to block). Applied to input (before_model)
and/or output (after_model).
Source code in packages/spine-middleware/src/spine_middleware/guardrails.py
spine_middleware.TenantBudget ¶
Enforce a cumulative per-tenant spend ceiling (cost and/or tokens).
Source code in packages/spine-middleware/src/spine_middleware/multitenancy.py
spend ¶
spine_middleware.MemoryRecall ¶
Search a :class:Memory for context and persist the exchange.
Source code in packages/spine-middleware/src/spine_middleware/memory.py
spine_middleware.Recorder ¶
Capture model responses and tool results during a live run.
Source code in packages/spine-middleware/src/spine_middleware/replay.py
recording ¶
Serialize the recording (JSON-friendly) for storage/replay.
Source code in packages/spine-middleware/src/spine_middleware/replay.py
spine_middleware.Replayer ¶
Serve recorded outputs in order; never calls the provider or tools.
Accepts a :class:Recorder or its recording() dict. When the recording
is exhausted it falls through to the live provider/tool (so a longer run than
was recorded still progresses).
Source code in packages/spine-middleware/src/spine_middleware/replay.py
Backends (spine_backends)¶
spine_backends.SQLiteCheckpoint ¶
Durable :class:~spine_core.checkpoint.CheckpointStore over SQLite.
Source code in packages/spine-backends/src/spine_backends/sqlite.py
revision
async
¶
Current optimistic-lock revision for a session (0 if absent).
spine_backends.RedisCheckpoint ¶
Durable :class:~spine_core.checkpoint.CheckpointStore over Redis.
Source code in packages/spine-backends/src/spine_backends/redis.py
spine_backends.PostgresCheckpoint ¶
Durable :class:~spine_core.checkpoint.CheckpointStore over Postgres.
Source code in packages/spine-backends/src/spine_backends/postgres.py
spine_backends.InMemoryVectorMemory ¶
Process-local vector memory; recall by embedding cosine similarity.
Source code in packages/spine-backends/src/spine_backends/memory.py
spine_backends.BufferMemory ¶
Non-semantic recency memory: search returns the most recent records.
Cheap and predictable when similarity is not needed (e.g. a rolling notes
buffer). search ignores the query text.
Source code in packages/spine-backends/src/spine_backends/memory.py
spine_backends.PgVectorMemory ¶
Memory over Postgres + pgvector with cosine-distance recall.
Source code in packages/spine-backends/src/spine_backends/pgvector.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
spine_backends.HashEmbedder ¶
Deterministic, offline hashed bag-of-features embedding (L2-normalized).
Good for tests and small/offline deployments; not as expressive as a learned
model. Swap for OpenAIEmbedder (or your own) in production.
Source code in packages/spine-backends/src/spine_backends/embeddings.py
spine_backends.OpenAIEmbedder ¶
Embeds via the OpenAI embeddings API (lazy client; injectable for tests).
Source code in packages/spine-backends/src/spine_backends/embeddings.py
Providers (spine_providers)¶
spine_providers.OpenAIProvider ¶
A Spine provider backed by OpenAI Chat Completions (lazy SDK client).
Source code in packages/spine-providers/src/spine_providers/openai.py
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | |
spine_providers.AnthropicProvider ¶
A Spine provider backed by Anthropic's Messages API.
The SDK client is created lazily on first call, so constructing the provider
(e.g. via the registry) never requires an API key or a network round-trip.
Inject client to test without the SDK.
Source code in packages/spine-providers/src/spine_providers/anthropic.py
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | |
Eval (spine_eval)¶
spine_eval.evaluate
async
¶
evaluate(
agent: Agent,
dataset: Dataset,
scorers: list[Scorer] | None = None,
*,
concurrency: int = 1,
) -> EvalReport
Evaluate agent over dataset; each case runs in a fresh session.
concurrency bounds simultaneous cases. Keep it at 1 when the provider or
a scorer is not safe to call concurrently.
Source code in packages/spine-eval/src/spine_eval/runner.py
spine_eval.load_dataset ¶
Load a Dataset from a .yaml/.yml or .json file.
Accepts either a top-level {"cases": [...]} mapping or a bare list of
cases. Each case needs at least input; id defaults to its position.
Source code in packages/spine-eval/src/spine_eval/loader.py
spine_eval.EvalReport ¶
Bases: BaseModel
Aggregate metrics across all cases plus the per-case detail.
Source code in packages/spine-eval/src/spine_eval/models.py
spine_eval.Case ¶
Bases: BaseModel
One evaluation case: an input and (optionally) what a good answer contains.
Source code in packages/spine-eval/src/spine_eval/models.py
spine_eval.LLMJudge ¶
Grade the answer with another model (LLM-as-judge).
Source code in packages/spine-eval/src/spine_eval/scorers.py
Orchestration (spine_orchestration)¶
spine_orchestration.Sequential ¶
Run agents in order, feeding each answer as the next agent's input.
Source code in packages/spine-orchestration/src/spine_orchestration/patterns.py
spine_orchestration.supervisor ¶
supervisor(
model: str,
workers: dict[str, Agent],
*,
system: str | None = None,
**kwargs: object,
) -> Agent
Build a supervisor agent that delegates to workers as tools.
Source code in packages/spine-orchestration/src/spine_orchestration/patterns.py
spine_orchestration.Handoff ¶
A team of agents that can transfer the conversation to a named peer.
Each agent is given transfer_to_<peer> tools. When an agent calls one,
its turn ends and the named peer takes over with the original task. Bounded
by max_handoffs so a transfer cycle can't run forever.
Source code in packages/spine-orchestration/src/spine_orchestration/patterns.py
Adapters¶
spine_mcp.MCPToolset ¶
Connects to one MCP server and exposes its tools to a Spine agent.
Usage::
async with MCPToolset(url="https://mcp.example.com/mcp") as mcp:
agent = Agent("anthropic:claude-sonnet-4-6", tools=await mcp.load_tools())
await agent.run("...")
Pass session= to drive an existing/mock ClientSession (used in tests).
Source code in packages/spine-mcp/src/spine_mcp/toolset.py
load_tools
async
¶
Connect (if needed), list the server's tools, and wrap them.
Source code in packages/spine-mcp/src/spine_mcp/toolset.py
spine_a2a.A2AAgent ¶
A handle to a remote A2A agent reached over JSON-RPC.
Source code in packages/spine-a2a/src/spine_a2a/client.py
spine_otel.OTelMiddleware ¶
Bridges Spine's hook points to OpenTelemetry spans.
Construct with a configured Tracer (or rely on the global provider).
One instance is safe to share across concurrent runs: per-run state is keyed
by session id, and tool spans by session:tool_call_id.
Source code in packages/spine-otel/src/spine_otel/middleware.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | |