@tiny-fish/sdk 0.0.5 → 0.0.7
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 +231 -206
- package/dist/_utils/client.d.ts +14 -9
- package/dist/_utils/client.d.ts.map +1 -1
- package/dist/_utils/client.js +93 -41
- package/dist/_utils/client.js.map +1 -1
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +39 -65
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/types.d.ts +258 -127
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js +133 -41
- package/dist/agent/types.js.map +1 -1
- package/dist/browser/index.d.ts +16 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +29 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/types.d.ts +17 -0
- package/dist/browser/types.d.ts.map +1 -0
- package/dist/browser/types.js +15 -0
- package/dist/browser/types.js.map +1 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -0
- package/dist/client.js.map +1 -1
- package/dist/fetch/index.d.ts +10 -0
- package/dist/fetch/index.d.ts.map +1 -0
- package/dist/fetch/index.js +37 -0
- package/dist/fetch/index.js.map +1 -0
- package/dist/fetch/types.d.ts +176 -0
- package/dist/fetch/types.d.ts.map +1 -0
- package/dist/fetch/types.js +69 -0
- package/dist/fetch/types.js.map +1 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/runs/index.d.ts +1 -1
- package/dist/runs/index.d.ts.map +1 -1
- package/dist/runs/index.js +25 -16
- package/dist/runs/index.js.map +1 -1
- package/dist/runs/types.d.ts +114 -66
- package/dist/runs/types.d.ts.map +1 -1
- package/dist/runs/types.js +48 -6
- package/dist/runs/types.js.map +1 -1
- package/dist/search/index.d.ts +10 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +29 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/types.d.ts +34 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +25 -0
- package/dist/search/types.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
1
|
# TinyFish TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Typed access to TinyFish web agents, fetch extraction, remote browser sessions, run history, and search.
|
|
4
|
+
|
|
5
|
+
Use the SDK when you want to:
|
|
6
|
+
|
|
7
|
+
- automate a page with a natural-language goal
|
|
8
|
+
- stream live progress events and a browser preview URL
|
|
9
|
+
- queue jobs and poll them later
|
|
10
|
+
- fetch clean page content from up to 10 URLs at once
|
|
11
|
+
- create a remote browser session for direct CDP control
|
|
12
|
+
- query TinyFish Search from the same client
|
|
4
13
|
|
|
5
14
|
## Installation
|
|
6
15
|
|
|
7
16
|
```bash
|
|
8
|
-
npm install
|
|
17
|
+
npm install @tiny-fish/sdk
|
|
9
18
|
```
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
Requirements:
|
|
21
|
+
|
|
22
|
+
- Node.js 18+
|
|
23
|
+
- a TinyFish API key from [agent.tinyfish.ai/api-keys](https://agent.tinyfish.ai/api-keys)
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
Authenticate with either the constructor or `TINYFISH_API_KEY`:
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
```ts
|
|
28
|
+
import { TinyFish } from "@tiny-fish/sdk";
|
|
29
|
+
|
|
30
|
+
const client = new TinyFish({
|
|
31
|
+
apiKey: process.env.TINYFISH_API_KEY,
|
|
32
|
+
});
|
|
33
|
+
```
|
|
16
34
|
|
|
17
35
|
## Quickstart
|
|
18
36
|
|
|
19
|
-
|
|
20
|
-
import { TinyFish } from "tinyfish";
|
|
37
|
+
`agent.stream()` is the best default for product integrations because it gives you progress updates while the run is happening.
|
|
21
38
|
|
|
22
|
-
|
|
39
|
+
```ts
|
|
40
|
+
import { TinyFish } from "@tiny-fish/sdk";
|
|
41
|
+
|
|
42
|
+
const client = new TinyFish();
|
|
23
43
|
|
|
24
44
|
const stream = await client.agent.stream(
|
|
25
45
|
{
|
|
26
|
-
goal: "
|
|
27
|
-
url: "https://
|
|
46
|
+
goal: "Extract the top 5 headlines",
|
|
47
|
+
url: "https://news.ycombinator.com",
|
|
28
48
|
},
|
|
29
49
|
{
|
|
30
|
-
|
|
31
|
-
|
|
50
|
+
onStarted: (event) => console.log(`Run: ${event.run_id}`),
|
|
51
|
+
onStreamingUrl: (event) => console.log(`Watch live: ${event.streaming_url}`),
|
|
52
|
+
onProgress: (event) => console.log(`> ${event.purpose}`),
|
|
53
|
+
onComplete: (event) => console.log(event.result),
|
|
32
54
|
},
|
|
33
55
|
);
|
|
34
56
|
|
|
35
57
|
for await (const event of stream) {
|
|
36
|
-
|
|
58
|
+
if (event.type === "COMPLETE") {
|
|
59
|
+
console.log(`Finished with status ${event.status}`);
|
|
60
|
+
}
|
|
37
61
|
}
|
|
38
62
|
```
|
|
39
63
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
const client = new TinyFish();
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
> All methods are async and return promises. There is no synchronous client — JavaScript is async-native.
|
|
47
|
-
|
|
48
|
-
## Methods
|
|
49
|
-
|
|
50
|
-
| Method | Description | Returns | Blocks? |
|
|
51
|
-
|--------|-------------|---------|---------|
|
|
52
|
-
| [`agent.stream()`](#agentstream--real-time-events) | Stream live SSE events as the agent works | `AgentStream` | No |
|
|
53
|
-
| [`agent.run()`](#agentrun--block-until-done) | Run an automation, wait for the result | `AgentRunResponse` | Yes |
|
|
54
|
-
| [`agent.queue()`](#agentqueue--fire-and-forget) | Start an automation, return immediately | `AgentRunAsyncResponse` | No |
|
|
55
|
-
| [`runs.get()`](#runsget--retrieve-a-single-run) | Retrieve a single run by ID | `Run` | — |
|
|
56
|
-
| [`runs.list()`](#runslist--list-and-filter-runs) | List runs with filtering, sorting, pagination | `RunListResponse` | — |
|
|
57
|
-
|
|
58
|
-
---
|
|
64
|
+
Need request-scoped cancellation without changing the client-wide timeout? Pass an `AbortSignal` as the optional second argument:
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
Opens a Server-Sent Events stream. You get live progress updates as the agent works, plus a URL for a live browser preview. This is the recommended integration method.
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
import { TinyFish } from "tinyfish";
|
|
66
|
-
|
|
67
|
-
const client = new TinyFish();
|
|
66
|
+
```ts
|
|
67
|
+
const controller = new AbortController();
|
|
68
68
|
|
|
69
69
|
const stream = await client.agent.stream(
|
|
70
70
|
{
|
|
@@ -72,275 +72,300 @@ const stream = await client.agent.stream(
|
|
|
72
72
|
url: "https://news.ycombinator.com",
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
|
-
|
|
76
|
-
onStreamingUrl: (e) => console.log(`Watch: ${e.streaming_url}`),
|
|
77
|
-
onProgress: (e) => console.log(` > ${e.purpose}`),
|
|
78
|
-
onComplete: (e) => console.log(`Done: ${e.status}`),
|
|
75
|
+
signal: controller.signal,
|
|
79
76
|
},
|
|
80
77
|
);
|
|
81
78
|
|
|
82
|
-
|
|
83
|
-
// Callbacks fire automatically during iteration.
|
|
84
|
-
// You can also inspect events directly:
|
|
85
|
-
if (event.type === "COMPLETE") {
|
|
86
|
-
console.log(event.result);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
79
|
+
controller.abort();
|
|
89
80
|
```
|
|
90
81
|
|
|
91
|
-
|
|
82
|
+
## Choose an API
|
|
92
83
|
|
|
93
|
-
|
|
84
|
+
| Method | Use it when | Returns |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `client.agent.stream()` | You want live events and a browser preview URL | `AgentStream` |
|
|
87
|
+
| `client.agent.run()` | You want one blocking request that waits for the final result | `AgentRunResponse` |
|
|
88
|
+
| `client.agent.queue()` | You want to enqueue work and check back later | `AgentRunAsyncResponse` |
|
|
89
|
+
| `client.fetch.getContents()` | You want extracted page content without running a browser agent | `FetchResponse` |
|
|
90
|
+
| `client.browser.sessions.create()` | You want a remote browser session and CDP connection info | `BrowserSession` |
|
|
91
|
+
| `client.runs.get()` | You already have a `run_id` and need the latest state | `Run` |
|
|
92
|
+
| `client.runs.list()` | You want to list or filter historical runs | `RunListResponse` |
|
|
93
|
+
| `client.search.query()` | You want TinyFish Search results | `SearchQueryResponse` |
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
## Core workflows
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
### Run and wait
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
Use `agent.run()` for scripts, cron jobs, and backend tasks that should block until the result is ready.
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
```ts
|
|
102
|
+
import {
|
|
103
|
+
BrowserProfile,
|
|
104
|
+
ProxyCountryCode,
|
|
105
|
+
RunStatus,
|
|
106
|
+
TinyFish,
|
|
107
|
+
} from "@tiny-fish/sdk";
|
|
106
108
|
|
|
107
109
|
const client = new TinyFish();
|
|
108
110
|
|
|
109
111
|
const response = await client.agent.run({
|
|
110
|
-
goal: "
|
|
111
|
-
url: "https://
|
|
112
|
-
browser_profile: BrowserProfile.STEALTH,
|
|
113
|
-
proxy_config: {
|
|
112
|
+
goal: "Find the price of the latest MacBook Pro",
|
|
113
|
+
url: "https://www.apple.com/shop/buy-mac/macbook-pro",
|
|
114
|
+
browser_profile: BrowserProfile.STEALTH,
|
|
115
|
+
proxy_config: {
|
|
114
116
|
enabled: true,
|
|
115
|
-
country_code: ProxyCountryCode.US,
|
|
117
|
+
country_code: ProxyCountryCode.US,
|
|
116
118
|
},
|
|
117
119
|
});
|
|
118
120
|
|
|
119
121
|
if (response.status === RunStatus.COMPLETED) {
|
|
120
122
|
console.log(response.result);
|
|
121
123
|
} else {
|
|
122
|
-
console.
|
|
124
|
+
console.error(response.error?.message);
|
|
123
125
|
}
|
|
124
126
|
```
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
`run()` also accepts an optional second argument with `signal`:
|
|
127
129
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| `status` | `RunStatus` | `COMPLETED`, `FAILED`, etc. |
|
|
131
|
-
| `run_id` | `string \| null` | Unique run identifier |
|
|
132
|
-
| `result` | `Record<string, unknown> \| null` | Extracted data (`null` if failed) |
|
|
133
|
-
| `error` | `RunError \| null` | Error details (`null` if succeeded) |
|
|
134
|
-
| `num_of_steps` | `number` | Number of steps the agent took |
|
|
135
|
-
| `started_at` | `string \| null` | ISO 8601 timestamp when the run started |
|
|
136
|
-
| `finished_at` | `string \| null` | ISO 8601 timestamp when the run finished |
|
|
130
|
+
```ts
|
|
131
|
+
const controller = new AbortController();
|
|
137
132
|
|
|
138
|
-
|
|
133
|
+
const response = await client.agent.run(
|
|
134
|
+
{
|
|
135
|
+
goal: "Extract the page title",
|
|
136
|
+
url: "https://example.com",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
signal: controller.signal,
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
```
|
|
139
143
|
|
|
140
|
-
###
|
|
144
|
+
### Queue and poll
|
|
141
145
|
|
|
142
|
-
|
|
146
|
+
Use `agent.queue()` when you do not want to keep the request open.
|
|
143
147
|
|
|
144
|
-
```
|
|
145
|
-
import {
|
|
148
|
+
```ts
|
|
149
|
+
import { RunStatus, TinyFish } from "@tiny-fish/sdk";
|
|
146
150
|
|
|
147
151
|
const client = new TinyFish();
|
|
148
152
|
|
|
149
153
|
const queued = await client.agent.queue({
|
|
150
|
-
goal: "Extract the
|
|
151
|
-
url: "https://
|
|
154
|
+
goal: "Extract all job titles from the careers page",
|
|
155
|
+
url: "https://example.com/careers",
|
|
152
156
|
});
|
|
153
157
|
|
|
154
158
|
if (queued.error) {
|
|
155
|
-
|
|
156
|
-
process.exit(1);
|
|
159
|
+
throw new Error(queued.error.message);
|
|
157
160
|
}
|
|
158
161
|
|
|
159
|
-
|
|
162
|
+
let run = await client.runs.get(queued.run_id);
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (run.status === RunStatus.COMPLETED || run.status === RunStatus.FAILED) {
|
|
165
|
-
console.log(run.result);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
await new Promise((r) => setTimeout(r, 5000));
|
|
164
|
+
while (run.status === RunStatus.PENDING || run.status === RunStatus.RUNNING) {
|
|
165
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
166
|
+
run = await client.runs.get(run.run_id);
|
|
169
167
|
}
|
|
170
|
-
```
|
|
171
168
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
const response = await client.agent.queue({ goal, url });
|
|
176
|
-
if (response.error) {
|
|
177
|
-
// response.run_id is null here
|
|
178
|
-
console.error(response.error.message);
|
|
169
|
+
if (run.status === RunStatus.COMPLETED) {
|
|
170
|
+
console.log(run.result);
|
|
179
171
|
} else {
|
|
180
|
-
|
|
181
|
-
const run = await client.runs.get(response.run_id);
|
|
172
|
+
console.error(run.error?.message ?? `Run ended with status: ${run.status}`);
|
|
182
173
|
}
|
|
183
174
|
```
|
|
184
175
|
|
|
185
|
-
|
|
186
|
-
|-------|------|-------------|
|
|
187
|
-
| `run_id` | `string \| null` | Run ID to poll with `runs.get()` |
|
|
188
|
-
| `error` | `RunError \| null` | Error if queuing itself failed |
|
|
176
|
+
`queue()` also accepts an optional second argument with `signal` for cancelling just the enqueue request.
|
|
189
177
|
|
|
190
|
-
|
|
178
|
+
### Fetch clean content
|
|
191
179
|
|
|
192
|
-
|
|
180
|
+
Use `fetch.getContents()` when you want extracted content from URLs without a browser-agent run.
|
|
193
181
|
|
|
194
|
-
|
|
182
|
+
```ts
|
|
183
|
+
import { FetchFormat, TinyFish } from "@tiny-fish/sdk";
|
|
195
184
|
|
|
196
|
-
|
|
197
|
-
const run = await client.runs.get("run_abc123");
|
|
185
|
+
const client = new TinyFish();
|
|
198
186
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
187
|
+
const response = await client.fetch.getContents({
|
|
188
|
+
urls: ["https://example.com", "https://example.org"],
|
|
189
|
+
format: FetchFormat.Markdown,
|
|
190
|
+
links: true,
|
|
191
|
+
image_links: false,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
console.log(response.results);
|
|
195
|
+
console.log(response.errors);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`fetch.getContents()` accepts 1 to 10 URLs. `FetchResult.text` is:
|
|
199
|
+
|
|
200
|
+
- `string` for `FetchFormat.Markdown` and `FetchFormat.Html`
|
|
201
|
+
- `Record<string, unknown>` for `FetchFormat.Json`
|
|
202
|
+
- `null` if extraction failed for that item
|
|
203
|
+
|
|
204
|
+
### Create a browser session
|
|
205
|
+
|
|
206
|
+
Use `browser.sessions.create()` when you want connection details for direct browser control.
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
import { TinyFish } from "@tiny-fish/sdk";
|
|
210
|
+
|
|
211
|
+
const client = new TinyFish();
|
|
212
|
+
|
|
213
|
+
const session = await client.browser.sessions.create({
|
|
214
|
+
url: "https://example.com",
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
console.log(session.session_id);
|
|
218
|
+
console.log(session.cdp_url);
|
|
219
|
+
console.log(session.base_url);
|
|
204
220
|
```
|
|
205
221
|
|
|
206
|
-
|
|
222
|
+
### Inspect and list runs
|
|
207
223
|
|
|
208
|
-
|
|
209
|
-
|-------|------|-------------|
|
|
210
|
-
| `run_id` | `string` | Unique identifier |
|
|
211
|
-
| `status` | `RunStatus` | `PENDING`, `RUNNING`, `COMPLETED`, `FAILED`, `CANCELLED` |
|
|
212
|
-
| `goal` | `string` | The goal that was given |
|
|
213
|
-
| `result` | `Record<string, unknown> \| null` | Extracted data (`null` if not completed) |
|
|
214
|
-
| `error` | `RunError \| null` | Error details (`null` if succeeded) |
|
|
215
|
-
| `streaming_url` | `string \| null` | Live browser URL (available while running) |
|
|
216
|
-
| `browser_config` | `BrowserConfig \| null` | Proxy/browser settings used |
|
|
217
|
-
| `created_at` | `string` | ISO 8601 timestamp when the run was created |
|
|
218
|
-
| `started_at` | `string \| null` | ISO 8601 timestamp when execution started |
|
|
219
|
-
| `finished_at` | `string \| null` | ISO 8601 timestamp when execution finished |
|
|
220
|
-
| `num_of_steps` | `number` | Number of steps the agent took |
|
|
224
|
+
Fetch a single run when you already know its `run_id`:
|
|
221
225
|
|
|
222
|
-
|
|
226
|
+
```ts
|
|
227
|
+
const run = await client.runs.get("run_abc123");
|
|
223
228
|
|
|
224
|
-
|
|
229
|
+
console.log(run.status);
|
|
230
|
+
console.log(run.result);
|
|
231
|
+
console.log(run.streaming_url);
|
|
232
|
+
```
|
|
225
233
|
|
|
226
|
-
|
|
234
|
+
Use `runs.list()` for filtering and pagination:
|
|
227
235
|
|
|
228
|
-
|
|
236
|
+
```ts
|
|
237
|
+
import { RunStatus, SortDirection, TinyFish } from "@tiny-fish/sdk";
|
|
229
238
|
|
|
230
|
-
|
|
231
|
-
import { RunStatus, SortDirection } from "tinyfish";
|
|
239
|
+
const client = new TinyFish();
|
|
232
240
|
|
|
233
241
|
const response = await client.runs.list({
|
|
234
|
-
status: RunStatus.COMPLETED,
|
|
235
|
-
goal: "headlines",
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
sort_direction: SortDirection.DESC, // optional — "asc" or "desc"
|
|
239
|
-
limit: 10, // optional — max runs per page
|
|
240
|
-
cursor: undefined, // optional — pagination cursor from previous response
|
|
242
|
+
status: RunStatus.COMPLETED,
|
|
243
|
+
goal: "headlines",
|
|
244
|
+
sort_direction: SortDirection.DESC,
|
|
245
|
+
limit: 10,
|
|
241
246
|
});
|
|
242
247
|
|
|
243
248
|
for (const run of response.data) {
|
|
244
|
-
console.log(`${run.run_id} | ${run.goal}`);
|
|
249
|
+
console.log(`${run.run_id} | ${run.status} | ${run.goal}`);
|
|
245
250
|
}
|
|
246
251
|
|
|
247
|
-
// Pagination
|
|
248
252
|
if (response.pagination.has_more) {
|
|
249
|
-
const nextPage = await client.runs.list({
|
|
253
|
+
const nextPage = await client.runs.list({
|
|
254
|
+
cursor: response.pagination.next_cursor ?? undefined,
|
|
255
|
+
});
|
|
256
|
+
console.log(`Fetched ${nextPage.data.length} more runs`);
|
|
250
257
|
}
|
|
251
258
|
```
|
|
252
259
|
|
|
253
|
-
|
|
260
|
+
### Query search
|
|
254
261
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
| `data` | `Run[]` | List of runs |
|
|
258
|
-
| `pagination.total` | `number` | Total runs matching filters |
|
|
259
|
-
| `pagination.has_more` | `boolean` | Whether more pages exist |
|
|
260
|
-
| `pagination.next_cursor` | `string \| null` | Pass to `cursor` for the next page |
|
|
262
|
+
```ts
|
|
263
|
+
import { TinyFish } from "@tiny-fish/sdk";
|
|
261
264
|
|
|
262
|
-
|
|
265
|
+
const client = new TinyFish();
|
|
263
266
|
|
|
264
|
-
|
|
267
|
+
const response = await client.search.query({
|
|
268
|
+
query: "tinyfish sdk",
|
|
269
|
+
location: "US",
|
|
270
|
+
language: "en",
|
|
271
|
+
});
|
|
265
272
|
|
|
266
|
-
|
|
273
|
+
console.log(response.query);
|
|
274
|
+
console.log(response.total_results);
|
|
275
|
+
console.log(response.results[0]?.title);
|
|
276
|
+
```
|
|
267
277
|
|
|
268
|
-
|
|
278
|
+
## Streaming events
|
|
269
279
|
|
|
270
|
-
|
|
271
|
-
const client = new TinyFish({
|
|
272
|
-
apiKey: "your-api-key", // optional — or set TINYFISH_API_KEY env var
|
|
273
|
-
baseURL: "https://agent.tinyfish.ai", // optional — default shown
|
|
274
|
-
timeout: 600_000, // optional — milliseconds (default: 600,000 = 10 min)
|
|
275
|
-
maxRetries: 2, // optional — retry attempts (default: 2)
|
|
276
|
-
});
|
|
277
|
-
```
|
|
280
|
+
`agent.stream()` guarantees this event order:
|
|
278
281
|
|
|
279
|
-
|
|
282
|
+
- `STARTED`
|
|
283
|
+
- `STREAMING_URL`
|
|
284
|
+
- `PROGRESS` repeated zero or more times
|
|
285
|
+
- `COMPLETE`
|
|
280
286
|
|
|
281
|
-
|
|
287
|
+
`HEARTBEAT` events may also appear, but they are keepalive events rather than part of the guaranteed ordered sequence.
|
|
282
288
|
|
|
283
|
-
|
|
289
|
+
You can consume the stream in two ways:
|
|
284
290
|
|
|
285
|
-
-
|
|
286
|
-
-
|
|
291
|
+
- callbacks like `onProgress` and `onComplete`
|
|
292
|
+
- direct iteration with `for await...of`
|
|
287
293
|
|
|
288
|
-
|
|
289
|
-
import { BrowserProfile } from "tinyfish";
|
|
294
|
+
To stop a stream early, call `await stream.close()`.
|
|
290
295
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
296
|
+
## Configuration
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
import { TinyFish } from "@tiny-fish/sdk";
|
|
300
|
+
|
|
301
|
+
const client = new TinyFish({
|
|
302
|
+
apiKey: process.env.TINYFISH_API_KEY,
|
|
303
|
+
baseURL: "https://agent.tinyfish.ai",
|
|
304
|
+
timeout: 600_000,
|
|
305
|
+
maxRetries: 2,
|
|
295
306
|
});
|
|
296
307
|
```
|
|
297
308
|
|
|
298
|
-
|
|
309
|
+
Defaults:
|
|
299
310
|
|
|
300
|
-
|
|
311
|
+
- `baseURL`: `https://agent.tinyfish.ai`
|
|
312
|
+
- `timeout`: `600000` ms
|
|
313
|
+
- `maxRetries`: `2`
|
|
301
314
|
|
|
302
|
-
|
|
303
|
-
import { ProxyCountryCode } from "tinyfish";
|
|
315
|
+
The SDK automatically retries `408`, `429`, and `5xx` responses with exponential backoff. Authentication, validation, and not-found errors fail immediately.
|
|
304
316
|
|
|
305
|
-
|
|
306
|
-
goal: "...",
|
|
307
|
-
url: "...",
|
|
308
|
-
proxy_config: { enabled: true, country_code: ProxyCountryCode.US },
|
|
309
|
-
});
|
|
310
|
-
```
|
|
317
|
+
## Browser profiles and proxies
|
|
311
318
|
|
|
312
|
-
|
|
319
|
+
`agent.run()`, `agent.queue()`, and `agent.stream()` all accept the same execution parameters:
|
|
313
320
|
|
|
314
|
-
|
|
321
|
+
- `goal` and `url` are required
|
|
322
|
+
- `browser_profile` can be `BrowserProfile.LITE` or `BrowserProfile.STEALTH`
|
|
323
|
+
- `proxy_config` can enable a proxy and optionally pin a country
|
|
324
|
+
|
|
325
|
+
Supported proxy country codes:
|
|
326
|
+
|
|
327
|
+
- `US`
|
|
328
|
+
- `GB`
|
|
329
|
+
- `CA`
|
|
330
|
+
- `DE`
|
|
331
|
+
- `FR`
|
|
332
|
+
- `JP`
|
|
333
|
+
- `AU`
|
|
315
334
|
|
|
316
335
|
## Error handling
|
|
317
336
|
|
|
318
|
-
```
|
|
319
|
-
import {
|
|
337
|
+
```ts
|
|
338
|
+
import {
|
|
339
|
+
AuthenticationError,
|
|
340
|
+
RateLimitError,
|
|
341
|
+
SDKError,
|
|
342
|
+
TinyFish,
|
|
343
|
+
} from "@tiny-fish/sdk";
|
|
320
344
|
|
|
321
345
|
const client = new TinyFish();
|
|
322
346
|
|
|
323
347
|
try {
|
|
324
|
-
|
|
348
|
+
await client.agent.run({
|
|
349
|
+
goal: "Extract the page title",
|
|
350
|
+
url: "https://example.com",
|
|
351
|
+
});
|
|
325
352
|
} catch (error) {
|
|
326
353
|
if (error instanceof AuthenticationError) {
|
|
327
|
-
console.
|
|
354
|
+
console.error("Invalid API key");
|
|
328
355
|
} else if (error instanceof RateLimitError) {
|
|
329
|
-
console.
|
|
356
|
+
console.error("Rate limited");
|
|
330
357
|
} else if (error instanceof SDKError) {
|
|
331
|
-
console.
|
|
358
|
+
console.error(error.message);
|
|
359
|
+
} else {
|
|
360
|
+
throw error;
|
|
332
361
|
}
|
|
333
362
|
}
|
|
334
363
|
```
|
|
335
364
|
|
|
336
|
-
The SDK automatically retries transient errors (`408`, `429`, `5xx`) up to `maxRetries` times with exponential backoff. Non-retryable errors (`401`, `400`, `404`) throw immediately.
|
|
337
|
-
|
|
338
|
-
For the full exception hierarchy and internal architecture, see [docs/internal/exceptions-and-errors-guide.md](docs/internal/exceptions-and-errors-guide.md).
|
|
339
|
-
|
|
340
365
|
## Guides
|
|
341
366
|
|
|
342
|
-
- [Streaming
|
|
343
|
-
- [
|
|
344
|
-
- [
|
|
345
|
-
- [
|
|
346
|
-
- [
|
|
367
|
+
- [Streaming guide](https://github.com/tinyfish-io/ux-labs/blob/main/sdk/sdk-typescript/docs/streaming-guide.md)
|
|
368
|
+
- [Pagination guide](https://github.com/tinyfish-io/ux-labs/blob/main/sdk/sdk-typescript/docs/pagination-guide.md)
|
|
369
|
+
- [Proxy and browser profiles](https://github.com/tinyfish-io/ux-labs/blob/main/sdk/sdk-typescript/docs/proxy-and-browser-profiles.md)
|
|
370
|
+
- [Error hierarchy and internals](https://github.com/tinyfish-io/ux-labs/blob/main/sdk/sdk-typescript/docs/internal/exceptions-and-errors-guide.md)
|
|
371
|
+
- [Architecture notes for SDK contributors](https://github.com/tinyfish-io/ux-labs/blob/main/sdk/sdk-typescript/ARCHITECTURE.md)
|
package/dist/_utils/client.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ export interface ClientOptions {
|
|
|
7
7
|
timeout?: number;
|
|
8
8
|
maxRetries?: number;
|
|
9
9
|
}
|
|
10
|
+
interface RequestOptions {
|
|
11
|
+
signal?: AbortSignal | undefined;
|
|
12
|
+
}
|
|
13
|
+
interface GetRequestOptions extends RequestOptions {
|
|
14
|
+
params?: Record<string, string | number | boolean | undefined>;
|
|
15
|
+
}
|
|
16
|
+
interface PostRequestOptions extends RequestOptions {
|
|
17
|
+
json?: unknown;
|
|
18
|
+
}
|
|
10
19
|
export declare class BaseClient {
|
|
11
20
|
private readonly _apiKey;
|
|
12
21
|
readonly baseURL: string;
|
|
@@ -20,6 +29,7 @@ export declare class BaseClient {
|
|
|
20
29
|
protected _buildHeaders(): Record<string, string>;
|
|
21
30
|
/** Inject api_integration from TF_API_INTEGRATION env var into JSON body. */
|
|
22
31
|
private static _injectIntegration;
|
|
32
|
+
private _buildRequestSignal;
|
|
23
33
|
/**
|
|
24
34
|
* Core request method with retry and error mapping.
|
|
25
35
|
* All public methods (get, post, postStream) delegate here.
|
|
@@ -33,14 +43,9 @@ export declare class BaseClient {
|
|
|
33
43
|
private _parseErrorMessage;
|
|
34
44
|
/** Maps HTTP status codes to typed error classes. Matches Python SDK's _make_status_error. */
|
|
35
45
|
private _makeStatusError;
|
|
36
|
-
get<T>(path: string, options?:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
post<T>(path: string, options?: {
|
|
40
|
-
json?: unknown;
|
|
41
|
-
}): Promise<T>;
|
|
42
|
-
postStream(path: string, options?: {
|
|
43
|
-
json?: unknown;
|
|
44
|
-
}): Promise<ReadableStream<string>>;
|
|
46
|
+
get<T = unknown>(path: string, options?: GetRequestOptions): Promise<T>;
|
|
47
|
+
post<T = unknown>(path: string, options?: PostRequestOptions): Promise<T>;
|
|
48
|
+
postStream(path: string, options?: PostRequestOptions): Promise<ReadableStream<string>>;
|
|
45
49
|
}
|
|
50
|
+
export {};
|
|
46
51
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/_utils/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqBH,MAAM,WAAW,aAAa;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/_utils/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqBH,MAAM,WAAW,aAAa;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,cAAc;IACvB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACjC;AAED,UAAU,iBAAkB,SAAQ,cAAc;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;CAC/D;AAED,UAAU,kBAAmB,SAAQ,cAAc;IAClD,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAYD,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,OAAO,GAAE,aAAkB;IAcvC;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAejC,SAAS,CAAC,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAUjD,6EAA6E;IAC7E,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAYjC,OAAO,CAAC,mBAAmB;IAyC3B;;;OAGG;YACW,QAAQ;IAmFtB;;;;OAIG;YACW,kBAAkB;IAuBhC,8FAA8F;YAChF,gBAAgB;IAmCxB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,CAAC;IAgBvE,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;IAKzE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;CAS7F"}
|