Argosvix
Docs menuSDK reference

SDK Reference

API reference for @argosvix/sdk. Wrap your AI client once with wrap() and every call is recorded automatically.


Install

npm install @argosvix/sdk@alpha <provider-sdk>

Use openai, @anthropic-ai/sdk, @google/genai, or @mistralai/mistralai as <provider-sdk> (you can mix multiple providers).


wrap(client, options)

Returns a wrapped instance of your AI client. For typical usage (calling create, consuming streams with for-await) you can drop it in without touching the rest of your code.

OpenAI's advanced APIs mostly work as-is after wrapping: .withResponse(), and streaming .tee() / .toReadableStream() / .controller (abort) all keep working. To use them on streams, set stream_options explicitly (without it, a compatibility wrapper is returned for usage recording, and these methods are absent). Two caveats: .asResponse() (reading the raw Response directly) is not supported because it cannot coexist with recording — use the unwrapped client for those specific calls. And since the full stream is read for recording, slow consumption of a received stream temporarily holds the whole response in memory.

import { wrap } from "@argosvix/sdk";
import OpenAI from "openai";

const openai = wrap(new OpenAI(), {
  apiKey: process.env.ARGOSVIX_API_KEY,
  tags: { service: "my-app", env: "prod" },
});

options.apiKey (required)

The argk_... token issued on the API keys page. Pass it from an environment variable.

options.tags (optional)

Arbitrary key/value pairs you can use as filter and aggregation axes on the dashboard. Common examples:

tags: {
  service: "my-app",     // split multiple services in one dashboard
  env: "prod",           // separate staging vs prod counts
  feature: "summarize",  // compare cost / latency per feature
  userId: "u_xxx",       // per-user usage measurement (PII caution — hash recommended)
}

⚠️ Do not put end-user PII (email, name, etc.) into tags (see Terms § 4, paragraph 2).

options.sessionId (optional)

An ID that groups calls belonging to the same session (conversation). When set, it is stored on each record as sessionId and can be used to filter by session in the query API. In the Python SDK, pass session_id="...".

const openai = wrap(new OpenAI(), {
  apiKey: process.env.ARGOSVIX_API_KEY,
  sessionId: "sess_2026_07_08_abc",
});

options.captureContent (optional, default false)

When true, prompt and completion bodies are included in the records. Non-streaming calls are supported across all 4 providers; streaming calls also capture bodies on all observed paths (OpenAI Chat / OpenAI Responses / Anthropic / Gemini / Mistral, in both TypeScript and Python), accumulating up to 256KB per call — anything beyond is dropped and a truncated marker is appended, and if a stream is interrupted the body captured so far is still recorded.

When a response contains tool calls (function calling), the tool names and arguments are also recorded as toolCalls (PII inside arguments is masked under the same rules as bodies).

const openai = wrap(new OpenAI(), {
  apiKey: process.env.ARGOSVIX_API_KEY,
  captureContent: true,
});

In the Python SDK, pass capture_content=True.

client = wrap(OpenAI(), api_key=os.environ["ARGOSVIX_API_KEY"], capture_content=True)

How it works and how it stays safe:

  • PII masking always runs before sending (emails, card numbers, phone numbers, national IDs, and IP addresses are replaced with [REDACTED_*]).
  • On the server, bodies are stored (AES-256-GCM encrypted) only when the account is on Pro or above and has explicitly opted in to plaintext storage in the dashboard. Without that consent, submitted bodies are discarded, not stored.
  • Viewing, deleting, and access logs for stored bodies are managed under Privacy & Data in the dashboard settings. See Terms Article 4-2 for details.

Deployed prompts and version tagging (resolvePrompt / withPrompt)

Fetch the currently deployed version of a managed prompt from the SDK, and automatically tag calls made with it as prompt ({name}@v{version}) — the foundation for per-version quality and cost comparison.

import { resolvePrompt, withPrompt } from "@argosvix/sdk";

const p = await resolvePrompt("support-bot", {
  apiKey: process.env.ARGOSVIX_API_KEY!,
  // label: "production" (default)
});

await withPrompt(p, async () => {
  // Calls inside get tags.prompt = "support-bot@v3" automatically
  await openai.chat.completions.create({
    model: "gpt-5.5",
    messages: [{ role: "system", content: p.template }],
  });
});
  • resolvePrompt keeps a 60-second TTL cache and falls back to a stale entry on network or server failures, so your hot path never blocks on prompt resolution (a 404 for a missing deployment still throws).
  • An explicit tags.prompt on a call takes precedence over the ambient tag.
  • The Python SDK mirrors this with resolve_prompt(name, api_key=...) and the with_prompt(p): context manager.

flushClient(client)

In short-lived runtimes (Cloudflare Workers, AWS Lambda, Vercel Edge, and similar) you must await flushClient() inside the handler's finally block. Without it, records will not reach the dashboard because the runtime terminates before the SDK finishes sending.

import { wrap, flushClient } from "@argosvix/sdk";

const client = wrap(new OpenAI(), {
  apiKey: process.env.ARGOSVIX_API_KEY,
});

export default {
  async fetch(req, env) {
    try {
      return await handler(client, req, env);
    } finally {
      await flushClient(client);
    }
  },
};

Long-lived processes (Node.js server, Bun, Deno deploy) don't need it. The TypeScript SDK sends automatically once its buffer reaches 100 records (call flushClient() any time to send earlier); the Python SDK flushes in the background roughly every 5 seconds. wrap() is best-effort by design: a failed send to Argosvix never breaks your application's LLM call.


Framework integrations

If you call models through a framework instead of a provider client directly, use the matching integration. Both record the same fields as wrap() (provider, model, tokens, cost, latency, TTFT, cache/reasoning tokens), support the same four providers (OpenAI / Anthropic / Google Gemini / Mistral), and honour budget/policy gates and withTrace grouping. Recording is best-effort — it never breaks your model call.

Vercel AI SDK (ai package)

argosvixMiddleware() returns a wrapLanguageModel-compatible middleware (LanguageModelV2 / V4). Every call through generateText / streamText / generateObject — including calls the AI SDK issues internally for tool loops and multi-step agents — is recorded.

import { openai } from "@ai-sdk/openai";
import { wrapLanguageModel, generateText } from "ai";
import { argosvixMiddleware, flushClient } from "@argosvix/sdk";

const observed = argosvixMiddleware({ apiKey: process.env.ARGOSVIX_API_KEY });
const model = wrapLanguageModel({ model: openai("gpt-5.5"), middleware: observed });

try {
  await generateText({ model, prompt: "hi" });
} finally {
  await flushClient(observed); // or: await observed.flush()
}

Other providers run normally but are not recorded — pass provider in the config to force a mapping.

LangChain.js

argosvixLangChainHandler() returns a callback handler. Pass it in callbacks (per call or at model construction) and every LLM call through LangChain — including chains and agents — is recorded.

import { ChatOpenAI } from "@langchain/openai";
import { argosvixLangChainHandler, flushClient } from "@argosvix/sdk";

const handler = argosvixLangChainHandler({ apiKey: process.env.ARGOSVIX_API_KEY });
const model = new ChatOpenAI({ model: "gpt-5.5" });

try {
  await model.invoke("hi", { callbacks: [handler] });
} finally {
  await flushClient(handler); // or: await handler.flush()
}

Covered methods per provider

ProviderCovered methods
OpenAIchat.completions.create, responses.create (both with streaming)
Anthropicmessages.create (with streaming)
Geminimodels.generateContent, models.generateContentStream
Mistralchat.complete, chat.stream

A note on interrupting streams early in the Python SDK: breaking out of a synchronous iteration records immediately, but breaking out of async for does not guarantee immediate cleanup due to Python language semantics. To record reliably, consume the stream with async with, or call await stream.aclose() after breaking.

Any other method passes through (not recorded, but errors are not swallowed either). If you want a method outside this list to be recorded, email hello@argosvix.com.


Types

import type { ArgosvixConfig } from "@argosvix/sdk";

interface ArgosvixConfig {
  /** argk_... token issued on the dashboard */
  apiKey: string;
  /** Arbitrary key/value pairs (filter / aggregation axes) */
  tags?: Record<string, string | number | boolean>;
  /** Custom base URL (e.g. proxy or testing; usually not needed) */
  endpoint?: string;
}

Troubleshooting

  • No records appear on the dashboard — check that you didn't forget flushClient (in short-lived runtimes), verify network reachability, and double-check the apiKey for typos.
  • Records take a while to appear — sends are batched (TypeScript: at 100 records or on flushClient(); Python: roughly every 5 seconds). For low-traffic processes, call flushClient() / flush() to see records immediately.
  • Cost shows as zero — the pricing table for that provider or model may not be registered yet. Email hello@argosvix.com and we can add it.

Support

hello@argosvix.com

Last updated: 2026-07-09