````skill
---
name: agentbyte-llm-client
description: Guide for initializing Agentbyte chat and embedding clients for OpenAI/Azure OpenAI. Use this when setting up authentication, provider fallback, or validating usage/cost metadata from results.
---

Use this skill when a user needs to initialize Agentbyte model clients (`OpenAI*` / `AzureOpenAI*`) for either chat completion or embeddings.

## Supported client families

- **Chat:** `OpenAIChatCompletionClient`, `AzureOpenAIChatCompletionClient`
- **Embeddings:** `OpenAIEmbeddingClient`, `AzureOpenAIEmbeddingClient`

## Core Patterns

### 1. OpenAI Chat Client Initialization

#### Method A: Env-based factory (Recommended)
```python
from agentbyte.llm.openai import OpenAIChatCompletionClient

model_client = OpenAIChatCompletionClient.from_api_key(
    model="gpt-4o",
    config={"max_completion_tokens": 500},
)
```

#### Method B: Direct Dependency Injection
```python
import os
from openai import AsyncOpenAI
from agentbyte.llm.openai import OpenAIChatCompletionClient

raw_client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"], timeout=30.0)
model_client = OpenAIChatCompletionClient(model="gpt-4o", client=raw_client)
```

### 2. Azure OpenAI Chat Client Initialization

#### Method A: Managed Identity (Azure-hosted production)
```python
from agentbyte.llm.azure_openai import AzureOpenAIChatCompletionClient

model_client = AzureOpenAIChatCompletionClient.from_default_credential(
    model="gpt-4o-mini"
)
```

#### Method B: Certificate Auth (Service Principal)
```python
import os
from agentbyte.llm.azure_openai import AzureOpenAIChatCompletionClient

model_client = AzureOpenAIChatCompletionClient.from_certificate(
    model="gpt-4o-mini",
    tenant_id=os.environ["AZURE_TENANT_ID"],
    client_id=os.environ["AZURE_CLIENT_ID"],
    certificate_data=os.environ["AZURE_CERT_DATA"],
)
```

### 3. Embedding Client Initialization (single-provider fallback)

```python
import os
from agentbyte.llm import OpenAIEmbeddingClient, AzureOpenAIEmbeddingClient


def build_embedding_client():
    if os.getenv("OPENAI_API_KEY"):
        return (
            "openai",
            OpenAIEmbeddingClient.from_api_key(
                model="text-embedding-3-small",
                config={"encoding_format": "float"},
            ),
        )

    model = os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME")
    if not model:
        raise ValueError(
            "Set OPENAI_API_KEY or AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME to build an embedding client."
        )

    if os.getenv("AZURE_OPENAI_API_KEY"):
        return (
            "azure-openai",
            AzureOpenAIEmbeddingClient.from_api_key(
                model=model,
                api_version=os.getenv("AZURE_OPENAI_API_VERSION", "2024-10-21"),
            ),
        )

    return (
        "azure-openai",
        AzureOpenAIEmbeddingClient.from_certificate(
            model=model,
            api_version=os.getenv("AZURE_OPENAI_API_VERSION", "2024-10-21"),
        ),
    )


provider, embedding_client = build_embedding_client()
```

### 4. Embedding result usage (current API)

```python
single = await embedding_client.create("alpha")
vector = single.embedding
all_vectors = single.embeddings
tokens = single.usage.tokens_input
cost = single.usage.cost_estimate
```

For batch input, use `embeddings`:

```python
batch = await embedding_client.create_batch(["alpha", "beta"])

first_vector = batch.embedding
vectors = batch.embeddings
tokens = batch.usage.tokens_input
cost = batch.usage.cost_estimate
```

`create(...)` and `create_batch(...)` return `EmbeddingResult`.

`EmbeddingResult` has this invariant:

- `result.embedding == result.embeddings[0]`
- `create(...)` returns one vector in `result.embeddings`, and the same vector is also exposed as `result.embedding`
- `create_batch(...)` returns all vectors in `result.embeddings`, and `result.embedding` is just the first vector for convenience

## Guardrails

- **Environment Loading:** Always use `load_dotenv(find_dotenv(), override=True)` before initializing clients in scripts or notebooks.
- **Client Reuse:** Prefer creating one client instance and reusing it instead of re-initializing for each call.
- **Factory vs. Constructor:** Use factory methods (`from_api_key`, `from_certificate`) for standard auth. Use constructor injection only for custom-configured SDK instances.
- **Single-provider init for embeddings:** In notebooks/demos, initialize OpenAI **or** Azure (not both) to avoid missing-env failures.
- **Embedding API shape:** Do not expect raw `list[float]` from `create(...)`; read vectors from `EmbeddingResult`.
- **Preferred field choice:** Use `result.embedding` when you expect exactly one vector. Use `result.embeddings` when you need batch-shaped output or want code that treats single and batch calls uniformly.
- **Do not assume `embedding` is batch output:** `result.embedding` is only the first vector, even for `create_batch(...)`.
- **Cost precision:** `usage.cost_estimate` is rounded to 15 decimals; tiny single-call embedding costs can still be very small.

````
