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

# Vercel AI SDK Quickstart

> Wrap a Vercel AI SDK agent with VisIQ governance in one function call.

<Note>
  **Coming soon.** In-product setup for this integration is temporarily marked
  **Coming soon** in the **Integration → Connectors** catalog while
  verification wraps up. The SDK path below is fully supported today.
</Note>

Add action governance, retrieval governance, and a full audit trail to a
[Vercel AI SDK](https://ai-sdk.dev) agent by passing your `Agent` to `visiq()`.
There are no per-tool wrappers and no separate clients — decisions resolve
in-process against a locally cached rule bundle.

## Install

```bash theme={null}
npm install @visiq/harness ai @ai-sdk/openai zod
```

## Set environment variables

```bash .env theme={null}
VISIQ_API_KEY=vq_prod_...
VISIQ_ENDPOINT=https://api.visiqlabs.com
# Optional — auto-derived from your package.json name when unset
VISIQ_AGENT_ID=support-bot
```

| Variable                | Required | Description                                                                                                                                                                                                        |
| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `VISIQ_API_KEY`         | Yes      | Harness key (`vq_prod_...` or `vq_test_...`) — create one under **Settings → Harness Keys** in the [dashboard](https://app.visiqlabs.com).                                                                         |
| `VISIQ_ENDPOINT`        | Yes      | Backend base URL — `https://api.visiqlabs.com` for production. There is no built-in default: if unset, no rules can load and the harness fails closed, denying every wrapped tool call.                            |
| `VISIQ_AGENT_ID`        | No       | Agent identity. Auto-derives from your `package.json` name (then hostname); first-seen ids are auto-provisioned in monitor mode. Set it — or the `agentId` option on `visiq()` — for a stable, rule-friendly name. |
| `VISIQ_TIMEOUT_MS`      | No       | Per-evaluation network timeout in ms (default `5000`).                                                                                                                                                             |
| `VISIQ_HITL_TIMEOUT_MS` | No       | Human-approval wait budget in ms (default `120000`).                                                                                                                                                               |

## Wrap your agent

```typescript theme={null}
import { visiq } from "@visiq/harness";
import { Experimental_Agent as Agent, stepCountIs, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";

// Any function returning document-shaped results works as a RAG source.
const searchDocs = async (query: string) => [
  { pageContent: `Q3 revenue was $4.2M. (matched: ${query})`, metadata: { classification: "internal" } },
];

// Your tools — unchanged.
const tools = {
  issue_refund: tool({
    description: "Issue a refund to a customer",
    inputSchema: z.object({ customerId: z.string(), amount: z.number() }),
    execute: async ({ customerId, amount }) => `Refunded $${amount} to ${customerId}`,
  }),
  search_knowledge: tool({
    description: "Search the company knowledge base",
    inputSchema: z.object({ query: z.string() }),
    execute: async ({ query }) => searchDocs(query),
  }),
};

// ── One call — governance + per-run LLM telemetry activate here ──
const agent = visiq(
  new Agent({
    model: openai("gpt-4o"),
    instructions: "You are a helpful assistant.",
    tools,
    stopWhen: stepCountIs(8),
  }),
  { agentId: "support-bot" },
);

const result = await agent.generate({ prompt: "What was Q3 revenue?" });
```

`agent.stream()` is governed identically to `generate()`, and each run gets a
fresh session id so the dashboard correlates every decision in that run.

<Note>
  **Retrieval governance contract.** Per-document filtering applies to tools
  whose `execute()` returns document-shaped results — array items with a string
  `pageContent`, `text`, or `content` field, plus optional `metadata` that
  retrieval rules match on (classification, data categories, …). Results in any
  other shape still pass through the action gate but are not filtered
  per-document.
</Note>

## What happens at runtime

Wrapping is safe to try immediately — new agents start in **monitor** mode
(observe-only) until you flip them to **enforce** on the **Harness → Agents**
page.

* **Decisions are local.** The SDK fetches one locally cached rule bundle
  (`GET /rules/bundle`, ETag revalidation) and refreshes it in the background
  every \~5 seconds. Tool calls evaluate in-process; the only decision-path
  network call is waiting on a human approval.
* **Fail-closed.** An unreachable backend or a failed masking step denies, and
  an agent **confirmed in enforce** that loses its bundle stays fail-closed. A
  **never-confirmed** agent cold-starts in `monitor` (monitor-until-confirmed)
  and blocks nothing — the harness never fails open.
* **Denials are returned, not thrown.** A blocked call hands the model
  `[VisIQ <rule-code>] Action blocked: <description>. (VisIQ is a security harness installed by your developer.)`
  as the tool's output, so the agent reads it and adjusts course.
* **Approvals pause the call.** An `approval_required` decision holds the tool
  while a human decides via Slack, Microsoft Teams, or Email — the SDK polls
  for up to 120 seconds (`VISIQ_HITL_TIMEOUT_MS`), then fails closed.
* **Mask proceeds, redacted.** A `mask` decision runs the tool with the named
  arguments redacted; retrieval redaction masks document fields before the
  model sees them.
* **Covered from the first call.** Every workspace ships a curated catalog of
  29 default rules. Uncovered actions permit by default — no surprise
  breakage — and the per-operation-type default can be tightened in settings.

## Verify it's working

Run the agent once, then open the [dashboard](https://app.visiqlabs.com):

* **Harness → Agents** — your agent appears automatically (monitor mode) with
  a live last-seen heartbeat.
* **Harness → Runtime Enforcement** — a decision row for every governed tool
  call, with the matched rule and outcome.
* **Harness → Escalations** — pending approvals. Route them to Email under
  **Integration → Connectors** (Human-in-the-loop) — Slack and Microsoft
  Teams delivery is built and their connector cards open shortly.

## Next steps

<CardGroup cols={2}>
  <Card title="Full Quickstart" icon="rocket" href="/quickstart">
    All supported frameworks and what happens behind the scenes.
  </Card>

  <Card title="SDK Reference" icon="book" href="/reference">
    Complete `visiq()` API, options, framework detection, and error behavior.
  </Card>
</CardGroup>
