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

# Agents & Automation

> Build unattended, agentic, or automated systems on Prem API: which integration to use, required config, and the operational gotchas that matter at scale.

This page is for anyone building a system that calls Prem API **without a human watching each call**: agent loops, batch jobs, evaluation harnesses, or any tool that fires many requests unattended. Unattended callers hit different failure modes than an interactive app — a truncated response, a burned rate-limit budget, or a duplicated retry does not get noticed until it has already happened many times.

<Tip>
  If you want an AI coding agent (Claude Code, Cursor, Windsurf) to help you **write** this integration, see [Use LLMs](/use-llms) — it loads the Prem API docs into your coding agent's context. This page is about the system you build calling Prem API, not the coding agent that helps you build it.
</Tip>

## Pick your integration

|                  | TypeScript SDK                            | Confidential Proxy                                                                                              |
| ---------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Best for**     | Node.js agents, single-process automation | Polyglot agent frameworks (LangChain, Python/Go agent loops), anything already using an OpenAI or Anthropic SDK |
| **Encryption**   | In-process                                | A local HTTP process encrypts/decrypts for you                                                                  |
| **Code changes** | Use `@premai/api-sdk` instead of `openai` | None — point `baseURL` at the proxy                                                                             |

See [Developer Experience](/developer-experience) for both, in detail. For an agent that runs continuously, run the Confidential Proxy as a **background daemon** rather than in the foreground:

```bash theme={"system"}
confidential-proxy start --compat openai
confidential-proxy status
```

See [Confidential Proxy](/confidential-proxy#run-the-proxy-as-a-daemon) for the full daemon lifecycle (`start` / `stop` / `status`, PID and log files, graceful shutdown).

## Required configuration

Both integration paths need the same four values. Set them once, in the environment the agent runs in — not per call:

| Variable       | Used by | Description                                                                                           |
| -------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| `PREM_API_KEY` | Both    | Your API key. See [API Keys](/api-keys).                                                              |
| `CLIENT_KEK`   | Both    | Your Key Encryption Key. You generate and keep it; Prem never sees it. See [Encryption](/encryption). |
| `PROXY_URL`    | Both    | The Prem API Gateway endpoint.                                                                        |
| `ENCLAVE_URL`  | Both    | The enclave endpoint.                                                                                 |

Get the current `PROXY_URL` / `ENCLAVE_URL` values from [`dashboard.prem.io/endpoints.json`](https://dashboard.prem.io/endpoints.json) at deploy time rather than hardcoding them.

## Gotchas that only show up at automation scale

These are easy to miss in a one-off script and expensive to miss in a loop that runs thousands of times.

<AccordionGroup>
  <Accordion title="Reasoning is on by default and is billed">
    Reasoning models generate a chain-of-thought before every answer unless you turn it off.
    Those tokens are billed, count against your rate limit, and share the same inference's token budget as the visible answer — a tight `max_completion_tokens` can be consumed entirely by reasoning, leaving `message.content: null`.

    Default to `reasoning_effort: "none"` in automated pipelines unless you explicitly consume the reasoning trace.
  </Accordion>

  <Accordion title="One active stream per API key on the encrypted endpoint">
    The encrypted `/rvenc/chat/completions` endpoint (used by the TypeScript SDK) always responds over `text/event-stream`, even when you don't set `stream: true` in your request. If a second call comes in on the same API key while one is still in flight, it can return `429` with:

    ```json theme={"system"}
    {"status": 429, "error": "You already have an active chat stream. Please wait for it to complete or try again in a few moments."}
    ```

    This is separate from the per-tier concurrent-request limits in [Rate limits](/rate-limits). If your agent parallelizes work on the same key, serialize calls per key or use a distinct API key per concurrent worker.
  </Accordion>

  <Accordion title="429 responses don't all look the same">
    Some `429`s come with a structured body and a `Retry-After` header. Others — for example, throttling applied upstream of the gateway — return a generic body with no `Retry-After` header at all. Branch on the HTTP status code, not the body shape, and fall back to your own exponential backoff when the header is missing. See [Rate limits](/rate-limits#non-standard-429-responses).
  </Accordion>

  <Accordion title="Retries need to be idempotent">
    An agent that retries blindly after a timeout or a `5xx` can duplicate the underlying action (a file upload, a resource creation). Send an `Idempotency-Key` header so a retried request has the same effect as the original. See [Idempotency](/idempotency).
  </Accordion>

  <Accordion title="Check finish_reason, not just content">
    A `null` or empty `message.content` is not necessarily a failed call. If `finish_reason` is `"length"`, the token budget ran out — from reasoning, from a long answer, or both. Treat it as truncation and retry with a larger `max_completion_tokens` or a lower `reasoning_effort`, not as an empty result to discard.
  </Accordion>
</AccordionGroup>

## A request shaped for unattended use

```typescript theme={"system"}
import createRvencClient from "@premai/api-sdk";

const client = await createRvencClient({
  apiKey: process.env.PREM_API_KEY,
  clientKEK: process.env.CLIENT_KEK,
});

const response = await client.chat.completions.create({
  model: "glm-5.2",
  messages: [{ role: "user", content: "Summarize this log file." }],
  reasoning_effort: "none",       // skip reasoning unless you consume it
  max_completion_tokens: 4096,    // headroom for the answer
}, {
  headers: { "Idempotency-Key": crypto.randomUUID() }, // safe to retry
});

const choice = response.choices[0];
if (choice.finish_reason === "length") {
  // truncated — raise max_completion_tokens or retry, don't treat as empty
}
console.log(choice.message.content);
```

## Before you deploy

* [ ] `reasoning_effort` set deliberately (`none` by default, or a value you've budgeted `max_completion_tokens` for)
* [ ] Retries use exponential backoff and don't assume `Retry-After` is present
* [ ] Idempotency keys on any retried write
* [ ] Concurrent calls on the same API key are serialized, or spread across multiple keys
* [ ] Every response checks `finish_reason` before treating `content` as final
* [ ] `support_id` is logged on every error for support escalation

<Note>
  This checklist is agent-specific. For the full production checklist (key management, tiers, attestation), see [Production Checklist](/production-checklist).
</Note>

## Related

<CardGroup cols={2}>
  <Card title="Rate limits" icon="wave-pulse" href="/rate-limits" arrow="true">
    Limits by tier, retry code, and non-standard 429 bodies.
  </Card>

  <Card title="Idempotency" icon="fingerprint" href="/idempotency" arrow="true">
    Make retries safe with the Idempotency-Key header.
  </Card>

  <Card title="Confidential Proxy" icon="server" href="/confidential-proxy" arrow="true">
    Daemon mode, config, and connecting any language.
  </Card>
</CardGroup>
