Python client SDK for PromptLedger — prompt registry, execution tracking, and lineage
Project description
promptledger-client
Python client SDK for PromptLedger — a prompt registry, execution tracking, and lineage service for GenAI applications.
Installation
pip install promptledger-client
Quick Start
import os
from promptledger_client import AsyncPromptLedgerClient, RegistrationPayload
async def main():
async with AsyncPromptLedgerClient(
base_url=os.environ["PROMPTLEDGER_API_URL"],
api_key=os.environ["PROMPTLEDGER_API_KEY"],
) as client:
# 1. Register prompts at startup (idempotent)
await client.register_code_prompts([
RegistrationPayload(
name="my_agent.turn",
template_source="You are a research agent. {{instructions}}",
)
])
# 2. Execute — PL calls the LLM, logs the span, returns result + span_id
state = {"trace_id": "my-run-001", "phase_span_id": "phase-abc"}
result = await client.execute(
prompt_name="my_agent.turn",
messages=[
{"role": "system", "content": "You are a research agent."},
{"role": "user", "content": "Summarise the key findings."},
],
mode="mode2",
state=state, # reads trace_id/phase_span_id, writes last_span_id
agent_id="researcher",
max_tokens=512,
)
print(result.response_text)
print(f"span_id: {result.span_id}") # use as parent for child spans
print(f"cost: ${result.telemetry.total_cost}")
print(f"last_span_id: {state['last_span_id']}") # written back by execute()
Core Methods
| Method | When to use |
|---|---|
execute() |
All LLM calls — Mode 1 and Mode 2. PL makes the LLM call, creates the span automatically, returns response_text + span_id. |
register_code_prompts() |
At service startup to register or version-track prompt templates defined in code. Idempotent. |
log_span() |
Low-level span logging for non-LLM steps: workflow phase spans, guardrail child spans, tool call spans. |
get_trace_summary() |
After a workflow run — retrieve aggregated token usage and cost for a full trace. |
health() |
Health check — returns True if the PromptLedger API is reachable. |
execute() Reference
result = await client.execute(
prompt_name="my_agent.turn", # required — links execution to registered prompt
messages=[...], # Mode 2: caller-constructed messages array
variables={...}, # Mode 1: template variables (PL renders template)
mode="mode2", # "mode1" or "mode2" (default: "mode2")
state=state, # optional — reads/writes span IDs
agent_id="researcher", # optional — tagged on the auto-created span
max_tokens=512,
temperature=0.7,
)
# result.response_text: str
# result.span_id: str | None — ID of the span created during execution
# result.execution_id: str
# result.telemetry.prompt_tokens: int
# result.telemetry.completion_tokens: int
# result.telemetry.latency_ms: int
# result.telemetry.total_cost: float | None
state dict behaviour
If state is provided:
state["trace_id"]→span.trace_idstate.get("phase_span_id")→span.parent_span_id- After execution:
state["last_span_id"] = result.span_id
This eliminates manual span ID threading across Lobster workflow steps or any stateless multi-step pipeline.
Span Hierarchy Pattern
from promptledger_client.models import SpanPayload
# Phase-level parent spans — use log_span() directly (no LLM call)
state["phase_span_id"] = await client.log_span(SpanPayload(
trace_id=state["trace_id"],
name="open_discussion",
kind="workflow.phase",
status="ok",
))
# Agent LLM turns — use execute() (PL makes LLM call, auto-creates span)
result = await client.execute(
prompt_name="paper_agent_discussion",
messages=[...],
mode="mode2",
state=state, # parented under phase_span_id automatically
agent_id="paper_1",
)
# Guardrail child spans — use log_span() with parent = the turn span
await client.log_span(SpanPayload(
trace_id=state["trace_id"],
parent_span_id=state["last_span_id"], # child of the turn, not the phase
agent_id="guardrail",
name="guardrail_check",
kind="guardrail.check",
status="ok",
attributes={"violations_found": 0},
))
Context Helpers (single-process async only)
For simple in-process async workflows (not Lobster/Celery/serverless):
from promptledger_client.context import start_trace, current_trace_id, set_parent_span_id
Warning: Do not use contextvars across Lobster workflow steps, Celery tasks, or Railway sleeping cycles — they do not survive process boundaries. Use the
statedict pattern withexecute()instead.
Exceptions
| Exception | When raised |
|---|---|
AuthError |
401 — invalid or missing API key |
NotFoundError |
404 — prompt or trace not found |
PromptLedgerError |
400, 5xx — validation errors or server errors |
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 promptledger_client-0.2.0.tar.gz.
File metadata
- Download URL: promptledger_client-0.2.0.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93f41e4aa9049835d19cb42ffbfa80f545ebe59a50662a47f5aecbaa596b29d2
|
|
| MD5 |
6a64b264421f4d72d7578bdfe787a71b
|
|
| BLAKE2b-256 |
dc169eaa568eac18de7ba5a0a8c3c46c0c6245b1feed1a214e9b1cd1a52b13c0
|
File details
Details for the file promptledger_client-0.2.0-py3-none-any.whl.
File metadata
- Download URL: promptledger_client-0.2.0-py3-none-any.whl
- Upload date:
- Size: 9.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64d445c3b1e8a6d8236bad33a29791dac33c190e238f752b7fd44f8cd2413a89
|
|
| MD5 |
0157239efbea8542371a64095c2c3d89
|
|
| BLAKE2b-256 |
00ffe2eb3d1651479807bd1dca315f7fc9536d0c25fb1d6829d72990f7a8206d
|