Skip to main content
Use this path when your runtime is TypeScript-first and already built around the Vercel AI SDK. Run CLI Setup and TypeScript SDK first, then add the AI SDK layer. CAW does not ship a dedicated AI SDK adapter. The recommended pattern is to keep CAW behind a small set of AI SDK tools backed by @cobo/agentic-wallet.

5-minute outcome

  1. Create CAW-backed tools in TypeScript
  2. Submit a pact before execution
  3. Execute a blockchain action
  4. Return policy denials as normal tool output
  5. Track the result by request_id

Step 1: Install

npm install @cobo/agentic-wallet ai @ai-sdk/openai zod

Step 2: Configure environment

export AGENT_WALLET_API_URL=https://api.agenticwallet.cobo.com
export AGENT_WALLET_API_KEY=your-api-key
export OPENAI_API_KEY=your-openai-api-key

Step 3: Build a narrow CAW tool set

vercel_ai_sdk_quickstart.ts
import { generateText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
import {
  Configuration,
  PactsApi,
  TransactionRecordsApi,
  TransactionsApi,
} from '@cobo/agentic-wallet';

const config = new Configuration({
  apiKey: process.env.AGENT_WALLET_API_KEY!,
  basePath: process.env.AGENT_WALLET_API_URL!,
});

const pactsApi = new PactsApi(config);
const txApi = new TransactionsApi(config);
const recordsApi = new TransactionRecordsApi(config);

async function returnPolicyDenial<T>(work: () => Promise<T>) {
  try {
    return await work();
  } catch (error) {
    return (error as {
      response?: { data?: { error?: Record<string, unknown> } };
    }).response?.data?.error ?? { error: 'UNKNOWN_ERROR' };
  }
}

const tools = {
  submit_pact: tool({
    description: 'Submit a pact and return the pact id.',
    inputSchema: z.object({
      wallet_id: z.string(),
      intent: z.string(),
    }),
    execute: async ({ wallet_id, intent }) => {
      const response = await pactsApi.submitPact({
        wallet_id,
        intent,
        spec: {
          completion_conditions: [{ type: 'time_elapsed', threshold: '86400' }],
        },
      });
      return response.data.result;
    },
  }),
  contract_call: tool({
    description: 'Execute a policy-enforced contract call.',
    inputSchema: z.object({
      wallet_uuid: z.string(),
      contract_addr: z.string(),
      calldata: z.string(),
      request_id: z.string(),
    }),
    execute: async ({ wallet_uuid, contract_addr, calldata, request_id }) => {
      return await returnPolicyDenial(async () => {
        const response = await txApi.contractCall(wallet_uuid, {
          chain_id: 'BASE_ETH',
          contract_addr,
          calldata,
          value: '0',
          request_id,
        });
        return response.data.result;
      });
    },
  }),
  get_transaction_record_by_request_id: tool({
    description: 'Look up a transaction record by request id.',
    inputSchema: z.object({
      wallet_uuid: z.string(),
      request_id: z.string(),
    }),
    execute: async ({ wallet_uuid, request_id }) => {
      const response = await recordsApi.getTransactionRecordByRequestId(wallet_uuid, request_id);
      return response.data.result;
    },
  }),
};

const result = await generateText({
  model: openai('gpt-4.1-mini'),
  tools,
  maxSteps: 6,
  system:
    'Before executing blockchain actions, submit a pact and wait until it is active. If a tool returns a policy denial, read the suggestion and retry with compliant params. After submission, track the result by request_id.',
  prompt:
    'Submit a pact, execute a contract call with request_id swap-2026-001, adapt if denied, then look up the transaction record.',
});

console.log(result.text);
Start with this subset:
  • submit_pact
  • contract_call or transfer_tokens
  • get_transaction_record_by_request_id
Add get_audit_logs once you want the model to summarize operator history too. Do not expose wallet management, delegation, and every transaction primitive unless the runtime really needs them.

Design guidance

  • keep the tool set narrow and role-specific
  • use pact submission as a mandatory step before execution
  • return policy denials as normal tool output so the model can adapt
  • prefer transaction-record tracking over raw transaction polling