> ## Documentation Index
> Fetch the complete documentation index at: https://www.adaline.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# With Adaline SDKs

> Instrument your AI application with full tracing control using the TypeScript or Python SDK

The Adaline SDK is the recommended way to integrate your AI application with Adaline. Beyond sending traces and spans, the SDK gives you deployment management with automatic caching, smart buffering with batched flushes, built-in retries with exponential backoff, and health monitoring — all production-ready out of the box.

## What the SDK gives you

| Capability | Description |
| - | - |
| **Deployment management** | Fetch deployed prompts by ID or environment, with automatic background refresh and local caching. |
| **Structured observability** | Log traces and spans with 8 content types covering LLM calls, tool executions, retrieval, embeddings, guardrails, and custom logic. |
| **Smart buffering** | Traces and spans are buffered in memory and flushed in configurable batches — no request-per-span overhead. |
| **Automatic retries** | Failed API calls are retried with exponential backoff (5xx and network errors). 4xx errors fail immediately. |
| **Health monitoring** | Inspect flush status and background refresh health at runtime to detect issues before they become incidents. |
| **Nested spans** | Model complex workflows with parent-child span hierarchies — agents calling tools calling sub-agents. |
| **Session tracking** | Group related traces by session ID to follow multi-turn conversations or multi-request workflows. |
| **Evaluation variables** | Attach variable values to spans so they flow into continuous evaluations and datasets automatically. |

## Install

> [tab] TypeScript
>
> ```bash theme={null}
> npm install @adaline/client
> ```

> [tab] Python
>
> ```bash theme={null}
> pip install adaline-client
> ```

## Initialize the client

> [tab] TypeScript
>
> ```typescript theme={null}
> import { Adaline } from "@adaline/client";
>
> const adaline = new Adaline({ apiKey: "your-api-key" });
> ```

> [tab] Python
>
> ```python theme={null}
> from adaline.main import Adaline
>
> adaline = Adaline(api_key="your-api-key")
> ```

> [!TIP]
>
> Set the `ADALINE_API_KEY` environment variable and omit the `apiKey` parameter to avoid hardcoding secrets. The SDK reads from this variable automatically.

## Manage deployments

The SDK can fetch deployed prompt configurations — including the model, provider settings, messages, tools, and variables — so your application always uses the latest version without redeploying code.

### Fetch a specific deployment

> [tab] TypeScript
>
> ```typescript theme={null}
> const deployment = await adaline.getDeployment({
>   promptId: "your-prompt-id",
>   deploymentId: "your-deployment-id",
> });
>
> const config = deployment.prompt.config;
> console.log(config.providerName);  // "openai"
> console.log(config.model);         // "gpt-4"
> console.log(config.settings);      // { temperature: 0.7, maxTokens: 1000 }
>
> const messages = deployment.prompt.messages;
> const tools = deployment.prompt.tools;
> const variables = deployment.prompt.variables;
> ```

> [tab] Python
>
> ```python theme={null}
> deployment = await adaline.get_deployment(
>     prompt_id="your-prompt-id",
>     deployment_id="your-deployment-id",
> )
>
> config = deployment.prompt.config
> print(config.provider_name)  # "openai"
> print(config.model)          # "gpt-4"
> print(config.settings)       # {"temperature": 0.7, "maxTokens": 1000}
>
> messages = deployment.prompt.messages
> tools = deployment.prompt.tools
> variables = deployment.prompt.variables
> ```

### Fetch the latest deployment for an environment

> [tab] TypeScript
>
> ```typescript theme={null}
> const deployment = await adaline.getLatestDeployment({
>   promptId: "your-prompt-id",
>   deploymentEnvironmentId: "your-environment-id",
> });
> ```

> [tab] Python
>
> ```python theme={null}
> deployment = await adaline.get_latest_deployment(
>     prompt_id="your-prompt-id",
>     deployment_environment_id="your-environment-id",
> )
> ```

### Auto-refresh deployments in production

For long-running services, use `initLatestDeployment` to set up a cached deployment that refreshes automatically (default every 60 seconds) in the background. When you deploy a new prompt version in Adaline, your application picks it up without a restart.

> [tab] TypeScript
>
> ```typescript theme={null}
> const controller = await adaline.initLatestDeployment({
>   promptId: "your-prompt-id",
>   deploymentEnvironmentId: "your-environment-id",
> });
>
> // Use the cached deployment in request handlers
> const deployment = await controller.get();
>
> // Force a fresh fetch (bypasses cache)
> const fresh = await controller.get(true);
>
> // Check background refresh health
> const status = controller.backgroundStatus();
> // { stopped: false, consecutiveFailures: 0, lastError: null, lastRefreshed: Date }
>
> // Stop the background refresh when shutting down
> controller.stop();
> ```

> [tab] Python
>
> ```python theme={null}
> controller = await adaline.init_latest_deployment(
>     prompt_id="your-prompt-id",
>     deployment_environment_id="your-environment-id",
> )
>
> deployment = await controller.get()
> fresh = await controller.get(force_refresh=True)
>
> status = controller.get_background_status()
> # {"stopped": False, "consecutive_failures": 0, "last_error": None, "last_refreshed": datetime}
>
> await controller.stop()
> ```

## Initialize the monitor

The monitor manages the lifecycle of traces and spans — buffering them in memory, batching them together, and flushing them to the Adaline API on a timer or when the buffer fills up.

> [tab] TypeScript
>
> ```typescript theme={null}
> const monitor = adaline.initMonitor({ projectId: "your-project-id" });
> ```

> [tab] Python
>
> ```python theme={null}
> monitor = adaline.init_monitor(project_id="your-project-id")
> ```

## Create a trace

A trace represents a single end-to-end request flow — for example, one user message that triggers an LLM call, a tool execution, and a final response.

> [tab] TypeScript
>
> ```typescript theme={null}
> const trace = monitor.logTrace({
>   name: "user-request",
>   status: "unknown",
>   sessionId: "session-abc123",
>   referenceId: "custom-uuid",
>   tags: ["production", "v2.1"],
>   attributes: {
>     userId: "user-456",
>     region: "us-east-1",
>     featureFlag: "new-prompt-v2",
>   },
> });
> ```

> [tab] Python
>
> ```python theme={null}
> trace = monitor.log_trace(
>     name="user-request",
>     status="unknown",
>     session_id="session-abc123",
>     reference_id="custom-uuid",
>     tags=["production", "v2.1"],
>     attributes={
>         "userId": "user-456",
>         "region": "us-east-1",
>         "featureFlag": "new-prompt-v2",
>     },
> )
> ```

## Add spans

Each operation inside a trace is a span. Spans carry a **content type** that tells Adaline what kind of operation it represents — an LLM call, a tool execution, a vector retrieval, and more.

### Create a span

> [tab] TypeScript
>
> ```typescript theme={null}
> const span = trace.logSpan({
>   name: "chat-completion",
>   promptId: "your-prompt-id",
>   deploymentId: "your-deployment-id",
>   runEvaluation: true,
>   tags: ["v2.1", "production"],
>   attributes: { region: "us-east-1", customerId: "dd2-cew3d2-saf32" },
> });
> ```

> [tab] Python
>
> ```python theme={null}
> span = trace.log_span(
>     name="chat-completion",
>     prompt_id="your-prompt-id",
>     deployment_id="your-deployment-id",
>     run_evaluation=True,
>     tags=["v2.1", "production"],
>     attributes={"region": "us-east-1", "customerId": "dd2-cew3d2-saf32" },
> )
> ```

### Update and end a span

After performing the operation, update the span with the result and end it:

> [tab] TypeScript
>
> ```typescript theme={null}
> const response = await openai.chat.completions.create({ ... });
>
> span.update({
>   status: "success",
>   content: {
>     type: "Model",
>     provider: "openai",
>     model: "gpt-4",
>     input: JSON.stringify({ messages }),
>     output: JSON.stringify(response),
>   },
> });
>
> span.end();
> ```

> [tab] Python
>
> ```python theme={null}
> from adaline_api.models.log_span_content import LogSpanContent
> from adaline_api.models.log_span_model_content import LogSpanModelContent
>
> response = openai.chat.completions.create(...)
>
> span.update({
>     "status": "success",
>     "content": LogSpanContent(
>         actual_instance=LogSpanModelContent(
>             type="Model",
>             provider="openai",
>             model="gpt-4",
>             input=json.dumps({"messages": messages}),
>             output=json.dumps(response.model_dump()),
>         )
>     ),
> })
>
> span.end()
> ```

### Nested spans

Spans can contain child spans to model hierarchical workflows — an agent span containing tool call spans, or a RAG span containing embedding and retrieval sub-spans:

```typescript theme={null}
const agentSpan = trace.logSpan({ name: "agent-orchestrator" });

const toolSpan = agentSpan.logSpan({ name: "search-tool" });
// ... execute tool ...
toolSpan.update({ status: "success", content: { type: "Tool", ... } });
toolSpan.end();

const llmSpan = agentSpan.logSpan({ name: "final-response" });
// ... generate response ...
llmSpan.update({ status: "success", content: { type: "Model", ... } });
llmSpan.end();

agentSpan.end();
```

## Span content types

The `content.type` field tells Adaline what kind of operation a span represents. Each type carries `input` and `output` as JSON strings, plus type-specific fields.

### Model

LLM chat completions and text generation. Captures the provider, model, cost, and optionally expected output for evaluation.

For the best experience, stringify the exact request payload you send to your AI provider as `input` and the full response as `output`. When you use a supported provider, Adaline automatically extracts token usage, calculates cost, and surfaces model metadata. See [Span content: input and output](https://www.adaline.ai/docs/instrument/advanced-usage.md#span-content-input-and-output) for full details and examples. You can also use [Adaline's own content schema](https://www.adaline.ai/docs/reference/sdk/v2/typescript/types/MessageContent.md) for `input` and `output`, although this is more advanced and requires custom transformations.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Model",
    provider: "openai",
    model: "gpt-4",
    input: JSON.stringify(params),
    output: JSON.stringify(response),
    cost: 0.0032, // optional, override the cost calculated by Adaline
  },
});
```

### ModelStream

Streaming LLM responses. Captures both the raw stream chunks and an aggregated output.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "ModelStream",
    provider: "openai",
    model: "gpt-4",
    input: JSON.stringify({ messages }),
    output: rawStreamChunks,
    aggregateOutput: JSON.stringify(aggregatedResponse),
    cost: 0.0028, // optional, override the cost calculated by Adaline
  },
});
```

### Tool

Function or tool call execution.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Tool",
    input: JSON.stringify({ index: 0, id: "tool-123", name: "get-weather", arguments: JSON.stringify({ city: "San Francisco" }) }),
    output: JSON.stringify({ index: 0, id: "tool-123", name: "get-weather", data: JSON.stringify({ temperature: 62, condition: "foggy" }) }),
  },
});
```

### Retrieval

Vector search, document retrieval, or any RAG retrieval step.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Retrieval",
    input: JSON.stringify({ query: "password reset steps" }),
    output: JSON.stringify({ documents: [
      { id: "doc1", score: 0.95, text: "..." },
      { id: "doc2", score: 0.89, text: "..." }
    ] }),
  },
});
```

### Embeddings

Embedding generation.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Embeddings",
    input: JSON.stringify({ texts: ["How do I reset my password?"] }),
    output: JSON.stringify({ embeddings: [[0.012, -0.034, ...]] }),
  },
});
```

### Function

Custom business logic, data transforms, or any application-specific operation.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Function",
    input: JSON.stringify({ operation: "get-user-plan", userId: "user-456" }),
    output: JSON.stringify({ operation: "get-user-plan", userId: "user-456", plan: "enterprise", features: [...] }),
  },
});
```

### Guardrail

Safety checks, content filters, PII detection, or compliance rules.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Guardrail",
    input: JSON.stringify({ text: userMessage, checks: ["toxicity", "pii"] }),
    output: JSON.stringify({ text: userMessage, checks: ["toxicity", "pii"], passed: true, flags: [] }),
  },
});
```

### Other

Any operation that doesn't fit the types above.

```typescript theme={null}
span.update({
  status: "success",
  content: {
    type: "Other",
    input: JSON.stringify({ custom: "input" }),
    output: JSON.stringify({ custom: "output" }),
  },
});
```

All content types share `type`, `input` (JSON string), and `output` (JSON string).

## End the trace and flush

Always end the trace and flush remaining data. Calling `end()` on a trace recursively ends all child spans that haven't been ended yet.

> [tab] TypeScript
>
> ```typescript theme={null}
> trace.update({ status: "success" });
> trace.end();
>
> await monitor.flush();
> ```

> [tab] Python
>
> ```python theme={null}
> trace.update({"status": "success"})
> trace.end()
>
> await monitor.flush()
> ```

> [!WARNING]
>
> Traces and spans that are never ended will never be flushed. Always call `end()` — use `try`/`finally` blocks to guarantee it runs even when errors occur.

## Attach variables for evaluation

Attach variable values to spans so they flow into [continuous evaluations](https://www.adaline.ai/docs/monitor/setup-continuous-evaluations.md) and can be captured into [datasets](https://www.adaline.ai/docs/monitor/build-logs-from-dataset.md). Variables are set on the span's **content** object (specifically on `Model` or `ModelStream` content types), not on `logSpan()` directly:

> [tab] TypeScript
>
> ```typescript theme={null}
> const span = trace.logSpan({ name: "chat-completion" });
>
> span.update({
>   status: "success",
>   content: {
>     type: "Model",
>     provider: "openai",
>     model: "gpt-4",
>     variables: {
>       user_question: { name: "user_question", value: { modality: "text", value: userInput } },
>       context: { name: "context", value: { modality: "text", value: retrievedContext } },
>     },
>     input: JSON.stringify(params),
>     output: JSON.stringify(response),
>   },
> });
> ```

> [tab] Python
>
> ```python theme={null}
> from adaline_api.models.log_span_content import LogSpanContent
> from adaline_api.models.log_span_model_content import LogSpanModelContent
>
> span = trace.log_span(name="chat-completion")
>
> span.update({
>     "status": "success",
>     "content": LogSpanContent(
>         actual_instance=LogSpanModelContent(
>             type="Model",
>             provider="openai",
>             model="gpt-4",
>             variables={
>                 "user_question": {"modality": "text", "value": user_input},
>                 "context": {"modality": "text", "value": retrieved_context},
>             },
>             input=json.dumps(params),
>             output=json.dumps(response.model_dump()),
>         )
>     ),
> })
> ```

Variables support `text`, `image`, and `pdf` modalities. See [Log attachments](https://www.adaline.ai/docs/instrument/log-attachments.md) for full details on attaching variables, attributes, and tags.

## Buffering, batching, and retries

The SDK handles reliability so you don't have to.

### How the buffer works

1. When you call `logTrace()` or `logSpan()`, entries are added to an in-memory buffer.
2. A background timer flushes the buffer every `flushInterval` seconds.
3. If the buffer reaches `maxBufferSize`, it flushes immediately.
4. Each flush sends a batch of entries in a single API call.

### Retry behavior

| Scenario | Behavior |
| - | - |
| **5xx server errors** | Retried with exponential backoff (1s initial, 10s max, 20s total budget). |
| **Network errors** | Retried with exponential backoff (same as 5xx). |
| **4xx client errors** | Fail immediately — no retry. Check your API key and request payload. |
| **Consecutive failures** | After `maxContinuousFlushFailures` consecutive failures, the background timer stops. |

### Health monitoring

Inspect the monitor's flush status at runtime to detect issues:

> [tab] TypeScript
>
> ```typescript theme={null}
> console.log(`Sent: ${monitor.sentCount}, Dropped: ${monitor.droppedCount}, Buffered: ${monitor.buffer.length}`);
> ```

> [tab] Python
>
> ```python theme={null}
> print(f"Sent: {monitor.sent_count}, Dropped: {monitor.dropped_count}, Buffered: {len(monitor.buffer)}")
> ```

## Graceful shutdown

In production, handle process signals to flush remaining data before the process exits:

> [!TIP]
>
> **Serverless environments (AWS Lambda, Vercel Functions, Cloudflare Workers, etc.):** The SDK flushes buffered traces and spans on a background interval, but serverless functions can exit before the next flush fires. Always call `await monitor.flush()` (TypeScript) or `await monitor.flush()` (Python) explicitly before your handler returns to ensure nothing is lost.

> [tab] TypeScript
>
> ```typescript theme={null}
> process.on("SIGTERM", async () => {
>   await monitor.flush();
>   monitor.stop();
>   controller.stop();
>   process.exit(0);
> });
> ```

> [tab] Python
>
> ```python theme={null}
> import signal
>
> async def shutdown(sig, loop):
>     await monitor.flush()
>     monitor.stop()
>     await controller.stop()
>
> loop = asyncio.get_event_loop()
> loop.add_signal_handler(signal.SIGTERM, lambda: asyncio.create_task(shutdown(signal.SIGTERM, loop)))
> ```

## Next steps

> [card] [Advanced Tracing Patterns](https://www.adaline.ai/docs/instrument/advanced-usage.md)
>
> Multi-step workflows, tool-calling agents, session tracking, and error handling patterns.

> [card] [Log User Feedback](https://www.adaline.ai/docs/instrument/log-user-feedback.md)
>
> Attach thumbs up/down, ratings, and comments to traces.

> [card] [Log Attachments](https://www.adaline.ai/docs/instrument/log-attachments.md)
>
> Attach attributes, tags, variables, and metadata to traces and spans.

> [card] [SDK Reference](https://www.adaline.ai/docs/reference/sdk/v2/overview)
>
> Complete class and type reference for the TypeScript and Python SDKs.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.