SDK Reference¶
Complete API reference for the Coalex SDKs:
- Python SDK (
coalexv1.9.0) -- published on PyPI - TypeScript SDK (
@coalex-ai/sdkv1.7.0) -- published on npm
Installation¶
See Installation for all extras and framework-specific options.
Usage Pattern¶
Every Coalex integration follows the same pattern:
graph LR
A[register] --> B[auto_instrument]
B --> B2[declare_agent]
B2 --> C[coalex_context]
C --> D[evaluate]
D --> E[resolve]
1. Register -- connect to Coalex¶
Call once at application startup. Configures the global TracerProvider with an OTLP exporter pointing at your Coalex proxy.
2. Auto-instrument -- patch LLM frameworks¶
Automatically patches all installed LLM libraries (OpenAI, LangChain, LlamaIndex, etc.) to emit OpenInference spans.
3. Wrap with context -- tag every span¶
All spans created inside a coalex_context block inherit the agent metadata, making them queryable in the dashboard.
4. Declare agent -- register before traces¶
Pre-register your agent so the dashboard recognizes it before traces arrive.
5. Evaluate -- assess risk¶
Submit agent output for automated risk assessment. Low-risk outputs are auto-approved; high-risk ones are escalated for human review.
6. Resolve -- human-in-the-loop¶
When an output is escalated, a human reviewer approves, rejects, or corrects it.
Public API¶
Core Functions¶
| Function | Description | Reference |
|---|---|---|
register() |
Configure the OTLP exporter and global TracerProvider | Details |
declare_agent() |
Pre-register an agent before traces arrive | Details |
coalex_context() |
Create a parent span with agent metadata | Details |
auto_instrument() |
Patch all installed LLM frameworks | Details |
get_prompt() |
Fetch prompt templates from Prompt Vault (Python) | Details |
evaluate() |
Submit output for risk-based evaluation | Details |
resolve() |
Submit human review for an escalation | Details |
Data Classes¶
| Class | Description | Reference |
|---|---|---|
AgentDeclaration |
Result of declare_agent() |
Details |
PromptVersion |
Result of get_prompt() |
Details |
EvaluationDecision |
Result of evaluate() |
Details |
ResolutionResult |
Result of resolve() |
Details |
MetricResult |
Per-field metric scores | Details |
Extension Decorators / Wrappers¶
Instrument custom pipeline steps without LlamaIndex or LangChain. See Extensions.
| Python Decorator | TypeScript Wrapper | Span Kind | Reference |
|---|---|---|---|
@retrieval_span |
retrievalSpan() |
RETRIEVER |
Details |
@embedding_span |
embeddingSpan() |
EMBEDDING |
Details |
@reranker_span |
rerankerSpan() |
RERANKER |
Details |
@tool_span |
toolSpan() |
TOOL |
Details |
@guardrail_span |
guardrailSpan() |
GUARDRAIL |
Details |
Full Example¶
import os
import coalex
from coalex.ext.retrieval import retrieval_span, Document
from openai import OpenAI
# 1. Register
coalex.register(
endpoint=os.environ["COALEX_ENDPOINT"],
api_key=os.environ["COALEX_API_KEY"],
service_name="medical-agent",
)
# 2. Auto-instrument
coalex.auto_instrument()
# 3. Declare agent (recommended)
coalex.declare_agent(agent_id="medical-bot", display_name="Medical Bot")
# 4. Custom retrieval step
@retrieval_span(name="knowledge_base", query_arg="query")
def retrieve(query: str) -> list[Document]:
# Your retrieval logic here
return [Document(content="...", id="doc-1", score=0.95)]
# 5. Agent invocation
client = OpenAI()
with coalex.coalex_context(agent_id="medical-bot", request_id="req-456"):
docs = retrieve(query="What are the side effects?")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"Based on: {docs[0].content}"}],
)
answer = response.choices[0].message.content
# 6. Evaluate
decision = coalex.evaluate(
request_id="req-456",
input={"question": "What are the side effects?"},
output={"answer": answer},
metrics={"answer": ["f1", "semantic_similarity"]},
)
# 7. Resolve (if escalated)
if decision.status == "escalated":
result = coalex.resolve(
escalation_id=decision.escalation_id,
decision="approved",
reviewer={"name": "Dr. Smith", "email": "dr.smith@hospital.org"},
)
import { register, coalexContext, autoInstrument, declareAgent, evaluate, resolve } from "@coalex-ai/sdk";
import { retrievalSpan, type Document } from "@coalex-ai/sdk/ext";
import OpenAI from "openai";
// 1. Register
register({
endpoint: process.env.COALEX_ENDPOINT!,
apiKey: process.env.COALEX_API_KEY!,
serviceName: "medical-agent",
});
// 2. Auto-instrument
autoInstrument();
// 3. Declare agent (recommended)
await declareAgent({ agentId: "medical-bot", displayName: "Medical Bot" });
// 4. Custom retrieval step
const retrieve = retrievalSpan(
{ name: "knowledge_base" },
async (query: string): Promise<Document[]> => {
// Your retrieval logic here
return [{ content: "...", id: "doc-1", score: 0.95 }];
},
);
// 5. Agent invocation
const client = new OpenAI();
await coalexContext({ agentId: "medical-bot", requestId: "req-456" }, async () => {
const docs = await retrieve("What are the side effects?");
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: `Based on: ${docs[0].content}` }],
});
const answer = response.choices[0].message.content;
// 6. Evaluate
const decision = await evaluate({
requestId: "req-456",
input: { question: "What are the side effects?" },
output: { answer },
metrics: { answer: ["f1", "semantic_similarity"] },
});
// 7. Resolve (if escalated)
if (decision.status === "escalated") {
const result = await resolve({
escalationId: decision.escalationId!,
decision: "approved",
reviewer: { name: "Dr. Smith", email: "dr.smith@hospital.org" },
});
}
});
API Reference¶
coalex ¶
Coalex Python SDK — AI governance observability.
Classes¶
AgentDeclaration
dataclass
¶
ConsoleAuthError ¶
Bases: Exception
A call did not carry a valid Console signature. Never says which check failed, to the caller.
The reason is available to the agent's own logs via reason; it must not travel back to
whoever made the call, or the error becomes an oracle for guessing a valid token.
Source code in coalex/console_auth.py
ConsoleCaller
dataclass
¶
Who the Console says this turn belongs to, once the signature has been verified.
Source code in coalex/console_auth.py
ConsoleKeys ¶
Bases: Mapping[str, str]
The Console's public keys by kid, fetched on demand and cached.
Reads are what verify_console_call does: kid in keys then keys[kid]. Both may fetch,
so both may block for up to timeout_seconds. In an async agent, call :meth:refresh at
startup — after that the steady state is a dict lookup, and a fetch only happens once per TTL or
when a key id is seen that is not held.
A fetch that fails leaves the previous keys in place. Serving a slightly stale key is better than refusing every call because the Console was briefly unreachable; a key that is genuinely gone stops verifying anyway, because the signature will not match.
Source code in coalex/console_jwks.py
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 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 | |
Methods:¶
refresh ¶
Fetch now, regardless of the TTL. Returns the keys held afterwards.
Never raises: a failure logs and keeps whatever was already cached. The caller cannot do anything useful with the exception — a missing key surfaces later as a refused token, which is the correct failure and the one the verifier already reports.
Source code in coalex/console_jwks.py
ComposedQuestion
dataclass
¶
What a Question Composer decides the card shows (spec §6).
Everything the approver reads, and nothing else: the question, the curated summary, the values, and the schema that says how each value is answered. A composer that returns these four has decided the whole card.
Source code in coalex/decision_request.py
ContextPayload
dataclass
¶
What the human needs to judge (spec §4.1, §6 de-biasing).
Deliberately excludes the agent's reasoning, confidence, and risk score — those
stay in the trace for compliance and never reach the approval card. output is
shown as an editable answer, not as persuasion.
Source code in coalex/decision_request.py
DecisionRequest
dataclass
¶
The gateway-proof HITL seam (spec §4). See module docstring.
Source code in coalex/decision_request.py
Methods:¶
to_dict ¶
Serialize to the wire JSON the Console (and future Gateway) consume.
Keys are snake_case and mirror the TypeScript SDK's serializeDecisionRequest
exactly, so the seam is one shared contract across both SDKs.
Source code in coalex/decision_request.py
ElicitationAction ¶
Bases: StrEnum
Elicitation result action for a resolved task (spec §5).
accept = approved (optionally with content = corrections); decline =
rejected (+ reason, flows back to the agent as deny-with-instruction); cancel =
expired / timed out.
Source code in coalex/decision_request.py
ElicitationResult
dataclass
¶
The resolution of a task (spec §5, §7.2).
Carries the elicitation action plus the DORA who-did-what trail: reviewer
(SSO identity), reason, and timestamp. content holds corrections for an
accept-with-content; reason holds the decline instruction returned to the agent.
Source code in coalex/decision_request.py
IdentityComposer ¶
v1 (spec §6): the card shows what the producer sent, minus what §6 keeps out.
Deliberately does nothing interesting. Its whole value is that it is a SEAM — swapping it for a composer that renders a long document as a document, or annotates a recipient outside the organisation, changes the card with no change to the card's code.
The one thing it does do is drop the forbidden keys. That is not new behaviour for the Console,
which has filtered them at render since COA-1739 and still does; it is new for everyone else,
because until now an agent's reasoning or risk_score reached the wire and only one client
knew to look away.
Source code in coalex/decision_request.py
LegibleComposer ¶
Marks the fields a single-line input cannot show, so the card can render them as documents.
This is the composer the seam was built for, and the defect is real: a Connect IQ approval
carries a ~2,000-character markdown brief — headings, bullet lists, client and campaign
facts. Its JSON type is string, so the card falls through to its last branch and renders it
in a one-line <Input>. The approver is then asked to tick "Checked" against facts they were
never shown. An approval nobody can read is not governance; it is a rubber stamp that leaves an
audit trail.
It DECORATES another composer rather than replacing it, because legibility is orthogonal to
what the question says: LegibleComposer(GatewayComposer()) keeps the gateway's "Approve
calling 'wire_funds'…" question and still makes a long argument readable. Stacking is the
point — an all-or-nothing composer would force every deployment to reimplement the others.
It adds no content. §6 is not relaxed by making things legible: this changes how a value is SHOWN, never which values exist, and never adds a word of its own to the card.
Source code in coalex/decision_request.py
QuestionComposer ¶
Bases: Protocol
Turns an escalation into what the approver reads (spec §6).
The indirection exists so the card never renders the raw payload. A producer's output is shaped
for a machine — a 2,000-character markdown brief is a string, and the card, being
schema-driven, renders it in a single-line input the approver cannot read. Deciding that such a
value is a document and not a text field is this stage's job; there is nowhere else it belongs,
because the schema is the producer's and the card is generic.
Composers must not add what §6 keeps out. Making the facts LEGIBLE is the job; explaining them is not, and an agent's reasoning, confidence or risk score must not reach the card through a composed summary any more than through a field.
Source code in coalex/decision_request.py
ResolverPolicy
dataclass
¶
Who may resolve this request (spec §4.3): self or role:<name>.
Source code in coalex/decision_request.py
Methods:¶
parse
classmethod
¶
Parse the self | role:<name> config string into a policy.
Source code in coalex/decision_request.py
to_spec ¶
ResumeHook
dataclass
¶
How the producer resumes after resolution (spec §4.4).
v1 (SDK path): the LangGraph checkpoint-resume callback promoted to a first-class
field — the agent registers its resume url (and/or checkpoint_id) when it
escalates. Future (Gateway path): completing/failing the held MCP task_id.
Source code in coalex/decision_request.py
Methods:¶
from_dict
classmethod
¶
Rebuild a ResumeHook from its to_dict() wire shape (spec §4.4).
The inverse of to_dict — used when a persisted escalation carries a stored hook
(escalations.resume_hook, COA-1761) that must become a DecisionRequest. An
unrecognized kind falls back to checkpoint rather than raising, so a forward
Gateway value can never break the SDK read path.
Source code in coalex/decision_request.py
TaskState ¶
Bases: StrEnum
MCP task states carried by a Decision Request (spec §5 / COA-1278).
working (agent in-flight, pre-escalation) and failed (technical error /
future Gateway path) have no current escalation-status equivalent; they exist so
the enum is complete for the shared Console+Gateway backbone.
Source code in coalex/decision_request.py
EvaluationDecision
dataclass
¶
Result of an evaluate() call.
Source code in coalex/evaluate.py
GuardResult
dataclass
¶
Outcome of :func:guard_tool_call.
decision is the final branch: allow (tool ran, result holds its return value),
escalate (paused pending a human — escalation_id is the Decision Request), or block
(denied; tool never ran).
Source code in coalex/gateway.py
AgentInventory
dataclass
¶
What an agent declares about itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
endpoint
|
str
|
Where a turn is POSTed — the URL the Console will talk to. |
required |
tools
|
Sequence[str]
|
The names of the tools this agent exposes. Names only: whether a tool is governed is the org's call, not the agent's. |
()
|
resume_url
|
str | None
|
Where a paused run is resumed, if the agent supports being paused. |
None
|
name
|
str | None
|
The agent's name on the platform. Defaults to |
None
|
Source code in coalex/inventory.py
PromptVersion
dataclass
¶
A single prompt version returned by the Prompt Vault.
Source code in coalex/prompts.py
ResolutionResult
dataclass
¶
Result of a resolve() call.
Source code in coalex/resolve.py
Functions:¶
declare_agent ¶
declare_agent(
*,
agent_id: str,
display_name: str | None = None,
metadata: dict | None = None,
_config: CoalexConfig | None = None,
_api_key: str | None = None,
) -> AgentDeclaration
Register or declare an agent before traces arrive.
This is the building block for lazy agent registration. When COA-264's set_prompt() is implemented, it will call this internally to ensure the agent exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
str
|
Unique agent identifier (the merge key). |
required |
display_name
|
str | None
|
Optional human-friendly name. |
None
|
metadata
|
dict | None
|
Optional metadata (accepted but not persisted yet). |
None
|
_config
|
CoalexConfig | None
|
Override config (testing only). |
None
|
_api_key
|
str | None
|
Override API key (testing only). |
None
|
Source code in coalex/agents.py
instrument_anthropic ¶
instrument_bedrock ¶
instrument_google_genai ¶
Instrument Google GenAI (google-genai SDK) specifically.
instrument_langchain ¶
instrument_llamaindex ¶
instrument_openai ¶
instrument_vertexai ¶
verify_console_call ¶
verify_console_call(
token: str | None,
*,
audience: str,
public_keys: Mapping[str, str] | str,
leeway_seconds: int = DEFAULT_LEEWAY_SECONDS,
now: float | None = None,
) -> ConsoleCaller
Verify a Console-signed call, returning who it is for. Raises :class:ConsoleAuthError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str | None
|
The bearer token from the request, without the |
required |
audience
|
str
|
This agent's own name. A token minted for another agent is refused, so one org's Console cannot reach another org's agent with a token it was legitimately given. |
required |
public_keys
|
Mapping[str, str] | str
|
|
required |
leeway_seconds
|
int
|
Clock skew tolerance. |
DEFAULT_LEEWAY_SECONDS
|
now
|
float | None
|
Override the clock, for tests. |
None
|
The order matters: the signature is checked before any claim is read. Claims from an
unverified token are attacker-controlled strings, and reading them first — even to pick a key —
is how verification gets subverted. Only kid, from the header, selects the key, and an
unknown kid is a refusal rather than a fallback to some default key.
Source code in coalex/console_auth.py
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 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 | |
coalex_context ¶
coalex_context(
*,
agent_id: str,
request_id: str | None = None,
version: str | None = None,
prompt_version: int | None = None,
prompt_type: str | None = None,
) -> Generator[None, None, None]
Create a parent span with Coalex attributes for all child spans.
All spans created inside this context are descendants of a
coalex.invocation span that carries the agent metadata.
This makes every child span queryable by agent_id, request_id,
and version in the Bronze layer.
Context vars are set before the span is created so that
CoalexAttributePropagator can propagate attributes even
across trace boundaries (e.g. when LangChain auto-instrumentors
create new root spans with separate trace IDs).
Do not wrap a generator that is consumed after the enclosing function returns. A streaming HTTP response is the usual case: the body generator runs once the handler has already returned, so this block exits in a different Context from the one it entered, and the variables cannot be restored (COA-1980). Enter the context inside the generator instead, so its lifetime matches the work it describes::
async def body():
with coalex_context(agent_id=..., request_id=...):
async for token in agent.stream(...):
yield token
Getting this wrong no longer raises — it leaks a context var and logs at debug — but the spans will be attributed to whatever context happens to be current, which is rarely what you meant.
prompt_version / prompt_type let an agent that fetches its prompt
once at startup (outside any request trace) attribute each request to a
prompt version. get_prompt() only stamps the trace it is called in, so
the cache-at-startup pattern needs the version passed here per request
(COA-1339). When omitted, any value already set by get_prompt() is left
untouched.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent_id
|
str
|
Identifier for the AI agent. |
required |
request_id
|
str | None
|
Unique request/invocation ID. |
None
|
version
|
str | None
|
Agent version string. |
None
|
prompt_version
|
int | None
|
Prompt Vault version driving this invocation. |
None
|
prompt_type
|
str | None
|
Prompt type (e.g. |
None
|
Source code in coalex/context.py
current_agent_id ¶
Return the agent_id of the active coalex_context(), or None outside one.
Lets evaluate() propagate the agent_id for mid-run escalations (LangGraph interrupt → evaluate before the trace ingests), which the server cannot yet resolve from silver_traces/silver_requests (COA-1076).
Source code in coalex/context.py
from_escalation ¶
from_escalation(
escalation: Mapping[str, Any] | Any,
*,
resolver: ResolverPolicy | str | None = None,
resume_hook: ResumeHook | None = None,
question: str | None = None,
composer: QuestionComposer | None = None,
) -> DecisionRequest
Materialize an escalation as a Decision Request (spec §4, COA-1278).
Accepts the escalation as the API JSON dict or any object with matching attributes
(e.g. the transformer's EscalationItem). The task state and elicitation action
follow spec §5's mapping. The escalation has no resolver/resume-hook of its own, so
the producer supplies them here; resolver defaults to self.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
escalation
|
Mapping[str, Any] | Any
|
The escalation dict/object (status + fields). |
required |
resolver
|
ResolverPolicy | str | None
|
Resolver policy or its |
None
|
resume_hook
|
ResumeHook | None
|
How the producer resumes after resolution (spec §4.4). |
None
|
composer
|
QuestionComposer | None
|
Decides what the card shows (spec §6). Default :class: |
None
|
question
|
str | None
|
Overrides the composed question. Kept for callers that passed one before the composer existed; a composer is the better place to decide it. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the escalation carries an unrecognized status. |
Source code in coalex/decision_request.py
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | |
resume_body_from_result ¶
Map a resolved ElicitationResult → the JSON body an agent's resume endpoint expects (COA-1668).
The exact wire shape the working PharmaConnect resume path reads back (pilot-bluepharma-v2
agent/src/runtime/api.py ResumeRequest + domain/approval.py request_approval):
{"decision", "corrections", "reason", "reviewer_name", "reviewer_email"}
Mapping from ElicitationAction (spec §5):
ACCEPTwith nocontent→decision="approved"ACCEPTwithcontent→decision="corrected",corrections=contentDECLINE→decision="rejected",reasoncarried through verbatim (deny-with-instruction)CANCEL→decision="expired"
Pure: no I/O. The resolve-trigger (COA-1671) POSTs this to resume_hook.url to resume the run.
Source code in coalex/decision_request.py
task_state_for_status ¶
Map an escalation status to its MCP task state (spec §5).
Source code in coalex/decision_request.py
decide_policy ¶
decide_policy(
*,
governed: bool,
risk_tier: str | None = None,
trust_score: float | None = None,
blocked: bool = False,
) -> PolicyDecision
Pure policy decision (COA-1751): (governed, risk_tier, trust_score) → allow | escalate | block.
Deterministic and side-effect-free. trust_score is the 0-100 dial (COA-1345/COA-1795). Rules:
blocked(orrisk_tier == "blocked") → block — never runs.- not
governed→ allow — ungoverned tools always pass (Scene 1 / YOLO). - governed +
risk_tier == "high"→ escalate — a high-risk (destructive) tool always needs a human, regardless of trust; no auto-approve on that path. - governed +
trust_score >= HIGH_TRUST_MIN→ allow — earned autonomy (Scene 4). - governed, otherwise → escalate — the default governed behaviour (Scene ⅔).
Source code in coalex/gateway.py
guard_tool_call ¶
guard_tool_call(
*,
tool_name: str,
arguments: dict[str, Any],
governed: bool,
run: Callable[[], Any],
request_id: str,
agent_id: str | None = None,
risk_tier: str | None = None,
trust_score: float | None = None,
resolver: str = "self",
blocked: bool = False,
resume_hook: ResumeHook | None = None,
_config: CoalexConfig | None = None,
_api_key: str | None = None,
) -> GuardResult
Wrap one tool call in the Gateway v0 policy (COA-1756). Same agent, same prompt — the config
(the governed flag) decides whether the wire executes or becomes an escalation.
- allow → runs
run()and records an allowed-call audit row; returns its result. - escalate → does NOT run the tool; calls the existing SDK
evaluate()(creating a pending Decision Request the Console resolves; pause/resume ridesresume_hook+ the resolve callback, exactly as PharmaConnect does today). If the risk engine instead auto-approves, the tool runs; if it rejects, the tool is blocked. - block → does NOT run the tool; records a blocked-call audit row.
run is a zero-arg callable that executes the underlying tool (so allow/auto-approved actually
invoke it, while escalate/block never do). It must be synchronous: an async callable would
return an un-awaited coroutine, and this raises rather than record a call that never happened.
This fails closed, and that is deliberate (COA-2181). If Coalex is unreachable at the moment
a decision is needed — the escalate path calls evaluate(), which raises on a transport
error or a non-2xx — the exception propagates and your tool does not run. A governance
layer that waves calls through when it cannot reach its own control plane is not governing.
The behaviour was always this; what was missing was anyone saying so. A developer saw a raw
httpx.ConnectError and had to infer, from a stack trace, that their governed action had been
prevented. It is now logged in those words before the exception leaves this function.
Source code in coalex/gateway.py
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 | |
declare_inventory ¶
declare_inventory(
inventory: AgentInventory,
*,
config: CoalexConfig,
api_key: str,
default_name: str,
) -> bool
POST the declaration. Returns whether it landed; never raises.
register() runs at application startup, so this must not be able to stop an agent from
starting. A governance registration failing is a reason to log loudly, not a reason for a
customer's agent to be down — the agent still traces, and the declaration retries on next boot.
Source code in coalex/inventory.py
get_prompt ¶
get_prompt(
*,
agent: str,
name: str,
version: str = "production",
_config: CoalexConfig | None = None,
_api_key: str | None = None,
) -> PromptVersion
Fetch a prompt template from the Prompt Vault.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent
|
str
|
Agent ID (e.g., "sales-copilot"). |
required |
name
|
str
|
Prompt name (e.g., "system"). |
required |
version
|
str
|
"production" (default), "staging", "draft", "latest", or integer. |
'production'
|
_config
|
CoalexConfig | None
|
Override config (testing only). |
None
|
_api_key
|
str | None
|
Override API key (testing only). |
None
|
Source code in coalex/prompts.py
flush_ungoverned ¶
Deliver what the spool is holding. Returns how many landed. Never raises.
Called after a SUCCESSFUL platform call as well as from record, because success is the only
honest signal that the platform is back. A spool that only drains when the next failure happens
would keep the backlog exactly as long as the outage lasts, and then some.
Source code in coalex/ungoverned.py
record_ungoverned ¶
record_ungoverned(
*,
request_id: str,
action: str,
error: str,
_config: Any = None,
_api_key: str | None = None,
) -> None
Record that action ran without governance, because the platform could not be reached.
Call it from the except around evaluate(), beside the decision to proceed. It does not
change that decision and cannot fail it.
Delivery is attempted immediately and spooled to disk if it does not land, which is the usual case: the reason this is being called is that the platform was unreachable a moment ago.
Source code in coalex/ungoverned.py
register ¶
register(
*,
endpoint: str = "https://traces.azure.coalex.ai",
api_key: str = "dev",
service_name: str = "coalex-sdk-python",
filter_non_ai_spans: bool = False,
suppress_export_errors: bool = True,
genai_semconv: bool | None = None,
declare: AgentInventory | None = None,
) -> None
Configure the Coalex OTLP exporter.
Call once at application startup. Sets the global TracerProvider with a BatchSpanProcessor exporting OTLP/HTTP to the Coalex proxy.
The SDK always sends through the proxy (via LB) so that auth validation is in the path. Never send directly to the collector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
endpoint
|
str
|
Coalex proxy HTTP endpoint (default: cloud). |
'https://traces.azure.coalex.ai'
|
api_key
|
str
|
API key for proxy authentication (default: "dev" for local). |
'dev'
|
service_name
|
str
|
Service name for OTLP resource (default: "coalex-sdk-python"). |
'coalex-sdk-python'
|
filter_non_ai_spans
|
bool
|
If True, only export AI/LLM spans (default: False). |
False
|
suppress_export_errors
|
bool
|
If True, suppress export errors gracefully (default: True). |
True
|
genai_semconv
|
bool | None
|
If True, additively emit OTel GenAI attributes
( |
None
|
declare
|
AgentInventory | None
|
Optionally tell the platform where this agent lives and what tools it has
(COA-1969), so it appears in the Console without anyone registering it by hand.
Best-effort: a failure is logged and startup continues. Omit it and |
None
|
Source code in coalex/__init__.py
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 | |