notte-sdk 0.0.22 → 1.9.1
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/LICENSE +21 -0
- package/README.md +594 -102
- package/dist/index.d.mts +2529 -254
- package/dist/index.d.ts +2529 -254
- package/dist/index.js +4219 -1417
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4161 -1422
- package/dist/index.mjs.map +1 -1
- package/dist/proxy/core.d.mts +1 -1
- package/dist/proxy/core.d.ts +1 -1
- package/dist/proxy/core.js +27 -4
- package/dist/proxy/core.js.map +1 -1
- package/dist/proxy/core.mjs +27 -4
- package/dist/proxy/core.mjs.map +1 -1
- package/dist/proxy/next.d.mts +12 -7
- package/dist/proxy/next.d.ts +12 -7
- package/dist/proxy/next.js +27 -4
- package/dist/proxy/next.js.map +1 -1
- package/dist/proxy/next.mjs +27 -4
- package/dist/proxy/next.mjs.map +1 -1
- package/dist/{types-DmqqdEMP.d.mts → types-C5V9BOux.d.mts} +3 -1
- package/dist/{types-DmqqdEMP.d.ts → types-C5V9BOux.d.ts} +3 -1
- package/package.json +33 -4
package/README.md
CHANGED
|
@@ -4,8 +4,119 @@
|
|
|
4
4
|
|
|
5
5
|
The official TypeScript SDK for Notte API, providing cloud-hosted browser sessions with precise control, LLM-powered web agents for automated tasks, serverless functions, and secure credential management.
|
|
6
6
|
|
|
7
|
+
## Contributing
|
|
8
|
+
|
|
9
|
+
This directory is a standalone npm package. Node.js 22 and 24 are tested in CI;
|
|
10
|
+
Python tooling is not required to build or test it.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cd node-sdk
|
|
14
|
+
npm ci
|
|
15
|
+
npm run typecheck
|
|
16
|
+
npm run test:unit -- --run
|
|
17
|
+
npx vitest run test/function-stream.local.test.ts # also part of npm run test:unit
|
|
18
|
+
npm run build
|
|
19
|
+
node scripts/check-package.js
|
|
20
|
+
npm pack --dry-run
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`npm run build` compiles the checked-in client without contacting the API.
|
|
24
|
+
To update the generated client, run `npm run generate:staging`, review the diff,
|
|
25
|
+
and commit it. `npm run check:staging` checks for drift without editing your files.
|
|
26
|
+
|
|
27
|
+
### Generated resource methods
|
|
28
|
+
|
|
29
|
+
The SDK generates client-bound methods for `sessions`, `agents`, `functions`,
|
|
30
|
+
`vaults`, `personas`, and `profiles` from the checked-in OpenAPI-derived types
|
|
31
|
+
and operations. No per-call client or `throwOnError` is needed:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const client = new NotteClient();
|
|
35
|
+
await client.sessions.stop(sessionId);
|
|
36
|
+
const vault = await client.vaults.create({ name: 'default' });
|
|
37
|
+
const copy = await client.functions.fork(functionId);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Arguments are path IDs in URL order, then the request body (if any), query
|
|
41
|
+
parameters (if any), and optional `{ signal }` cancellation options. For example,
|
|
42
|
+
`client.sessions.stop(sessionId, { close_reason: 'manual' }, { signal })`.
|
|
43
|
+
Operations with required request headers require a final options object, for
|
|
44
|
+
example `client.sessions.createPayment(sessionId, body, undefined, { headers: { 'idempotency-key': key } })`.
|
|
45
|
+
Keep the same idempotency key when retrying the same payment request. The SDK
|
|
46
|
+
binds `x-notte-api-key` automatically; callers cannot override it through typed headers.
|
|
47
|
+
Methods return the API response body and throw the client's typed API errors.
|
|
48
|
+
The five existing `list()` methods still return arrays for compatibility;
|
|
49
|
+
the newly added `profiles.list()` returns the API pagination response.
|
|
50
|
+
|
|
51
|
+
These are API operations, not lifecycle helpers: they do not poll for completion,
|
|
52
|
+
decrypt credentials, or manage cleanup. Continue using `Session().use()`,
|
|
53
|
+
`Agent().run()`, `Function().run()`, and `Vault()` for those behaviors. Existing
|
|
54
|
+
standalone generated exports remain supported.
|
|
55
|
+
|
|
56
|
+
`npm run generate` refreshes this layer too. Use `npm run resources:generate`
|
|
57
|
+
to regenerate it offline, `npm run resources:check` to detect stale output, and
|
|
58
|
+
`npm run resources:test` for generator regressions. Method-name aliases live in
|
|
59
|
+
the generator; request shapes and routes come from generated OpenAPI types.
|
|
60
|
+
|
|
61
|
+
For the isolated live test, set `NOTTE_API_KEY` and
|
|
62
|
+
`NOTTE_API_URL=https://us-staging.notte.cc`, then run:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx vitest run test/function-create-run.integration.test.ts
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This test creates its own function and deletes it afterward. Other live suites
|
|
69
|
+
may require pre-existing fixtures; see [test documentation](test/README.md).
|
|
70
|
+
The `node sdk cicd` workflow runs on every PR touching `node-sdk/`:
|
|
71
|
+
|
|
72
|
+
- `tests` runs unit tests, local HTTP integration tests, type checks, and package
|
|
73
|
+
checks on Node.js 22 and 24, including for fork PRs.
|
|
74
|
+
- `integration-tests` runs the isolated live function lifecycle tests against
|
|
75
|
+
staging on same-repository PRs. Fork PRs skip this credentialed job.
|
|
76
|
+
|
|
77
|
+
Both jobs also run on main pushes and manual workflow runs on main. API drift
|
|
78
|
+
checks remain limited to main pushes and manual workflow runs on main.
|
|
79
|
+
|
|
80
|
+
### Releases
|
|
81
|
+
|
|
82
|
+
The npm package remains `notte-sdk`. Its MIT license is in [LICENSE](LICENSE);
|
|
83
|
+
the repository root license does not replace this package's license.
|
|
84
|
+
|
|
85
|
+
The Node SDK is released together with the Python SDK, from the same tag and at
|
|
86
|
+
the same version. Cutting a release means creating a GitHub release tagged
|
|
87
|
+
`vX.Y.Z` on [nottelabs/notte](https://github.com/nottelabs/notte/releases):
|
|
88
|
+
|
|
89
|
+
- `pypi-release.yml` publishes the Python packages to PyPI as `X.Y.Z`.
|
|
90
|
+
- `node-sdk-publish.yml` sets this package's version to `X.Y.Z`, runs the
|
|
91
|
+
typecheck, unit tests, streaming test and export smoke test, publishes to npm
|
|
92
|
+
with provenance, then installs the published version back from npm to verify it.
|
|
93
|
+
|
|
94
|
+
`package.json` stays at `0.0.0-dev` on `main`; the version is only set in CI
|
|
95
|
+
from the tag, like the `.dev` placeholder in the Python `pyproject.toml` files.
|
|
96
|
+
Publishing uses npm trusted publishing (GitHub OIDC) bound to this repository,
|
|
97
|
+
workflow `node-sdk-publish.yml` and environment `npm`, so no npm token is stored
|
|
98
|
+
in the repository. To dry-run a release build locally, run `make release X.Y.Z`
|
|
99
|
+
in this directory; it never publishes.
|
|
100
|
+
|
|
101
|
+
Importing the SDK does not contact the npm registry. Constructing a `NotteClient`
|
|
102
|
+
performs a one-time, non-blocking check per process and warns when a newer
|
|
103
|
+
release exists, like the Python SDK. Set `NOTTE_SDK_DISABLE_VERSION_CHECK=1` to
|
|
104
|
+
disable it. To explicitly check for an update, call `await checkForLatestVersion()`
|
|
105
|
+
from `notte-sdk`.
|
|
106
|
+
API URLs must use HTTPS, except HTTP loopback addresses for local development.
|
|
107
|
+
|
|
7
108
|
## Features
|
|
8
109
|
|
|
110
|
+
### Server-side proxy security
|
|
111
|
+
|
|
112
|
+
`createNotteProxy` from `notte-sdk/next` requires an `authenticate` callback at
|
|
113
|
+
runtime. Without one, requests return 401 even when a server API key is configured.
|
|
114
|
+
The callback must verify caller identity and authorize access to requested
|
|
115
|
+
resources. Returning a user-specific Notte API key isolates accounts; returning
|
|
116
|
+
void uses the shared server key and requires application-level ownership checks.
|
|
117
|
+
An endpoint allowlist is not a substitute for authorization. Relative HTTP proxy
|
|
118
|
+
clients poll agent status for completion because they cannot use backend WebSockets.
|
|
119
|
+
|
|
9
120
|
- 🌐 **Cloud Browser Sessions** - Access remote browsers with full control
|
|
10
121
|
- 🤖 **LLM-Powered Agents** - Intelligent web automation with natural language
|
|
11
122
|
- 🔒 **Secret Vaults** - Enterprise-grade credential management with end-to-end encryption
|
|
@@ -14,6 +125,7 @@ The official TypeScript SDK for Notte API, providing cloud-hosted browser sessio
|
|
|
14
125
|
- 📡 **Real-time Updates** - WebSocket support for live agent monitoring
|
|
15
126
|
- 📝 **Type Safety** - Full TypeScript support with generated types
|
|
16
127
|
- ⚡ **Serverless Functions** - Run pre-built automation workflows with simple API calls
|
|
128
|
+
- 🔍 **Web Search, Secrets and Usage** - Search the web, manage workspace secrets and read billing usage
|
|
17
129
|
- 🔄 **Auto-sync** - Generated from OpenAPI spec, always up-to-date
|
|
18
130
|
|
|
19
131
|
## Installation
|
|
@@ -35,7 +147,7 @@ const notte = new NotteClient({
|
|
|
35
147
|
});
|
|
36
148
|
|
|
37
149
|
// Use session with automatic cleanup (mirrors Python's context manager)
|
|
38
|
-
await notte.Session({
|
|
150
|
+
await notte.Session({ idle_timeout_minutes: 5 }).use(async (session) => {
|
|
39
151
|
const status = await session.status();
|
|
40
152
|
console.log('Session status:', status);
|
|
41
153
|
});
|
|
@@ -52,13 +164,13 @@ const notte = new NotteClient();
|
|
|
52
164
|
await notte.Session().use(async (session) => {
|
|
53
165
|
const agent = notte.Agent({ session, max_steps: 10 });
|
|
54
166
|
|
|
55
|
-
const response = await agent.run(
|
|
56
|
-
"Find the best Italian restaurant in San Francisco and book a table for 2 at 7pm today",
|
|
57
|
-
(update) => {
|
|
167
|
+
const response = await agent.run({
|
|
168
|
+
task: "Find the best Italian restaurant in San Francisco and book a table for 2 at 7pm today",
|
|
169
|
+
updateHandler: (update) => {
|
|
58
170
|
// Receive real-time updates via WebSocket
|
|
59
|
-
console.log(`
|
|
171
|
+
console.log(`[${update.type}]`, update.data);
|
|
60
172
|
}
|
|
61
|
-
);
|
|
173
|
+
});
|
|
62
174
|
|
|
63
175
|
console.log(`Agent completed: ${response.success ? 'Success' : 'Failed'}`);
|
|
64
176
|
console.log(`Answer: ${response.answer}`);
|
|
@@ -74,10 +186,15 @@ The main client for interacting with the Notte API.
|
|
|
74
186
|
```typescript
|
|
75
187
|
import { NotteClient } from 'notte-sdk';
|
|
76
188
|
|
|
77
|
-
const notte = new NotteClient(
|
|
189
|
+
const notte = new NotteClient({
|
|
190
|
+
apiKey: process.env.NOTTE_API_KEY, // defaults to NOTTE_API_KEY
|
|
191
|
+
baseUrl: 'https://api.notte.cc', // defaults to NOTTE_API_URL or https://api.notte.cc
|
|
192
|
+
timeoutMs: 60_000, // per-request timeout, default 60 s
|
|
193
|
+
verbose: false, // log every request
|
|
194
|
+
});
|
|
78
195
|
|
|
79
196
|
// Create sessions
|
|
80
|
-
const session = notte.Session({
|
|
197
|
+
const session = notte.Session({ idle_timeout_minutes: 5, max_duration_minutes: 30 });
|
|
81
198
|
|
|
82
199
|
// Create agents
|
|
83
200
|
const agent = notte.Agent({ session, max_steps: 15 });
|
|
@@ -87,8 +204,32 @@ const vault = notte.Vault({ name: 'My Vault' });
|
|
|
87
204
|
|
|
88
205
|
// Create personas
|
|
89
206
|
const persona = notte.Persona({ create_vault: true });
|
|
207
|
+
|
|
208
|
+
// Check that the API is reachable (rejects with NotteAPIError otherwise)
|
|
209
|
+
await notte.healthCheck();
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Listing resources
|
|
213
|
+
|
|
214
|
+
Every resource has a `list()` namespace, mirroring `client.sessions.list()` and
|
|
215
|
+
friends in Python. Options are the generated query parameters of the matching
|
|
216
|
+
endpoint (`SessionListOptions`, `AgentListOptions`, `VaultListOptions`,
|
|
217
|
+
`FunctionListOptions`, `PersonaListOptions`).
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
const sessions = await notte.sessions.list({ only_active: true });
|
|
221
|
+
const agents = await notte.agents.list({ page_size: 10 });
|
|
222
|
+
const vaults = await notte.vaults.list();
|
|
223
|
+
const functions = await notte.functions.list();
|
|
224
|
+
const personas = await notte.personas.list({ only_active: true });
|
|
90
225
|
```
|
|
91
226
|
|
|
227
|
+
#### Database preview branches
|
|
228
|
+
|
|
229
|
+
Set `NOTTE_DB_PREVIEW_BRANCH` (or pass `dbPreview` to the client) to route every
|
|
230
|
+
request and websocket handshake to a database preview branch. This is an internal
|
|
231
|
+
option used when testing API changes.
|
|
232
|
+
|
|
92
233
|
### Session
|
|
93
234
|
|
|
94
235
|
Manages browser sessions with automatic lifecycle management.
|
|
@@ -99,7 +240,7 @@ import { NotteClient } from 'notte-sdk';
|
|
|
99
240
|
const notte = new NotteClient();
|
|
100
241
|
|
|
101
242
|
// Context manager pattern (automatic start/stop)
|
|
102
|
-
await notte.Session({
|
|
243
|
+
await notte.Session({ idle_timeout_minutes: 5 }).use(async (session) => {
|
|
103
244
|
// Session is automatically started
|
|
104
245
|
console.log('Session ID:', session.getId());
|
|
105
246
|
|
|
@@ -120,7 +261,7 @@ try {
|
|
|
120
261
|
}
|
|
121
262
|
|
|
122
263
|
// Async iterator pattern
|
|
123
|
-
for await (const session of notte.Session({
|
|
264
|
+
for await (const session of notte.Session({ max_duration_minutes: 15 })) {
|
|
124
265
|
// Use session here
|
|
125
266
|
const status = await session.status();
|
|
126
267
|
console.log('Session active:', status);
|
|
@@ -128,15 +269,102 @@ for await (const session of notte.Session({ timeoutMinutes: 15 })) {
|
|
|
128
269
|
}
|
|
129
270
|
```
|
|
130
271
|
|
|
272
|
+
#### Browser control
|
|
273
|
+
|
|
274
|
+
Drive the page with typed actions, exactly like `session.execute(...)` in Python.
|
|
275
|
+
Element ids (`B1`, `I2`, ...) must come from a live `observe()` call.
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { NotteClient, actions, ActionExecutionError } from 'notte-sdk';
|
|
279
|
+
|
|
280
|
+
const notte = new NotteClient();
|
|
281
|
+
|
|
282
|
+
await notte.Session().use(async (session) => {
|
|
283
|
+
await session.execute(actions.goto({ url: 'https://www.notte.cc' }));
|
|
284
|
+
|
|
285
|
+
const observation = await session.observe({ perception_type: 'deep' });
|
|
286
|
+
console.log(observation.space);
|
|
287
|
+
|
|
288
|
+
// Plain objects work too; the `type` field is a discriminated union
|
|
289
|
+
await session.execute({ type: 'click', id: 'B1' });
|
|
290
|
+
await session.execute(actions.fill({ selector: 'internal:text="Email"', value: 'me@example.com' }));
|
|
291
|
+
|
|
292
|
+
// A failed action throws ActionExecutionError with the server-side error type
|
|
293
|
+
try {
|
|
294
|
+
await session.execute(actions.click({ id: 'B999' }));
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (error instanceof ActionExecutionError) console.log(error.errorType, error.userMessage);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Or inspect the result yourself
|
|
300
|
+
const result = await session.execute(actions.click({ id: 'B999' }), { raiseOnFailure: false });
|
|
301
|
+
console.log(result.success, result.message);
|
|
302
|
+
|
|
303
|
+
// Run JavaScript in the page and fetch through the page (cookies, proxy, fingerprint).
|
|
304
|
+
// Relative URLs resolve against the page; plaintext http targets are refused unless allowInsecure is set.
|
|
305
|
+
const title = await session.evaluateJs('document.title');
|
|
306
|
+
const summary = await session.fetch('/api/rest_v1/page/summary/Main_Page').then(r => r.json());
|
|
307
|
+
|
|
308
|
+
// Scrape the current page
|
|
309
|
+
const markdown = await session.scrape({ only_main_content: true });
|
|
310
|
+
|
|
311
|
+
// Cookies
|
|
312
|
+
const cookies = await session.getCookies();
|
|
313
|
+
await session.setCookies(cookies);
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
#### Playwright access
|
|
318
|
+
|
|
319
|
+
`playwright-core` is an optional peer dependency (`npm install playwright-core`),
|
|
320
|
+
the counterpart of `pip install notte-sdk[playwright]`:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
await notte.Session().use(async (session) => {
|
|
324
|
+
const page = await session.page(); // connected over CDP, cached
|
|
325
|
+
await page.goto('https://www.notte.cc');
|
|
326
|
+
await page.screenshot({ path: 'screenshot.png' });
|
|
327
|
+
|
|
328
|
+
// Or connect your own tooling
|
|
329
|
+
const cdpUrl = await session.cdpUrl();
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### Replays and cookie files
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// Persist login state between runs: loaded on start, appended on stop
|
|
337
|
+
const session = notte.Session({ cookie_file: './cookies.json' });
|
|
338
|
+
|
|
339
|
+
await session.use(async () => { /* ... */ });
|
|
340
|
+
|
|
341
|
+
// Replays are generated after stop(); replay() polls until ready (240 s by default)
|
|
342
|
+
const replay = await session.replay();
|
|
343
|
+
await session.downloadReplay('./session.mp4');
|
|
344
|
+
```
|
|
345
|
+
|
|
131
346
|
#### Session Methods
|
|
132
347
|
|
|
133
|
-
- `start()` - Start the session
|
|
134
|
-
- `stop()` - Stop the session
|
|
348
|
+
- `start()` - Start the session (retries 5xx errors 3 times, waits 30 s on cluster overload)
|
|
349
|
+
- `stop(closeReason?)` - Stop the session
|
|
135
350
|
- `status()` - Get session status
|
|
136
|
-
- `viewer()` - Open the live session viewer in the local default browser
|
|
137
351
|
- `use(callback)` - Context manager pattern
|
|
138
352
|
- `getId()` - Get session ID
|
|
139
353
|
- `isSessionActive()` - Check if session is running
|
|
354
|
+
- `execute(action, options?)` - Execute a typed action; throws `ActionExecutionError` on failure unless `raiseOnFailure: false`
|
|
355
|
+
- `observe(options?)` - Observe the page (`perception_type`, `min_nb_actions`, `max_nb_actions`)
|
|
356
|
+
- `scrape(options?)` - Scrape the page as markdown, images, or structured data (see [Scraping](#scraping))
|
|
357
|
+
- `evaluateJs(code, options?)` - Evaluate JavaScript and return the stringified result
|
|
358
|
+
- `fetch(url, options?)` - Issue an HTTP request from inside the page
|
|
359
|
+
- `setCookies(cookies)` / `setCookiesFromFile(path)` / `getCookies()` - Manage cookies
|
|
360
|
+
- `cdpUrl()` - Chrome DevTools Protocol websocket URL
|
|
361
|
+
- `page()` - Playwright `Page` connected over CDP (requires `playwright-core`)
|
|
362
|
+
- `debugInfo()` / `debugTabInfo(tabIdx?)` - Debug URLs and tab metadata
|
|
363
|
+
- `replay(options?)` / `downloadReplay(path?)` - Session recording
|
|
364
|
+
- `getScript(options?)` - Python code reproducing the session
|
|
365
|
+
- `viewer()` - Open the live session viewer in the local default browser
|
|
366
|
+
- `storage` - The `RemoteFileStorage` attached with the `storage` option
|
|
367
|
+
- `client.sessions.list(options?)` - List sessions
|
|
140
368
|
|
|
141
369
|
### Agent
|
|
142
370
|
|
|
@@ -153,25 +381,25 @@ await notte.Session().use(async (session) => {
|
|
|
153
381
|
max_steps: 10
|
|
154
382
|
});
|
|
155
383
|
|
|
156
|
-
// Non-blocking: start agent and get ID
|
|
157
|
-
|
|
158
|
-
console.log('Agent started:', agentId);
|
|
384
|
+
// Non-blocking: start agent and get its ID
|
|
385
|
+
await agent.start({ task: "Navigate to Google and search for 'TypeScript'" });
|
|
386
|
+
console.log('Agent started:', agent.agentId);
|
|
159
387
|
|
|
160
388
|
// Check agent status
|
|
161
389
|
const status = await agent.status();
|
|
162
390
|
console.log('Agent status:', status);
|
|
163
391
|
|
|
164
392
|
// Blocking: run agent and wait for completion with live updates
|
|
165
|
-
const response = await agent.run(
|
|
166
|
-
"Find the latest TypeScript documentation",
|
|
167
|
-
(update) => {
|
|
393
|
+
const response = await agent.run({
|
|
394
|
+
task: "Find the latest TypeScript documentation",
|
|
395
|
+
updateHandler: (update) => {
|
|
168
396
|
if (update.type === 'step') {
|
|
169
397
|
console.log(`Step update:`, update.data);
|
|
170
398
|
} else if (update.type === 'completion') {
|
|
171
399
|
console.log(`Completed:`, update.data);
|
|
172
400
|
}
|
|
173
401
|
}
|
|
174
|
-
);
|
|
402
|
+
});
|
|
175
403
|
|
|
176
404
|
console.log('Final result:', response);
|
|
177
405
|
});
|
|
@@ -179,12 +407,15 @@ await notte.Session().use(async (session) => {
|
|
|
179
407
|
|
|
180
408
|
#### Agent Methods
|
|
181
409
|
|
|
182
|
-
- `start(
|
|
183
|
-
- `run(
|
|
410
|
+
- `start(request)` - Start agent with `{ task, url?, ... }` (non-blocking)
|
|
411
|
+
- `run(request)` - Start agent and wait for completion (blocking); pass `updateHandler` for live updates
|
|
184
412
|
- `status()` - Get agent status
|
|
185
413
|
- `stop()` - Stop the agent
|
|
186
|
-
- `
|
|
187
|
-
- `
|
|
414
|
+
- `agentId` - The agent ID (read-only property, available after `start()` / `run()`)
|
|
415
|
+
- `sessionId` - The session ID the agent runs in (read-only property)
|
|
416
|
+
- `hasStarted()` - Whether `start()`/`run()` was called on this instance (local check)
|
|
417
|
+
- `isActive()` - Whether the agent is still active on the server (fetches the status)
|
|
418
|
+
- `isRunning()` - Deprecated alias of `hasStarted()`; it does not contact the API
|
|
188
419
|
|
|
189
420
|
#### Structured answers with Zod
|
|
190
421
|
|
|
@@ -231,15 +462,6 @@ await vault.addCredentials('https://github.com/', {
|
|
|
231
462
|
const strongPassword = vault.generatePassword(20, true); // 20 chars with special chars
|
|
232
463
|
const simplePassword = vault.generatePassword(12, false); // 12 chars, no special chars
|
|
233
464
|
|
|
234
|
-
// Add credit card information
|
|
235
|
-
await vault.setCreditCard({
|
|
236
|
-
card_holder_name: 'John Doe',
|
|
237
|
-
card_number: '4111111111111111',
|
|
238
|
-
card_cvv: '123',
|
|
239
|
-
expiry_month: '12',
|
|
240
|
-
expiry_year: '2025'
|
|
241
|
-
});
|
|
242
|
-
|
|
243
465
|
// Use with agents for automatic credential management
|
|
244
466
|
await notte.Session().use(async (session) => {
|
|
245
467
|
const agent = notte.Agent({
|
|
@@ -259,22 +481,21 @@ const credentials = await existingVault.listCredentials();
|
|
|
259
481
|
|
|
260
482
|
// Cleanup
|
|
261
483
|
await vault.deleteCredentials('https://github.com/');
|
|
262
|
-
await vault.deleteCreditCard();
|
|
263
484
|
await vault.stop(); // Deletes entire vault
|
|
264
485
|
```
|
|
265
486
|
|
|
266
487
|
#### Vault Methods
|
|
267
488
|
|
|
268
|
-
- `addCredentials(url, credentials)` - Store credentials for a URL
|
|
269
|
-
- `
|
|
489
|
+
- `addCredentials(url, credentials)` - Store credentials for a URL (validated client-side like Python: root domain, exactly one of `email`/`username`, base32 `mfa_secret`)
|
|
490
|
+
- `addCredentialsFromEnv(url)` - Read `{DOMAIN}_EMAIL` / `{DOMAIN}_USERNAME` / `{DOMAIN}_PASSWORD` / `{DOMAIN}_MFA_SECRET` from the environment
|
|
491
|
+
- `getCredentials(url)` - Retrieve credentials for a URL; throws `NotteAPIError` when none exist
|
|
492
|
+
- `hasCredential(url)` - Whether credentials exist for a URL
|
|
270
493
|
- `deleteCredentials(url)` - Delete credentials for a URL
|
|
271
494
|
- `listCredentials()` - List all stored credentials
|
|
272
|
-
- `setCreditCard(card)` - Store credit card information
|
|
273
|
-
- `getCreditCard()` - Retrieve credit card information
|
|
274
|
-
- `deleteCreditCard()` - Delete credit card information
|
|
275
495
|
- `generatePassword(length?, includeSpecialChars?)` - Generate secure passwords
|
|
276
496
|
- `delete()` - Delete the entire vault
|
|
277
497
|
- `stop()` - Stop and delete the vault
|
|
498
|
+
- `client.vaults.list(options?)` - List vaults
|
|
278
499
|
|
|
279
500
|
#### Security Features
|
|
280
501
|
|
|
@@ -292,15 +513,12 @@ import { NotteClient } from 'notte-sdk';
|
|
|
292
513
|
|
|
293
514
|
const notte = new NotteClient();
|
|
294
515
|
|
|
295
|
-
// Create a new persona with vault
|
|
296
|
-
const persona = notte.Persona({
|
|
297
|
-
create_vault: true,
|
|
298
|
-
create_phone_number: true
|
|
299
|
-
});
|
|
516
|
+
// Create a new persona with a vault
|
|
517
|
+
const persona = notte.Persona({ create_vault: true });
|
|
300
518
|
|
|
301
|
-
// Get persona information
|
|
302
|
-
|
|
303
|
-
console.log(`
|
|
519
|
+
// Get persona information (the first call initializes the persona)
|
|
520
|
+
const info = await persona.get();
|
|
521
|
+
console.log(`Email: ${info.email}`);
|
|
304
522
|
|
|
305
523
|
// Read emails sent to the persona
|
|
306
524
|
const emails = await persona.emails({
|
|
@@ -323,9 +541,9 @@ await notte.Session().use(async (session) => {
|
|
|
323
541
|
vault_id: persona.vault.vaultId // Agent will use persona's vault
|
|
324
542
|
});
|
|
325
543
|
|
|
326
|
-
const result = await agent.run(
|
|
327
|
-
`Create an account on GitHub using the persona credentials`
|
|
328
|
-
);
|
|
544
|
+
const result = await agent.run({
|
|
545
|
+
task: `Create an account on GitHub using the persona credentials`
|
|
546
|
+
});
|
|
329
547
|
console.log(`Account created: ${result.success}`);
|
|
330
548
|
});
|
|
331
549
|
|
|
@@ -345,10 +563,9 @@ await persona.stop(); // Deletes persona and all associated data
|
|
|
345
563
|
|
|
346
564
|
#### Persona Methods
|
|
347
565
|
|
|
566
|
+
- `get()` - Fetch (and initialize) the persona information
|
|
348
567
|
- `emails(options?)` - Read emails sent to the persona
|
|
349
568
|
- `sms(options?)` - Read SMS messages sent to the persona
|
|
350
|
-
- `createNumber(options?)` - Create a phone number for the persona
|
|
351
|
-
- `deleteNumber()` - Delete the persona's phone number
|
|
352
569
|
- `addCredentials(url)` - Add auto-generated credentials to the persona's vault
|
|
353
570
|
- `delete()` - Delete the persona
|
|
354
571
|
- `stop()` - Stop and delete the persona
|
|
@@ -368,7 +585,7 @@ const sms = await persona.sms(options);
|
|
|
368
585
|
|
|
369
586
|
#### Persona Features
|
|
370
587
|
|
|
371
|
-
- **Complete Digital Identity** - Unique email address
|
|
588
|
+
- **Complete Digital Identity** - Unique email address
|
|
372
589
|
- **2FA Support** - Receive and read SMS verification codes automatically
|
|
373
590
|
- **Automated Account Creation** - Seamless integration with agents for signup flows
|
|
374
591
|
- **Vault Integration** - Optional secure credential storage
|
|
@@ -390,16 +607,17 @@ const fn = notte.NotteFunction({
|
|
|
390
607
|
decryption_key: 'optional-decryption-key' // optional, for encrypted outputs
|
|
391
608
|
});
|
|
392
609
|
|
|
393
|
-
//
|
|
610
|
+
// Stream logs to console.log and wait for the final result (default)
|
|
394
611
|
const result = await fn.run({
|
|
395
612
|
url: 'https://example.com',
|
|
396
613
|
query: 'extract pricing information'
|
|
397
614
|
});
|
|
398
615
|
|
|
399
616
|
console.log('Run ID:', result.function_run_id);
|
|
617
|
+
console.log('Result:', result.result);
|
|
400
618
|
|
|
401
619
|
// Retrieve the run result / metadata later
|
|
402
|
-
const metadata = await fn.
|
|
620
|
+
const metadata = await fn.getRun(result.function_run_id);
|
|
403
621
|
console.log('Status:', metadata.status); // 'active' | 'closed' | 'failed'
|
|
404
622
|
console.log('Result:', metadata);
|
|
405
623
|
```
|
|
@@ -424,28 +642,60 @@ fail explicitly if that runtime is unavailable or at capacity; they do not fall
|
|
|
424
642
|
back to Lambda. Browser sessions keep their own duration limits. Existing
|
|
425
643
|
schedules continue to use the standard runtime during the pilot.
|
|
426
644
|
|
|
427
|
-
####
|
|
645
|
+
#### Create a run before execution
|
|
428
646
|
|
|
429
|
-
|
|
647
|
+
`createRun()` is optional: use it when you need a run ID before execution starts.
|
|
648
|
+
It only creates the cloud run record. Pass the returned ID as `functionRunId` to
|
|
649
|
+
execute that record; omitting `functionRunId` makes `run()` create a new run.
|
|
430
650
|
|
|
431
651
|
```typescript
|
|
432
652
|
const fn = notte.NotteFunction({ function_id: 'your-function-id' });
|
|
433
|
-
const { function_run_id } = await fn.
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
653
|
+
const { function_run_id } = await fn.createRun();
|
|
654
|
+
console.log('Run ID before execution:', function_run_id);
|
|
655
|
+
|
|
656
|
+
const pending = fn.run(
|
|
657
|
+
{ url: 'https://example.com' },
|
|
658
|
+
{ functionRunId: function_run_id },
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
// Do other work here, then wait for completion.
|
|
662
|
+
const result = await pending;
|
|
663
|
+
console.log(result.result);
|
|
664
|
+
|
|
665
|
+
const metadata = await fn.getRun(function_run_id);
|
|
666
|
+
console.log(metadata.status);
|
|
447
667
|
```
|
|
448
668
|
|
|
669
|
+
`getRun()` fetches the current status and stored result without waiting for execution
|
|
670
|
+
to finish. `retrieve()` remains a compatible alias. Execution results contain the
|
|
671
|
+
function's structured output; the stored `metadata.result` is serialized JSON.
|
|
672
|
+
|
|
673
|
+
Keeping the promise lets your JavaScript continue while the HTTP request remains
|
|
674
|
+
open. Keep the process running until it completes. This is not a detached job.
|
|
675
|
+
With `{ stream: false }`, the SDK returns JSON without live logs, but standard
|
|
676
|
+
execution still waits for completion.
|
|
677
|
+
|
|
678
|
+
#### Streaming options and migration
|
|
679
|
+
|
|
680
|
+
**Breaking change:** `run()` now defaults to `stream: true`, matching the Python SDK.
|
|
681
|
+
It consumes the event stream, prints logs as they arrive, and resolves with the
|
|
682
|
+
final response, including `status` and `result`. Existing callers that require a
|
|
683
|
+
JSON response without live logs must add `{ stream: false }` as the second argument.
|
|
684
|
+
|
|
685
|
+
Failed executions throw by default. Set `raiseOnFailure: false` to inspect the
|
|
686
|
+
failed response yourself. Transport and malformed-stream errors still throw.
|
|
687
|
+
Use `onLog` to route logs to your application (or `onLog: () => {}` to silence them):
|
|
688
|
+
|
|
689
|
+
```typescript
|
|
690
|
+
const result = await fn.run({ url: 'https://example.com' }, {
|
|
691
|
+
onLog: message => console.log('[function]', message),
|
|
692
|
+
raiseOnFailure: false,
|
|
693
|
+
});
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
Options belong in the second argument; a `stream` field in the first argument
|
|
697
|
+
is a script input and does not change streaming behavior.
|
|
698
|
+
|
|
449
699
|
#### Downloading the function code
|
|
450
700
|
|
|
451
701
|
```typescript
|
|
@@ -472,24 +722,153 @@ const fn = notte.NotteFunction({
|
|
|
472
722
|
const code = await fn.download();
|
|
473
723
|
```
|
|
474
724
|
|
|
725
|
+
#### Creating and managing functions
|
|
726
|
+
|
|
727
|
+
Upload a Python script to create a function, like `NotteFunction(path=...)` in Python.
|
|
728
|
+
Creation is lazy: the upload happens on the first call that needs the function id.
|
|
729
|
+
|
|
730
|
+
```typescript
|
|
731
|
+
const fn = notte.NotteFunction({ path: './my_function.py', name: 'price-monitor', description: 'Checks prices' });
|
|
732
|
+
|
|
733
|
+
const details = await fn.get(); // metadata, versions and download link
|
|
734
|
+
await fn.update({ path: './my_function_v2.py' }); // upload a new version
|
|
735
|
+
await fn.updateMetadata({ name: 'price-monitor-v2' });
|
|
736
|
+
await fn.rollback({ version: details.latest_version });
|
|
737
|
+
|
|
738
|
+
await fn.setSchedule({ cron: '0 9 * * *', variables: { url: 'https://example.com' } });
|
|
739
|
+
await fn.deleteSchedule();
|
|
740
|
+
|
|
741
|
+
const runs = await fn.runs(); // all runs, including completed ones
|
|
742
|
+
const functions = await notte.functions.list();
|
|
743
|
+
|
|
744
|
+
await fn.delete();
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
`run()` waits at most 300 s by default; pass `timeoutMs` to change it. A failed
|
|
748
|
+
run throws `FailedToRunCloudFunctionError` unless `raiseOnFailure: false`.
|
|
749
|
+
|
|
475
750
|
#### Function Methods
|
|
476
751
|
|
|
477
|
-
- `run(variables?)` -
|
|
478
|
-
- `
|
|
752
|
+
- `run(variables?, options?)` - Stream logs and wait for completion; use `stream: false` for the backend's JSON response without live logs. Options: `runtime`, `functionRunId`, `onLog`, `raiseOnFailure`, `timeoutMs`
|
|
753
|
+
- `get(options?)` - Function metadata, versions and download link
|
|
754
|
+
- `update(options)` / `updateMetadata(body)` - Upload a new version / change name, description
|
|
755
|
+
- `delete()` - Delete the function
|
|
756
|
+
- `setSchedule(body)` / `deleteSchedule()` - Manage the cron schedule
|
|
757
|
+
- `rollback(options)` - Roll back to a previous version
|
|
758
|
+
- `runs(options?)` - List runs (all runs by default, `only_active: true` for active ones)
|
|
759
|
+
- `createRun()` - Create a cloud run record without executing it
|
|
760
|
+
- `getRun(functionRunId)` - Get current metadata/result for a specific run
|
|
761
|
+
- `retrieve(functionRunId)` - Compatibility alias for `getRun()`
|
|
479
762
|
- `download(options?)` - Download the function code, optionally writing it to `options.path`
|
|
480
763
|
- `getUrl(options?)` - Get the (decrypted) download url of the function code
|
|
481
764
|
- `getFunctionId()` - Get the function ID
|
|
482
765
|
- `functionId` - The function ID (read-only property)
|
|
483
766
|
- `decryptionKey` - The decryption key, if provided (read-only property)
|
|
484
767
|
|
|
768
|
+
### File Storage
|
|
769
|
+
|
|
770
|
+
Upload files for a session to use and download files the session produced,
|
|
771
|
+
the counterpart of `client.FileStorage()` in Python.
|
|
772
|
+
|
|
773
|
+
```typescript
|
|
774
|
+
import { NotteClient, FileExistsError } from 'notte-sdk';
|
|
775
|
+
|
|
776
|
+
const notte = new NotteClient();
|
|
777
|
+
const storage = notte.FileStorage();
|
|
778
|
+
let sessionId = '';
|
|
779
|
+
let fileId = '';
|
|
780
|
+
|
|
781
|
+
await notte.Session({ storage }).use(async (session) => {
|
|
782
|
+
sessionId = session.getId()!;
|
|
783
|
+
|
|
784
|
+
// Upload from a path, a Blob or a Uint8Array
|
|
785
|
+
const uploaded = await storage.upload('./invoice.pdf');
|
|
786
|
+
fileId = uploaded.id;
|
|
787
|
+
|
|
788
|
+
// ... let the session / an agent download something ...
|
|
789
|
+
|
|
790
|
+
const downloads = await storage.list({ source: 'session_download' });
|
|
791
|
+
for (const file of downloads.files) {
|
|
792
|
+
const path = await storage.download(file.id, './downloads');
|
|
793
|
+
console.log('saved', path);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const info = await storage.metadata(uploaded.id);
|
|
797
|
+
await storage.delete(uploaded.id);
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// Files of a closed session
|
|
801
|
+
const files = notte.FileStorage(sessionId);
|
|
802
|
+
await files.download(fileId, './downloads', { force: true }); // overwrite instead of FileExistsError
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
`notte.Files(sessionId)` exposes the same operations returning `Blob`s instead of writing to disk.
|
|
806
|
+
|
|
807
|
+
### Web Search
|
|
808
|
+
|
|
809
|
+
Search the public web with `POST /search`. The default `outputType` returns
|
|
810
|
+
ranked results; `sourcedAnswer` returns a written answer with its sources.
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
const { results } = await notte.search('notte browser automation', { depth: 'fast' });
|
|
814
|
+
results.forEach(item => console.log(item.name, item.url));
|
|
815
|
+
|
|
816
|
+
const { answer, sources } = await notte.search('what is notte?', { outputType: 'sourcedAnswer' });
|
|
817
|
+
console.log(answer, sources.map(s => s.url));
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
Extra fields such as `maxResults` or `includeDomains` are forwarded to the search
|
|
821
|
+
provider. `SearchOptions` and the `SearchResultsResponse` /
|
|
822
|
+
`SearchSourcedAnswerResponse` shapes are exported.
|
|
823
|
+
|
|
824
|
+
### Anything API
|
|
825
|
+
|
|
826
|
+
`notte.anything.start({ task })` (`POST /anything/start`) turns a plain-English
|
|
827
|
+
description of a web task into a deployed, reusable function. Building is slow and
|
|
828
|
+
billable; prefer `notte.functions.list()` when a ready-made function already fits.
|
|
829
|
+
The API response is not typed by the OpenAPI spec and is exposed as an opaque
|
|
830
|
+
`AnythingStartResponse` record (it references the built function, e.g. `function_id`).
|
|
831
|
+
|
|
832
|
+
```typescript
|
|
833
|
+
const started = await notte.anything.start({ task: 'fetch the top 3 hacker news posts' });
|
|
834
|
+
console.log(started);
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Secrets
|
|
838
|
+
|
|
839
|
+
Workspace secrets (`/secrets`) are scoped by namespace: `llm_provider` keys are
|
|
840
|
+
used by agents and scraping, `function_env` values are injected into function runs.
|
|
841
|
+
Listing never returns values, only metadata with a `key_hint`.
|
|
842
|
+
|
|
843
|
+
```typescript
|
|
844
|
+
const meta = await notte.secrets.store({ namespace: 'function_env', name: 'API_TOKEN', value: 'xyz' });
|
|
845
|
+
const { value } = await notte.secrets.get('API_TOKEN', 'function_env');
|
|
846
|
+
const secrets = await notte.secrets.list({ namespace: 'function_env' });
|
|
847
|
+
await notte.secrets.delete(meta.id);
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
### Usage
|
|
851
|
+
|
|
852
|
+
Read billing usage for the current (or a given) monthly period, and page through
|
|
853
|
+
per-request usage logs.
|
|
854
|
+
|
|
855
|
+
```typescript
|
|
856
|
+
const usage = await notte.usage.get();
|
|
857
|
+
console.log(`${usage.session_count} sessions, $${usage.total_cost} this period`);
|
|
858
|
+
|
|
859
|
+
const page = await notte.usage.logs({ endpoint: 'sessions.start', page: 1, page_size: 50 });
|
|
860
|
+
page.items.forEach(log => console.log(log.created_at, log.endpoint, log.duration_ms));
|
|
861
|
+
```
|
|
862
|
+
|
|
485
863
|
## Advanced Usage
|
|
486
864
|
|
|
487
865
|
### Session Configuration
|
|
488
866
|
|
|
489
867
|
```typescript
|
|
490
868
|
const session = notte.Session({
|
|
491
|
-
|
|
492
|
-
//
|
|
869
|
+
idle_timeout_minutes: 5, // Close the session after this much inactivity
|
|
870
|
+
max_duration_minutes: 45, // Hard limit on the session lifetime
|
|
871
|
+
// Add other session options as supported by the API (SessionOptions)
|
|
493
872
|
});
|
|
494
873
|
```
|
|
495
874
|
|
|
@@ -504,36 +883,87 @@ const agent = notte.Agent({
|
|
|
504
883
|
|
|
505
884
|
### Error Handling
|
|
506
885
|
|
|
886
|
+
Every error thrown by the SDK extends `NotteError`, mirroring `notte_sdk.errors`
|
|
887
|
+
in Python. Generated API calls reject with a `NotteAPIError` carrying the request
|
|
888
|
+
`path`, the HTTP `statusCode` and the parsed response body in `error`; the API can
|
|
889
|
+
flag failures as `NotteAPIExecutionError`. Client-side problems use dedicated
|
|
890
|
+
classes: `AuthenticationError` (missing key), `InvalidRequestError`,
|
|
891
|
+
`NotteTimeoutError` (request or wait deadline exceeded),
|
|
892
|
+
`FailedToRunCloudFunctionError`, `ScrapeFailedError` and `ActionExecutionError`.
|
|
893
|
+
|
|
507
894
|
```typescript
|
|
895
|
+
import { NotteAPIError, NotteError, NotteTimeoutError } from 'notte-sdk';
|
|
896
|
+
|
|
508
897
|
try {
|
|
509
898
|
await notte.Session().use(async (session) => {
|
|
510
899
|
const agent = notte.Agent({ session });
|
|
511
|
-
const response = await agent.run("Complete a complex task");
|
|
900
|
+
const response = await agent.run({ task: "Complete a complex task" });
|
|
512
901
|
|
|
513
902
|
if (!response.success) {
|
|
514
|
-
console.error('Agent failed:', response.
|
|
903
|
+
console.error('Agent failed:', response.answer);
|
|
515
904
|
}
|
|
516
905
|
});
|
|
517
906
|
} catch (error) {
|
|
518
|
-
|
|
907
|
+
if (error instanceof NotteAPIError) {
|
|
908
|
+
console.error(`API ${error.statusCode} on ${error.path}:`, error.apiMessage ?? error.error);
|
|
909
|
+
} else if (error instanceof NotteTimeoutError) {
|
|
910
|
+
console.error('Timed out:', error.message);
|
|
911
|
+
} else if (error instanceof NotteError) {
|
|
912
|
+
console.error('SDK error:', error.message);
|
|
913
|
+
} else {
|
|
914
|
+
throw error;
|
|
915
|
+
}
|
|
519
916
|
}
|
|
520
917
|
```
|
|
521
918
|
|
|
919
|
+
### Timeouts and retries
|
|
920
|
+
|
|
921
|
+
CAPTCHA solving has a separate `captchaTimeoutSeconds` budget (default 180).
|
|
922
|
+
`session.execute()` polls pending solves using requests of at most 10 seconds,
|
|
923
|
+
then resumes an ordinary action only when the backend confirms it did not execute.
|
|
924
|
+
Actions that already ran are never replayed. Navigation, closure, provider failure,
|
|
925
|
+
and deadline expiry preserve the normal `raiseOnFailure` behavior. Ordinary HTTP
|
|
926
|
+
transport failures are not automatically retried. Deploy backend CAPTCHA polling
|
|
927
|
+
support before upgrading the SDK.
|
|
928
|
+
|
|
929
|
+
The client applies a per-request timeout (`timeoutMs`, default 60 000 ms; `0`
|
|
930
|
+
disables it) through response-body consumption and rejects with `NotteTimeoutError`
|
|
931
|
+
when it elapses. Explicit streams use the caller's signal for body cancellation;
|
|
932
|
+
function runs supply their own execution deadline. `retry()` wraps an async function so it is re-attempted on failure, like the Python
|
|
933
|
+
`@retry` decorator:
|
|
934
|
+
|
|
935
|
+
```typescript
|
|
936
|
+
import { NotteClient, retry } from 'notte-sdk';
|
|
937
|
+
|
|
938
|
+
const notte = new NotteClient({ timeoutMs: 30_000 });
|
|
939
|
+
|
|
940
|
+
const start = retry(() => notte.Session().start(), {
|
|
941
|
+
maxTries: 3,
|
|
942
|
+
delayMs: 1_000,
|
|
943
|
+
shouldRetry: error => error instanceof NotteTimeoutError,
|
|
944
|
+
});
|
|
945
|
+
await start();
|
|
946
|
+
```
|
|
947
|
+
|
|
522
948
|
### WebSocket Updates
|
|
523
949
|
|
|
524
|
-
The `agent.run()` method provides real-time updates via WebSocket
|
|
950
|
+
The `agent.run()` method provides real-time updates via WebSocket through the
|
|
951
|
+
`updateHandler` option:
|
|
525
952
|
|
|
526
953
|
```typescript
|
|
527
|
-
const response = await agent.run(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
954
|
+
const response = await agent.run({
|
|
955
|
+
task: "Your task",
|
|
956
|
+
updateHandler: (update) => {
|
|
957
|
+
switch (update.type) {
|
|
958
|
+
case 'step':
|
|
959
|
+
console.log('Step:', update.data);
|
|
960
|
+
break;
|
|
961
|
+
case 'completion':
|
|
962
|
+
console.log('Task completed:', update.data);
|
|
963
|
+
break;
|
|
964
|
+
default:
|
|
965
|
+
console.log('Update:', update);
|
|
966
|
+
}
|
|
537
967
|
}
|
|
538
968
|
});
|
|
539
969
|
```
|
|
@@ -571,7 +1001,7 @@ from notte_sdk import NotteClient
|
|
|
571
1001
|
notte = NotteClient()
|
|
572
1002
|
|
|
573
1003
|
# Session context manager
|
|
574
|
-
with notte.Session(
|
|
1004
|
+
with notte.Session(idle_timeout_minutes=2) as session:
|
|
575
1005
|
status = session.status()
|
|
576
1006
|
print(status)
|
|
577
1007
|
|
|
@@ -589,7 +1019,7 @@ import { NotteClient } from 'notte-sdk';
|
|
|
589
1019
|
const notte = new NotteClient();
|
|
590
1020
|
|
|
591
1021
|
// Session context manager equivalent
|
|
592
|
-
await notte.Session({
|
|
1022
|
+
await notte.Session({ idle_timeout_minutes: 2 }).use(async (session) => {
|
|
593
1023
|
const status = await session.status();
|
|
594
1024
|
console.log(status);
|
|
595
1025
|
});
|
|
@@ -597,7 +1027,7 @@ await notte.Session({ timeoutMinutes: 2 }).use(async (session) => {
|
|
|
597
1027
|
// Agent usage
|
|
598
1028
|
await notte.Session().use(async (session) => {
|
|
599
1029
|
const agent = notte.Agent({ session, max_steps: 10 });
|
|
600
|
-
const response = await agent.run("Find the best italian restaurant in SF");
|
|
1030
|
+
const response = await agent.run({ task: "Find the best italian restaurant in SF" });
|
|
601
1031
|
console.log(`Agent completed: ${response.success}, answer: ${response.answer}`);
|
|
602
1032
|
});
|
|
603
1033
|
```
|
|
@@ -635,7 +1065,7 @@ npm test
|
|
|
635
1065
|
npm run test -- --coverage
|
|
636
1066
|
|
|
637
1067
|
# Run specific test file
|
|
638
|
-
npm run test
|
|
1068
|
+
npm run test test/client.test.ts
|
|
639
1069
|
```
|
|
640
1070
|
|
|
641
1071
|
### Regenerating from API
|
|
@@ -654,15 +1084,15 @@ This will fetch the latest API specification and update the generated client cod
|
|
|
654
1084
|
The SDK is built with full TypeScript support:
|
|
655
1085
|
|
|
656
1086
|
```typescript
|
|
657
|
-
import { NotteClient,
|
|
1087
|
+
import { NotteClient, type SessionResponse, type LegacyAgentStatusResponse } from 'notte-sdk';
|
|
658
1088
|
|
|
659
1089
|
const notte = new NotteClient();
|
|
660
1090
|
|
|
661
1091
|
// All types are properly inferred
|
|
662
1092
|
await notte.Session().use(async (session) => {
|
|
663
|
-
const status:
|
|
1093
|
+
const status: SessionResponse = await session.status();
|
|
664
1094
|
const agent = notte.Agent({ session });
|
|
665
|
-
const response:
|
|
1095
|
+
const response: LegacyAgentStatusResponse = await agent.run({ task: "task" });
|
|
666
1096
|
});
|
|
667
1097
|
```
|
|
668
1098
|
|
|
@@ -670,24 +1100,35 @@ await notte.Session().use(async (session) => {
|
|
|
670
1100
|
|
|
671
1101
|
### Types
|
|
672
1102
|
|
|
673
|
-
The SDK exports all generated types from the OpenAPI specification
|
|
1103
|
+
The SDK exports all generated types from the OpenAPI specification alongside the
|
|
1104
|
+
hand-written option types:
|
|
674
1105
|
|
|
675
1106
|
```typescript
|
|
676
1107
|
import type {
|
|
677
1108
|
NotteClientConfig,
|
|
678
1109
|
SessionOptions,
|
|
679
|
-
|
|
1110
|
+
SessionResponse,
|
|
1111
|
+
SessionListOptions,
|
|
680
1112
|
AgentConstructor,
|
|
681
1113
|
AgentRunRequest,
|
|
682
1114
|
AgentUpdateHandler,
|
|
1115
|
+
AgentListOptions,
|
|
683
1116
|
VaultConstructor,
|
|
684
|
-
|
|
685
|
-
|
|
1117
|
+
VaultListOptions,
|
|
1118
|
+
CredentialsDictInput,
|
|
686
1119
|
Credential,
|
|
687
1120
|
PersonaConstructor,
|
|
688
1121
|
MessageReadOptions,
|
|
689
1122
|
PersonaListOptions,
|
|
690
|
-
|
|
1123
|
+
FunctionConstructor,
|
|
1124
|
+
FunctionListOptions,
|
|
1125
|
+
RetryOptions,
|
|
1126
|
+
NotteAPIErrorBody,
|
|
1127
|
+
SearchOptions,
|
|
1128
|
+
SearchResultsResponse,
|
|
1129
|
+
AnythingStartResponse,
|
|
1130
|
+
SecretMetadata,
|
|
1131
|
+
UsageResponse,
|
|
691
1132
|
} from 'notte-sdk';
|
|
692
1133
|
```
|
|
693
1134
|
|
|
@@ -698,6 +1139,57 @@ MIT
|
|
|
698
1139
|
## Support
|
|
699
1140
|
|
|
700
1141
|
For issues and questions:
|
|
701
|
-
- GitHub Issues: [Report issues](https://github.com/notte/
|
|
1142
|
+
- GitHub Issues: [Report issues](https://github.com/nottelabs/notte/issues)
|
|
702
1143
|
- Documentation: [docs.notte.cc](https://docs.notte.cc)
|
|
703
1144
|
- Python SDK: [notte-sdk](https://pypi.org/project/notte-sdk/)
|
|
1145
|
+
|
|
1146
|
+
## Managed authentication
|
|
1147
|
+
|
|
1148
|
+
Use existing connection IDs with a session. `start()` waits for authentication by
|
|
1149
|
+
default, and `.use()` always invokes its callback only after the session is ready:
|
|
1150
|
+
|
|
1151
|
+
```typescript
|
|
1152
|
+
const session = client.Session({ auth_ids: ["<connection-id>"], auth_retry: 2 });
|
|
1153
|
+
await session.use(async (ready) => {
|
|
1154
|
+
await ready.execute({ type: "goto", url: "https://example.com" });
|
|
1155
|
+
});
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
For a nonblocking start, wait explicitly before browser actions or CDP access:
|
|
1159
|
+
|
|
1160
|
+
```typescript
|
|
1161
|
+
const abortController = new AbortController();
|
|
1162
|
+
const session = client.Session({ auth_ids: ["<connection-id>"] });
|
|
1163
|
+
await session.start({ wait_for_authentication: false });
|
|
1164
|
+
try {
|
|
1165
|
+
await session.waitForAuth({ timeoutMs: 615_000, signal: abortController.signal });
|
|
1166
|
+
await session.execute({ type: "goto", url: "https://example.com" });
|
|
1167
|
+
} finally {
|
|
1168
|
+
await session.stop();
|
|
1169
|
+
}
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
Waiting polls session readiness through short requests. It never restarts the
|
|
1173
|
+
session or submits another login. `auth_retry` controls server-side login retries
|
|
1174
|
+
(0 to 2) and is omitted from requests without `auth_ids`. A failed or cancelled
|
|
1175
|
+
startup wait closes the created session. A standalone `waitForAuth()` leaves
|
|
1176
|
+
cleanup to the caller.
|
|
1177
|
+
|
|
1178
|
+
Connection operations are available through `client.managedAuth`:
|
|
1179
|
+
|
|
1180
|
+
```typescript
|
|
1181
|
+
const check = await client.managedAuth.checkConnection("<connection-id>");
|
|
1182
|
+
// checkConnection only verifies; refreshConnection can log in if needed.
|
|
1183
|
+
const operation = await client.managedAuth.refreshConnection("<connection-id>", {
|
|
1184
|
+
wait: false,
|
|
1185
|
+
auth_retry: 2,
|
|
1186
|
+
});
|
|
1187
|
+
const completed = await client.managedAuth.waitForAuth(operation);
|
|
1188
|
+
// To explicitly request a new login:
|
|
1189
|
+
await client.managedAuth.reauthenticateConnection("<connection-id>");
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
Refresh and reauthentication wait by default. Use `getOperation(operation.id)`
|
|
1193
|
+
for individual status reads. Cancelling an operation wait does not cancel the
|
|
1194
|
+
server operation. An HTTP 409 remains an ownership conflict and is not retried.
|
|
1195
|
+
These helpers require a backend with the managed-auth lifecycle endpoints.
|