Contextwaise

Contextwaise is in early access: API keys and the dashboard open at launch. Join the waitlist to get yours first.

Docs · Vercel AI SDK›
Agent SDK

Vercel AI SDK

One call wraps your model and tools. Everything else in your agent stays the same.

Setup#

Create one Contextwaise instance per agent, then wrap the model and tools you already pass to generateText:

import { generateText, isStepCount } from "ai";
import { openai } from "@ai-sdk/openai";
import { createContextwaise } from "contextwaise";
import { withContextwaise } from "contextwaise/ai-sdk";

// Reads CONTEXTWAISE_API_KEY and CONTEXTWAISE_URL from the environment.
const cw = createContextwaise({
  agent: "code-review",
  budgets: { read_file: 1500 },
});

const { model, tools } = withContextwaise(cw, {
  model: openai("gpt-6.1-sol"),
  tools: myTools,
});

const { text } = await generateText({
  model,
  tools,
  prompt: "Why are the tests failing?",
  stopWhen: isStepCount(10),
});

Create the instance once, at module level, and reuse it across requests: it remembers each tool call's decision so later steps replay it.

Streaming#

The wrapped model and tools work the same way with streamText:

import { streamText, isStepCount } from "ai";

const result = streamText({ model, tools, messages, stopWhen: isStepCount(10) });
return result.toUIMessageStreamResponse();

What changes, what doesn't#

  • The model reads Contextwaise's view of each tool result, through the AI SDK's own toModelOutput hook.
  • Your app still gets every tool's full output: in steps, in the UI stream, and in your tool's return value.
  • The history stores the view, so later turns resend the same bytes. Apps that rebuild messages from UI history on every turn get the same view again: decisions are replayed by tool call id.
  • Your tools are unchanged: same names, schemas and code.

The expand tool#

An expand tool is added to your tools automatically. When a result was trimmed, the model sees a short note with a reference, and can call expand with that reference and a question describing what it needs. It gets back the matching parts of the original output, or the start of it if no question is given.

Note
Calls to expand are a quality signal: they show where trimming went too far. The dashboard shows an expand rate per tool: when it is high, raise that tool's budget.

How relevance knows the intent#

A tool's arguments rarely say why it was called (run_tests(), ls .). The adapter records the user's latest message and any text the model wrote before the call, and uses it with the arguments to judge which parts of the result matter.

Serverless and scripts#

Dashboard reports are sent in the background, in batches. In short-lived processes, flush them before the process ends:

export async function POST(req: Request) {
  const { text } = await generateText({ model, tools, prompt, stopWhen: isStepCount(10) });
  await cw.flush(); // send pending dashboard reports before the function ends
  return Response.json({ text });
}

Reports that can't be sent are dropped: they never slow down or fail your agent.