Python SDK client for the Keystone agent evaluation + sandboxed-execution platform
Project description
Keystone SDK for Python
Python client for the Keystone agent evaluation + sandboxed-execution platform. Shares a single source of truth with the TypeScript and Go SDKs — byte-identical cost estimates and prompt rendering across all three.
Install
pip install polarity-keystone
Zero external runtime dependencies — uses only urllib from the standard
library.
60-second quick start: Eval()
The shortest path from "I have an agent" to "I have an evaluation":
from polarity_keystone import Eval, Factuality, AnswerRelevancy
result = Eval(
"summarisation-quality",
data=[
{"input": "Long article about whales...", "expected": "Whales are mammals."},
{"input": "Article about Java GC...", "expected": "Java GC reclaims memory."},
],
task=lambda input: my_agent(input), # your agent / prompt
scores=[
Factuality(model="paragon-fast"),
AnswerRelevancy(),
],
max_concurrency=4,
)
print(result.summary) # p50/p95/mean per scorer
If KEYSTONE_API_KEY is set, the run is also recorded to your dashboard;
otherwise it stays purely local. Same shape in TypeScript and Go.
Sandbox-as-a-tool ergonomics
create() / get() / list() return a bound SandboxHandle so an agent
loop can call the sandbox without threading the ID:
sb = ks.sandboxes.create(spec_id="spec-123")
sb.exec("python script.py")
sb.write("/tmp/input.json", json.dumps(payload))
out = sb.read("/tmp/output.json")
diff = sb.diff()
sb.destroy()
Same pattern on ExperimentHandle and AgentSnapshotHandle:
exp = ks.experiments.create("nightly", spec_id="s")
results = exp.run_and_wait(scores=[Factuality(), ExactMatch(expected_key="expected")])
cmp = exp.compare(other_exp) # handle or string ID
m = exp.metrics()
snap = ks.agents.upload("codex", "./bundle", entrypoint=["python3", "agent.py"])
snap.delete()
The handles delegate field access to the underlying dataclass, so reading
sb.id, exp.status, snap.version keeps working unchanged. The old
service-level methods (ks.sandboxes.run_command(id, …),
ks.experiments.run(id)) stay too — handle methods just call them.
Auto-instrument every LLM client at once
from polarity_keystone import auto_instrument
auto_instrument(sandbox_id=os.environ.get("KEYSTONE_SANDBOX_ID"))
# Patches every installed provider in-place. Subsequent OpenAI/Anthropic/
# Mistral/Google/LiteLLM/Claude Agent SDK/DSPy/LangChain calls auto-trace.
Wraps OpenAI, Anthropic, Mistral, Google GenAI, LiteLLM, Claude Agent SDK, DSPy, LangChain in one call — every prompt, token count, and tool call shows up in your dashboard with no other code changes.
Manual tracing when you want it
from polarity_keystone import traced
# 1. Decorator
@traced
def fetch_user(uid: str) -> dict:
return db.users.find(uid)
# 2. Named decorator
@traced(name="planning-phase")
def plan(prompt: str) -> str:
return llm.complete(prompt)
# 3. Context manager
with traced(name="embed-doc"):
openai.embeddings.create(...)
Spans automatically nest using contextvar-based parent linking — no need to plumb a context object through your code.
What's in the SDK
- 9 client services —
sandboxes,specs,experiments,alerts,agents,datasets,scoring,export,prompts - 3 bound handles —
SandboxHandle,ExperimentHandle,AgentSnapshotHandlewith delegated methods - 29 built-in scorers across 5 families:
- Heuristic (6):
ExactMatch,Levenshtein,NumericDiff,JSONDiff,JSONValidity,SemanticListContains - LLM-judge (9):
Factuality,Battle,ClosedQA,Humor,Moderation,Summarization,SQLJudge,Translation,Security - RAG (8):
ContextPrecision,ContextRecall,ContextRelevancy,ContextEntityRecall,Faithfulness,AnswerRelevancy,AnswerSimilarity,AnswerCorrectness - Embedding (1):
EmbeddingSimilarity - Sandbox invariants (5):
FileExists,FileContains,CommandExits,SQLEquals,LLMJudge
- Heuristic (6):
@Scorerdecorator — wrap any(scenario) -> scorefunctionEval(name, data, task, scores)— Braintrust-style one-call eval primitive@traceddecorator + context manager — auto-capture spans with contextvar-based propagation- Client wrapping —
ks.wrap(openai_client, sandbox_id=...)adds transparent trace reporting (sync / async / streaming) auto_instrument()— single call patches every installed provider (OpenAI, Anthropic, Mistral, Google GenAI, LiteLLM, Claude Agent SDK, DSPy, LangChain)- Prompt management —
ks.prompts.create(slug, template)/ks.prompts.get(slug)/Prompt.render(**vars)with server-side audit + byte-identical local renderer - Bulk export —
ks.export.traces(...),.spans(...),.scenarios(...),.scores(...)auto-paginate;ks.export.experiment(id)for full JSON or NDJSON dumps - OpenTelemetry bridge —
wrap()emitsgen_ai.*metadata;register_otel_flush()piggy-backs on program shutdown
Versioning
Semver. 0.x = alpha/beta while the API shape settles.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file polarity_keystone-0.2.5.tar.gz.
File metadata
- Download URL: polarity_keystone-0.2.5.tar.gz
- Upload date:
- Size: 80.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81f6a8d04d48b3b3046ede337f5eef85d382466b745347b748cdefdebfaff12f
|
|
| MD5 |
dcd9c0286f9606acf14789eb82a2d08e
|
|
| BLAKE2b-256 |
e5e381f3fe5b07ae60863e5cdfd595a45e430576396a5db00ccc29d329b50803
|
File details
Details for the file polarity_keystone-0.2.5-py3-none-any.whl.
File metadata
- Download URL: polarity_keystone-0.2.5-py3-none-any.whl
- Upload date:
- Size: 81.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b9d279a9695281aca73bdc53674b5b29e1612c831d65357d3b974ad4bd08238
|
|
| MD5 |
16f660301cd77f0537982759368516c2
|
|
| BLAKE2b-256 |
ddd02be3b950497e19df82956be46fad0628ca3fdd08f0e5ba72fa791ab16550
|