@takoviz/ai-sdk 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -8
- package/dist/index.d.ts +288 -39
- package/dist/index.js +129 -51
- package/package.json +15 -6
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npm install @takoviz/ai-sdk ai
|
|
|
10
10
|
|
|
11
11
|
## Setup
|
|
12
12
|
|
|
13
|
-
Get an API key from the [Tako
|
|
13
|
+
Get an API key from the [Tako developer console](https://tako.com/console/api-keys) and set it as an environment variable:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
export TAKO_API_KEY=your_api_key_here
|
|
@@ -32,7 +32,7 @@ import { openai } from '@ai-sdk/openai';
|
|
|
32
32
|
import { generateText, isStepCount } from 'ai';
|
|
33
33
|
|
|
34
34
|
const { text } = await generateText({
|
|
35
|
-
model: openai('gpt-
|
|
35
|
+
model: openai('gpt-5.4-mini'),
|
|
36
36
|
prompt: 'Did AMD or Nvidia grow headcount faster over the last decade?',
|
|
37
37
|
tools: { tako_answer: takoAnswer() },
|
|
38
38
|
stopWhen: isStepCount(5),
|
|
@@ -60,10 +60,10 @@ const tools = {
|
|
|
60
60
|
```typescript
|
|
61
61
|
takoSearch({
|
|
62
62
|
apiKey: 'your_api_key', // optional; defaults to TAKO_API_KEY
|
|
63
|
-
baseUrl: 'https://
|
|
63
|
+
baseUrl: 'https://tako.com', // optional; override for staging
|
|
64
64
|
effort: 'fast', // 'fast' (default) | 'instant' | 'deep'
|
|
65
65
|
sources: { // a source is searched iff its key is present; omit to search both
|
|
66
|
-
|
|
66
|
+
data: { count: 5, includeContents: false }, // legacy alias: tako
|
|
67
67
|
web: { count: 5, includeContents: false },
|
|
68
68
|
},
|
|
69
69
|
countryCode: 'US', // default 'US'
|
|
@@ -81,13 +81,62 @@ takoSearch({
|
|
|
81
81
|
```typescript
|
|
82
82
|
takoContents({
|
|
83
83
|
apiKey: 'your_api_key',
|
|
84
|
-
baseUrl: 'https://
|
|
84
|
+
baseUrl: 'https://tako.com',
|
|
85
85
|
mode: 'url', // 'url' (default) → presigned link; 'inline' → content in the response
|
|
86
86
|
});
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The LLM supplies only the dynamic input: `{ query }` for `takoSearch`/`takoAnswer`, and `{ url }` (a card's `webpage_url` or a web result's `url`) for `takoContents`.
|
|
90
90
|
|
|
91
|
+
### Search and answer options
|
|
92
|
+
|
|
93
|
+
Both tools take the same config. Every field is optional; omit one and the API's default applies.
|
|
94
|
+
|
|
95
|
+
| Option | Type | Notes |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| `effort` | `"fast" \| "instant" \| "deep"` | Default `"fast"`. |
|
|
98
|
+
| `countryCode` / `locale` / `timezone` | `string` | Default `"US"` / `"en-US"`. |
|
|
99
|
+
| `location` | `{ latitude, longitude }` | End-user coordinates. |
|
|
100
|
+
| `outputSettings.imageDarkMode` | `boolean` | |
|
|
101
|
+
| `outputSettings.forceRefresh` | `boolean` | Instant mode only. |
|
|
102
|
+
|
|
103
|
+
**`sources.data`** — the curated Tako source:
|
|
104
|
+
|
|
105
|
+
| Option | Type | Notes |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| `count` | `number` | 1-20, server default 5. |
|
|
108
|
+
| `includeContents` | `boolean` | Inline the card data. |
|
|
109
|
+
| `contentFormat` | `"csv" \| "json_records" \| "json_compact"` | Server default `"json_compact"`. |
|
|
110
|
+
| `nodeIds` | `string[]` | Pin graph nodes. Ids come from the `/v1/graph` endpoints. |
|
|
111
|
+
| `strict` | `boolean` | Return only cards matching a pinned node. Requires `nodeIds`. |
|
|
112
|
+
| `mode` | `"url" \| "inline"` | Server default `"inline"`. Accepted, but the API documents no effect on Tako cards. |
|
|
113
|
+
|
|
114
|
+
**`sources.web`**:
|
|
115
|
+
|
|
116
|
+
| Option | Type | Notes |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| `count` | `number` | 1-20. Server default 5 for `takoSearch`, 3 for `takoAnswer`. |
|
|
119
|
+
| `includeContents` | `boolean` | Include full article text. |
|
|
120
|
+
| `category` | `"news" \| "sports" \| "finance"` | Only `"news"` filters today. |
|
|
121
|
+
| `includeDomains` / `excludeDomains` | `string[]` | Bare hosts, for example `"cnn.com"`. |
|
|
122
|
+
| `publishedAfter` / `publishedBefore` | `string` | ISO `"YYYY-MM-DD"`. Results with no known date are kept. |
|
|
123
|
+
| `snippetMaxChars` | `number` | Server default 1000. |
|
|
124
|
+
| `articleContentMaxChars` | `number` | Server default 30000. |
|
|
125
|
+
|
|
126
|
+
### Contents options
|
|
127
|
+
|
|
128
|
+
| Option | Type | Notes |
|
|
129
|
+
| --- | --- | --- |
|
|
130
|
+
| `mode` | `"url" \| "inline"` | Default `"url"`. Changes the tool description the model reads. |
|
|
131
|
+
| `contentFormat` | `"csv" \| "json_records" \| "json_compact"` | Server default `"csv"` on this surface. |
|
|
132
|
+
| `maxRows` | `number` | Card exports only. The first 20 rows are free; **rows above that bill at the per-1000-row rate**. |
|
|
133
|
+
| `maxChars` | `number` | Web page text only. Server default 1000000, the full page text. |
|
|
134
|
+
| `quoteOnly` | `boolean` | Price the export without fetching it. The request is free and the payload is null. |
|
|
135
|
+
|
|
136
|
+
This SDK does not check the numeric ranges. The API enforces them, so a limit Tako raises works immediately without an SDK release. Most out-of-range values return a 400.
|
|
137
|
+
|
|
138
|
+
**`maxRows` is the exception, and it fails quietly.** A value above the 2,000-row ceiling is clamped, not rejected, and billing counts the rows actually returned. You get a short export, a charge for it, and no error. Check `total_rows` and `truncated` on the returned item to see what you actually got.
|
|
139
|
+
|
|
91
140
|
## Responses
|
|
92
141
|
|
|
93
142
|
`takoSearch` resolves to:
|
|
@@ -96,12 +145,40 @@ The LLM supplies only the dynamic input: `{ query }` for `takoSearch`/`takoAnswe
|
|
|
96
145
|
{
|
|
97
146
|
cards: TakoCard[]; // Tako knowledge cards (title, description, image_url, webpage_url, sources, ...)
|
|
98
147
|
web_results: TakoWebResult[];
|
|
99
|
-
contents_total_cost: number;
|
|
100
148
|
request_id: string;
|
|
149
|
+
usage?: TakoUsage | null; // { total_cost_usd, compute?, data? } — see note
|
|
101
150
|
}
|
|
102
151
|
```
|
|
103
152
|
|
|
104
|
-
|
|
153
|
+
> **Cost reporting.** `usage` is what the API spec defines for per-request cost, but as of 2026-08 it is not populated on any endpoint. For pricing today, read the per-item `content.cost` and `content.export_pricing` on each card, which are populated.
|
|
154
|
+
|
|
155
|
+
`takoAnswer` additionally includes `answer: string` (with `cards[0]` as the lead card). `takoContents` resolves to `{ contents: TakoContentItem[]; request_id: string; usage? }`.
|
|
156
|
+
|
|
157
|
+
The API guarantees only `request_id` — the contract permits omitting the collections — so the tools normalize: `cards`, `web_results` and `contents` are **always arrays**. No `?.` needed.
|
|
158
|
+
|
|
159
|
+
### Reading a card
|
|
160
|
+
|
|
161
|
+
Two fields are worth knowing about:
|
|
162
|
+
|
|
163
|
+
- **`exportable`** — whether `takoContents` can download that card's data. `false` means don't bother; the call returns 403. `true` is eligibility, not a guarantee, so still handle errors.
|
|
164
|
+
- **`data_freshness`** — `{ data_as_of, last_updated }`, so you can tell how current a number is.
|
|
165
|
+
|
|
166
|
+
### Reading a contents item
|
|
167
|
+
|
|
168
|
+
Each item carries a `cost` (USD) and either a presigned `url` + `expires_at` (url mode) or an inline payload (inline mode). `content_format` tells you what you got:
|
|
169
|
+
|
|
170
|
+
| `content_format` | Payload field | Meaning |
|
|
171
|
+
| --- | --- | --- |
|
|
172
|
+
| `null` *or absent* | `data` | A web page's extracted text |
|
|
173
|
+
| `'csv'` | `data` | Card data as CSV |
|
|
174
|
+
| `'json_records'` | `records` | Card data as row objects |
|
|
175
|
+
| `'json_compact'` | `dataset` | Card data as typed columns + positional rows |
|
|
176
|
+
|
|
177
|
+
`total_rows` and `truncated` tell you whether the card held more rows than were returned.
|
|
178
|
+
|
|
179
|
+
Which format you get depends on the surface. Left unset, `takoContents` returns `'csv'` for cards and no format for web pages, while a card inlined by `sources.data.includeContents` arrives as `'json_compact'` (a `dataset`). Set `contentFormat` to choose: on `takoContents` for an explicit fetch, or on `sources.data` for a card inlined by a search.
|
|
180
|
+
|
|
181
|
+
`content_format` is optional as well as nullable, so branch on it loosely — `content_format == null` means web text; `=== null` misses the absent case.
|
|
105
182
|
|
|
106
183
|
Full type definitions ship with the package.
|
|
107
184
|
|
|
@@ -115,17 +192,25 @@ import type {
|
|
|
115
192
|
TakoAnswerResult,
|
|
116
193
|
TakoContentsResult,
|
|
117
194
|
TakoCard,
|
|
195
|
+
TakoCardSource,
|
|
118
196
|
TakoWebResult,
|
|
119
197
|
TakoContentItem,
|
|
198
|
+
TakoDataset,
|
|
199
|
+
TakoUsage,
|
|
120
200
|
} from '@takoviz/ai-sdk';
|
|
121
201
|
```
|
|
122
202
|
|
|
203
|
+
The types mirror Tako's published OpenAPI document. `tests/contract/` validates them against a vendored copy of that spec and against [`tako-sdk`](https://www.npmjs.com/package/tako-sdk), Tako's official generated client, so a type that stops matching the API fails CI. Both references are pinned snapshots, refreshed by `pnpm spec:refresh` and a `tako-sdk` bump.
|
|
204
|
+
|
|
205
|
+
If you need the raw wire shapes (where collections are optional, before the tools normalize them), import `TakoSearchResponse`, `TakoAnswerResponse` or `TakoContentsResponse`.
|
|
206
|
+
|
|
123
207
|
## License
|
|
124
208
|
|
|
125
209
|
MIT
|
|
126
210
|
|
|
127
211
|
## Links
|
|
128
212
|
|
|
129
|
-
- [
|
|
213
|
+
- [Migrating from 2.x](./MIGRATING.md)
|
|
214
|
+
- [Tako documentation](https://docs.tako.com)
|
|
130
215
|
- [Vercel AI SDK](https://sdk.vercel.ai/docs)
|
|
131
216
|
- [GitHub repository](https://github.com/TakoData/ai-sdk)
|
package/dist/index.d.ts
CHANGED
|
@@ -2,34 +2,108 @@ import { Tool } from 'ai';
|
|
|
2
2
|
|
|
3
3
|
type TakoSearchEffort = "fast" | "instant" | "deep";
|
|
4
4
|
type TakoContentsMode = "url" | "inline";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/** Serialization of tabular (Tako card) data. Web text carries no format. */
|
|
6
|
+
type TakoContentFormat = "csv" | "json_records" | "json_compact";
|
|
7
|
+
/** Public source taxonomy for the card surfaces. */
|
|
8
|
+
type TakoSourceIndex = "data" | "web";
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Renamed to {@link TakoSourceIndex}, and the value set collapsed:
|
|
11
|
+
* 2.x had `"tako" | "web" | "connected_data" | "tako_deep_v2"`, this resolves to
|
|
12
|
+
* `"data" | "web"`. Comparisons against the removed values no longer compile.
|
|
13
|
+
*/
|
|
14
|
+
type TakoCardSourceIndex = TakoSourceIndex;
|
|
8
15
|
type TakoKnowledgeCardRelevance = "High" | "Medium" | "Low";
|
|
16
|
+
type TakoGraphNodeType = "metric" | "entity";
|
|
17
|
+
type TakoDatasetColumnType = "string" | "number" | "boolean" | "date" | "datetime";
|
|
18
|
+
/** Web result category. Only "news" filters today; the others are accepted and inert. */
|
|
19
|
+
type TakoWebCategory = "news" | "sports" | "finance";
|
|
9
20
|
interface TakoBaseConfig {
|
|
10
21
|
/** Tako API key. Falls back to TAKO_API_KEY / TAKO_API_TOKEN env vars. */
|
|
11
22
|
apiKey?: string;
|
|
12
|
-
/** API base URL. Default "https://
|
|
23
|
+
/** API base URL. Default "https://tako.com". */
|
|
13
24
|
baseUrl?: string;
|
|
14
25
|
}
|
|
15
26
|
interface TakoSourceOptions {
|
|
16
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Max results for this source, 1-20.
|
|
29
|
+
*
|
|
30
|
+
* The server default differs by tool: `takoSearch` returns 5, `takoAnswer`
|
|
31
|
+
* returns 3. Set this value when you need the same count from both.
|
|
32
|
+
*/
|
|
17
33
|
count?: number;
|
|
18
34
|
/** Inline this source's underlying data in the response. */
|
|
19
35
|
includeContents?: boolean;
|
|
20
36
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
/** Options for the curated Tako data source. Mirrors the API's `DataSourceSettings`. */
|
|
38
|
+
interface TakoDataSourceOptions extends TakoSourceOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Delivery for card data inlined by this search.
|
|
41
|
+
*
|
|
42
|
+
* The API documents this field as having no effect on Tako cards, which always
|
|
43
|
+
* return a small inline preview. It stays for schema stability. This is a
|
|
44
|
+
* different field from {@link TakoContentsConfig.mode}, which does control
|
|
45
|
+
* delivery for an explicit contents call.
|
|
46
|
+
*/
|
|
47
|
+
mode?: TakoContentsMode;
|
|
48
|
+
/** Serialization for inlined card data. Server default "json_compact". */
|
|
49
|
+
contentFormat?: TakoContentFormat;
|
|
50
|
+
/**
|
|
51
|
+
* Graph node ids to pin into the search. Get ids from the /v1/graph endpoints,
|
|
52
|
+
* which this SDK does not wrap. Ids do not survive a knowledge-graph rebuild:
|
|
53
|
+
* resolve them per request rather than storing them.
|
|
54
|
+
*/
|
|
55
|
+
nodeIds?: string[];
|
|
56
|
+
/** Return only cards that match a pinned node. Requires a non-empty `nodeIds`. */
|
|
57
|
+
strict?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** Options for the web source. Mirrors the API's `WebSourceSettings`. */
|
|
60
|
+
interface TakoWebSourceOptions extends TakoSourceOptions {
|
|
61
|
+
/** Restrict web results to a category. */
|
|
62
|
+
category?: TakoWebCategory;
|
|
63
|
+
/** Return only results from these bare hosts, for example "cnn.com". */
|
|
64
|
+
includeDomains?: string[];
|
|
65
|
+
/** Drop results from these bare hosts. */
|
|
66
|
+
excludeDomains?: string[];
|
|
67
|
+
/** Character cap on the excerpt per web result. Server default 1000. */
|
|
68
|
+
snippetMaxChars?: number;
|
|
69
|
+
/** Character cap on full article text when `includeContents` is true. Server default 30000. */
|
|
70
|
+
articleContentMaxChars?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Keep results published on or after this ISO date, "YYYY-MM-DD".
|
|
73
|
+
*
|
|
74
|
+
* This is not a recency guarantee. The API keeps a result whose publication
|
|
75
|
+
* date it does not know, so undated pages still arrive.
|
|
76
|
+
*/
|
|
77
|
+
publishedAfter?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Keep results published on or before this ISO date, "YYYY-MM-DD".
|
|
80
|
+
*
|
|
81
|
+
* The API keeps a result whose publication date it does not know.
|
|
82
|
+
*/
|
|
83
|
+
publishedBefore?: string;
|
|
84
|
+
}
|
|
85
|
+
/** @deprecated Renamed to {@link TakoDataSourceOptions}. */
|
|
86
|
+
type TakoCardSourceOptions = TakoDataSourceOptions;
|
|
87
|
+
/** End-user coordinates used to localize results. */
|
|
88
|
+
interface TakoGeoLocation {
|
|
89
|
+
/** Degrees, -90 to 90. */
|
|
90
|
+
latitude: number;
|
|
91
|
+
/** Degrees, -180 to 180. */
|
|
92
|
+
longitude: number;
|
|
24
93
|
}
|
|
25
94
|
interface TakoRetrievalConfig extends TakoBaseConfig {
|
|
26
95
|
/** "fast" (default) | "instant" | "deep". */
|
|
27
96
|
effort?: TakoSearchEffort;
|
|
28
|
-
/** Per-source settings. A source is searched iff its key is present. Omit to search
|
|
97
|
+
/** Per-source settings. A source is searched iff its key is present. Omit to search data + web. */
|
|
29
98
|
sources?: {
|
|
30
|
-
|
|
31
|
-
|
|
99
|
+
/** The curated Tako data source. */
|
|
100
|
+
data?: TakoDataSourceOptions;
|
|
101
|
+
web?: TakoWebSourceOptions;
|
|
102
|
+
/** @deprecated Use `data`. Legacy alias for the curated Tako source. */
|
|
103
|
+
tako?: TakoDataSourceOptions;
|
|
32
104
|
};
|
|
105
|
+
/** End-user coordinates. Use with `countryCode` for location-sensitive queries. */
|
|
106
|
+
location?: TakoGeoLocation;
|
|
33
107
|
/** ISO 3166-1 alpha-2 country code. Default "US". */
|
|
34
108
|
countryCode?: string;
|
|
35
109
|
/** BCP-47 locale tag. Default "en-US". */
|
|
@@ -45,35 +119,162 @@ interface TakoRetrievalConfig extends TakoBaseConfig {
|
|
|
45
119
|
interface TakoContentsConfig extends TakoBaseConfig {
|
|
46
120
|
/** "url" (default) returns a presigned link; "inline" returns content in the body. */
|
|
47
121
|
mode?: TakoContentsMode;
|
|
122
|
+
/** Serialization for card data. Server default "csv" on this surface. */
|
|
123
|
+
contentFormat?: TakoContentFormat;
|
|
124
|
+
/**
|
|
125
|
+
* Cap on rows returned for a card export. The server default is the 20-row free
|
|
126
|
+
* allowance. Rows above that allowance bill at the per-1000-row rate, so raise
|
|
127
|
+
* this only when you need the extra rows. Web urls ignore this field.
|
|
128
|
+
*/
|
|
129
|
+
maxRows?: number;
|
|
130
|
+
/** Character cap on extracted web page text. Server default 1000000, the full page text. Card urls ignore this field. */
|
|
131
|
+
maxChars?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Return only the price of the export, without the content. The request is free
|
|
134
|
+
* and the item's payload and url are null. The server ignores `mode` and
|
|
135
|
+
* `contentFormat`.
|
|
136
|
+
*/
|
|
137
|
+
quoteOnly?: boolean;
|
|
138
|
+
}
|
|
139
|
+
interface TakoUsageCompute {
|
|
140
|
+
/** USD cost of running the operation. */
|
|
141
|
+
cost_usd: number;
|
|
142
|
+
}
|
|
143
|
+
interface TakoUsageData {
|
|
144
|
+
/** USD cost of the inline data delivered in the response. */
|
|
145
|
+
cost_usd: number;
|
|
146
|
+
/** Number of billed data units (datasets) in the response. */
|
|
147
|
+
datasets: number;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Usage for one metered request. `total_cost_usd` always equals the sum of
|
|
151
|
+
* whichever breakdown components are present.
|
|
152
|
+
*
|
|
153
|
+
* The spec defines this as the successor to the removed `contents_total_cost`,
|
|
154
|
+
* but as of 2026-08 the API does not populate it on search, answer or contents
|
|
155
|
+
* (verified live across plain, deep and include_contents calls). Treat it as
|
|
156
|
+
* genuinely optional. For per-item pricing today, read `TakoResultContent.cost`
|
|
157
|
+
* and `TakoResultContent.export_pricing`, which are populated.
|
|
158
|
+
*/
|
|
159
|
+
interface TakoUsage {
|
|
160
|
+
/** Total quoted USD cost of this request. */
|
|
161
|
+
total_cost_usd: number;
|
|
162
|
+
/** Compute breakdown. Absent on surfaces with no compute step (contents). */
|
|
163
|
+
compute?: TakoUsageCompute | null;
|
|
164
|
+
/** Inline-data breakdown. Present only when billable inline data was emitted. */
|
|
165
|
+
data?: TakoUsageData | null;
|
|
166
|
+
}
|
|
167
|
+
interface TakoDatasetColumn {
|
|
168
|
+
name: string;
|
|
169
|
+
type: TakoDatasetColumnType;
|
|
170
|
+
/** Structured unit, e.g. "USD billions", "%". Null when unitless. */
|
|
171
|
+
unit?: string | null;
|
|
172
|
+
}
|
|
173
|
+
interface TakoDatasetSource {
|
|
174
|
+
/** Human-readable source name, e.g. "FRED". */
|
|
175
|
+
name: string;
|
|
176
|
+
index?: TakoSourceIndex;
|
|
48
177
|
}
|
|
178
|
+
type TakoDatasetCell = string | number | boolean | null;
|
|
179
|
+
/** Exact retrieved rows as positional arrays in `columns` order. */
|
|
180
|
+
interface TakoDataset {
|
|
181
|
+
columns: TakoDatasetColumn[];
|
|
182
|
+
rows: TakoDatasetCell[][];
|
|
183
|
+
total_rows: number;
|
|
184
|
+
truncated: boolean;
|
|
185
|
+
/** Source URL the dataset was derived from. */
|
|
186
|
+
ref: string;
|
|
187
|
+
sources: TakoDatasetSource[];
|
|
188
|
+
provenance?: "query" | "web_extraction";
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Rate card for a card export, so cost can be computed before fetching:
|
|
192
|
+
* `baseline_usd + row_cpm_usd * max(0, rows - free_rows) / 1000`.
|
|
193
|
+
*/
|
|
194
|
+
interface TakoExportPricing {
|
|
195
|
+
baseline_usd: number;
|
|
196
|
+
row_cpm_usd: number;
|
|
197
|
+
free_rows: number;
|
|
198
|
+
max_rows_ceiling: number;
|
|
199
|
+
}
|
|
200
|
+
/** Per-column metadata; entry i describes column i. */
|
|
201
|
+
interface TakoColumnDescriptor {
|
|
202
|
+
name?: string | null;
|
|
203
|
+
metric?: string | null;
|
|
204
|
+
entity?: string | null;
|
|
205
|
+
unit?: string | null;
|
|
206
|
+
dtype?: TakoDatasetColumnType | null;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Describes the downloadable content behind a result.
|
|
210
|
+
*
|
|
211
|
+
* Exactly one payload group is populated once contents are delivered: `data`
|
|
212
|
+
* (CSV or web text), `records` (verbose JSON), `dataset` (compact), or
|
|
213
|
+
* `url` + `expires_at` (presigned download). When every payload field is unset
|
|
214
|
+
* this is just a price quote.
|
|
215
|
+
*
|
|
216
|
+
* `content_format` distinguishes a web page's extracted text from a card's
|
|
217
|
+
* tabular data, but it is optional as well as nullable — web text may arrive as
|
|
218
|
+
* either `null` or an absent key. Test it loosely (`content_format == null`),
|
|
219
|
+
* never with `=== null`.
|
|
220
|
+
*/
|
|
49
221
|
interface TakoResultContent {
|
|
50
|
-
|
|
51
|
-
|
|
222
|
+
content_format?: TakoContentFormat | null;
|
|
223
|
+
/** USD price of this item. On search/answer cards this is a prospective /contents quote. */
|
|
224
|
+
cost?: number;
|
|
225
|
+
/** Inline payload as text: CSV card data, or a web page's extracted text. */
|
|
52
226
|
data?: string | null;
|
|
227
|
+
/** Inline card data as row objects keyed by column name ("json_records"). */
|
|
228
|
+
records?: Record<string, TakoDatasetCell>[] | null;
|
|
229
|
+
/** Inline card data as a compact dataset ("json_compact"). */
|
|
230
|
+
dataset?: TakoDataset | null;
|
|
231
|
+
/** Presigned download URL ("url" delivery mode). */
|
|
232
|
+
url?: string | null;
|
|
233
|
+
expires_at?: string | null;
|
|
234
|
+
/** True total rows in the card's data, independent of how many were returned. */
|
|
53
235
|
total_rows?: number | null;
|
|
54
236
|
truncated?: boolean;
|
|
237
|
+
export_pricing?: TakoExportPricing | null;
|
|
238
|
+
manifest?: TakoColumnDescriptor[] | null;
|
|
239
|
+
}
|
|
240
|
+
interface TakoContentItem extends TakoResultContent {
|
|
241
|
+
/** The originating result URL from the request. */
|
|
242
|
+
source_url: string;
|
|
55
243
|
}
|
|
56
|
-
interface
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
private_index_id: string;
|
|
63
|
-
/** Optional for private indexes. */
|
|
64
|
-
segment_id?: string | null;
|
|
65
|
-
}
|
|
66
|
-
interface TakoKnowledgeCardSource {
|
|
67
|
-
source_name: string | null;
|
|
68
|
-
source_description: string | null;
|
|
69
|
-
source_index: TakoCardSourceIndex | TakoCardSourceIndexSegment | TakoCardSourcePrivateIndex;
|
|
70
|
-
url: string | null;
|
|
244
|
+
interface TakoCardSource {
|
|
245
|
+
source_name?: string | null;
|
|
246
|
+
source_description?: string | null;
|
|
247
|
+
source_index: TakoSourceIndex;
|
|
248
|
+
url?: string | null;
|
|
249
|
+
/** Raw excerpts from the source page. Present for web sources; null for data. */
|
|
71
250
|
source_text?: string | null;
|
|
72
251
|
}
|
|
252
|
+
/** @deprecated Renamed to {@link TakoCardSource}. */
|
|
253
|
+
type TakoKnowledgeCardSource = TakoCardSource;
|
|
254
|
+
/** Both keys are always present on the wire, though either value may be null. */
|
|
73
255
|
interface TakoKnowledgeCardMethodology {
|
|
74
256
|
methodology_name: string | null;
|
|
75
257
|
methodology_description: string | null;
|
|
76
258
|
}
|
|
259
|
+
/** Graph node (entity or metric) behind a card. */
|
|
260
|
+
interface TakoCardNode {
|
|
261
|
+
/** Opaque public id (`ent::…` / `mt::…`). Not durable across graph rebuilds. */
|
|
262
|
+
id: string;
|
|
263
|
+
type: TakoGraphNodeType;
|
|
264
|
+
name: string;
|
|
265
|
+
description?: string | null;
|
|
266
|
+
}
|
|
267
|
+
interface TakoMetricDefinition {
|
|
268
|
+
name: string;
|
|
269
|
+
definition: string;
|
|
270
|
+
}
|
|
271
|
+
/** Freshness dates for a card's data. */
|
|
272
|
+
interface TakoDataFreshness {
|
|
273
|
+
/** Coverage date of the data. */
|
|
274
|
+
data_as_of?: string | null;
|
|
275
|
+
/** Date the data was last refreshed. */
|
|
276
|
+
last_updated?: string | null;
|
|
277
|
+
}
|
|
77
278
|
interface TakoCard {
|
|
78
279
|
card_id?: string | null;
|
|
79
280
|
title?: string | null;
|
|
@@ -82,32 +283,66 @@ interface TakoCard {
|
|
|
82
283
|
webpage_url?: string | null;
|
|
83
284
|
image_url?: string | null;
|
|
84
285
|
embed_url?: string | null;
|
|
85
|
-
sources?:
|
|
286
|
+
sources?: TakoCardSource[] | null;
|
|
86
287
|
methodologies?: TakoKnowledgeCardMethodology[] | null;
|
|
87
|
-
source_indexes?:
|
|
288
|
+
source_indexes?: TakoSourceIndex[] | null;
|
|
88
289
|
card_type?: string | null;
|
|
89
290
|
relevance?: TakoKnowledgeCardRelevance | null;
|
|
90
291
|
content?: TakoResultContent | null;
|
|
292
|
+
/**
|
|
293
|
+
* Whether /contents can download this card's data. `false` means the export is
|
|
294
|
+
* unavailable — don't call takoContents on it. `true` is eligible but not
|
|
295
|
+
* guaranteed (a 403 is still possible), so fall back to the inline preview.
|
|
296
|
+
*/
|
|
297
|
+
exportable?: boolean;
|
|
298
|
+
/** Relevance on a 1.0–5.0 scale. Only populated for entitled accounts. */
|
|
299
|
+
relevance_score?: number | null;
|
|
300
|
+
/** Graph nodes behind this card. Absent for web-only cards. */
|
|
301
|
+
nodes?: TakoCardNode[] | null;
|
|
302
|
+
metric_definitions?: TakoMetricDefinition[] | null;
|
|
303
|
+
data_freshness?: TakoDataFreshness | null;
|
|
91
304
|
}
|
|
92
305
|
interface TakoWebResult {
|
|
93
306
|
title: string;
|
|
94
307
|
url: string;
|
|
308
|
+
/** Excerpt(s) from the page that matched the query. */
|
|
95
309
|
snippet?: string | null;
|
|
96
310
|
source_name?: string | null;
|
|
97
311
|
publish_date?: string | null;
|
|
98
312
|
content?: TakoResultContent | null;
|
|
313
|
+
/** 1-based citation number for inline [N] markers. Null on raw retrieval. */
|
|
99
314
|
citation_number?: number | null;
|
|
100
315
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
316
|
+
/**
|
|
317
|
+
* The raw `POST /api/v3/search` body. Only `request_id` is guaranteed — the
|
|
318
|
+
* contract permits omitting the collections, though the API currently sends them
|
|
319
|
+
* empty. Tools normalize either shape and return {@link TakoSearchResult}.
|
|
320
|
+
*/
|
|
321
|
+
interface TakoSearchResponse {
|
|
322
|
+
cards?: TakoCard[];
|
|
323
|
+
web_results?: TakoWebResult[];
|
|
324
|
+
request_id: string;
|
|
325
|
+
usage?: TakoUsage | null;
|
|
326
|
+
}
|
|
327
|
+
/** The raw `POST /api/v1/answer` body. */
|
|
328
|
+
interface TakoAnswerResponse {
|
|
329
|
+
answer: string;
|
|
330
|
+
cards?: TakoCard[];
|
|
331
|
+
web_results?: TakoWebResult[];
|
|
332
|
+
request_id: string;
|
|
333
|
+
usage?: TakoUsage | null;
|
|
334
|
+
}
|
|
335
|
+
/** The raw `POST /api/v1/contents` body. */
|
|
336
|
+
interface TakoContentsResponse {
|
|
337
|
+
contents?: TakoContentItem[];
|
|
338
|
+
request_id: string;
|
|
339
|
+
usage?: TakoUsage | null;
|
|
105
340
|
}
|
|
106
341
|
interface TakoSearchResult {
|
|
107
342
|
cards: TakoCard[];
|
|
108
343
|
web_results: TakoWebResult[];
|
|
109
|
-
contents_total_cost: number;
|
|
110
344
|
request_id: string;
|
|
345
|
+
usage?: TakoUsage | null;
|
|
111
346
|
}
|
|
112
347
|
interface TakoAnswerResult {
|
|
113
348
|
/** Synthesized text answer. */
|
|
@@ -115,12 +350,13 @@ interface TakoAnswerResult {
|
|
|
115
350
|
/** Backing cards; cards[0] is the lead card. */
|
|
116
351
|
cards: TakoCard[];
|
|
117
352
|
web_results: TakoWebResult[];
|
|
118
|
-
contents_total_cost: number;
|
|
119
353
|
request_id: string;
|
|
354
|
+
usage?: TakoUsage | null;
|
|
120
355
|
}
|
|
121
356
|
interface TakoContentsResult {
|
|
122
357
|
contents: TakoContentItem[];
|
|
123
358
|
request_id: string;
|
|
359
|
+
usage?: TakoUsage | null;
|
|
124
360
|
}
|
|
125
361
|
|
|
126
362
|
/** Tako fast-pipeline search: returns Tako cards + web results, no LLM synthesis. */
|
|
@@ -128,14 +364,27 @@ declare function takoSearch(config?: TakoRetrievalConfig): Tool<{
|
|
|
128
364
|
query: string;
|
|
129
365
|
}, TakoSearchResult>;
|
|
130
366
|
|
|
131
|
-
/**
|
|
367
|
+
/**
|
|
368
|
+
* Tako answer: fast-pipeline retrieval plus an LLM-synthesized answer grounded in the results.
|
|
369
|
+
*
|
|
370
|
+
* Resolves to `{ answer, cards, web_results, ... }` — `cards[0]` is the lead card, carrying
|
|
371
|
+
* the chart `image_url`/`embed_url` you can surface in your own UI.
|
|
372
|
+
*/
|
|
132
373
|
declare function takoAnswer(config?: TakoRetrievalConfig): Tool<{
|
|
133
374
|
query: string;
|
|
134
375
|
}, TakoAnswerResult>;
|
|
135
376
|
|
|
136
|
-
/**
|
|
377
|
+
/**
|
|
378
|
+
* Download the data behind a result URL: a Tako card's CSV or a web page's text.
|
|
379
|
+
*
|
|
380
|
+
* `mode` sets the delivery, and is reflected in the tool description the model reads:
|
|
381
|
+
* - `"url"` (default) — a short-lived presigned download url. Use when handing a
|
|
382
|
+
* download/embed link to a user, or for large data you won't read yourself.
|
|
383
|
+
* - `"inline"` — the content in the response body, so the model can read and reason
|
|
384
|
+
* over the numbers directly.
|
|
385
|
+
*/
|
|
137
386
|
declare function takoContents(config?: TakoContentsConfig): Tool<{
|
|
138
387
|
url: string;
|
|
139
388
|
}, TakoContentsResult>;
|
|
140
389
|
|
|
141
|
-
export { type TakoAnswerResult, type TakoBaseConfig, type TakoCard, type
|
|
390
|
+
export { type TakoAnswerResponse, type TakoAnswerResult, type TakoBaseConfig, type TakoCard, type TakoCardNode, type TakoCardSource, type TakoCardSourceIndex, type TakoCardSourceOptions, type TakoColumnDescriptor, type TakoContentFormat, type TakoContentItem, type TakoContentsConfig, type TakoContentsMode, type TakoContentsResponse, type TakoContentsResult, type TakoDataFreshness, type TakoDataSourceOptions, type TakoDataset, type TakoDatasetCell, type TakoDatasetColumn, type TakoDatasetColumnType, type TakoDatasetSource, type TakoExportPricing, type TakoGeoLocation, type TakoGraphNodeType, type TakoKnowledgeCardMethodology, type TakoKnowledgeCardRelevance, type TakoKnowledgeCardSource, type TakoMetricDefinition, type TakoResultContent, type TakoRetrievalConfig, type TakoSearchEffort, type TakoSearchResponse, type TakoSearchResult, type TakoSourceIndex, type TakoSourceOptions, type TakoUsage, type TakoUsageCompute, type TakoUsageData, type TakoWebCategory, type TakoWebResult, type TakoWebSourceOptions, takoAnswer, takoContents, takoSearch };
|
package/dist/index.js
CHANGED
|
@@ -33,61 +33,127 @@ async function callTako(opts) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// src/request.ts
|
|
36
|
-
var DEFAULT_BASE_URL = "https://
|
|
36
|
+
var DEFAULT_BASE_URL = "https://tako.com";
|
|
37
37
|
function resolveApiKey(config) {
|
|
38
38
|
return config.apiKey ?? process.env.TAKO_API_KEY ?? process.env.TAKO_API_TOKEN;
|
|
39
39
|
}
|
|
40
40
|
function resolveBaseUrl(config) {
|
|
41
41
|
return (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
42
42
|
}
|
|
43
|
+
function buildWebSourceSettings(o) {
|
|
44
|
+
const body = {};
|
|
45
|
+
if (o.count !== void 0) body.count = o.count;
|
|
46
|
+
if (o.includeContents !== void 0) body.include_contents = o.includeContents;
|
|
47
|
+
if (o.category !== void 0) body.category = o.category;
|
|
48
|
+
if (o.includeDomains !== void 0) body.include_domains = o.includeDomains;
|
|
49
|
+
if (o.excludeDomains !== void 0) body.exclude_domains = o.excludeDomains;
|
|
50
|
+
if (o.snippetMaxChars !== void 0) body.snippet_max_chars = o.snippetMaxChars;
|
|
51
|
+
if (o.articleContentMaxChars !== void 0) {
|
|
52
|
+
body.article_content_max_chars = o.articleContentMaxChars;
|
|
53
|
+
}
|
|
54
|
+
if (o.publishedAfter !== void 0) body.published_after = o.publishedAfter;
|
|
55
|
+
if (o.publishedBefore !== void 0) body.published_before = o.publishedBefore;
|
|
56
|
+
return body;
|
|
57
|
+
}
|
|
58
|
+
function assertValidDataSourceOptions(o) {
|
|
59
|
+
if (o.strict && !o.nodeIds?.length) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"strict requires a non-empty nodeIds. Add node ids from the /v1/graph endpoints, or set strict to false."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function assertValidRetrievalConfig(config) {
|
|
66
|
+
const dataSource = config.sources?.data ?? config.sources?.tako;
|
|
67
|
+
if (dataSource) assertValidDataSourceOptions(dataSource);
|
|
68
|
+
}
|
|
69
|
+
function buildDataSourceSettings(o) {
|
|
70
|
+
assertValidDataSourceOptions(o);
|
|
71
|
+
const body = {};
|
|
72
|
+
if (o.count !== void 0) body.count = o.count;
|
|
73
|
+
if (o.includeContents !== void 0) body.include_contents = o.includeContents;
|
|
74
|
+
if (o.mode !== void 0) body.mode = o.mode;
|
|
75
|
+
if (o.contentFormat !== void 0) body.content_format = o.contentFormat;
|
|
76
|
+
if (o.nodeIds !== void 0) body.node_ids = o.nodeIds;
|
|
77
|
+
if (o.strict !== void 0) body.strict = o.strict;
|
|
78
|
+
return body;
|
|
79
|
+
}
|
|
80
|
+
function buildGeoLocation(o) {
|
|
81
|
+
return { latitude: o.latitude, longitude: o.longitude };
|
|
82
|
+
}
|
|
83
|
+
function buildOutputSettings(o) {
|
|
84
|
+
const body = {};
|
|
85
|
+
if (o.imageDarkMode !== void 0) body.image_dark_mode = o.imageDarkMode;
|
|
86
|
+
if (o.forceRefresh !== void 0) body.force_refresh = o.forceRefresh;
|
|
87
|
+
return body;
|
|
88
|
+
}
|
|
43
89
|
function buildSearchRequestBody(config, query) {
|
|
44
|
-
const body = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
locale: config.locale ?? "en-US"
|
|
49
|
-
};
|
|
90
|
+
const body = { query };
|
|
91
|
+
if (config.effort !== void 0) body.effort = config.effort;
|
|
92
|
+
if (config.countryCode !== void 0) body.country_code = config.countryCode;
|
|
93
|
+
if (config.locale !== void 0) body.locale = config.locale;
|
|
50
94
|
if (config.sources) {
|
|
51
95
|
const sources = {};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (config.sources.tako.includeContents !== void 0) tako.include_contents = config.sources.tako.includeContents;
|
|
56
|
-
if (config.sources.tako.deferDataRetrieval !== void 0) tako.defer_data_retrieval = config.sources.tako.deferDataRetrieval;
|
|
57
|
-
sources.tako = tako;
|
|
58
|
-
}
|
|
59
|
-
if (config.sources.web) {
|
|
60
|
-
const web = {};
|
|
61
|
-
if (config.sources.web.count !== void 0) web.count = config.sources.web.count;
|
|
62
|
-
if (config.sources.web.includeContents !== void 0) web.include_contents = config.sources.web.includeContents;
|
|
63
|
-
sources.web = web;
|
|
64
|
-
}
|
|
96
|
+
const dataSource = config.sources.data ?? config.sources.tako;
|
|
97
|
+
if (dataSource) sources.data = buildDataSourceSettings(dataSource);
|
|
98
|
+
if (config.sources.web) sources.web = buildWebSourceSettings(config.sources.web);
|
|
65
99
|
body.sources = sources;
|
|
66
100
|
}
|
|
101
|
+
if (config.location !== void 0) body.location = buildGeoLocation(config.location);
|
|
67
102
|
if (config.timezone !== void 0) body.timezone = config.timezone;
|
|
68
|
-
if (config.outputSettings)
|
|
69
|
-
const output = {};
|
|
70
|
-
if (config.outputSettings.imageDarkMode !== void 0) output.image_dark_mode = config.outputSettings.imageDarkMode;
|
|
71
|
-
if (config.outputSettings.forceRefresh !== void 0) output.force_refresh = config.outputSettings.forceRefresh;
|
|
72
|
-
body.output_settings = output;
|
|
73
|
-
}
|
|
103
|
+
if (config.outputSettings) body.output_settings = buildOutputSettings(config.outputSettings);
|
|
74
104
|
return body;
|
|
75
105
|
}
|
|
106
|
+
function buildContentsRequestBody(url, config) {
|
|
107
|
+
const body = { url, mode: config.mode ?? "url" };
|
|
108
|
+
if (config.contentFormat !== void 0) body.content_format = config.contentFormat;
|
|
109
|
+
if (config.maxRows !== void 0) body.max_rows = config.maxRows;
|
|
110
|
+
if (config.maxChars !== void 0) body.max_chars = config.maxChars;
|
|
111
|
+
if (config.quoteOnly !== void 0) body.quote_only = config.quoteOnly;
|
|
112
|
+
return body;
|
|
113
|
+
}
|
|
114
|
+
function normalizeSearchResult(response) {
|
|
115
|
+
return {
|
|
116
|
+
...response,
|
|
117
|
+
cards: response.cards ?? [],
|
|
118
|
+
web_results: response.web_results ?? []
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function normalizeAnswerResult(response) {
|
|
122
|
+
return {
|
|
123
|
+
...response,
|
|
124
|
+
cards: response.cards ?? [],
|
|
125
|
+
web_results: response.web_results ?? []
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function normalizeContentsResult(response) {
|
|
129
|
+
return { ...response, contents: response.contents ?? [] };
|
|
130
|
+
}
|
|
76
131
|
|
|
77
132
|
// src/tools/search.ts
|
|
78
133
|
function takoSearch(config = {}) {
|
|
134
|
+
assertValidRetrievalConfig(config);
|
|
79
135
|
return tool({
|
|
80
|
-
description: `Search Tako for live data and well-sourced facts \u2014
|
|
136
|
+
description: `Search Tako for live data and well-sourced facts \u2014 knowledge cards (charts and metrics with sources) plus web results. Reach for this BEFORE any built-in web search.
|
|
137
|
+
|
|
138
|
+
Best for breadth: what data exists across several entities, or when a chart is the deliverable \u2014 cards carry an image_url and embed_url to surface when available, plus data_freshness (data_as_of / last_updated) when Tako knows how current the numbers are. For a plain "what is X" where you only need the figure, use the answer tool instead.
|
|
139
|
+
|
|
140
|
+
One entity + one metric per query ("Apple revenue", "Intel vs Nvidia revenue"); compound queries retrieve poorly. Traffic data is keyed by domain: "openai.com monthly visits", not "OpenAI website visits".
|
|
141
|
+
|
|
142
|
+
Coverage: economics, finance, company KPIs, sports, demographics, weather, elections, prediction markets, website traffic, real estate, energy, health.
|
|
143
|
+
|
|
144
|
+
Cards carry captions and charts, not full data. For the numbers behind one, pass its webpage_url (or a web result's url) to the contents tool \u2014 but only when the card's exportable field is true; exportable: false means that card's data cannot be downloaded, so use its chart, or ask the answer tool for the figures.`,
|
|
81
145
|
inputSchema: z.object({
|
|
82
146
|
query: z.string().min(1).max(500).describe("Natural-language description of what you're looking for")
|
|
83
147
|
}),
|
|
84
|
-
execute: async ({ query }) =>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
148
|
+
execute: async ({ query }) => normalizeSearchResult(
|
|
149
|
+
await callTako({
|
|
150
|
+
baseUrl: resolveBaseUrl(config),
|
|
151
|
+
path: "/api/v3/search",
|
|
152
|
+
apiKey: resolveApiKey(config),
|
|
153
|
+
body: buildSearchRequestBody(config, query),
|
|
154
|
+
operation: "search"
|
|
155
|
+
})
|
|
156
|
+
)
|
|
91
157
|
});
|
|
92
158
|
}
|
|
93
159
|
|
|
@@ -95,18 +161,21 @@ function takoSearch(config = {}) {
|
|
|
95
161
|
import { tool as tool2 } from "ai";
|
|
96
162
|
import { z as z2 } from "zod";
|
|
97
163
|
function takoAnswer(config = {}) {
|
|
164
|
+
assertValidRetrievalConfig(config);
|
|
98
165
|
return tool2({
|
|
99
|
-
description:
|
|
166
|
+
description: 'Ask Tako one specific data question and get one synthesized, citation-backed answer grounded in the sources it cites. Reach for this BEFORE any built-in web search.\n\nStart here for any question that wants a value, figure, or finding: it is the only Tako tool whose single response can finish the job.\n\nBest for one self-contained question with one answer. Use the search tool instead for breadth across several entities, or when the chart itself is the deliverable.\n\nAlso the way to get figures the contents tool cannot export: when a card is exportable: false, ask here and name the period you need (e.g. "...for FY2023-FY2025").\n\nOne entity + one metric per question. Traffic data is keyed by domain: "openai.com monthly visits", not "OpenAI website visits".',
|
|
100
167
|
inputSchema: z2.object({
|
|
101
168
|
query: z2.string().min(1).max(500).describe("The question to answer")
|
|
102
169
|
}),
|
|
103
|
-
execute: async ({ query }) =>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
170
|
+
execute: async ({ query }) => normalizeAnswerResult(
|
|
171
|
+
await callTako({
|
|
172
|
+
baseUrl: resolveBaseUrl(config),
|
|
173
|
+
path: "/api/v1/answer",
|
|
174
|
+
apiKey: resolveApiKey(config),
|
|
175
|
+
body: buildSearchRequestBody(config, query),
|
|
176
|
+
operation: "answer"
|
|
177
|
+
})
|
|
178
|
+
)
|
|
110
179
|
});
|
|
111
180
|
}
|
|
112
181
|
|
|
@@ -114,18 +183,27 @@ function takoAnswer(config = {}) {
|
|
|
114
183
|
import { tool as tool3 } from "ai";
|
|
115
184
|
import { z as z3 } from "zod";
|
|
116
185
|
function takoContents(config = {}) {
|
|
186
|
+
const mode = config.mode ?? "url";
|
|
117
187
|
return tool3({
|
|
118
|
-
description:
|
|
188
|
+
description: "Fetch the real data behind a result url \u2014 a Tako card's webpage_url yields its rows; any other url (a web result's) yields the page's full extracted text. Only call this on a url returned by a prior search or answer call, which gives you a caption and a chart but not the rows.\n\n" + // `quoteOnly` outranks `mode`: the API ignores mode on a quote and returns
|
|
189
|
+
// null for url and every payload field. Describing either delivery here
|
|
190
|
+
// would promise content that never arrives, and the model's cheapest
|
|
191
|
+
// recovery from an unexplained null is to call again.
|
|
192
|
+
(config.quoteOnly ? "Configured for price quotes only: returns the export cost and rate card, and NO content. The url and data fields are always null and the call is free \u2014 report the price, and do not call again expecting rows.\n\n" : mode === "inline" ? "Returns the content in the response body \u2014 read and compute over the numbers directly.\n\n" : "Returns a short-lived presigned download url, NOT the data itself: surface the link, do not parse it or call again expecting rows.\n\n") + "Only cards whose exportable field is true can be downloaded; a non-exportable card always returns 403 and retrying will not change that \u2014 get its figures from the answer tool instead, naming the period you need. Web urls always work, so this is also the fallback when a search surfaced a relevant web result but no fitting data card.\n\nOn each returned item, content_format names the serialization for card data and is null or absent for web page text; total_rows and truncated tell you whether the card had more rows than were returned.",
|
|
119
193
|
inputSchema: z3.object({
|
|
120
|
-
|
|
194
|
+
// Validated as a url so a malformed value fails here, with a message the
|
|
195
|
+
// model can act on, instead of costing a priced round trip to the API.
|
|
196
|
+
url: z3.url().describe("A TakoCard.webpage_url or WebResult.url to download contents for")
|
|
121
197
|
}),
|
|
122
|
-
execute: async ({ url }) =>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
198
|
+
execute: async ({ url }) => normalizeContentsResult(
|
|
199
|
+
await callTako({
|
|
200
|
+
baseUrl: resolveBaseUrl(config),
|
|
201
|
+
path: "/api/v1/contents",
|
|
202
|
+
apiKey: resolveApiKey(config),
|
|
203
|
+
body: buildContentsRequestBody(url, config),
|
|
204
|
+
operation: "fetch contents"
|
|
205
|
+
})
|
|
206
|
+
)
|
|
129
207
|
});
|
|
130
208
|
}
|
|
131
209
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takoviz/ai-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Tako knowledge search, answer, and contents tools for the Vercel AI SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"sideEffects": false,
|
|
15
16
|
"files": [
|
|
16
17
|
"dist"
|
|
17
18
|
],
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
],
|
|
27
28
|
"author": "Tako",
|
|
28
29
|
"license": "MIT",
|
|
29
|
-
"homepage": "https://
|
|
30
|
+
"homepage": "https://tako.com",
|
|
30
31
|
"repository": {
|
|
31
32
|
"type": "git",
|
|
32
33
|
"url": "git+https://github.com/TakoData/ai-sdk.git"
|
|
@@ -42,15 +43,23 @@
|
|
|
42
43
|
"@ai-sdk/openai": "^4.0.0",
|
|
43
44
|
"@types/node": "^24.10.1",
|
|
44
45
|
"ai": "^7.0.0",
|
|
46
|
+
"ajv": "^8.20.0",
|
|
47
|
+
"ajv-formats": "^3.0.1",
|
|
48
|
+
"tako-sdk": "^1.1.10",
|
|
45
49
|
"tsup": "^8.5.0",
|
|
46
50
|
"tsx": "^4.20.6",
|
|
47
51
|
"typescript": "^5.9.3",
|
|
48
|
-
"vitest": "^3.0.0"
|
|
52
|
+
"vitest": "^3.0.0",
|
|
53
|
+
"yaml": "^2.9.0"
|
|
49
54
|
},
|
|
50
55
|
"scripts": {
|
|
51
56
|
"build": "tsup src/index.ts --format esm --dts",
|
|
52
57
|
"typecheck": "tsc --noEmit -p tsconfig.check.json",
|
|
53
58
|
"test": "vitest run",
|
|
54
|
-
"test:watch": "vitest"
|
|
59
|
+
"test:watch": "vitest",
|
|
60
|
+
"test:contract": "vitest run tests/contract",
|
|
61
|
+
"test:package": "node scripts/verify-package.mjs",
|
|
62
|
+
"lint:package": "npx -y publint@latest --strict --pack npm && npx -y @arethetypeswrong/cli@latest --pack . --ignore-rules cjs-resolves-to-esm",
|
|
63
|
+
"spec:refresh": "curl -fsSL https://docs.tako.com/api-reference/openapi.yaml -o tests/contract/openapi.yaml"
|
|
55
64
|
}
|
|
56
65
|
}
|