TypeScript Setup
Installation
Section titled “Installation”Install the core SDK, the Vitest integration and Vitest:
npm install -D "@attest-ai/core@>=1.1.0" "@attest-ai/vitest@>=1.1.0" "vitest@^4"Create an Agent
Section titled “Create an Agent”Use the agent() wrapper from @attest-ai/core: it supplies a TraceBuilder and returns an AgentResult. Your code or adapter records each LLM and tool call; the wrapper does not intercept arbitrary calls automatically. This is the quickstart-ts example from attest-examples:
/** * Simple customer support agent for Attest quickstart example. * * TypeScript port of the Python quickstart — same agent, same trace structure. */import { agent, type TraceBuilder } from "@attest-ai/core";
export const customerSupport = agent( "customer-support", (builder: TraceBuilder, args: Record<string, unknown>) => { const orderId = args.order_id as string;
// Simulate LLM call to understand the customer's request builder.addLlmCall("gpt-4", { args: { messages: [ { role: "user", content: `Customer wants to return order ${orderId}. Process the refund.`, }, ], }, result: { response: "I will process the refund for this order." }, });
// First tool: look up the order details builder.addToolCall("lookup_order", { args: { order_id: orderId }, result: { order_id: orderId, status: "delivered", amount: 89.99, customer: "John Doe", }, });
// Second tool: process the refund builder.addToolCall("process_refund", { args: { order_id: orderId, amount: 89.99 }, result: { refund_id: "RFD-001", status: "processed" }, });
// Set metadata builder.setMetadata({ total_tokens: 150, cost_usd: 0.005, latency_ms: 1200, model: "gpt-4", });
return { message: `Your refund of $89.99 has been processed successfully. Refund ID: RFD-001. The funds will appear in your account within 3-5 business days.`, structured: { refund_id: "RFD-001", amount: 89.99, status: "processed", }, }; },);Write Your First Test
Section titled “Write Your First Test”Build the assertion chain with attestExpect from @attest-ai/core and evaluate it with evaluate from @attest-ai/vitest:
/** * Tests for the customer support agent. * * Demonstrates Attest assertions across layers 1-4: * - Layer 1: Schema validation * - Layer 2: Cost and performance constraints * - Layer 3: Trace structure (tool ordering) * - Layer 4: Content validation */import { attestExpect } from "@attest-ai/core";import { evaluate } from "@attest-ai/vitest";import { describe, it, expect } from "vitest";import { customerSupport } from "./agent";
describe("customer support agent", () => { it("processes refunds correctly", async () => { const result = customerSupport({ order_id: "ORD-12345" });
const chain = attestExpect(result) // Layer 1: Schema validation .outputMatchesSchema({ type: "object", properties: { refund_id: { type: "string" }, amount: { type: "number" }, status: { type: "string" }, }, required: ["refund_id", "status"], }) // Layer 2: Cost and performance constraints .costUnder(0.01) .latencyUnder(5000) .tokensUnder(500) // Layer 3: Trace structure .toolsCalledInOrder(["lookup_order", "process_refund"]) .requiredTools(["lookup_order", "process_refund"]) .forbiddenTools(["delete_order", "cancel_refund"]) // Layer 4: Content validation .outputContains("refund") .outputContains("processed") .outputNotContains("error");
const evaluated = await evaluate(chain); expect(evaluated.passed).toBe(true); });});Before the first test, download and check the matching engine with npx attest doctor. On a cold machine the initial download can exceed Vitest’s default five-second test timeout. Then run the suite:
npx attest doctornpx vitest runevaluate(chain) throws on a hard failure and skips the test when an assertion could not be evaluated. Use inspect(chain) to get the results without enforcing them.
Using the TraceBuilder
Section titled “Using the TraceBuilder”Build traces manually for custom agent architectures. The metadata below is invented sample usage, not a provider price or measured API cost:
import { AgentResult, TraceBuilder, attestExpect } from "@attest-ai/core";import { evaluate } from "@attest-ai/vitest";import { it } from "vitest";
it("answers arithmetic", async () => { const builder = new TraceBuilder("my-agent"); builder.setInput({ query: "What is 2 + 2?" }); builder.addLlmCall("gpt-4.1", { args: { model: "gpt-4.1" }, result: { content: "4" } }); builder.setOutput({ message: "The answer is 4." }); builder.setMetadata({ total_tokens: 50, cost_usd: 0.001, latency_ms: 800 });
const result = new AgentResult(builder.build());
await evaluate(attestExpect(result).outputContains("4").costUnder(0.05));});Environment Variables
Section titled “Environment Variables”| Variable | Purpose |
|---|---|
OPENAI_API_KEY | OpenAI API key for judge/embedding assertions |
ATTEST_ENGINE_PATH | Override engine binary location |
ATTEST_SIMULATION | Skip embedding and judge provider calls; application calls still need mocks |
ATTEST_JUDGE_PROVIDER | LLM judge provider: openai, anthropic, gemini, acp |
ATTEST_JUDGE_MODEL | Model for judge assertions (e.g., gpt-4.1) |
Next Steps
Section titled “Next Steps”- Quickstart — Framework overview and assertion layers
- TypeScript Expect DSL — All assertion methods
- Framework Adapters — Adapter architecture and usage
- Multi-Agent Guide — Testing multi-agent systems