> ## 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

<Tabs>
  <Tab title="TypeScript">
    ```bash theme={null}
    npm install @adaline/client
    ```
  </Tab>

  <Tab title="Python">
    ```bash theme={null}
    pip install adaline-client
    ```
  </Tab>
</Tabs>

## Initialize the client

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { Adaline } from "@adaline/client";

    const adaline = new Adaline({ apiKey: "your-api-key" });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from adaline.main import Adaline

    adaline = Adaline(api_key="your-api-key")
    ```
  </Tab>
</Tabs>

<Tip>
  Set the `ADALINE_API_KEY` environment variable and omit the `apiKey` parameter to avoid hardcoding secrets. The SDK reads from this variable automatically.
</Tip>

## 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

<Tabs>
  <Tab title="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>

  <Tab title="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
    ```
  </Tab>
</Tabs>

### Fetch the latest deployment for an environment

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const deployment = await adaline.getLatestDeployment({
      promptId: "your-prompt-id",
      deploymentEnvironmentId: "your-environment-id",
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    deployment = await adaline.get_latest_deployment(
        prompt_id="your-prompt-id",
        deployment_environment_id="your-environment-id",
    )
    ```
  </Tab>
</Tabs>

### 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.

<Tabs>
  <Tab title="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>

  <Tab title="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()
    ```
  </Tab>
</Tabs>

## 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.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const monitor = adaline.initMonitor({ projectId: "your-project-id" });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    monitor = adaline.init_monitor(project_id="your-project-id")
    ```
  </Tab>
</Tabs>

## 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.

<Tabs>
  <Tab title="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>

  <Tab title="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",
        },
    )
    ```
  </Tab>
</Tabs>

## 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

<Tabs>
  <Tab title="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>

  <Tab title="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" },
    )
    ```
  </Tab>
</Tabs>

### Update and end a span

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

<Tabs>
  <Tab title="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>

  <Tab title="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()
    ```
  </Tab>
</Tabs>

### 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](/docs/instrument/advanced-usage#span-content-input-and-output) for full details and examples. You can also use [Adaline's own content schema](/docs/reference/sdk/v2/typescript/types/MessageContent) 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.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    trace.update({ status: "success" });
    trace.end();

    await monitor.flush();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    trace.update({"status": "success"})
    trace.end()

    await monitor.flush()
    ```
  </Tab>
</Tabs>

<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.
</Warning>

## Attach variables for evaluation

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

<Tabs>
  <Tab title="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>

  <Tab title="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()),
            )
        ),
    })
    ```
  </Tab>
</Tabs>

Variables support `text`, `image`, and `pdf` modalities. See [Log attachments](/docs/instrument/log-attachments) 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:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    console.log(`Sent: ${monitor.sentCount}, Dropped: ${monitor.droppedCount}, Buffered: ${monitor.buffer.length}`);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    print(f"Sent: {monitor.sent_count}, Dropped: {monitor.dropped_count}, Buffered: {len(monitor.buffer)}")
    ```
  </Tab>
</Tabs>

## 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.
</Tip>

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    process.on("SIGTERM", async () => {
      await monitor.flush();
      monitor.stop();
      controller.stop();
      process.exit(0);
    });
    ```
  </Tab>

  <Tab title="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)))
    ```
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Advanced Tracing Patterns" icon="git-branch" href="/docs/instrument/advanced-usage">
    Multi-step workflows, tool-calling agents, session tracking, and error handling patterns.
  </Card>

  <Card title="Log User Feedback" icon="message-circle" href="/docs/instrument/log-user-feedback">
    Attach thumbs up/down, ratings, and comments to traces.
  </Card>

  <Card title="Log Attachments" icon="paperclip" href="/docs/instrument/log-attachments">
    Attach attributes, tags, variables, and metadata to traces and spans.
  </Card>

  <Card title="SDK Reference" icon="braces" href="/docs/reference/sdk/v2/overview">
    Complete class and type reference for the TypeScript and Python SDKs.
  </Card>
</CardGroup>
