tako-sdk
v1.4.10
Published
JavaScript/TypeScript SDK for the Tako API
Readme
Tako TypeScript SDK
The Tako SDK provides typed access to the Tako API from Node.js (≥ 18), the browser, and edge runtimes. It ships fully typed request/response models, a Tako client, and a live agent-streaming API. Generated from Tako's OpenAPI spec with openapi-generator (typescript-fetch) — zero runtime dependencies.
Installation
npm install tako-sdkAuthentication
Create an API key from your Tako account and keep it out of source control:
import { Tako } from "tako-sdk";
const tako = new Tako({ apiKey: process.env.TAKO_API_KEY! });Caller channel
Every request carries X-Tako-Caller: channel=sdk_typescript, client_version="<version>"
so Tako can measure SDK share of API traffic. It holds the channel name and the
published package version, nothing about you or your query, and it has no effect
on what a request returns or how Tako bills it.
channel exists for Tako's own wrapper packages, such as the Tako AI SDK
integration, to attribute their traffic separately from this SDK's. The
CallerChannel type accepts only "sdk_typescript" and "ai_sdk" — you can't
pass an arbitrary product name.
Usage
const results = await tako.search({ query: "S&P 500 performance this year" });
console.log(results.request_id);
for (const card of results.cards ?? []) {
console.log(card.title, card.webpage_url);
}Operations
| Method | Description |
| -------------------------- | ----------------------------------------------------------------------- |
| tako.search(request) | Search the Tako knowledge base; returns matching cards and web results. |
| tako.answer(request) | Get a written answer with supporting cards. |
| tako.createCard(request) | Build a visualization card from component configurations. |
| tako.contents(request) | Fetch downloadable content (e.g. a CSV) for a card or web URL. |
Fetch the underlying data for a card returned by a search (guard for cards with no exportable content):
const results = await tako.search({ query: "US Oil Prices" });
const card = (results.cards ?? []).find((c) => c.webpage_url && c.content);
if (card?.webpage_url) {
const contents = await tako.contents({ url: card.webpage_url });
for (const item of contents.contents ?? []) console.log(item.content_format, item.url); // url is populated only in URL delivery mode (url?: string | null)
}Async only. JavaScript is uniformly promise-based, so there is a single
Takoclient (unlike the Python SDK's separateTako/AsyncTako). Every operation returns aPromise.
Agents
Two agent products hang off tako.agent:
| Namespace | Endpoint | Product |
| ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------ |
| tako.agent.retrieval.* | /v1/agent/retrieval/runs | Retrieval Agent — agentic data retrieval (multi-hop lookup, cohort resolution, structured outputs) |
| tako.agent.answer.* | /v1/agent/answer/runs | Answer Agent — opinionated agentic research returning cited prose |
Each exposes run(req) (202 dispatch → run handle), get(runId) (poll for status), and stream(req) (live SSE). (tako.agent.answer.*, the Answer Agent, is distinct from tako.answer(), the one-shot /v1/answer call.)
Streaming
Stream a run live over Server-Sent Events. The stream yields typed per-product envelopes (RetrievalAgentStreamEnvelope / AnswerAgentStreamEnvelope) and auto-reconnects (resuming via the last seq) on transient drops. Always close it (or use try/finally):
const stream = tako.agent.retrieval.stream({
query: "Which S&P 500 semis grew revenue fastest in 2024?",
});
try {
for await (const event of stream) {
console.log(event.seq, event.block.kind);
}
// The stream ends at stream_done. If it ended without a terminal result
// (and produced at least one event, so run_id is known), poll for status:
if (stream.result === null && stream.run_id !== null) {
const run = await tako.agent.retrieval.get(stream.run_id);
console.log(run.status);
}
} finally {
await stream.close();
}The Answer Agent is identical with tako.agent.answer.*. Tune reconnect behavior with the second argument — maxRetries (reconnect attempts after a transient drop, default 5) and readTimeoutMs (idle read before a connection is treated as dropped, default 120000):
const stream = tako.agent.retrieval.stream(
{ query: "..." },
{ maxRetries: 5, readTimeoutMs: 120_000 },
);Non-streaming dispatch/poll is also available: tako.agent.retrieval.run(req) returns a RetrievalAgentRun (202 dispatch); tako.agent.retrieval.get(runId) polls for status.
Structured output (Retrieval Agent)
Pass an output_schema (JSON Schema) to shape the response. Mark a property with "x-tako-dataset": true to request a dataset slot — filled with exact retrieved rows as a TakoDataset. Two helpers make this ergonomic:
deriveResponseSchema(schema)— the schemastructured_outputactually validates against (each slot becomesTakoDataset | null). Pair with a JSON Schema validator such as ajv.TakoDatasetView— a records view over a filled slot..recordsreturns one plain object per row (dependency-free).
import { Tako, TakoDatasetView, deriveResponseSchema } from "tako-sdk";
const schema = {
type: "object",
properties: {
headline: { type: "string" },
cohort: { "x-tako-dataset": true, columns: ["company", "revenue"] },
},
required: ["headline", "cohort"],
};
const tako = new Tako({ apiKey: process.env.TAKO_API_KEY! });
const dispatched = await tako.agent.retrieval.run({ query: "...", output_schema: schema });
const run = await tako.agent.retrieval.get(dispatched.run_id); // poll to a terminal status
const derived = deriveResponseSchema(schema); // validate with ajv against this
const output = run.result?.structured_output;
if (output) {
const view = new TakoDatasetView(output.cohort);
console.log(view.records); // [{ company: "Nvidia", revenue: 130497000000 }, ...]
}See examples/ for runnable scripts: retrieval_agent_streaming.ts, answer_agent_streaming.ts, and retrieval_agent_structured_output.ts.
Configuration
By default the client targets the Tako production API (https://tako.com/api). Override the base path for staging or self-host:
const tako = new Tako({ apiKey: "...", basePath: "https://staging.tako.com/api" });Error handling
Non-2xx responses throw a ResponseError carrying the raw Response:
import { ResponseError } from "tako-sdk";
try {
await tako.search({ query: "..." });
} catch (err) {
if (err instanceof ResponseError) {
console.error(err.response.status, await err.response.text());
} else {
throw err;
}
}TypeScript
All request/response models are exported as types:
import type {
SearchRequest,
SearchResponse, // .cards is Array<TakoCard>
AnswerResponse, // .cards is Array<TakoCard>
ContentsRequest,
ContentsResponse,
CreateCardRequest,
TakoCard, // card type returned by search() and answer()
ThinVizCard, // card type returned by createCard()
RetrievalAgentRunRequest,
RetrievalAgentStreamEnvelope,
AnswerAgentRunRequest,
AnswerAgentStreamEnvelope,
TakoDataset,
} from "tako-sdk";search and answer return TakoCard[] via SearchResponse.cards / AnswerResponse.cards. createCard returns a ThinVizCard.
License
MIT
