TypeScript SDK Reference
Full type-safe access to the Tapas API. Every response field is typed, every error is catchable, and every integration pattern is documented with working examples.
Installation
Install via your preferred package manager. The SDK ships with TypeScript types included — no @types package needed.
npm install @tapas-ai/sdk # or yarn add @tapas-ai/sdk # or pnpm add @tapas-ai/sdk
fetch support.Type Reference
All interfaces and types exported by @tapas-ai/sdk. Copy this block into your project to use Tapas types without installing the SDK.
// ─────────────────────────────────────────────────────────────────
// Core types exported from @tapas-ai/sdk
// ─────────────────────────────────────────────────────────────────
export type RoutingMethod = 'cosine' | 'smart-router' | 'hybrid';
export type ResponseMode = 'cache' | 'llm';
/** Full response returned by every Tapas query */
export interface TapasResponse {
/** How the answer was served: 'cache' (LEM) or 'llm' (full inference) */
mode: ResponseMode;
/** Whether Low Energy Mode was active for this query */
lemMode: boolean;
/** Full prose answer — populated in LLM mode */
answer: string;
/** Bullet-point list — populated in cache / LEM mode */
bullets: string[] | null;
/** Matched knowledge category name (e.g. "Quantum Computing") */
category: string;
/** Top-level domain slug (e.g. "science_technology") */
domain: string;
/** Cosine similarity score 0–1 between query and cached entry */
confidence: number;
/** Classification method used to route this query */
routingMethod: RoutingMethod;
/** Watt-hours consumed by this query */
energyWhUsed: number;
/** Watt-hours saved vs. full GPU inference */
energyWhSaved: number;
/** End-to-end latency in milliseconds */
responseTimeMs: number;
/** Cache entry ID — null when served by LLM */
cachedResponseId: string | null;
}
/** Options accepted by askTapas() and the TapasClient */
export interface TapasAskOptions {
/** The user's question */
query: string;
/** Enable Low Energy Mode — returns bullet points from cache */
lemMode?: boolean;
/** Hint the router to a specific domain slug */
domain?: string;
}
/** Configuration for TapasClient */
export interface TapasClientConfig {
apiKey: string;
baseUrl?: string; // defaults to 'https://tapas.one'
timeout?: number; // ms, defaults to 10000
}TapasClient
The primary SDK entry point. Initialise once at the module level and reuse across your application. The client handles retries, timeouts, and API key injection automatically.
import { TapasClient } from '@tapas-ai/sdk';
// Initialise once — reuse across your app
const tapas = new TapasClient({
apiKey: process.env.TAPAS_API_KEY!,
baseUrl: 'https://tapas.one',
timeout: 8000,
});
// ── Basic query ──────────────────────────────────────────────────
const response = await tapas.ask({
query: 'How does quantum computing work?',
lemMode: true,
});
if (response.mode === 'cache') {
// Served from semantic cache — 0.001 Wh used
console.log('Routing:', response.routingMethod, '@', response.confidence.toFixed(2));
console.log('Latency:', response.responseTimeMs, 'ms');
console.log('Saved:', response.energyWhSaved.toFixed(3), 'Wh');
(response.bullets ?? []).forEach(b => console.log('•', b));
} else {
// Full LLM inference — 3.0 Wh used
console.log('Answer:', response.answer);
console.log('Category:', response.category, '|', response.domain);
}| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | Your Tapas API key (required) |
| baseUrl | string | https://tapas.one | Override for self-hosted instances |
| timeout | number | 10000 | Request timeout in milliseconds |
Fetch Helper
Prefer not to install a package? Copy this zero-dependency typed helper directly into your project. It uses the native fetch API and returns a fully typed TapasResponse.
// Zero-dependency fetch helper (no SDK required)
async function askTapas(
options: TapasAskOptions,
baseUrl = 'https://tapas.one'
): Promise<TapasResponse> {
const url = baseUrl + '/api/trpc/query.ask';
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ json: options }),
});
if (!res.ok) throw new Error('Tapas API error: ' + res.status);
const data = await res.json();
return data.result.data as TapasResponse;
}Error Handling
The SDK exports typed error classes so you can handle rate limits, network failures, and API errors distinctly without string-matching error messages.
import { TapasError, TapasRateLimitError, TapasNetworkError } from '@tapas-ai/sdk';
try {
const response = await tapas.ask({ query: 'What is inflation?', lemMode: true });
console.log(response.bullets);
} catch (err) {
if (err instanceof TapasRateLimitError) {
// HTTP 429 — back off and retry
console.warn('Rate limited. Retry after:', err.retryAfter, 'ms');
} else if (err instanceof TapasNetworkError) {
// Network timeout or DNS failure
console.error('Network error:', err.message);
} else if (err instanceof TapasError) {
// All other Tapas API errors
console.error('Tapas error', err.statusCode, err.message);
} else {
throw err; // Re-throw unknown errors
}
}React Hook
A drop-in useTapas() hook for React applications. Manages loading, error, and response state — copy it directly into your hooks/ directory.
// hooks/useTapas.ts
import { useState, useCallback } from 'react';
import type { TapasResponse, TapasAskOptions } from '@tapas-ai/sdk';
interface UseTapasState {
data: TapasResponse | null;
loading: boolean;
error: string | null;
}
export function useTapas() {
const [state, setState] = useState<UseTapasState>({
data: null, loading: false, error: null,
});
const ask = useCallback(async (options: TapasAskOptions) => {
setState(s => ({ ...s, loading: true, error: null }));
try {
const res = await fetch('/api/trpc/query.ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ json: options }),
});
const json = await res.json();
setState({ data: json.result.data, loading: false, error: null });
} catch (e) {
setState(s => ({ ...s, loading: false, error: String(e) }));
}
}, []);
return { ...state, ask };
}
// ── Usage in a component ─────────────────────────────────────────
export function AskBox() {
const { data, loading, error, ask } = useTapas();
return (
<div>
<button
onClick={() => ask({ query: 'What is inflation?', lemMode: true })}
disabled={loading}
>
{loading ? 'Asking…' : 'Ask Tapas'}
</button>
{error && <p className="text-red-500">{error}</p>}
{data?.mode === 'cache' && (
<ul>
{(data.bullets ?? []).map((b, i) => <li key={i}>• {b}</li>)}
</ul>
)}
{data?.mode === 'llm' && <p>{data.answer}</p>}
</div>
);
}Batch Queries
Use Promise.all to fire multiple queries concurrently. Each query is independently cached — batch requests multiply your energy savings.
// Process multiple queries concurrently
const queries = [
'What is inflation?',
'How does CRISPR work?',
'Explain index funds',
];
const results = await Promise.all(
queries.map(query => tapas.ask({ query, lemMode: true }))
);
const totalSaved = results.reduce((sum, r) => sum + r.energyWhSaved, 0);
console.log(`Batch: ${results.length} queries, ${totalSaved.toFixed(3)} Wh saved`);
results.forEach((r, i) => {
console.log(`[${i + 1}] ${r.mode === 'cache' ? '⚡ cache' : '🤖 llm'} — ${r.category}`);
});