@tiny-fish/sdk 0.0.6 → 0.0.8

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.
Files changed (50) hide show
  1. package/README.md +175 -305
  2. package/dist/_utils/client.d.ts +2 -2
  3. package/dist/_utils/client.d.ts.map +1 -1
  4. package/dist/_utils/client.js.map +1 -1
  5. package/dist/agent/index.d.ts.map +1 -1
  6. package/dist/agent/index.js +34 -63
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/agent/types.d.ts +255 -129
  9. package/dist/agent/types.d.ts.map +1 -1
  10. package/dist/agent/types.js +133 -41
  11. package/dist/agent/types.js.map +1 -1
  12. package/dist/browser/index.d.ts +2 -4
  13. package/dist/browser/index.d.ts.map +1 -1
  14. package/dist/browser/index.js +10 -2
  15. package/dist/browser/index.js.map +1 -1
  16. package/dist/browser/types.d.ts +13 -9
  17. package/dist/browser/types.d.ts.map +1 -1
  18. package/dist/browser/types.js +12 -2
  19. package/dist/browser/types.js.map +1 -1
  20. package/dist/fetch/index.d.ts +1 -1
  21. package/dist/fetch/index.d.ts.map +1 -1
  22. package/dist/fetch/index.js +21 -13
  23. package/dist/fetch/index.js.map +1 -1
  24. package/dist/fetch/types.d.ts +167 -49
  25. package/dist/fetch/types.d.ts.map +1 -1
  26. package/dist/fetch/types.js +65 -7
  27. package/dist/fetch/types.js.map +1 -1
  28. package/dist/index.d.ts +7 -5
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +7 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/runs/index.d.ts +1 -1
  33. package/dist/runs/index.d.ts.map +1 -1
  34. package/dist/runs/index.js +25 -16
  35. package/dist/runs/index.js.map +1 -1
  36. package/dist/runs/types.d.ts +114 -66
  37. package/dist/runs/types.d.ts.map +1 -1
  38. package/dist/runs/types.js +48 -6
  39. package/dist/runs/types.js.map +1 -1
  40. package/dist/search/index.d.ts +2 -6
  41. package/dist/search/index.d.ts.map +1 -1
  42. package/dist/search/index.js +20 -8
  43. package/dist/search/index.js.map +1 -1
  44. package/dist/search/types.d.ts +31 -21
  45. package/dist/search/types.d.ts.map +1 -1
  46. package/dist/search/types.js +29 -2
  47. package/dist/search/types.js.map +1 -1
  48. package/dist/version.d.ts +1 -1
  49. package/dist/version.js +1 -1
  50. package/package.json +3 -2
package/README.md CHANGED
@@ -1,8 +1,15 @@
1
1
  # TinyFish TypeScript SDK
2
2
 
3
- The official TypeScript SDK for [TinyFish](https://agent.tinyfish.ai)
3
+ Typed access to TinyFish web agents, fetch extraction, remote browser sessions, run history, and search.
4
4
 
5
- For SDK design conventions and how new API surfaces should be added, see [ARCHITECTURE.md](ARCHITECTURE.md).
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
6
13
 
7
14
  ## Installation
8
15
 
@@ -10,81 +17,26 @@ For SDK design conventions and how new API surfaces should be added, see [ARCHIT
10
17
  npm install @tiny-fish/sdk
11
18
  ```
12
19
 
13
- Requires Node.js 18+. Also works with Bun and Deno.
14
-
15
- ## Get your API key
20
+ Requirements:
16
21
 
17
- Sign up and grab your key at [agent.tinyfish.ai/api-keys](https://agent.tinyfish.ai/api-keys).
22
+ - Node.js 18+
23
+ - a TinyFish API key from [agent.tinyfish.ai/api-keys](https://agent.tinyfish.ai/api-keys)
18
24
 
19
- ## Quickstart
25
+ Authenticate with either the constructor or `TINYFISH_API_KEY`:
20
26
 
21
- ```typescript
27
+ ```ts
22
28
  import { TinyFish } from "@tiny-fish/sdk";
23
29
 
24
- const client = new TinyFish({ apiKey: "your-api-key" });
25
-
26
- const stream = await client.agent.stream(
27
- {
28
- goal: "What is the current Bitcoin price?",
29
- url: "https://www.coinbase.com/price/bitcoin",
30
- },
31
- {
32
- onProgress: (e) => console.log(` > ${e.purpose}`),
33
- onComplete: (e) => console.log(e.result),
34
- },
35
- );
36
-
37
- for await (const event of stream) {
38
- // Callbacks fire automatically during iteration
39
- }
40
- ```
41
-
42
- Need per-request cancellation without changing the client-wide timeout? Pass an `AbortSignal` as the optional second argument:
43
-
44
- ```typescript
45
- const controller = new AbortController();
46
-
47
- const stream = await client.agent.stream(
48
- {
49
- goal: "Extract the top 5 headlines",
50
- url: "https://news.ycombinator.com",
51
- },
52
- {
53
- signal: controller.signal,
54
- },
55
- );
56
-
57
- controller.abort();
58
- ```
59
-
60
- Or set the `TINYFISH_API_KEY` environment variable and omit `apiKey`:
61
-
62
- ```typescript
63
- const client = new TinyFish();
30
+ const client = new TinyFish({
31
+ apiKey: process.env.TINYFISH_API_KEY,
32
+ });
64
33
  ```
65
34
 
66
- > All methods are async and return promises. There is no synchronous client — JavaScript is async-native.
67
-
68
- ## Methods
69
-
70
- | Method | Description | Returns | Blocks? |
71
- |--------|-------------|---------|---------|
72
- | [`agent.stream()`](#agentstream--real-time-events) | Stream live SSE events as the agent works | `AgentStream` | No |
73
- | [`agent.run()`](#agentrun--block-until-done) | Run an automation, wait for the result | `AgentRunResponse` | Yes |
74
- | [`agent.queue()`](#agentqueue--fire-and-forget) | Start an automation, return immediately | `AgentRunAsyncResponse` | No |
75
- | [`browser.sessions.create()`](#browsersessionscreate--create-a-browser-session) | Create a remote browser session | `BrowserSession` | — |
76
- | [`fetch.getContents()`](#fetchgetcontents--fetch-and-extract-content) | Fetch URLs and return extracted content | `FetchResponse` | — |
77
- | [`runs.get()`](#runsget--retrieve-a-single-run) | Retrieve a single run by ID | `Run` | — |
78
- | [`runs.list()`](#runslist--list-and-filter-runs) | List runs with filtering, sorting, pagination | `RunListResponse` | — |
79
- | [`search.query()`](#searchquery--run-a-web-search) | Run a web search query | `SearchQueryResponse` | — |
80
-
81
- ---
82
-
83
- ### `agent.stream()` — real-time events
35
+ ## Quickstart
84
36
 
85
- 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.
37
+ `agent.stream()` is the best default for product integrations because it gives you progress updates while the run is happening.
86
38
 
87
- ```typescript
39
+ ```ts
88
40
  import { TinyFish } from "@tiny-fish/sdk";
89
41
 
90
42
  const client = new TinyFish();
@@ -95,29 +47,23 @@ const stream = await client.agent.stream(
95
47
  url: "https://news.ycombinator.com",
96
48
  },
97
49
  {
98
- onStarted: (e) => console.log(`Started: ${e.run_id}`),
99
- onStreamingUrl: (e) => console.log(`Watch: ${e.streaming_url}`),
100
- onProgress: (e) => console.log(` > ${e.purpose}`),
101
- onComplete: (e) => console.log(`Done: ${e.status}`),
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),
102
54
  },
103
55
  );
104
56
 
105
57
  for await (const event of stream) {
106
- // Callbacks fire automatically during iteration.
107
- // You can also inspect events directly:
108
58
  if (event.type === "COMPLETE") {
109
- console.log(event.result);
59
+ console.log(`Finished with status ${event.status}`);
110
60
  }
111
61
  }
112
62
  ```
113
63
 
114
- **Returns `AgentStream`** an async iterable you iterate with `for await`. Events arrive in order: `STARTED` `STREAMING_URL` `PROGRESS` (repeated) → `COMPLETE`.
115
-
116
- Call `stream.close()` to abort early and stop yielding events.
117
-
118
- The second argument also accepts `signal` for request-scoped cancellation:
64
+ Need request-scoped cancellation without changing the client-wide timeout? Pass an `AbortSignal` as the optional second argument:
119
65
 
120
- ```typescript
66
+ ```ts
121
67
  const controller = new AbortController();
122
68
 
123
69
  const stream = await client.agent.stream(
@@ -127,53 +73,67 @@ const stream = await client.agent.stream(
127
73
  },
128
74
  {
129
75
  signal: controller.signal,
130
- onProgress: (e) => console.log(e.purpose),
131
76
  },
132
77
  );
133
78
 
134
79
  controller.abort();
135
80
  ```
136
81
 
137
- See the [Streaming Guide](docs/streaming-guide.md) for the full event lifecycle, event types, and advanced patterns.
82
+ ## Choose an API
138
83
 
139
- ---
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` |
140
94
 
141
- ### `agent.run()` — block until done
95
+ ## Core workflows
142
96
 
143
- Sends the automation and waits for it to finish. Returns the full result in one shot.
97
+ ### Run and wait
144
98
 
145
- ```typescript
146
- import { TinyFish, RunStatus, BrowserProfile, ProxyCountryCode } from "@tiny-fish/sdk";
147
- import type { ProxyConfig } from "@tiny-fish/sdk";
99
+ Use `agent.run()` for scripts, cron jobs, and backend tasks that should block until the result is ready.
100
+
101
+ ```ts
102
+ import {
103
+ BrowserProfile,
104
+ ProxyCountryCode,
105
+ RunStatus,
106
+ TinyFish,
107
+ } from "@tiny-fish/sdk";
148
108
 
149
109
  const client = new TinyFish();
150
110
 
151
111
  const response = await client.agent.run({
152
- goal: "Extract the top 5 headlines", // required what to do on the page
153
- url: "https://news.ycombinator.com", // required — URL to open
154
- browser_profile: BrowserProfile.STEALTH, // optional — "lite" (default) or "stealth"
155
- proxy_config: { // optional — proxy settings
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: {
156
116
  enabled: true,
157
- country_code: ProxyCountryCode.US, // optional — US, GB, CA, DE, FR, JP, AU
117
+ country_code: ProxyCountryCode.US,
158
118
  },
159
119
  });
160
120
 
161
121
  if (response.status === RunStatus.COMPLETED) {
162
122
  console.log(response.result);
163
123
  } else {
164
- console.log(`Failed: ${response.error?.message}`);
124
+ console.error(response.error?.message);
165
125
  }
166
126
  ```
167
127
 
168
- Like `stream()`, `run()` accepts an optional second argument with `signal`:
128
+ `run()` also accepts an optional second argument with `signal`:
169
129
 
170
- ```typescript
130
+ ```ts
171
131
  const controller = new AbortController();
172
132
 
173
133
  const response = await client.agent.run(
174
134
  {
175
- goal: "Extract the top 5 headlines",
176
- url: "https://news.ycombinator.com",
135
+ goal: "Extract the page title",
136
+ url: "https://example.com",
177
137
  },
178
138
  {
179
139
  signal: controller.signal,
@@ -181,113 +141,51 @@ const response = await client.agent.run(
181
141
  );
182
142
  ```
183
143
 
184
- **Returns `AgentRunResponse`:**
185
-
186
- | Field | Type | Description |
187
- |-------|------|-------------|
188
- | `status` | `RunStatus` | `COMPLETED`, `FAILED`, etc. |
189
- | `run_id` | `string \| null` | Unique run identifier |
190
- | `result` | `Record<string, unknown> \| null` | Extracted data (`null` if failed) |
191
- | `error` | `RunError \| null` | Error details (`null` if succeeded) |
192
- | `num_of_steps` | `number` | Number of steps the agent took |
193
- | `started_at` | `string \| null` | ISO 8601 timestamp when the run started |
194
- | `finished_at` | `string \| null` | ISO 8601 timestamp when the run finished |
195
-
196
- ---
197
-
198
- ### `agent.queue()` — fire and forget
144
+ ### Queue and poll
199
145
 
200
- Starts the automation in the background and returns a `run_id` immediately. Poll with `runs.get()` when you're ready for the result.
146
+ Use `agent.queue()` when you do not want to keep the request open.
201
147
 
202
- ```typescript
203
- import { TinyFish, RunStatus } from "@tiny-fish/sdk";
148
+ ```ts
149
+ import { RunStatus, TinyFish } from "@tiny-fish/sdk";
204
150
 
205
151
  const client = new TinyFish();
206
152
 
207
153
  const queued = await client.agent.queue({
208
- goal: "Extract the top 5 headlines",
209
- url: "https://news.ycombinator.com",
154
+ goal: "Extract all job titles from the careers page",
155
+ url: "https://example.com/careers",
210
156
  });
211
157
 
212
158
  if (queued.error) {
213
- console.error(`Failed to queue: ${queued.error.message}`);
214
- process.exit(1);
159
+ throw new Error(queued.error.message);
215
160
  }
216
161
 
217
- console.log(`Run started: ${queued.run_id}`);
162
+ let run = await client.runs.get(queued.run_id);
218
163
 
219
- // Poll for completion
220
- while (true) {
221
- const run = await client.runs.get(queued.run_id);
222
- if (run.status === RunStatus.COMPLETED || run.status === RunStatus.FAILED) {
223
- console.log(run.result);
224
- break;
225
- }
226
- 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);
227
167
  }
228
- ```
229
-
230
- `queue()` also accepts an optional `{ signal }` second argument when you want to cancel just that enqueue request.
231
-
232
- **Returns `AgentRunAsyncResponse`** — a discriminated union. Check `error` to narrow the type:
233
168
 
234
- ```typescript
235
- const response = await client.agent.queue({ goal, url });
236
- if (response.error) {
237
- // response.run_id is null here
238
- console.error(response.error.message);
169
+ if (run.status === RunStatus.COMPLETED) {
170
+ console.log(run.result);
239
171
  } else {
240
- // response.run_id is string here
241
- const run = await client.runs.get(response.run_id);
172
+ console.error(run.error?.message ?? `Run ended with status: ${run.status}`);
242
173
  }
243
174
  ```
244
175
 
245
- | Field | Type | Description |
246
- |-------|------|-------------|
247
- | `run_id` | `string \| null` | Run ID to poll with `runs.get()` |
248
- | `error` | `RunError \| null` | Error if queuing itself failed |
176
+ `queue()` also accepts an optional second argument with `signal` for cancelling just the enqueue request.
249
177
 
250
- ---
178
+ ### Fetch clean content
251
179
 
252
- ### `browser.sessions.create()` create a browser session
253
-
254
- Create a remote browser session and get back the connection details for direct CDP control. Pass a `url` to hint routing and start the session on a target page, or omit it to start at `about:blank`.
255
-
256
- ```typescript
257
- import { TinyFish } from "@tiny-fish/sdk";
180
+ Use `fetch.getContents()` when you want extracted content from URLs without a browser-agent run.
258
181
 
259
- const client = new TinyFish();
260
-
261
- const session = await client.browser.sessions.create({
262
- url: "https://example.com",
263
- });
264
-
265
- console.log(session.session_id);
266
- console.log(session.cdp_url);
267
- console.log(session.base_url);
268
- ```
269
-
270
- **Returns `BrowserSession`:**
271
-
272
- | Field | Type | Description |
273
- |-------|------|-------------|
274
- | `session_id` | `string` | Unique browser session identifier |
275
- | `cdp_url` | `string` | CDP WebSocket URL for connecting to the browser |
276
- | `base_url` | `string` | HTTPS base URL for the browser session |
277
-
278
- ---
279
-
280
- ### `fetch.getContents()` — fetch and extract content
281
-
282
- Fetch one or more URLs and return clean extracted content in markdown, html, or json form.
283
-
284
- ```typescript
182
+ ```ts
285
183
  import { FetchFormat, TinyFish } from "@tiny-fish/sdk";
286
184
 
287
185
  const client = new TinyFish();
288
186
 
289
187
  const response = await client.fetch.getContents({
290
- urls: ["https://example.com"],
188
+ urls: ["https://example.com", "https://example.org"],
291
189
  format: FetchFormat.Markdown,
292
190
  links: true,
293
191
  image_links: false,
@@ -297,100 +195,71 @@ console.log(response.results);
297
195
  console.log(response.errors);
298
196
  ```
299
197
 
300
- **Returns `FetchResponse`:**
301
-
302
- | Field | Type | Description |
303
- |-------|------|-------------|
304
- | `results` | `FetchResult[]` | Successfully fetched URLs and extracted content |
305
- | `errors` | `FetchError[]` | URLs that failed to fetch |
306
-
307
- `FetchResult.text` is:
198
+ `fetch.getContents()` accepts 1 to 10 URLs. `FetchResult.text` is:
308
199
 
309
- - `string` for `markdown` and `html`
310
- - `Record<string, unknown>` for `json`
200
+ - `string` for `FetchFormat.Markdown` and `FetchFormat.Html`
201
+ - `Record<string, unknown>` for `FetchFormat.Json`
311
202
  - `null` if extraction failed for that item
312
203
 
313
- ---
204
+ ### Create a browser session
314
205
 
315
- ### `runs.get()` retrieve a single run
206
+ Use `browser.sessions.create()` when you want connection details for direct browser control.
316
207
 
317
- Fetch the full details of a run by its ID.
208
+ ```ts
209
+ import { TinyFish } from "@tiny-fish/sdk";
318
210
 
319
- ```typescript
320
- const run = await client.runs.get("run_abc123");
211
+ const client = new TinyFish();
321
212
 
322
- console.log(run.status); // PENDING, RUNNING, COMPLETED, FAILED, CANCELLED
323
- console.log(run.result);
324
- console.log(run.goal);
325
- console.log(run.streaming_url); // live browser URL (while RUNNING)
326
- console.log(run.browser_config); // proxy/browser settings that were used
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);
327
220
  ```
328
221
 
329
- **Returns `Run`:**
222
+ ### Inspect and list runs
330
223
 
331
- | Field | Type | Description |
332
- |-------|------|-------------|
333
- | `run_id` | `string` | Unique identifier |
334
- | `status` | `RunStatus` | `PENDING`, `RUNNING`, `COMPLETED`, `FAILED`, `CANCELLED` |
335
- | `goal` | `string` | The goal that was given |
336
- | `result` | `Record<string, unknown> \| null` | Extracted data (`null` if not completed) |
337
- | `error` | `RunError \| null` | Error details (`null` if succeeded) |
338
- | `streaming_url` | `string \| null` | Live browser URL (available while running) |
339
- | `browser_config` | `BrowserConfig \| null` | Proxy/browser settings used |
340
- | `created_at` | `string` | ISO 8601 timestamp when the run was created |
341
- | `started_at` | `string \| null` | ISO 8601 timestamp when execution started |
342
- | `finished_at` | `string \| null` | ISO 8601 timestamp when execution finished |
343
- | `num_of_steps` | `number` | Number of steps the agent took |
224
+ Fetch a single run when you already know its `run_id`:
344
225
 
345
- **Throws:** `SDKError` if `run_id` is empty. `NotFoundError` if no run exists with that ID.
226
+ ```ts
227
+ const run = await client.runs.get("run_abc123");
346
228
 
347
- ---
229
+ console.log(run.status);
230
+ console.log(run.result);
231
+ console.log(run.streaming_url);
232
+ ```
348
233
 
349
- ### `runs.list()` list and filter runs
234
+ Use `runs.list()` for filtering and pagination:
350
235
 
351
- List runs with optional filtering, sorting, and cursor-based pagination. All parameters are optional.
236
+ ```ts
237
+ import { RunStatus, SortDirection, TinyFish } from "@tiny-fish/sdk";
352
238
 
353
- ```typescript
354
- import { RunStatus, SortDirection } from "@tiny-fish/sdk";
239
+ const client = new TinyFish();
355
240
 
356
241
  const response = await client.runs.list({
357
- status: RunStatus.COMPLETED, // optional — filter by status
358
- goal: "headlines", // optional — filter by goal text
359
- created_after: "2025-01-01T00:00:00Z", // optional — ISO 8601 lower bound
360
- created_before: "2025-12-31T23:59:59Z", // optional — ISO 8601 upper bound
361
- sort_direction: SortDirection.DESC, // optional — "asc" or "desc"
362
- limit: 10, // optional — max runs per page
363
- cursor: undefined, // optional — pagination cursor from previous response
242
+ status: RunStatus.COMPLETED,
243
+ goal: "headlines",
244
+ sort_direction: SortDirection.DESC,
245
+ limit: 10,
364
246
  });
365
247
 
366
248
  for (const run of response.data) {
367
- console.log(`${run.run_id} | ${run.goal}`);
249
+ console.log(`${run.run_id} | ${run.status} | ${run.goal}`);
368
250
  }
369
251
 
370
- // Pagination
371
252
  if (response.pagination.has_more) {
372
- const nextPage = await client.runs.list({ cursor: response.pagination.next_cursor! });
253
+ const nextPage = await client.runs.list({
254
+ cursor: response.pagination.next_cursor ?? undefined,
255
+ });
256
+ console.log(`Fetched ${nextPage.data.length} more runs`);
373
257
  }
374
258
  ```
375
259
 
376
- **Returns `RunListResponse`:**
377
-
378
- | Field | Type | Description |
379
- |-------|------|-------------|
380
- | `data` | `Run[]` | List of runs |
381
- | `pagination.total` | `number` | Total runs matching filters |
382
- | `pagination.has_more` | `boolean` | Whether more pages exist |
383
- | `pagination.next_cursor` | `string \| null` | Pass to `cursor` for the next page |
384
-
385
- See the [Pagination Guide](docs/pagination-guide.md) for full pagination loop examples.
260
+ ### Query search
386
261
 
387
- ---
388
-
389
- ### `search.query()` — run a web search
390
-
391
- Run a typed search query through the TinyFish Search API.
392
-
393
- ```typescript
262
+ ```ts
394
263
  import { TinyFish } from "@tiny-fish/sdk";
395
264
 
396
265
  const client = new TinyFish();
@@ -406,96 +275,97 @@ console.log(response.total_results);
406
275
  console.log(response.results[0]?.title);
407
276
  ```
408
277
 
409
- **Returns `SearchQueryResponse`:**
278
+ ## Streaming events
279
+
280
+ `agent.stream()` guarantees this event order:
410
281
 
411
- | Field | Type | Description |
412
- |-------|------|-------------|
413
- | `query` | `string` | The query that was executed |
414
- | `results` | `SearchResult[]` | Search results returned by the backend |
415
- | `total_results` | `number` | Total number of results returned |
282
+ - `STARTED`
283
+ - `STREAMING_URL`
284
+ - `PROGRESS` repeated zero or more times
285
+ - `COMPLETE`
416
286
 
417
- **Throws:** `SDKError` if `query` is empty. Standard API errors are handled by the shared SDK error hierarchy.
287
+ `HEARTBEAT` events may also appear, but they are keepalive events rather than part of the guaranteed ordered sequence.
418
288
 
419
- ---
289
+ You can consume the stream in two ways:
290
+
291
+ - callbacks like `onProgress` and `onComplete`
292
+ - direct iteration with `for await...of`
293
+
294
+ To stop a stream early, call `await stream.close()`.
420
295
 
421
296
  ## Configuration
422
297
 
423
- ### Client options
298
+ ```ts
299
+ import { TinyFish } from "@tiny-fish/sdk";
424
300
 
425
- ```typescript
426
301
  const client = new TinyFish({
427
- apiKey: "your-api-key", // optional — or set TINYFISH_API_KEY env var
428
- baseURL: "https://agent.tinyfish.ai", // optional — default shown
429
- timeout: 600_000, // optional — milliseconds (default: 600,000 = 10 min)
430
- maxRetries: 2, // optional — retry attempts (default: 2)
302
+ apiKey: process.env.TINYFISH_API_KEY,
303
+ baseURL: "https://agent.tinyfish.ai",
304
+ timeout: 600_000,
305
+ maxRetries: 2,
431
306
  });
432
307
  ```
433
308
 
434
- The SDK retries `408`, `429`, and `5xx` errors automatically with exponential backoff (0.5s base, max 8s wait).
309
+ Defaults:
435
310
 
436
- ### Browser profiles
311
+ - `baseURL`: `https://agent.tinyfish.ai`
312
+ - `timeout`: `600000` ms
313
+ - `maxRetries`: `2`
437
314
 
438
- Control the browser environment with `browser_profile`:
315
+ The SDK automatically retries `408`, `429`, and `5xx` responses with exponential backoff. Authentication, validation, and not-found errors fail immediately.
439
316
 
440
- - **`lite`** (default) fast, lightweight. Good for most sites.
441
- - **`stealth`** — anti-detection mode. Use for sites with bot protection.
317
+ ## Browser profiles and proxies
442
318
 
443
- ```typescript
444
- import { BrowserProfile } from "@tiny-fish/sdk";
319
+ `agent.run()`, `agent.queue()`, and `agent.stream()` all accept the same execution parameters:
445
320
 
446
- const response = await client.agent.run({
447
- goal: "...",
448
- url: "...",
449
- browser_profile: BrowserProfile.STEALTH,
450
- });
451
- ```
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
452
324
 
453
- ### Proxy configuration
325
+ Supported proxy country codes:
454
326
 
455
- Route requests through a proxy, optionally pinned to a country:
456
-
457
- ```typescript
458
- import { ProxyCountryCode } from "@tiny-fish/sdk";
459
-
460
- const response = await client.agent.run({
461
- goal: "...",
462
- url: "...",
463
- proxy_config: { enabled: true, country_code: ProxyCountryCode.US },
464
- });
465
- ```
466
-
467
- Available countries: `US`, `GB`, `CA`, `DE`, `FR`, `JP`, `AU`.
468
-
469
- See the [Proxy & Browser Profiles Guide](docs/proxy-and-browser-profiles.md) for more details.
327
+ - `US`
328
+ - `GB`
329
+ - `CA`
330
+ - `DE`
331
+ - `FR`
332
+ - `JP`
333
+ - `AU`
470
334
 
471
335
  ## Error handling
472
336
 
473
- ```typescript
474
- import { TinyFish, AuthenticationError, RateLimitError, SDKError } from "@tiny-fish/sdk";
337
+ ```ts
338
+ import {
339
+ AuthenticationError,
340
+ RateLimitError,
341
+ SDKError,
342
+ TinyFish,
343
+ } from "@tiny-fish/sdk";
475
344
 
476
345
  const client = new TinyFish();
477
346
 
478
347
  try {
479
- const response = await client.agent.run({ goal: "...", url: "..." });
348
+ await client.agent.run({
349
+ goal: "Extract the page title",
350
+ url: "https://example.com",
351
+ });
480
352
  } catch (error) {
481
353
  if (error instanceof AuthenticationError) {
482
- console.log("Invalid API key");
354
+ console.error("Invalid API key");
483
355
  } else if (error instanceof RateLimitError) {
484
- console.log("Rate limited (retries exhausted)");
356
+ console.error("Rate limited");
485
357
  } else if (error instanceof SDKError) {
486
- console.log("Something else went wrong");
358
+ console.error(error.message);
359
+ } else {
360
+ throw error;
487
361
  }
488
362
  }
489
363
  ```
490
364
 
491
- The SDK automatically retries transient errors (`408`, `429`, `5xx`) up to `maxRetries` times with exponential backoff. Non-retryable errors (`401`, `400`, `404`) throw immediately.
492
-
493
- For the full exception hierarchy and internal architecture, see [docs/internal/exceptions-and-errors-guide.md](docs/internal/exceptions-and-errors-guide.md).
494
-
495
365
  ## Guides
496
366
 
497
- - [Streaming Guide](docs/streaming-guide.md) — event lifecycle, callbacks vs iteration, event type reference
498
- - [Proxy & Browser Profiles](docs/proxy-and-browser-profiles.md) — stealth mode, proxy countries
499
- - [Pagination Guide](docs/pagination-guide.md) — filtering, sorting, cursor-based pagination
500
- - [Exceptions & Error Handling (internal)](docs/internal/exceptions-and-errors-guide.md) — layer-by-layer architecture
501
- - [Testing Guide](tests/testing-guide.md) — running and writing tests
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)
@@ -43,8 +43,8 @@ export declare class BaseClient {
43
43
  private _parseErrorMessage;
44
44
  /** Maps HTTP status codes to typed error classes. Matches Python SDK's _make_status_error. */
45
45
  private _makeStatusError;
46
- get<T>(path: string, options?: GetRequestOptions): Promise<T>;
47
- post<T>(path: string, options?: PostRequestOptions): Promise<T>;
46
+ get<T = unknown>(path: string, options?: GetRequestOptions): Promise<T>;
47
+ post<T = unknown>(path: string, options?: PostRequestOptions): Promise<T>;
48
48
  postStream(path: string, options?: PostRequestOptions): Promise<ReadableStream<string>>;
49
49
  }
50
50
  export {};