@cerebro-labs/agentnava-sdk 0.26.0 → 0.44.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.
Files changed (62) hide show
  1. package/README.md +204 -23
  2. package/account.d.ts +154 -0
  3. package/account.js +219 -0
  4. package/account.js.map +1 -0
  5. package/agent.d.ts +217 -88
  6. package/agent.js +295 -125
  7. package/agent.js.map +1 -1
  8. package/apps.generated.d.ts +154 -0
  9. package/apps.generated.js +152 -0
  10. package/apps.generated.js.map +1 -0
  11. package/attach.d.ts +25 -26
  12. package/attach.js +53 -66
  13. package/attach.js.map +1 -1
  14. package/connection.d.ts +79 -82
  15. package/connection.js +67 -134
  16. package/connection.js.map +1 -1
  17. package/conversation.d.ts +55 -35
  18. package/conversation.js +70 -50
  19. package/conversation.js.map +1 -1
  20. package/database.d.ts +53 -0
  21. package/database.js +69 -0
  22. package/database.js.map +1 -0
  23. package/end-user.d.ts +58 -47
  24. package/end-user.js +62 -72
  25. package/end-user.js.map +1 -1
  26. package/errors.d.ts +2 -1
  27. package/errors.js +2 -1
  28. package/errors.js.map +1 -1
  29. package/http.d.ts +5 -0
  30. package/http.js +109 -8
  31. package/http.js.map +1 -1
  32. package/import-tools.d.ts +48 -33
  33. package/import-tools.js +281 -127
  34. package/import-tools.js.map +1 -1
  35. package/index.d.ts +5 -2
  36. package/index.js +9 -2
  37. package/index.js.map +1 -1
  38. package/load-agent-dir.js +28 -5
  39. package/load-agent-dir.js.map +1 -1
  40. package/package.json +5 -1
  41. package/secret.d.ts +1 -1
  42. package/secret.js +1 -1
  43. package/secret.js.map +1 -1
  44. package/templates-inline.js +1 -1
  45. package/templates-inline.js.map +1 -1
  46. package/turn.d.ts +1 -1
  47. package/turn.js +77 -29
  48. package/turn.js.map +1 -1
  49. package/types.d.ts +409 -83
  50. package/types.js.map +1 -1
  51. package/version.d.ts +1 -1
  52. package/version.js +1 -1
  53. package/version.js.map +1 -1
  54. package/workflows.d.ts +10 -0
  55. package/workflows.js +16 -0
  56. package/workflows.js.map +1 -1
  57. package/workspace.d.ts +80 -62
  58. package/workspace.js +92 -75
  59. package/workspace.js.map +1 -1
  60. package/connection-status.d.ts +0 -28
  61. package/connection-status.js +0 -61
  62. package/connection-status.js.map +0 -1
package/README.md CHANGED
@@ -19,7 +19,7 @@ const agent = await ws.agents.create({
19
19
  instructions: 'Decide whether a late delivery qualifies for a refund.',
20
20
  });
21
21
 
22
- const conversation = await agent.start();
22
+ const conversation = await agent.start({ endUserId: 'u_ananya' });
23
23
  console.log(await conversation.ask('Order 4471 arrived nine days late.'));
24
24
  ```
25
25
 
@@ -30,30 +30,112 @@ only the things that are easy to get wrong.
30
30
 
31
31
  ## Connecting an account, end to end
32
32
 
33
- `authorize()` gives you a URL for your user to visit. `waitUntilReady()` tells
34
- you when they are done, so you do not have to write a polling loop or work out
35
- which field to believe.
33
+ An **account** is one saved sign-in to one app. A **connection** is an entry in
34
+ an agent's setup that names one, so the agent uses exactly that account and never
35
+ another. `ws.accounts.connect()` gives you a URL for a person to visit, and
36
+ `waitUntilConnected()` tells you when they are done.
36
37
 
37
38
  ```ts
38
- const { url } = await conversation.authorize('gmail');
39
+ import { App, Connection } from '@cerebro-labs/agentnava-sdk';
40
+
41
+ const { account, url } = await ws.accounts.connect({ app: App.GMAIL, nickname: 'Support inbox' });
39
42
  showToUser(url); // popup, redirect, QR code, your choice
40
- await conversation.waitUntilReady(); // resolves once nothing required is outstanding
43
+ await account.waitUntilConnected(); // resolves once they have signed in
44
+ await agent.connections.add(Connection.creatorAccount(App.GMAIL, account));
41
45
  ```
42
46
 
43
47
  How you show the URL is yours: this SDK authenticates with an API key, so it
44
48
  runs on your server, and the browser half is your application's.
45
49
 
46
- An OPTIONAL requirement does not hold the wait up, for the same reason it does
47
- not make `ready` false: the conversation genuinely works without it.
50
+ On timeout it throws `account_not_connected` and the message names the account
51
+ and where it stands. It is safe to call again; someone who has not finished
52
+ signing in may just need longer. After `account.reconnect()` it waits for the
53
+ new sign-in too: the account keeps working meanwhile, with `reconnecting` true.
48
54
 
49
- On timeout it throws `conversation_not_ready` and the message names what is
50
- still missing, e.g. `still waiting on: connection gmail`. It is safe to call
51
- again; someone who has not finished signing in may just need longer.
55
+ For an app each of YOUR users signs in to themselves, the connection uses the
56
+ end user's account. Each person signs in once, it is remembered for them, and
57
+ nothing is attached per conversation:
52
58
 
53
59
  ```ts
54
- await conversation.waitUntilReady({ timeoutMs: 120_000, intervalMs: 2_000, signal });
60
+ await agent.connections.add(Connection.endUserAccount(App.GOOGLE_CALENDAR));
61
+
62
+ const conversation = await agent.start({ endUserId: user.id });
63
+ for (const { app, url } of await conversation.accountsNeeded()) {
64
+ showToUser(app, url); // the ones this person has not connected yet
65
+ }
55
66
  ```
56
67
 
68
+ An end user's account is an ordinary `Account`: `ws.endUser(id).accounts.connect()`
69
+ returns one, and `waitUntilConnected()`, `ws.account(id)` and every other account
70
+ call work on it the same way. `account.data.owner` says whose it is.
71
+
72
+ The builders make plain objects, `{ app, account: '<id>' }` and
73
+ `{ app, endUser: true }`, and either object written by hand is accepted too.
74
+ `App.GMAIL` is the string `'gmail'`, so a plain string works anywhere a constant
75
+ does, including for an app added after your SDK version.
76
+
77
+ ## 0.44.0 is a breaking change: apps and accounts
78
+
79
+ Two words now mean two things. An **account** is one saved sign-in to one app.
80
+ A **connection** is an entry in an agent's setup: a name, an app, and whose
81
+ account it uses, built with `Connection.creatorAccount(app, account)` for the
82
+ agent creator's account or `Connection.endUserAccount(app)` for each end user's
83
+ own. A turn uses exactly the account the setup names. Nothing is attached to a
84
+ conversation any more, and nothing falls back to some other account of the same
85
+ app.
86
+
87
+ Upgrade together with the production release that serves the new routes:
88
+ 0.44 calls `/v1/accounts`, `/v1/end-users/:id/accounts` and the agent connection
89
+ routes, and the connection routes 0.43 calls are removed in that same release.
90
+ There is no compatibility shim: this package is pre-launch, so the old names
91
+ were removed rather than deprecated.
92
+
93
+ | 0.43 | 0.44 |
94
+ |---|---|
95
+ | `ws.connections.create({ provider })` | `ws.accounts.connect({ app, nickname? })`, returns `{ account, url }` |
96
+ | `ws.connections.create({ provider, agentId })` | `ws.accounts.connect({ app })`, then `agent.connections.add(Connection.creatorAccount(app, account))` |
97
+ | `ws.connections.create({ provider, endUserId })` | `ws.endUser(id).accounts.connect({ app })` |
98
+ | `ws.connections.list()` | `ws.accounts.list({ app? })`, each with `usedBy` |
99
+ | `ws.connections.list({ endUserId })` | `ws.endUser(id).accounts.list()` |
100
+ | `ws.connection(id)` | `ws.account(id)` |
101
+ | `Connection` (class): a signed-in account | `Account` (class). The name `Connection` now builds an entry of an agent's setup |
102
+ | `connection.get()`, returned `ConnectionStatus` | `account.get()`, returns `AccountData`; a missing account throws `account_not_found` |
103
+ | `connection.waitUntilConnected()` | `account.waitUntilConnected()`; times out with `account_not_connected` |
104
+ | `connection.revoke()` | `account.disconnect()`, returns `{ agents }`: the agents that lose it |
105
+ | `connection.provider`, `.connected`, `.owner`, `.endUserId` | `account.app`, `.status`, `.data.owner`, `.data.endUserId` |
106
+ | `connection.url` | the `url` that `connect` returns |
107
+ | none | `account.reconnect()`, `account.rename(nickname)`, `account.check()`, `account.label`, `account.nickname`, `account.usedBy`, `account.data.reconnecting` |
108
+ | `agent.authorize(provider)` | `ws.accounts.connect({ app })`, then `agent.connections.add(Connection.creatorAccount(app, account))` |
109
+ | `agent.attach(connection)` | `agent.connections.add(Connection.creatorAccount(app, account, { name? }))` |
110
+ | none | `agent.connections.add(Connection.endUserAccount(app, { name? }))` |
111
+ | none | `agent.connections.change(name, { account })` or `(name, { endUser: true })` |
112
+ | `agent.disconnect(provider)`, which deleted the shared account | `agent.connections.remove(name)`, which never touches the account |
113
+ | `agent.connections()` | `agent.connections.list()` |
114
+ | `agent.attach(secret)`, which was accepted and did nothing | refused with `not_a_secret`; attach a stored secret to a conversation instead |
115
+ | `agent.start({ attach: connection })` | `agent.start({ endUserId })`: the setup names the accounts |
116
+ | `conversation.authorize(provider)` | `conversation.accountsNeeded()`: the links an end user still has to sign in at |
117
+ | `conversation.attach(connection)` | none: the agent's setup decides |
118
+ | `endUser.connections.create({ provider })` | `endUser.accounts.connect({ app })` |
119
+ | `endUser.connections.list()` | `endUser.accounts.list()` |
120
+ | `endUser.revokeConnections()` | `endUser.accounts.disconnectAll()`, returns `{ disconnected }` |
121
+ | setup `connections: [{ provider, scope: 'fixed', connectionId }]` | `Connection.creatorAccount(app, account, { name? })`, which is `{ name?, app, account: '<id>' }` |
122
+ | setup `connections: [{ provider, scope: 'conversation' }]` | `Connection.endUserAccount(app, { name? })`, which is `{ name?, app, endUser: true }` |
123
+ | type `ConnectionRequirement` | `AgentConnection` (as read back) and `Connection` (as you send it), with `CreatorAccountConnection` and `EndUserAccountConnection` |
124
+ | type `ConnectionStatus`, keyed by `provider` | `ConnectionStatus`, keyed by `name`: `{ name, app, account?, endUser?, status, inDraft, removedInDraft }` |
125
+ | type `CredentialOwner` | removed: `AccountData.owner` is `'workspace'` or `'end-user'` |
126
+ | `Bindings.connections` | removed: `Bindings` carries `secrets` only |
127
+ | none | `App`: every app id as a constant (`App.GMAIL`), and the type `AppId` |
128
+
129
+ New error codes to branch on: `account_not_found`, `connection_name_taken`,
130
+ `account_app_mismatch`, `connection_not_found` (from
131
+ `agent.connections.change`), `account_not_connected` (from
132
+ `waitUntilConnected`), `account_required` (from `Connection.creatorAccount`
133
+ with no account), and `not_a_secret` (an account handed to `attach`).
134
+
135
+ Secrets did not move: `agent.attach({ secrets })`, `conversation.attach(secret)`,
136
+ `conversation.attach({ secrets })` and `agent.start({ attach: secret, secrets })`
137
+ work as before.
138
+
57
139
  ## 0.2.0 is a breaking change. Upgrade from 0.1.1, do not stay on it.
58
140
 
59
141
  "session" is gone from everything you touch. It survives only in our storage,
@@ -77,8 +159,8 @@ moved.
77
159
 
78
160
  ## Holding an object is free
79
161
 
80
- `ws.agent(id)`, `ws.conversation(id)` and `ws.project(id)` make **no network
81
- call**. You get something you can call methods on, and the first request happens
162
+ `ws.agent(id)`, `agent.conversation(id)`, `ws.project(id)` and `ws.account(id)`
163
+ make **no network call**. You get something you can call methods on, and the first request happens
82
164
  when you call one.
83
165
 
84
166
  Store the `id`, not the object. A returned object is a handle, not JSON.
@@ -97,16 +179,58 @@ for await (const e of conversation.ask('...')) { // as it happens
97
179
  ```
98
180
 
99
181
  **The message is sent when you call `ask`**, not when you await or iterate it.
100
- Calling `ask` twice asks twice.
182
+ Calling `ask` twice generates two submission keys and asks twice. If you need
183
+ to identify an explicit retry after a lost response, save a key before sending:
184
+
185
+ ```ts
186
+ const idempotencyKey = crypto.randomUUID();
187
+ const reply = await conversation.ask('...', { idempotencyKey });
188
+ ```
189
+
190
+ Reuse that key only with the same content in the same conversation. The API
191
+ refuses an already accepted turn with `turn_already_accepted` instead of running
192
+ it again. A new intentional question needs a new key. Errors include the
193
+ original key and instructions for checking status; a `retryable: false` error
194
+ must not be retried as a fresh submission.
101
195
 
102
196
  You may await the same turn more than once; it is a promise, and you get the same
103
197
  answer. You may not iterate it twice, or mix the two, because the events are a
104
198
  live stream rather than a stored list and the second consumer would receive
105
199
  nothing at all. That throws instead.
106
200
 
107
- **The turn is not your request.** It runs on our side, so a dropped connection
108
- does not cancel it. Read the answer back with `conversation.messages()` rather
109
- than asking again.
201
+ **The turn is not your request.** Once the server accepts it, a dropped
202
+ connection, aborting `AskOptions.signal`, or leaving a `for await` loop early
203
+ stops receiving the response. Accepted work can continue and normal billing
204
+ applies; disconnecting does not cancel server work or automatically refund the
205
+ turn. An already-aborted signal passed to `ask()` prevents submission, so no
206
+ turn is accepted or charged for that call.
207
+
208
+ Use a signal to limit how long your application waits:
209
+
210
+ ```ts
211
+ const controller = new AbortController();
212
+ const timer = setTimeout(() => controller.abort(), 10_000);
213
+ try {
214
+ const reply = await conversation.ask('Summarize the report.', {
215
+ signal: controller.signal,
216
+ });
217
+ save(reply);
218
+ } catch (error) {
219
+ if (!controller.signal.aborted) throw error;
220
+ // We stopped waiting. A turn already accepted by the server can still run.
221
+ } finally {
222
+ clearTimeout(timer);
223
+ }
224
+ ```
225
+
226
+ After an interruption, read `await conversation.messages()` before another
227
+ `ask()`. The answer may still be in progress, so check history again later
228
+ instead of submitting the same question again.
229
+
230
+ A successful `await` or `done` event requires the server's completion marker.
231
+ If the stream closes early, the SDK reports a nonretryable interruption even
232
+ when reply text already arrived; use the original submission key to check its
233
+ status before starting more work.
110
234
 
111
235
  ## Changing an agent publishes a version
112
236
 
@@ -150,13 +274,22 @@ await conversation.ask('What are the payment terms?');
150
274
  Anywhere under the root works. `input/` is a convention here and nothing
151
275
  enforces it, because the agent and your application share one namespace.
152
276
 
153
- ## Credentials have two tiers, and they do not substitute
277
+ ## Whose account an agent uses
278
+
279
+ Each connection in an agent's setup names one account, and a turn uses exactly
280
+ that one:
154
281
 
155
- `fixed` is set once on the agent and used by every conversation. `conversation`
156
- is supplied per conversation, so each user brings their own account.
282
+ | Built with | Whose | Who signs in |
283
+ |---|---|---|
284
+ | `Connection.creatorAccount(app, account)` | the agent creator's | you or a colleague, once; every conversation uses it |
285
+ | `Connection.endUserAccount(app)` | the end user's | each person, once, remembered for them |
157
286
 
158
- An account connected on the agent does **not** satisfy a declaration scoped
159
- `conversation`, and a conversation cannot supply a `fixed` one. Check
287
+ There is no fallback. An account that is not signed in leaves its connection
288
+ unavailable, and the agent says so rather than reaching for another account of
289
+ the same app.
290
+
291
+ Secrets still come in two tiers that do not substitute: `fixed` is set once on
292
+ the agent, `conversation` is supplied per conversation. Check
160
293
  `conversation.ready` and `conversation.requires` to see what is outstanding.
161
294
 
162
295
  ## Drafting tools from an API you already describe
@@ -184,6 +317,15 @@ the big one is `description-missing`: none of the three formats contains the
184
317
  sentence a model reads to pick a tool, and a bad description does not fail, it
185
318
  makes the agent call the wrong thing.
186
319
 
320
+ ### HTTP tool response limits
321
+
322
+ Declarative HTTP tools retain at most 64 KiB of response data and stop reading
323
+ when overflow is detected. The limit counts UTF-8 bytes, not characters. Oversized responses
324
+ return `ok: false`, `truncated: true`, and a `response_too_large` error body
325
+ with pagination/filtering guidance; the HTTP status remains the upstream
326
+ status. Partial JSON is never presented as a complete result. Use the API's
327
+ filters and pagination to retrieve a large dataset in bounded pages.
328
+
187
329
  ## Errors
188
330
 
189
331
  Every failure throws `AgentNavaError`.
@@ -220,6 +362,26 @@ Runs anywhere `fetch` exists: Node, Bun, Deno, Cloudflare Workers, the browser.
220
362
  `loadWorkflows` is the one exception; it reads a directory off disk and so needs
221
363
  Node or Bun.
222
364
 
365
+ ## Pointing at a different deployment
366
+
367
+ The SDK talks to `https://api.agentnava.com` unless you say otherwise. Two ways
368
+ to change it, and the explicit option wins over the environment variable.
369
+
370
+ ```ts
371
+ // a dedicated enterprise endpoint
372
+ const ws = AgentNava.getWorkspace({ apiKey, baseURL: 'https://acme.agentnava.example' });
373
+ ```
374
+
375
+ ```bash
376
+ # staging, which is where a test key works
377
+ AGENTNAVA_BASE_URL=https://api-staging.agentnava.com
378
+ ```
379
+
380
+ **A staging key against the production URL fails with `invalid api key`**, which
381
+ reads like a bad key rather than the wrong host. If you were given a test key,
382
+ set the staging URL above. A trailing slash is fine, and a base with a path
383
+ prefix works too, for an API gateway sitting in front of us.
384
+
223
385
  ## Licence
224
386
 
225
387
  Apache License 2.0. See `LICENSE`, and `NOTICE` for the attribution that
@@ -228,3 +390,22 @@ section 4(d) asks you to carry along.
228
390
  Free to use, modify and redistribute, including commercially, with an
229
391
  explicit patent grant. Section 6 grants no rights to the names: "AgentNava"
230
392
  and "Cerebro Labs" remain trademarks of Cerebro Labs, Inc.
393
+
394
+
395
+ ### Where an agent is live (0.41)
396
+
397
+ `agent.get()` and `ws.agents.list()` carry a read-only `status`: where the agent is live, by the rule the API runs it by, and in `needs` any required account or secret not set up yet (it still runs; the tools that use them fail until they are).
398
+
399
+ ### Enterprise HTTP contracts (0.34)
400
+
401
+ Requires the corresponding API and runtime update. Parameter types include object and array, nested properties/items, per-property required, nullable, integer and additionalProperties. Use choices for primitive enums. Supply native JSON values to paramsJson; an object body is not a JSON-encoded string.
402
+
403
+ The OpenAPI importer respects operation security, document security, and security:[] (public); defining a scheme alone does not enable it. Bearer, Basic and header/query API keys are supported. It preserves inherited parameters, resolves acyclic local schema references, and URL-encodes path/query values. Omitted optional query/header values and an optional whole body are not sent; missing required values still fail before HTTP. Secrets in query values use secretsEncoded.
404
+
405
+ The `secretName` override can represent only one credential per operation. The importer checks each security alternative together with the operation's credential header parameters and selects the first compatible alternative. If none can use a single credential, the importer skips the operation with a warning instead of reusing the same secret for independent credentials. Omit the override to generate independent secret names, or configure the operation explicitly.
406
+
407
+ Review import warnings: an unsupported schema keyword or auth requirement skips the entire operation, even when it belongs to an optional parameter. Choosing among security alternatives produces a warning. This is a supported subset, not full JSON Schema/OpenAPI validation: compatible object `allOf` schemas are supported; other composition, recursive/external references, structured query serialization, cookie authentication, OAuth acquisition/refresh and unimplemented schema constraints need explicit integration. Schemas cannot declare a property named `__proto__`, which the Workers schema adapter cannot preserve.
408
+
409
+ Schema references with sibling keywords also require explicit configuration: those keywords can add constraints to the referenced schema, so the importer rejects the operation rather than discarding them. This check applies at every step of a reference chain. Response-only properties marked `readOnly: true` are still omitted before importing their request schemas.
410
+
411
+ All three execution paths share one HTTP executor. Results include lower-cased Link, Retry-After, request ID, ETag, Last-Modified, Content-Type and rate-limit headers. Credential-bearing headers are excluded and known secret values in metadata are redacted. HTTP errors and oversized responses have ok:false at the outer tool envelope too. The response byte limit remains 64 KiB: filter or paginate larger records.
package/account.d.ts ADDED
@@ -0,0 +1,154 @@
1
+ import type { Http } from './http.ts';
2
+ import type { AccountData, AccountStatus, UsedBy } from './types.ts';
3
+ /**
4
+ * One saved sign-in to one app, that you hold and act on.
5
+ *
6
+ * AN ACCOUNT IS NOT A CONNECTION, and the two words used to be one, which is
7
+ * how an agent came to own a Gmail login that nothing else could see. An
8
+ * ACCOUNT is a sign-in: Gmail, signed in as support@example.com. A CONNECTION is
9
+ * an entry in an agent's setup that names one: "this agent uses Gmail, through
10
+ * that account". Many agents can name one account, and reconnecting it once
11
+ * fixes all of them.
12
+ *
13
+ * ```ts
14
+ * const { account, url } = await ws.accounts.connect({ app: App.GMAIL, nickname: 'Support inbox' });
15
+ * showToUser(url); // they sign in on Google's own page
16
+ * await account.waitUntilConnected();
17
+ * await agent.connections.add(Connection.creatorAccount(App.GMAIL, account));
18
+ * ```
19
+ *
20
+ * Nobody handles a token, you included: the person signs in on the app's own
21
+ * page, and this object says who they signed in as, never how.
22
+ *
23
+ * ONE KIND OF OBJECT FOR BOTH OWNERS. The agent creator's account and one of
24
+ * your end users' are the same class, reached by the same routes: every method
25
+ * here works on any account in the workspace, and `data.owner` says whose it
26
+ * is. So `ws.account(id).waitUntilConnected()` is how you wait for an end user
27
+ * to finish signing in, too.
28
+ *
29
+ * A CLASS, like `Database` and `Secret`: you hold it and act on it, rather than
30
+ * threading an id through calls. Holding one makes no request. `ws.account(id)`
31
+ * is free and the first call on it is the first round trip.
32
+ */
33
+ export declare class Account {
34
+ #private;
35
+ readonly id: string;
36
+ private snapshot?;
37
+ constructor(http: Http, id: string, snapshot?: AccountData);
38
+ private get base();
39
+ /** The app's catalog id: `'gmail'`, `'hubspot'`. Named for what the person
40
+ * signing in recognises, never for whoever we buy the sign-in from. */
41
+ get app(): string | undefined;
42
+ /** Who it is signed in as: the email or username the app reports. Null until
43
+ * somebody has finished signing in. */
44
+ get label(): string | null | undefined;
45
+ /** Your own name for it, such as `'Support inbox'`. */
46
+ get nickname(): string | null | undefined;
47
+ /** Where the sign-in stands, from the last read: `'pending'`, `'connected'`,
48
+ * `'needs_sign_in'` or `'error'`.
49
+ *
50
+ * Reads the snapshot rather than the network. Undefined means this handle
51
+ * has not read yet, NOT that the account is disconnected: call `get()`. */
52
+ get status(): AccountStatus | undefined;
53
+ /** The agents whose setup names this account, from the last read. The
54
+ * question to ask before disconnecting it: who loses it? */
55
+ get usedBy(): UsedBy[] | undefined;
56
+ /** The last-known record, from whatever call produced this object. */
57
+ get data(): AccountData | undefined;
58
+ /**
59
+ * An account goes over the wire as its id, the way a `Date` goes as its ISO
60
+ * string: `JSON.stringify({ account })` sends `"acc_..."`.
61
+ *
62
+ * That is what lets a connection written as a plain object,
63
+ * `{ app, account }`, take the Account you are holding in
64
+ * `ws.agents.create()` and `agent.update()`. It also matches the rule for
65
+ * every handle in this SDK: store the id, not the object.
66
+ */
67
+ toJSON(): string;
68
+ /**
69
+ * Read it back.
70
+ *
71
+ * A MISSING ACCOUNT THROWS (`account_not_found`, 404), and never comes back
72
+ * as an empty record. An account that does not exist and one that is not
73
+ * signed in yet are different answers. The connection this replaced once
74
+ * answered a miss with a made-up blank, so storing an id and reading it back
75
+ * gave you something that did not know what it was.
76
+ */
77
+ get(): Promise<AccountData>;
78
+ /**
79
+ * Wait until the person has finished signing in.
80
+ *
81
+ * The companion to `ws.accounts.connect()`, `ws.endUser(id).accounts
82
+ * .connect()` and `reconnect()`. Those hand you a url; this tells you when
83
+ * the person is done, so you do not write a polling loop or guess which
84
+ * field to believe.
85
+ *
86
+ * DONE MEANS CONNECTED AND NOT RECONNECTING. During a reconnect the account
87
+ * keeps working (`status` stays `'connected'`) while `reconnecting` is true,
88
+ * so a check on `status` alone would return before the person had signed in
89
+ * again. This waits for both.
90
+ *
91
+ * THROWS on the deadline (`account_not_connected`), naming the account and
92
+ * where it stands, rather than returning an account that is still pending.
93
+ * Safe to call again: somebody who has not finished may just need longer.
94
+ *
95
+ * Polls rather than subscribing: there is a person in the middle, so a few
96
+ * seconds costs nothing, and it works from any runtime without a socket.
97
+ */
98
+ waitUntilConnected(options?: {
99
+ timeoutMs?: number;
100
+ intervalMs?: number;
101
+ }): Promise<Account>;
102
+ /**
103
+ * Send the person to sign in again, and get the link.
104
+ *
105
+ * What to call when an account `needs_sign_in`. Every agent that names it
106
+ * follows, so reconnecting once fixes all of them. The sign-in that worked is
107
+ * kept until the new one succeeds, so an abandoned link breaks nothing:
108
+ * meanwhile `data.reconnecting` is true, and `waitUntilConnected()` waits
109
+ * for it to clear.
110
+ *
111
+ * If the person signs in as SOMEBODY ELSE, that becomes a NEW account and
112
+ * this one is left as it was, so no agent switches mailbox without anyone
113
+ * deciding it should. List accounts to find the new one, then change the
114
+ * connections that should use it.
115
+ */
116
+ reconnect(): Promise<{
117
+ url: string;
118
+ }>;
119
+ /** Give it your own name, such as `'Support inbox'`, shown beside who it is
120
+ * signed in as. The app and the sign-in do not change. */
121
+ rename(nickname: string): Promise<Account>;
122
+ /** Ask the app whether the sign-in still works, and read the answer. A
123
+ * revoked sign-in comes back as `needs_sign_in`, not as an exception: it is
124
+ * the answer this call exists to get. */
125
+ check(): Promise<AccountData>;
126
+ /**
127
+ * Sign it out at the app and remove it here.
128
+ *
129
+ * ALWAYS ALLOWED, unlike deleting a database that an agent still names. It
130
+ * returns the agents whose setup names the account, so you can tell whoever
131
+ * owns them: from their next turn those connections report that the account
132
+ * was disconnected. Nothing switches to another account in its place.
133
+ *
134
+ * Removing a connection from an agent is the other thing, and it never
135
+ * touches the account: `agent.connections.remove(name)`.
136
+ */
137
+ disconnect(): Promise<{
138
+ agents: UsedBy[];
139
+ }>;
140
+ }
141
+ /**
142
+ * The account a response carries, or a thrown error. Never a blank.
143
+ *
144
+ * A 404 already throws in the transport, with the API's `account_not_found`.
145
+ * This covers the other way to end up with nothing: a 200 whose body has no
146
+ * account in it, which would otherwise become a snapshot of `undefined` that
147
+ * reads, at every call site, exactly like an account nobody has read yet.
148
+ */
149
+ export declare function accountIn(res: {
150
+ account?: AccountData;
151
+ } | undefined, path: string): AccountData;
152
+ /** The id a connection sends for its account: an `Account` by its id, an id
153
+ * as it is. */
154
+ export declare function accountIdOf(account: Account | string): string;