Skip to content

register()

Configure the Coalex OTLP exporter. Call once at application startup before any other Coalex SDK calls.


Signature

def 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,
) -> None
interface RegisterOptions {
    endpoint?: string;          // default: "https://traces.azure.coalex.ai"
    apiKey?: string;            // default: "dev"
    serviceName?: string;       // default: "coalex-sdk-typescript"
    filterNonAiSpans?: boolean; // default: false
    suppressExportErrors?: boolean; // default: true
}

function register(options?: RegisterOptions): void

Parameters

Parameter Type Default Description
endpoint str "https://traces.azure.coalex.ai" Coalex proxy HTTP endpoint. Use the cloud default or your self-hosted proxy URL.
api_key str "dev" API key for proxy authentication. Use "dev" for local development with docker compose.
service_name str "coalex-sdk-python" OpenTelemetry service name. Appears in the Coalex dashboard as the service identifier.
filter_non_ai_spans bool False When True, only AI/LLM spans are exported. HTTP, DB, and other non-AI spans are dropped before export.
suppress_export_errors bool True When True, export errors are logged but do not raise exceptions. Set to False for debugging connectivity issues.
genai_semconv bool \| None None When True, additively emit OTel GenAI attributes (gen_ai.input.messages / gen_ai.output.messages / gen_ai.system_instructions) derived from OpenInference messages. Defaults to the COALEX_GENAI_SEMCONV env var, or False when unset. See Semantic conventions. (Python SDK)

All parameters are keyword-only (enforced by *).


Returns

None. The function configures global state as a side effect.


What it does

Calling register() performs the following setup:

  1. Creates an OpenTelemetry Resource with service.name set to service_name.
  2. Creates an OTLPSpanExporter pointing at {endpoint}/v1/traces with an Authorization: Bearer {api_key} header.
  3. Wraps the exporter in a SafeOTLPSpanExporter (suppresses transient network errors when suppress_export_errors=True).
  4. Optionally wraps in a FilteringSpanExporter (when filter_non_ai_spans=True).
  5. Optionally wraps in a GenAISemconvExporter (when genai_semconv=True) that adds gen_ai.* message attributes at export time.
  6. Creates a TracerProvider with a CoalexAttributePropagator (copies coalex.* attributes from parent to child spans) and a BatchSpanProcessor.
  7. Sets the TracerProvider as the global OpenTelemetry tracer provider via trace.set_tracer_provider().

Call once only

register() sets the global TracerProvider. Calling it multiple times replaces the provider, which can cause spans to be dropped. Always call it once at the top of your application entrypoint.


Examples

Cloud deployment

import os
import coalex

coalex.register(
    endpoint=os.environ["COALEX_ENDPOINT"],
    api_key=os.environ["COALEX_API_KEY"],
    service_name="claims-agent",
)
import { register } from "@coalex-ai/sdk";

register({
    endpoint: process.env.COALEX_ENDPOINT!,
    apiKey: process.env.COALEX_API_KEY!,
    serviceName: "claims-agent",
});

Local development

import coalex

coalex.register(
    endpoint="http://localhost:8080",
    api_key="dev",
    service_name="my-agent-dev",
)
import { register } from "@coalex-ai/sdk";

register({
    endpoint: "http://localhost:8080",
    apiKey: "dev",
    serviceName: "my-agent-dev",
});

Debugging export issues

import coalex

coalex.register(
    endpoint="https://your-org.coalex.ai",
    api_key="your-api-key",
    service_name="my-agent",
    suppress_export_errors=False,  # raises on export failure
)
import { register } from "@coalex-ai/sdk";

register({
    endpoint: "https://your-org.coalex.ai",
    apiKey: "your-api-key",
    serviceName: "my-agent",
    suppressExportErrors: false, // throws on export failure
});

Filtering non-AI spans

import coalex

coalex.register(
    endpoint="https://your-org.coalex.ai",
    api_key="your-api-key",
    service_name="my-agent",
    filter_non_ai_spans=True,  # only export LLM/AI spans
)
import { register } from "@coalex-ai/sdk";

register({
    endpoint: "https://your-org.coalex.ai",
    apiKey: "your-api-key",
    serviceName: "my-agent",
    filterNonAiSpans: true, // only export LLM/AI spans
});

Declaring your agent

By default the platform learns about your agent from its traces — it appears in the dashboard once it sends telemetry. That is enough to observe it, but not enough to talk to it: the Console needs to know where the agent lives before an operator can start a session with it.

Pass declare and the agent registers itself at startup:

import coalex
from coalex import AgentInventory

coalex.register(
    endpoint="https://your-org.coalex.ai",
    api_key="your-api-key",
    service_name="my-agent",
    declare=AgentInventory(
        endpoint="https://my-agent.internal/chat",
        tools=["lookup_portfolio", "wire_funds"],
        resume_url="https://my-agent.internal/chat/resume",
    ),
)
import { register } from "@coalex-ai/sdk";

register({
    endpoint: "https://your-org.coalex.ai",
    apiKey: "your-api-key",
    serviceName: "my-agent",
    declare: {
        endpoint: "https://my-agent.internal/chat",
        tools: ["lookup_portfolio", "wire_funds"],
        resumeUrl: "https://my-agent.internal/chat/resume",
    },
});

The agent name defaults to service_name, so the agent you declare and the agent your traces are attributed to are the same one.

What you can declare, and what you cannot

An agent declares where it lives and what tools it has. It cannot declare whether those tools are governed, or who may approve them:

Who decides What
Your agent, here endpoint, resume URL, tool names
Your organisation, in the dashboard which tools require approval, and which role may approve

That separation is deliberate. If an agent could declare governed: false about its own tools, the thing being governed would be the author of its own governance — which is not governance at all, and not something you could defend to an auditor. Sending a policy field is rejected with a 422 rather than silently ignored.

Declared tools start ungoverned and the agent starts hidden from the Console until somebody in your organisation makes those calls. Declaring yourself is not the same as being chosen.


Notes

  • Declaring is best-effort. If the platform is unreachable at startup, the SDK logs a warning and carries on — your agent still starts and still traces, and the declaration is retried the next time it boots. A governance registration failing is never a reason for your agent to be down.
  • The SDK always sends traces through the proxy (via load balancer) so that authentication is validated in the request path. Never point endpoint directly at the collector.
  • The api_key is sent as a Bearer token in the Authorization header on every OTLP export request.
  • The BatchSpanProcessor buffers spans and exports them in batches asynchronously, so register() returns immediately.
  • If you need to use a custom TracerProvider (e.g., with additional processors or exporters), configure it yourself and pass it to auto_instrument(tracer_provider=...) instead of calling register().

API Reference

coalex.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 (gen_ai.input.messages / gen_ai.output.messages / gen_ai.system_instructions) derived from OpenInference's message attributes — the normalised shape the trace viewer and judge want (COA-380). Defaults to the COALEX_GENAI_SEMCONV env var (1/true/yes/on), or False when unset.

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 register() makes no network call at all, exactly as before.

None
Source code in coalex/__init__.py
def 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.

    Args:
        endpoint: Coalex proxy HTTP endpoint (default: cloud).
        api_key: API key for proxy authentication (default: "dev" for local).
        service_name: Service name for OTLP resource (default: "coalex-sdk-python").
        filter_non_ai_spans: If True, only export AI/LLM spans (default: False).
        suppress_export_errors: If True, suppress export errors gracefully (default: True).
        genai_semconv: If True, additively emit OTel GenAI attributes
            (``gen_ai.input.messages`` / ``gen_ai.output.messages`` / ``gen_ai.system_instructions``)
            derived from OpenInference's message attributes — the normalised shape the trace
            viewer and judge want (COA-380). Defaults to the ``COALEX_GENAI_SEMCONV`` env var
            (``1``/``true``/``yes``/``on``), or False when unset.
        declare: 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 ``register()``
            makes no network call at all, exactly as before.
    """
    global _config, _api_key

    import os

    from opentelemetry import trace
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
        OTLPSpanExporter,
    )
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor

    from coalex.filtering_exporter import FilteringSpanExporter
    from coalex.genai_semconv import GenAISemconvExporter
    from coalex.safe_exporter import SafeOTLPSpanExporter
    from coalex.span_processor import CoalexAttributePropagator

    if genai_semconv is None:
        genai_semconv = os.environ.get("COALEX_GENAI_SEMCONV", "").strip().lower() in ("1", "true", "yes", "on")

    _config = CoalexConfig(endpoint=endpoint, service_name=service_name)
    _api_key = api_key

    resource = Resource({"service.name": service_name})

    base_exporter = OTLPSpanExporter(
        endpoint=f"{_config.endpoint}/v1/traces",
        headers={"Authorization": f"Bearer {api_key}"},
    )

    # Wrap exporter chain (innermost first): OTLP -> Safe -> Filtering -> GenAI bridge.
    # The GenAI bridge sits outermost so it enriches spans with gen_ai.* before filtering/OTLP.
    safe_exporter = SafeOTLPSpanExporter(base_exporter, suppress_errors=suppress_export_errors)
    final_exporter = FilteringSpanExporter(safe_exporter) if filter_non_ai_spans else safe_exporter
    if genai_semconv:
        final_exporter = GenAISemconvExporter(final_exporter)

    provider = TracerProvider(resource=resource)
    provider.add_span_processor(CoalexAttributePropagator())
    provider.add_span_processor(BatchSpanProcessor(final_exporter))
    trace.set_tracer_provider(provider)

    if declare is not None:
        from coalex.inventory import declare_inventory as _declare

        # Deliberately last: tracing is configured before we talk to anyone, so an agent whose
        # control plane is unreachable still exports spans.
        _declare(
            declare,
            config=_config,
            api_key=api_key,
            default_name=service_name,
        )