@extrovert.dev/sdk 0.1.0-pre.6 → 0.1.0-pre.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.
- package/README.md +151 -65
- package/dist/index.cjs +532 -116
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +549 -278
- package/dist/index.d.ts +549 -278
- package/dist/index.js +532 -117
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* on 429/5xx, honors `Retry-After`, and surfaces every failure as a typed {@link ApiError}.
|
|
7
7
|
*/
|
|
8
8
|
/** The library version, surfaced in the User-Agent. Kept in sync with package.json by build. */
|
|
9
|
-
declare const SDK_VERSION = "0.1.0-pre.
|
|
9
|
+
declare const SDK_VERSION = "0.1.0-pre.8";
|
|
10
10
|
interface RetryOptions {
|
|
11
11
|
/** Max retry attempts for idempotent requests on 429/5xx/network errors. Default 2. */
|
|
12
12
|
maxRetries: number;
|
|
@@ -33,7 +33,7 @@ type ReviewInclude = "category" | "turns";
|
|
|
33
33
|
declare function serializeInclude(include?: readonly string[]): string | undefined;
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Extrovert API
|
|
36
|
+
* Extrovert API: typed request/response models.
|
|
37
37
|
*
|
|
38
38
|
* These mirror the Extrovert V1 REST contract (`/v1`, §8 of the build spec). The Go API does not
|
|
39
39
|
* exist yet; field shapes here are the source of truth the client codes against and are validated
|
|
@@ -52,13 +52,13 @@ type IsoTimestamp = string;
|
|
|
52
52
|
* its caveats but cannot exceed them (§5).
|
|
53
53
|
*
|
|
54
54
|
* The `mailbox:*` scope strings are the live wire contract (stored in issued keys'
|
|
55
|
-
* caveats) and are NOT renamed despite the public "inbox" product naming
|
|
56
|
-
* them would invalidate every key already
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* the BYO reviewer decision plane.
|
|
55
|
+
* caveats) and are NOT renamed despite the public "inbox" product naming: renaming
|
|
56
|
+
* them would invalidate every key already issued. `domain:manage` gates onboarding
|
|
57
|
+
* for domains the customer already controls. `commerce:request` permits quotes,
|
|
58
|
+
* requests, and status reads, but never a human approval transition or direct spend.
|
|
59
|
+
* `review:act` gates the BYO reviewer decision plane.
|
|
60
60
|
*/
|
|
61
|
-
type Scope = "mailbox:create" | "mailbox:read" | "mailbox:send" | "mailbox:quota" | "mailbox:credentials" | "mailbox:delete" | "webhook:write" | "domain:manage" | "domain:purchase" | "review:act" | "signup:verify";
|
|
61
|
+
type Scope = "mailbox:create" | "mailbox:read" | "mailbox:send" | "mailbox:quota" | "mailbox:credentials" | "mailbox:delete" | "webhook:write" | "domain:manage" | "domain:read" | "domain:purchase" | "commerce:request" | "review:act" | "signup:verify";
|
|
62
62
|
/** How a Extrovert domain was onboarded (§7). */
|
|
63
63
|
type OnboardingMode = "shared" | "purchased" | "ns_delegated" | "manual";
|
|
64
64
|
/** Lifecycle status of an agent principal. */
|
|
@@ -68,35 +68,35 @@ type InboxStatus = "provisioning" | "live" | "disabled" | "deleted";
|
|
|
68
68
|
/** Direction of a message relative to the inbox that owns it. */
|
|
69
69
|
type MessageDirection = "inbound" | "outbound";
|
|
70
70
|
/**
|
|
71
|
-
* Request body for `POST /v1/enroll`. An agent redeems a `pk_enroll_...` token to
|
|
71
|
+
* Request body for `POST /v1/enroll`. An agent redeems a `pk_enroll_...` token to issue a scoped
|
|
72
72
|
* agent key. Idempotent on `agent_handle` (à la AgentMail's `client_id`).
|
|
73
73
|
*/
|
|
74
74
|
interface EnrollRequest {
|
|
75
75
|
/**
|
|
76
76
|
* The raw enrollment token, format `pk_enroll_<id>_<secret>`. Shown once at issue
|
|
77
|
-
* time. REQUIRED
|
|
77
|
+
* time. REQUIRED: this is the wire field the server reads (`json:"token"`); the
|
|
78
78
|
* request is serialized verbatim, so the field name must match the contract.
|
|
79
79
|
*/
|
|
80
80
|
token: string;
|
|
81
81
|
/**
|
|
82
82
|
* Stable client-chosen handle for this agent. Redeeming twice with the same handle returns the
|
|
83
|
-
* same agent rather than
|
|
83
|
+
* same agent rather than creating a new one.
|
|
84
84
|
*/
|
|
85
85
|
agent_handle: string;
|
|
86
|
-
/** Optional human-readable label for the
|
|
86
|
+
/** Optional human-readable label for the created agent. */
|
|
87
87
|
agent_name?: string;
|
|
88
88
|
/**
|
|
89
89
|
* Optional idempotency key (sent as the `Idempotency-Key` header). A retry with
|
|
90
|
-
* the same key replays the original enrollment response instead of
|
|
90
|
+
* the same key replays the original enrollment response instead of reissuing.
|
|
91
91
|
*/
|
|
92
92
|
client_id?: string;
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
95
|
* Response from `POST /v1/enroll`. The `agent_key` is the short-lived, per-agent scoped key the
|
|
96
|
-
* agent uses for all subsequent calls
|
|
96
|
+
* agent uses for all subsequent calls: never an org-wide key (§5, §14).
|
|
97
97
|
*/
|
|
98
98
|
interface EnrollResponse {
|
|
99
|
-
/** The
|
|
99
|
+
/** The created agent principal id, e.g. `agt_7Hq2...`. */
|
|
100
100
|
agent_id: string;
|
|
101
101
|
/**
|
|
102
102
|
* The scoped agent key, format `pk_agent_<id>_<secret>`. Returned once. Treat as a secret and
|
|
@@ -106,13 +106,13 @@ interface EnrollResponse {
|
|
|
106
106
|
/** Scopes granted to this key (a subset of the enrollment token's scopes). */
|
|
107
107
|
scopes: Scope[];
|
|
108
108
|
/**
|
|
109
|
-
* The fixed org the
|
|
109
|
+
* The fixed org the issued key is bound to (the token's resolved org). The agent
|
|
110
110
|
* cannot change it; it is the canonical org for every subsequent call.
|
|
111
111
|
*/
|
|
112
112
|
org_id?: string;
|
|
113
113
|
/**
|
|
114
|
-
* The fixed project the
|
|
115
|
-
* agent cannot change it
|
|
114
|
+
* The fixed project the issued key is bound to (the token's resolved project). The
|
|
115
|
+
* agent cannot change it: there is no mutable project selector for a scoped key.
|
|
116
116
|
*/
|
|
117
117
|
project_id?: string;
|
|
118
118
|
}
|
|
@@ -128,7 +128,7 @@ interface Agent {
|
|
|
128
128
|
/**
|
|
129
129
|
* One arbitrary metadata value stored on an inbox. The wire allows string, number,
|
|
130
130
|
* or boolean (nested objects and arrays are rejected). In a PATCH (update) body a
|
|
131
|
-
* value of `null` for a key DELETES that key (the merge/null-delete semantics
|
|
131
|
+
* value of `null` for a key DELETES that key (the merge/null-delete semantics :
|
|
132
132
|
* see {@link UpdateInboxRequest.metadata}); a read shape ({@link Inbox.metadata})
|
|
133
133
|
* never contains `null`.
|
|
134
134
|
*/
|
|
@@ -146,25 +146,28 @@ type InboxMetadata = Record<string, InboxMetadataValue>;
|
|
|
146
146
|
*/
|
|
147
147
|
type InboxMetadataPatch = Record<string, InboxMetadataValue | null>;
|
|
148
148
|
/**
|
|
149
|
-
* Request body for `POST /v1/inboxes`. All fields optional
|
|
150
|
-
*
|
|
149
|
+
* Request body for `POST /v1/inboxes`. All fields are optional. The default path
|
|
150
|
+
* creates an address on the account's platform shared domain.
|
|
151
151
|
*/
|
|
152
152
|
interface CreateInboxRequest {
|
|
153
153
|
/**
|
|
154
|
-
* Desired local part (before the `@`).
|
|
155
|
-
*
|
|
154
|
+
* Desired local part (before the `@`). Shared-domain names are normalized,
|
|
155
|
+
* must be at least 5 characters, and cannot use reserved names. If omitted,
|
|
156
|
+
* the server generates a random handle.
|
|
157
|
+
* Example: `agent7` -> `agent7@extrovertmail.com` for paid accounts or
|
|
158
|
+
* `agent7@free.extrovertmail.com` for free accounts.
|
|
156
159
|
*/
|
|
157
160
|
username?: string;
|
|
158
161
|
/**
|
|
159
|
-
* Domain to
|
|
160
|
-
* shared
|
|
162
|
+
* Domain to create the inbox on. Must be an org domain the calling key is
|
|
163
|
+
* scoped to. If omitted, the account's shared domain is used.
|
|
161
164
|
*/
|
|
162
165
|
domain?: string;
|
|
163
166
|
/** Human-readable display name used in the `From:` header on sends. */
|
|
164
167
|
display_name?: string;
|
|
165
168
|
/**
|
|
166
169
|
* Idempotency handle. Re-creating with the same `client_id` returns the existing inbox rather
|
|
167
|
-
* than
|
|
170
|
+
* than creating a duplicate.
|
|
168
171
|
*/
|
|
169
172
|
client_id?: string;
|
|
170
173
|
/**
|
|
@@ -181,14 +184,14 @@ interface CreateInboxRequest {
|
|
|
181
184
|
*/
|
|
182
185
|
metadata?: InboxMetadata;
|
|
183
186
|
/**
|
|
184
|
-
* Optional assertion that must match the key's bound project
|
|
187
|
+
* Optional assertion that must match the key's bound project: NEVER a selector.
|
|
185
188
|
* A mismatch is a 403. The inbox is always created in the key's stored project;
|
|
186
189
|
* the assertion only lets a caller defend against a misrouted key.
|
|
187
190
|
*/
|
|
188
191
|
project_id?: string;
|
|
189
192
|
/**
|
|
190
|
-
* Whether to return
|
|
191
|
-
*
|
|
193
|
+
* Whether to return paid-inbox credentials (IMAP/SMTP password) in the response.
|
|
194
|
+
* Requires the `mailbox:credentials` permission and defaults to false.
|
|
192
195
|
*/
|
|
193
196
|
return_credentials?: boolean;
|
|
194
197
|
}
|
|
@@ -223,15 +226,17 @@ interface UpdateInboxRequest {
|
|
|
223
226
|
*/
|
|
224
227
|
metadata?: InboxMetadataPatch | null;
|
|
225
228
|
/**
|
|
226
|
-
* Optional assertion that must match the key's bound project
|
|
229
|
+
* Optional assertion that must match the key's bound project: NEVER a selector.
|
|
227
230
|
* A mismatch is a 403.
|
|
228
231
|
*/
|
|
229
232
|
project_id?: string;
|
|
230
233
|
}
|
|
231
234
|
/**
|
|
232
|
-
* IMAP/SMTP connection config + login for
|
|
235
|
+
* IMAP/SMTP connection config + login for a paid inbox. Export requires the
|
|
236
|
+
* `mailbox:credentials` permission. On create it is present only when
|
|
233
237
|
* `return_credentials` was requested. (The IMAP/SMTP host/port/password are mail
|
|
234
|
-
* protocol internals
|
|
238
|
+
* protocol internals. Exported credentials do not mean direct SMTP is enabled.
|
|
239
|
+
* Check `direct_smtp_enabled` on the inbox before attempting an SMTP send.)
|
|
235
240
|
*/
|
|
236
241
|
interface InboxCredentials {
|
|
237
242
|
imap_host: string;
|
|
@@ -239,7 +244,7 @@ interface InboxCredentials {
|
|
|
239
244
|
smtp_host: string;
|
|
240
245
|
smtp_port: number;
|
|
241
246
|
username: string;
|
|
242
|
-
/** Plaintext password
|
|
247
|
+
/** Plaintext mailbox password. Credential reads can return it again. Treat every response as a secret. */
|
|
243
248
|
password: string;
|
|
244
249
|
}
|
|
245
250
|
/** A provisioned inbox (read shape). */
|
|
@@ -252,7 +257,7 @@ interface Inbox {
|
|
|
252
257
|
object?: "inbox";
|
|
253
258
|
/**
|
|
254
259
|
* The canonical OPAQUE inbox id and path key (`/v1/inboxes/{inbox_id}` /
|
|
255
|
-
* `/v1/projects/{project_id}/inboxes/{inbox_id}`). Treat it as opaque
|
|
260
|
+
* `/v1/projects/{project_id}/inboxes/{inbox_id}`). Treat it as opaque: do not parse
|
|
256
261
|
* the `pmbx_` prefix.
|
|
257
262
|
*/
|
|
258
263
|
id: string;
|
|
@@ -261,11 +266,11 @@ interface Inbox {
|
|
|
261
266
|
*/
|
|
262
267
|
org_id?: string;
|
|
263
268
|
/**
|
|
264
|
-
* The project this inbox belongs to (RFC D9)
|
|
269
|
+
* The project this inbox belongs to (RFC D9): the partition key. Optional for
|
|
265
270
|
* legacy/mock shapes.
|
|
266
271
|
*/
|
|
267
272
|
project_id?: string;
|
|
268
|
-
/** Full address, e.g. `agent7@
|
|
273
|
+
/** Full address, e.g. `agent7@extrovertmail.com`. A within-project email alias for {@link Inbox.id}. */
|
|
269
274
|
address: string;
|
|
270
275
|
username: string;
|
|
271
276
|
domain: string;
|
|
@@ -273,10 +278,17 @@ interface Inbox {
|
|
|
273
278
|
status: InboxStatus;
|
|
274
279
|
/** Onboarding mode of the domain this inbox lives on. */
|
|
275
280
|
onboarding_mode: OnboardingMode;
|
|
276
|
-
/** Agent that owns this inbox, if
|
|
281
|
+
/** Agent that owns this inbox, if created by an agent key. */
|
|
277
282
|
agent_id: string | null;
|
|
278
283
|
/** Effective enforced rolling-24-hour recipient cap for this inbox. */
|
|
279
284
|
daily_send_limit: number;
|
|
285
|
+
/**
|
|
286
|
+
* Whether raw protocol SMTP is currently allowed. It defaults to false, is
|
|
287
|
+
* controlled by a human per inbox, and is effective only while the inbox has a
|
|
288
|
+
* paid entitlement. Exported credentials do not imply this is true. API, SDK,
|
|
289
|
+
* and MCP sends remain governed by the Review Loop regardless of this value.
|
|
290
|
+
*/
|
|
291
|
+
direct_smtp_enabled: boolean;
|
|
280
292
|
/**
|
|
281
293
|
* Inbound webhook registered for this inbox, if any. The wire field is
|
|
282
294
|
* `webhook_url` (the server returns `webhook_url`, never `inbound_webhook_url`);
|
|
@@ -285,7 +297,7 @@ interface Inbox {
|
|
|
285
297
|
webhook_url?: string | null;
|
|
286
298
|
/**
|
|
287
299
|
* Arbitrary key-value metadata stored on the inbox (AgentMail parity). Always an
|
|
288
|
-
* object
|
|
300
|
+
* object: `{}` when none is set, never null. Values are string, number, or
|
|
289
301
|
* boolean. Project-scoped: an agent key only reads/mutates metadata for inboxes in
|
|
290
302
|
* its bound project.
|
|
291
303
|
*/
|
|
@@ -375,7 +387,7 @@ interface AttachmentInput {
|
|
|
375
387
|
* A stored message in an inbox (read shape). Mirrors the canonical Go wire shape
|
|
376
388
|
* (`messageResponse`): `id` is the opaque, inbox-resolvable id; `inbox` is the
|
|
377
389
|
* owning address; `seen` is the native IMAP \Seen read state (Extrovert has no
|
|
378
|
-
* Gmail-style labels
|
|
390
|
+
* Gmail-style labels: read/unread is the \Seen flag); `folder` is the IMAP
|
|
379
391
|
* mailbox; `date` is the raw `Date` header.
|
|
380
392
|
*/
|
|
381
393
|
interface Message {
|
|
@@ -387,6 +399,8 @@ interface Message {
|
|
|
387
399
|
from: EmailAddress;
|
|
388
400
|
to: EmailAddress[];
|
|
389
401
|
cc?: EmailAddress[];
|
|
402
|
+
/** Reply-To addresses parsed from the source message. */
|
|
403
|
+
reply_to?: EmailAddress[];
|
|
390
404
|
subject: string;
|
|
391
405
|
/** Decoded text/plain MIME alternative; null when absent and never derived from HTML. */
|
|
392
406
|
text: string | null;
|
|
@@ -398,6 +412,10 @@ interface Message {
|
|
|
398
412
|
extracted_html?: string | null;
|
|
399
413
|
/** RFC 5322 `Message-ID` header value. */
|
|
400
414
|
message_id: string;
|
|
415
|
+
/** Source RFC 5322 parent Message-ID, when present. */
|
|
416
|
+
in_reply_to?: string;
|
|
417
|
+
/** Source RFC 5322 References chain, when present. */
|
|
418
|
+
references?: string;
|
|
401
419
|
/** IMAP folder the message lives in (e.g. `INBOX`, `Junk`). */
|
|
402
420
|
folder?: string;
|
|
403
421
|
/** Whether the message has been read (native IMAP \Seen flag). */
|
|
@@ -433,7 +451,7 @@ interface SearchMessagesParams {
|
|
|
433
451
|
offset?: number;
|
|
434
452
|
cursor?: string;
|
|
435
453
|
}
|
|
436
|
-
/** Request body for `PATCH /v1/inboxes/{addr}/messages/{id}
|
|
454
|
+
/** Request body for `PATCH /v1/inboxes/{addr}/messages/{id}`: read-state toggle. */
|
|
437
455
|
interface MarkReadRequest {
|
|
438
456
|
/** true to set the \Seen flag (read), false to clear it (unread). */
|
|
439
457
|
read: boolean;
|
|
@@ -490,7 +508,7 @@ interface SendRequest {
|
|
|
490
508
|
/** Override the `Reply-To` header. */
|
|
491
509
|
reply_to?: string;
|
|
492
510
|
/**
|
|
493
|
-
* Idempotency key
|
|
511
|
+
* Idempotency key: a replay with the same key returns the first response
|
|
494
512
|
* instead of sending a second message.
|
|
495
513
|
*
|
|
496
514
|
* Sent as the `Idempotency-Key` HEADER and STRIPPED from the JSON body: the
|
|
@@ -527,7 +545,7 @@ interface SendRequest {
|
|
|
527
545
|
* Request body for the canonical thread-aware reply,
|
|
528
546
|
* `POST /v1/inboxes/{addr}/reply`. Exactly one of `thread_id` / `message_id`
|
|
529
547
|
* selects the parent; the server derives `to` (original participants), the
|
|
530
|
-
* `Re:`-prefixed subject, and the `In-Reply-To` / `References` headers
|
|
548
|
+
* `Re:`-prefixed subject, and the `In-Reply-To` / `References` headers: you do
|
|
531
549
|
* NOT pass `to`. Set `reply_all` to reply to every thread recipient.
|
|
532
550
|
*/
|
|
533
551
|
interface ReplyRequest {
|
|
@@ -535,6 +553,12 @@ interface ReplyRequest {
|
|
|
535
553
|
thread_id?: string;
|
|
536
554
|
/** Reply to this specific message. One of thread_id / message_id. */
|
|
537
555
|
message_id?: string;
|
|
556
|
+
/**
|
|
557
|
+
* Optional optimistic stale-context guard for a thread reply. Use the
|
|
558
|
+
* `last_message_id` from the thread you read; a 409 means the thread advanced.
|
|
559
|
+
* This detects stale context at submission, but is not an atomic send lock.
|
|
560
|
+
*/
|
|
561
|
+
expected_last_message_id?: string;
|
|
538
562
|
/** At least one of `text` / `html` is required. */
|
|
539
563
|
text?: string;
|
|
540
564
|
html?: string;
|
|
@@ -544,7 +568,7 @@ interface ReplyRequest {
|
|
|
544
568
|
reply_to?: string;
|
|
545
569
|
/** Reply to all thread recipients, not just the original sender. */
|
|
546
570
|
reply_all?: boolean;
|
|
547
|
-
/** See {@link SendRequest.idempotency_key}
|
|
571
|
+
/** See {@link SendRequest.idempotency_key}: sent as a header, never in the body. */
|
|
548
572
|
idempotency_key?: string;
|
|
549
573
|
headers?: Record<string, string>;
|
|
550
574
|
/** Files to attach (base64). Emitted as a multipart/mixed message. */
|
|
@@ -566,7 +590,7 @@ interface ReplyRequest {
|
|
|
566
590
|
* A forward is governed by the SAME review policy as a send, and for a stronger
|
|
567
591
|
* reason: it is an outbound message to arbitrary NEW recipients that quotes an
|
|
568
592
|
* entire inbound thread. Leaving it outside the policy would have made forward
|
|
569
|
-
* the documented bypass
|
|
593
|
+
* the documented bypass: and a worse one than a bare send, because it
|
|
570
594
|
* exfiltrates a received conversation.
|
|
571
595
|
*/
|
|
572
596
|
interface ForwardRequest {
|
|
@@ -593,7 +617,7 @@ interface ForwardRequest {
|
|
|
593
617
|
/** Agent-supplied confidence (0..1); see {@link SendRequest.category_confidence}. */
|
|
594
618
|
category_confidence?: number;
|
|
595
619
|
composition_token?: string;
|
|
596
|
-
/** See {@link SendRequest.idempotency_key}
|
|
620
|
+
/** See {@link SendRequest.idempotency_key}: sent as a header, never in the body. */
|
|
597
621
|
idempotency_key?: string;
|
|
598
622
|
}
|
|
599
623
|
/**
|
|
@@ -603,8 +627,8 @@ interface ForwardRequest {
|
|
|
603
627
|
* Its shape differs per verb, which is why almost every field is optional and
|
|
604
628
|
* this type is NOT the whole story (see {@link SendOutcome}):
|
|
605
629
|
*
|
|
606
|
-
* - `send` → `{status:"sent", message_id, review_id}
|
|
607
|
-
* - `reply`/`forward` → `{message_id, thread_id, review_id}
|
|
630
|
+
* - `send` → `{status:"sent", message_id, review_id}`: **no `thread_id`**.
|
|
631
|
+
* - `reply`/`forward` → `{message_id, thread_id, review_id}`: no `status`.
|
|
608
632
|
*
|
|
609
633
|
* `thread_id` was declared REQUIRED here for a long time while the send path
|
|
610
634
|
* never returned one, so `res.thread_id` typechecked and was `undefined` at
|
|
@@ -619,7 +643,7 @@ interface SendResult {
|
|
|
619
643
|
kind?: undefined;
|
|
620
644
|
/** Extrovert message id of the sent outbound message. */
|
|
621
645
|
message_id: string;
|
|
622
|
-
/** Thread id
|
|
646
|
+
/** Thread id: present on reply/forward; ABSENT on the direct-send response. */
|
|
623
647
|
thread_id?: string;
|
|
624
648
|
/**
|
|
625
649
|
* Opaque review id (rr_…) of the review row that governed this send. Every
|
|
@@ -637,16 +661,16 @@ interface SendResult {
|
|
|
637
661
|
* Every shape `inbox.send()` / `.reply()` / `.forward()` / `.submitForReview()`
|
|
638
662
|
* can return, discriminated by `kind`.
|
|
639
663
|
*
|
|
640
|
-
* There are three, because the resolved review policy
|
|
664
|
+
* There are three, because the resolved review policy: not the caller: decides
|
|
641
665
|
* what happens to an outbound message:
|
|
642
666
|
*
|
|
643
|
-
* - {@link QueuedForReviewResult} (`kind:"queued_for_review"`, 202)
|
|
667
|
+
* - {@link QueuedForReviewResult} (`kind:"queued_for_review"`, 202): parked for
|
|
644
668
|
* a human. **Nothing has been delivered yet.** Monitor
|
|
645
669
|
* `reviewEvents.wait({review_id})` until a `sent` or `send_failed` event
|
|
646
670
|
* arrives.
|
|
647
|
-
* - {@link SentResult} (`kind:"sent"`, 200)
|
|
671
|
+
* - {@link SentResult} (`kind:"sent"`, 200): delivered immediately, returned to
|
|
648
672
|
* callers that opted into the review loop by passing mode/intent/category_id.
|
|
649
|
-
* - {@link SendResult} (no `kind`, 202)
|
|
673
|
+
* - {@link SendResult} (no `kind`, 202): the legacy immediate-send body for a
|
|
650
674
|
* caller that mentioned none of those fields.
|
|
651
675
|
*
|
|
652
676
|
* Under the default `require_review` policy a send WITHOUT an `intent` does not
|
|
@@ -658,15 +682,15 @@ type SendOutcome = SendResult | SentResult | QueuedForReviewResult;
|
|
|
658
682
|
/** Per-send agent assertion (D3/D6). The resolved policy may downgrade `direct`. */
|
|
659
683
|
type ReviewMode = "review" | "direct";
|
|
660
684
|
/**
|
|
661
|
-
* The account/inbox review policy
|
|
685
|
+
* The account/inbox review policy: the AUTHORITY on what happens to an outbound
|
|
662
686
|
* message. There is no way for a caller to opt out of it.
|
|
663
687
|
*
|
|
664
|
-
* - `require_review
|
|
688
|
+
* - `require_review`: the default for every account. A send WITHOUT an `intent`
|
|
665
689
|
* is rejected 422 `intent_required` (nothing sent, nothing queued); a send
|
|
666
690
|
* WITH one is queued for a human (202 `queued_for_review`).
|
|
667
|
-
* - `allow_direct
|
|
691
|
+
* - `allow_direct`: a bare send (no mode/intent/category_id) is delivered
|
|
668
692
|
* immediately. Supplying an intent, or `mode: "review"`, still queues it.
|
|
669
|
-
* - `auto_send_graduated
|
|
693
|
+
* - `auto_send_graduated`: a categorized message that clears the graduation
|
|
670
694
|
* gates auto-sends; everything else is queued.
|
|
671
695
|
*
|
|
672
696
|
* Read {@link Inbox.effective_review_policy} once before your first send rather
|
|
@@ -685,7 +709,7 @@ interface ReviewIntent {
|
|
|
685
709
|
urgency?: string;
|
|
686
710
|
};
|
|
687
711
|
}
|
|
688
|
-
/** A review request (rr_…)
|
|
712
|
+
/** A review request (rr_…): the pre-send record under the Review Loop. */
|
|
689
713
|
interface Review {
|
|
690
714
|
id: string;
|
|
691
715
|
state: ReviewState;
|
|
@@ -718,8 +742,8 @@ interface Review {
|
|
|
718
742
|
* `failed`**.
|
|
719
743
|
*
|
|
720
744
|
* `failed` is included deliberately even though it is not in the formal
|
|
721
|
-
* terminal set: nothing in the product can move a failed review
|
|
722
|
-
* cannot re-approve it
|
|
745
|
+
* terminal set: nothing in the product can move a failed review: the console
|
|
746
|
+
* cannot re-approve it: so a flag that said `false` there would invite an
|
|
723
747
|
* agent to wait forever on a row nobody will ever touch.
|
|
724
748
|
*
|
|
725
749
|
* An agent that lost its event cursor (a crash, a fresh process) reads this
|
|
@@ -733,7 +757,7 @@ interface Review {
|
|
|
733
757
|
send_error?: string;
|
|
734
758
|
/**
|
|
735
759
|
* How the message was released, once sent: `human_reviewed`,
|
|
736
|
-
* `reviewer_approved`, `graduated_auto` or `agent_direct
|
|
760
|
+
* `reviewer_approved`, `graduated_auto` or `agent_direct`: without a turns
|
|
737
761
|
* fetch.
|
|
738
762
|
*/
|
|
739
763
|
send_path?: string;
|
|
@@ -757,6 +781,7 @@ interface ReviewTurn {
|
|
|
757
781
|
}
|
|
758
782
|
/** Filters for listing review requests (spec §5.2). */
|
|
759
783
|
interface ListReviewsParams {
|
|
784
|
+
composer?: "me";
|
|
760
785
|
state?: ReviewState | ReviewState[];
|
|
761
786
|
category_id?: string;
|
|
762
787
|
inbox?: string;
|
|
@@ -775,7 +800,7 @@ interface ReviewFeedbackComment {
|
|
|
775
800
|
* The human's assembled feedback for a review (spec §11), returned by
|
|
776
801
|
* `reviews.feedback(id)`: the unified + structured diff of the human edit, the human
|
|
777
802
|
* comments / rejection feedback, the decision, and the rules born from this review
|
|
778
|
-
* (rule_ ids whose source_review_id is this review). $0 LLM
|
|
803
|
+
* (rule_ ids whose source_review_id is this review). $0 LLM: pure assembly.
|
|
779
804
|
*/
|
|
780
805
|
interface ReviewFeedback {
|
|
781
806
|
review_id: string;
|
|
@@ -792,7 +817,7 @@ interface PostReviewChatRequest {
|
|
|
792
817
|
}
|
|
793
818
|
/**
|
|
794
819
|
* Body for posting a new agent draft under a parent_revision CAS (spec §5.2; M5,
|
|
795
|
-
* D17). parent_revision is the PRIMARY CAS
|
|
820
|
+
* D17). parent_revision is the PRIMARY CAS: it must equal the draft's current
|
|
796
821
|
* revision, else 409 STALE with NO mutation. version is OPTIONAL belt-and-suspenders.
|
|
797
822
|
*/
|
|
798
823
|
interface SubmitRevisionRequest {
|
|
@@ -801,7 +826,7 @@ interface SubmitRevisionRequest {
|
|
|
801
826
|
subject?: string;
|
|
802
827
|
/**
|
|
803
828
|
* The redrafted plain-text body. Canonical, matching `text` on send / reply /
|
|
804
|
-
* forward
|
|
829
|
+
* forward: the same concept should not have two names in the one flow an
|
|
805
830
|
* agent runs most.
|
|
806
831
|
*/
|
|
807
832
|
text?: string;
|
|
@@ -854,7 +879,7 @@ type ReviewEventReason =
|
|
|
854
879
|
* cancel, so compose and submit a NEW message rather than retrying this one.
|
|
855
880
|
*/
|
|
856
881
|
| "send_failed"
|
|
857
|
-
/** Withdrawn
|
|
882
|
+
/** Withdrawn: by you, by a human, or as the close-out of a failed send. */
|
|
858
883
|
| "cancelled"
|
|
859
884
|
/**
|
|
860
885
|
* You were front-run: the review reached a terminal state while you were
|
|
@@ -862,9 +887,9 @@ type ReviewEventReason =
|
|
|
862
887
|
* `cancel_review` answered 409 `terminal`. STOP retrying that review.
|
|
863
888
|
*/
|
|
864
889
|
| "front_run_next"
|
|
865
|
-
/** RESERVED
|
|
890
|
+
/** RESERVED: never emitted. Terminal success is `sent`. */
|
|
866
891
|
| "approved"
|
|
867
|
-
/** RESERVED
|
|
892
|
+
/** RESERVED: no production producer (the D13 staleness detector is unbuilt). */
|
|
868
893
|
| "staleness";
|
|
869
894
|
/**
|
|
870
895
|
* One durable review nudge (ndg_…) drained from the AUTHORITATIVE liveness queue
|
|
@@ -880,13 +905,14 @@ interface ReviewEvent {
|
|
|
880
905
|
payload?: Record<string, unknown>;
|
|
881
906
|
created_at: IsoTimestamp;
|
|
882
907
|
}
|
|
883
|
-
/** The agent's per-(agent, review) ack frontier
|
|
908
|
+
/** The agent's per-(agent, review) ack frontier: its strict-FIFO position. */
|
|
884
909
|
interface ReviewEventCursor {
|
|
885
910
|
review_id: string;
|
|
886
911
|
last_acked_seq: number;
|
|
887
912
|
}
|
|
888
|
-
/** Drain result for list/wait
|
|
913
|
+
/** Drain result for list/wait: un-acked events in FIFO seq order + cursors. */
|
|
889
914
|
interface ReviewEventsResult {
|
|
915
|
+
pending_reviews?: number;
|
|
890
916
|
events: ReviewEvent[];
|
|
891
917
|
cursors?: ReviewEventCursor[];
|
|
892
918
|
}
|
|
@@ -901,7 +927,7 @@ interface ListReviewEventsParams {
|
|
|
901
927
|
* A category (cat_…) in the Review Loop registry (D9/D10). `name` + `description`
|
|
902
928
|
* are skill-style metadata the agent fuzzy-matches against; nothing keys on the
|
|
903
929
|
* name (renames never break a reference). Categories are CUSTOMER-scoped and
|
|
904
|
-
* agent-attributed
|
|
930
|
+
* agent-attributed: the deliberate cross-agent-404 exception. Opaque ids only.
|
|
905
931
|
*/
|
|
906
932
|
interface Category {
|
|
907
933
|
id: string;
|
|
@@ -930,13 +956,13 @@ interface ProposeCategoryRequest {
|
|
|
930
956
|
/** Defaults to org_shared server-side. */
|
|
931
957
|
scope?: "org_shared" | "agent_private";
|
|
932
958
|
}
|
|
933
|
-
/** Rename / re-describe a category
|
|
959
|
+
/** Rename / re-describe a category: metadata only (spec §5.5; D10). */
|
|
934
960
|
interface UpdateCategoryRequest {
|
|
935
961
|
name?: string;
|
|
936
962
|
description?: string;
|
|
937
963
|
}
|
|
938
964
|
/**
|
|
939
|
-
* The account-wide default risk dial (Review Loop, D4/D12)
|
|
965
|
+
* The account-wide default risk dial (Review Loop, D4/D12): the values a per-
|
|
940
966
|
* category null override inherits. The single user-configurable brand-risk lever.
|
|
941
967
|
*/
|
|
942
968
|
interface AccountRiskDial {
|
|
@@ -974,7 +1000,7 @@ interface CategoryRiskDial {
|
|
|
974
1000
|
}
|
|
975
1001
|
/**
|
|
976
1002
|
* The effective risk dial (Review Loop, agent plane; D4/D12): the account default
|
|
977
|
-
* plus every category's overrides. Read-only for agents
|
|
1003
|
+
* plus every category's overrides. Read-only for agents: flipping the dial is a
|
|
978
1004
|
* console (human) action (D16).
|
|
979
1005
|
*/
|
|
980
1006
|
interface RiskDial {
|
|
@@ -1027,7 +1053,7 @@ type ReviewerAction = "approve" | "edit" | "reject" | "escalate";
|
|
|
1027
1053
|
* The REVIEWER's read-only decision surface for a review (BYO review-agent plane;
|
|
1028
1054
|
* D5/§9), returned by `reviews.decisionContext(id)`: the intent + current draft + the
|
|
1029
1055
|
* append-only thread + the two-circuit-breaker budget. `force_to_human` is true when
|
|
1030
|
-
* EITHER breaker has tripped
|
|
1056
|
+
* EITHER breaker has tripped: the reviewer's next reject would be FORCED to the human
|
|
1031
1057
|
* regardless of intent (the human is the only terminal authority, D17).
|
|
1032
1058
|
*/
|
|
1033
1059
|
interface ReviewDecisionContext {
|
|
@@ -1051,7 +1077,7 @@ interface ReviewDecisionContext {
|
|
|
1051
1077
|
/**
|
|
1052
1078
|
* Body for a reviewer decision (`reviews.decide(id, req)`; reviewer_decide, D5/§9).
|
|
1053
1079
|
* `action` is approve|edit|reject|escalate. `revision`/`version` are the optimistic CAS
|
|
1054
|
-
|
|
1080
|
+
*: a mismatch is a 409 STALE with NO mutation (the human always wins, D17). subject/
|
|
1055
1081
|
* body carry the edited content for the edit action; feedback is the reviewer's note.
|
|
1056
1082
|
*/
|
|
1057
1083
|
interface ReviewerDecisionRequest {
|
|
@@ -1068,8 +1094,8 @@ interface ReviewerDecisionRequest {
|
|
|
1068
1094
|
feedback?: string;
|
|
1069
1095
|
}
|
|
1070
1096
|
/**
|
|
1071
|
-
* The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform
|
|
1072
|
-
* with the COMPOSER's creds (approve/edit
|
|
1097
|
+
* The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform sent
|
|
1098
|
+
* with the COMPOSER's creds (approve/edit: the reviewer NEVER holds mailbox:send);
|
|
1073
1099
|
* `kind=sent_to_human` when the draft returned to the human queue (reject/escalate, or
|
|
1074
1100
|
* a reject FORCED to the human by a circuit breaker, with `forced_by_breaker` naming it).
|
|
1075
1101
|
*/
|
|
@@ -1085,7 +1111,7 @@ interface ReviewerDecisionResult {
|
|
|
1085
1111
|
/**
|
|
1086
1112
|
* The D19/§8 backlog-reconciliation snapshot for a category (agent-readable, $0-LLM).
|
|
1087
1113
|
* Counts the QUEUED drafts that are stale vs current-enough against the current
|
|
1088
|
-
* category rules-version + house-style version (a pure integer compare). Read-only
|
|
1114
|
+
* category rules-version + house-style version (a pure integer compare). Read-only :
|
|
1089
1115
|
* the agent READS the picture; the human / hooks TRIGGER the actual sweep.
|
|
1090
1116
|
*/
|
|
1091
1117
|
interface ScanBacklogStatus {
|
|
@@ -1108,7 +1134,7 @@ interface PacingItem {
|
|
|
1108
1134
|
state: "behind_cursor" | "in_window_fresh" | "in_window_redrafting" | "ahead";
|
|
1109
1135
|
}
|
|
1110
1136
|
/**
|
|
1111
|
-
* The demand-driven pacing snapshot for a category (agent-readable, $0-LLM
|
|
1137
|
+
* The demand-driven pacing snapshot for a category (agent-readable, $0-LLM: M7 Slice
|
|
1112
1138
|
* B/§8): the human review cursor, the effective window/ceiling/interval, the queued
|
|
1113
1139
|
* count, and each queued draft's in-window/redrafting/behind-cursor classification.
|
|
1114
1140
|
* Read-only; the cursor advances from the human's console approve/reject/edit actions.
|
|
@@ -1121,7 +1147,7 @@ interface CategoryPacingState {
|
|
|
1121
1147
|
cursor_advanced_count: number;
|
|
1122
1148
|
/** Effective freshness window (default org_settings.lookahead_window=3). */
|
|
1123
1149
|
lookahead_window: number;
|
|
1124
|
-
/** HARD per-nudge fan-out ceiling (default 10)
|
|
1150
|
+
/** HARD per-nudge fan-out ceiling (default 10): one nudge can never fan to 500. */
|
|
1125
1151
|
rework_batch_max: number;
|
|
1126
1152
|
/** Per-agent token-bucket interval that coalesces feedback storms (default 5000). */
|
|
1127
1153
|
nudge_min_interval_ms: number;
|
|
@@ -1183,6 +1209,8 @@ interface Rule {
|
|
|
1183
1209
|
author_kind: "agent" | "human";
|
|
1184
1210
|
created_at: IsoTimestamp;
|
|
1185
1211
|
updated_at: IsoTimestamp;
|
|
1212
|
+
source_review_id?: string;
|
|
1213
|
+
source_turn_id?: string;
|
|
1186
1214
|
}
|
|
1187
1215
|
/** Filter for the ordered get_rules read (spec §5.4; §7). */
|
|
1188
1216
|
interface GetRulesParams {
|
|
@@ -1202,11 +1230,11 @@ interface RuleSnapshot extends Page<Rule> {
|
|
|
1202
1230
|
/**
|
|
1203
1231
|
* Save / edit a writing rule (append-only by supersession; spec §5.4; D11).
|
|
1204
1232
|
*
|
|
1205
|
-
* Layering (org/project): an agent-plane save is ALWAYS project-layer
|
|
1233
|
+
* Layering (org/project): an agent-plane save is ALWAYS project-layer: the saved
|
|
1206
1234
|
* rule's `rule_layer` is `project`, bound to the calling key's project. There is no
|
|
1207
1235
|
* settable `rule_layer` here: an agent cannot create org-layer / house-style
|
|
1208
1236
|
* (`rule_layer="org"`) rules in v1; authoring org rules is a console/admin action.
|
|
1209
|
-
* (`scope: "general"` still means a house-style rule WITHIN the project layer
|
|
1237
|
+
* (`scope: "general"` still means a house-style rule WITHIN the project layer :
|
|
1210
1238
|
* `scope` is the category axis, `rule_layer` is the ownership axis.)
|
|
1211
1239
|
*/
|
|
1212
1240
|
interface SaveRuleRequest {
|
|
@@ -1229,7 +1257,7 @@ interface SaveRuleRequest {
|
|
|
1229
1257
|
/**
|
|
1230
1258
|
* D8 retro-propagation HUMAN OPT-IN (default false). When true, a NEW category rule
|
|
1231
1259
|
* that could apply to pending siblings enqueues ONE propagate_general_rule nudge
|
|
1232
|
-
* (siblings + suggested_batch) so the agent redrafts a FEW at a time
|
|
1260
|
+
* (siblings + suggested_batch) so the agent redrafts a FEW at a time: never the
|
|
1233
1261
|
* whole queue. Set only after the human said "apply to N pending?".
|
|
1234
1262
|
*/
|
|
1235
1263
|
propagate_to_pending?: boolean;
|
|
@@ -1286,7 +1314,7 @@ interface SentResult {
|
|
|
1286
1314
|
};
|
|
1287
1315
|
/**
|
|
1288
1316
|
* The review row that governed this send (ADDITIVE). Present on every send the
|
|
1289
|
-
* service routed, i.e. all of them
|
|
1317
|
+
* service routed, i.e. all of them: it is the handle that makes a post-crash
|
|
1290
1318
|
* `reviews.get(id)` possible on the direct path too.
|
|
1291
1319
|
*/
|
|
1292
1320
|
review?: {
|
|
@@ -1306,14 +1334,20 @@ interface Thread {
|
|
|
1306
1334
|
/** Owning inbox address. */
|
|
1307
1335
|
inbox_id: string;
|
|
1308
1336
|
subject: string;
|
|
1309
|
-
/**
|
|
1337
|
+
/** List/search summaries use the latest envelope; thread detail may include the full conversation set. */
|
|
1310
1338
|
participants: string[];
|
|
1311
1339
|
message_count: number;
|
|
1312
1340
|
last_message_at: IsoTimestamp;
|
|
1313
1341
|
/** Most-recent-message preview snippet. */
|
|
1314
1342
|
snippet: string;
|
|
1343
|
+
/** Whether the latest message is unread. */
|
|
1344
|
+
unread?: boolean;
|
|
1345
|
+
/** Whether the newest message has one or more attachments. */
|
|
1346
|
+
last_message_has_attachments?: boolean;
|
|
1347
|
+
/** Opaque message id for optimistic reply freshness checks. */
|
|
1348
|
+
last_message_id?: string;
|
|
1315
1349
|
}
|
|
1316
|
-
/** A thread plus its messages (oldest-first)
|
|
1350
|
+
/** A thread plus its messages (oldest-first): `GET /v1/inboxes/{addr}/threads/{id}`. */
|
|
1317
1351
|
interface ThreadDetail extends Thread {
|
|
1318
1352
|
messages: Message[];
|
|
1319
1353
|
}
|
|
@@ -1485,7 +1519,7 @@ interface SuppressionEntry {
|
|
|
1485
1519
|
/**
|
|
1486
1520
|
* The result of a pre-check (`GET /v1/suppressions?recipient=…`): whether the
|
|
1487
1521
|
* caller's OWN org suppresses the recipient, plus the matching org rows. Reflects
|
|
1488
|
-
* only the caller's org state
|
|
1522
|
+
* only the caller's org state: never a global/shared/cross-tenant opt-out.
|
|
1489
1523
|
*/
|
|
1490
1524
|
interface SuppressionPrecheck {
|
|
1491
1525
|
recipient: string;
|
|
@@ -1504,7 +1538,7 @@ interface ListSuppressionsParams {
|
|
|
1504
1538
|
/** Opaque cursor from a previous page's `next_cursor`. */
|
|
1505
1539
|
cursor?: string;
|
|
1506
1540
|
}
|
|
1507
|
-
/** One
|
|
1541
|
+
/** One nameserver record the customer must publish for delegated setup. */
|
|
1508
1542
|
interface DomainRecord {
|
|
1509
1543
|
name: string;
|
|
1510
1544
|
type: string;
|
|
@@ -1518,40 +1552,43 @@ type DomainScope = "org" | "project";
|
|
|
1518
1552
|
/**
|
|
1519
1553
|
* Request body for `POST /v1/domains`. Onboards/adds a domain for the customer.
|
|
1520
1554
|
*
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1524
|
-
* purchased-domain plan limit, enforced before any registrar spend). `manual` and
|
|
1525
|
-
* `ns_delegated` need `domain:manage` only.
|
|
1555
|
+
* Requires the `domain:manage` scope. This request only adds a delegated inbox
|
|
1556
|
+
* domain the customer controls; it cannot register one.
|
|
1557
|
+
* New registrations use the separate commerce quote/request workflow.
|
|
1526
1558
|
*/
|
|
1527
1559
|
interface OnboardDomainRequest {
|
|
1528
1560
|
domain: string;
|
|
1529
1561
|
/**
|
|
1530
|
-
* Onboarding path. Defaults to `ns_delegated` server-side when omitted.
|
|
1531
|
-
* additionally requires the `domain:purchase` scope.
|
|
1562
|
+
* Onboarding path. Defaults to `ns_delegated` server-side when omitted.
|
|
1532
1563
|
*/
|
|
1533
|
-
mode?:
|
|
1534
|
-
/** A-record IP served at a delegated zone's apex (ns_delegated only). */
|
|
1535
|
-
mail_host_ip?: string;
|
|
1564
|
+
mode?: "ns_delegated";
|
|
1536
1565
|
/**
|
|
1537
1566
|
* Domain visibility. Defaults to `org` (org-shared, usable by every project in the
|
|
1538
1567
|
* org). `project` binds the domain to the key's OWN bound project (never
|
|
1539
|
-
* client-selected) so it is only visible/
|
|
1568
|
+
* client-selected) so it is only visible/creatable from that project. A
|
|
1540
1569
|
* legacy/unscoped key (no bound project) falls back to `org`.
|
|
1541
1570
|
*/
|
|
1542
1571
|
scope?: DomainScope;
|
|
1543
1572
|
/**
|
|
1544
|
-
* Optional assertion that must match the key's bound project
|
|
1573
|
+
* Optional assertion that must match the key's bound project: NEVER a selector.
|
|
1545
1574
|
* A mismatch is a 403. The binding is always derived from the key.
|
|
1546
1575
|
*/
|
|
1547
1576
|
project_id?: string;
|
|
1548
1577
|
}
|
|
1549
1578
|
/**
|
|
1550
1579
|
* The agent-facing view of one onboarded domain (mirrors the Go `domainResponse`).
|
|
1551
|
-
* `
|
|
1552
|
-
*
|
|
1580
|
+
* `delegation_ns` is present on get / onboard / verify for delegated domains and
|
|
1581
|
+
* empty on list reads. `records` remains for legacy response compatibility.
|
|
1553
1582
|
*/
|
|
1554
1583
|
interface Domain {
|
|
1584
|
+
/** Authoritative outcome. Absent only when talking to an older server; never infer readiness from DKIM. */
|
|
1585
|
+
readiness?: DomainReadiness;
|
|
1586
|
+
/** Customer DNS health, independent of mail provisioning readiness. */
|
|
1587
|
+
delegation?: {
|
|
1588
|
+
status: "pending" | "confirmed" | "rechecking" | "check_delayed" | "action_required";
|
|
1589
|
+
checked_at?: string;
|
|
1590
|
+
confirmed_at?: string;
|
|
1591
|
+
};
|
|
1555
1592
|
id: string;
|
|
1556
1593
|
domain: string;
|
|
1557
1594
|
mode: OnboardingMode;
|
|
@@ -1566,10 +1603,48 @@ interface Domain {
|
|
|
1566
1603
|
/** Human-facing copy for what the customer must do next. */
|
|
1567
1604
|
instruction?: string;
|
|
1568
1605
|
}
|
|
1606
|
+
interface DomainStatusEvent {
|
|
1607
|
+
id: string;
|
|
1608
|
+
type: string;
|
|
1609
|
+
domain: string;
|
|
1610
|
+
summary: string;
|
|
1611
|
+
data: {
|
|
1612
|
+
domain: string;
|
|
1613
|
+
readiness: DomainReadiness;
|
|
1614
|
+
};
|
|
1615
|
+
created_at: string;
|
|
1616
|
+
}
|
|
1617
|
+
interface DomainStatusEventPage {
|
|
1618
|
+
items: DomainStatusEvent[];
|
|
1619
|
+
next_cursor: string;
|
|
1620
|
+
has_more: boolean;
|
|
1621
|
+
poll_after_seconds: number;
|
|
1622
|
+
}
|
|
1623
|
+
interface DomainReadiness {
|
|
1624
|
+
status: "waiting_for_dns" | "checking" | "setting_up" | "ready" | "action_required" | "needs_attention";
|
|
1625
|
+
label: string;
|
|
1626
|
+
summary: string;
|
|
1627
|
+
reason: string;
|
|
1628
|
+
action_required_by: "customer" | "extrovert" | "none";
|
|
1629
|
+
next_action: "check_dns_entries" | "restore_dns" | "wait" | "create_inbox" | "use_inbox" | "ask_owner_to_create_inbox";
|
|
1630
|
+
/** Domain configuration only; creating an inbox still requires permission and available plan capacity. */
|
|
1631
|
+
ready_for_inboxes: boolean;
|
|
1632
|
+
checked_at?: IsoTimestamp;
|
|
1633
|
+
next_check_at?: IsoTimestamp;
|
|
1634
|
+
poll_after_seconds: number;
|
|
1635
|
+
/** Omitted without inbox-read permission. Counts never imply organization-wide visibility for an agent. */
|
|
1636
|
+
inboxes?: {
|
|
1637
|
+
scope: "agent" | "project" | "organization";
|
|
1638
|
+
total: number;
|
|
1639
|
+
ready: number;
|
|
1640
|
+
setting_up: number;
|
|
1641
|
+
needs_attention: number;
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1569
1644
|
/**
|
|
1570
1645
|
* Result of an ACCEPTED domain offboard (`DELETE /v1/domains/{domain}` → HTTP 202).
|
|
1571
|
-
* Teardown
|
|
1572
|
-
* the DNS zone/records and the domain row
|
|
1646
|
+
* Teardown: reaping the outbound provider senders + routing rows, then scrubbing
|
|
1647
|
+
* the DNS zone/records and the domain row: runs as an async job. Poll `status_url`
|
|
1573
1648
|
* (`GET /v1/jobs/{job_id}`, via {@link Job} / `client.getJob(job_id)`) until
|
|
1574
1649
|
* `status` is terminal (succeeded/failed/cancelled); the domain is ACCEPTED for
|
|
1575
1650
|
* offboard, not yet fully torn down when this returns.
|
|
@@ -1594,6 +1669,95 @@ interface Job {
|
|
|
1594
1669
|
updated_at: IsoTimestamp;
|
|
1595
1670
|
finished_at?: IsoTimestamp;
|
|
1596
1671
|
}
|
|
1672
|
+
/** One exact reason a commerce request cannot advance automatically. */
|
|
1673
|
+
interface CommerceBlocker {
|
|
1674
|
+
code: string;
|
|
1675
|
+
message: string;
|
|
1676
|
+
scope?: "org" | "project" | "agent" | string;
|
|
1677
|
+
limit_id?: string;
|
|
1678
|
+
used_cents?: number;
|
|
1679
|
+
reserved_cents?: number;
|
|
1680
|
+
limit_cents?: number;
|
|
1681
|
+
requested_cents?: number;
|
|
1682
|
+
used_count?: number;
|
|
1683
|
+
reserved_count?: number;
|
|
1684
|
+
limit_count?: number;
|
|
1685
|
+
reset_at?: IsoTimestamp;
|
|
1686
|
+
manage_url?: string;
|
|
1687
|
+
}
|
|
1688
|
+
/** Request body for the non-spending domain quote endpoint. */
|
|
1689
|
+
interface QuoteDomainRequest {
|
|
1690
|
+
domain: string;
|
|
1691
|
+
}
|
|
1692
|
+
/** Current, expiring domain registration quote. Quoting never purchases. */
|
|
1693
|
+
interface DomainQuote {
|
|
1694
|
+
object: "domain_quote";
|
|
1695
|
+
domain: string;
|
|
1696
|
+
available: boolean;
|
|
1697
|
+
currency: string;
|
|
1698
|
+
quote_cents: number;
|
|
1699
|
+
renewal_cents: number;
|
|
1700
|
+
premium: boolean;
|
|
1701
|
+
quote_expires_at: IsoTimestamp;
|
|
1702
|
+
required_plan?: string;
|
|
1703
|
+
required_plan_price_cents?: number;
|
|
1704
|
+
blockers: CommerceBlocker[];
|
|
1705
|
+
}
|
|
1706
|
+
type CommerceRequestKind = "domain_purchase" | "plan_change";
|
|
1707
|
+
interface RequestDomainPurchaseRequest {
|
|
1708
|
+
domain: string;
|
|
1709
|
+
/** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
|
|
1710
|
+
idempotency_key: string;
|
|
1711
|
+
scope?: DomainScope;
|
|
1712
|
+
rationale?: string;
|
|
1713
|
+
auto_renew?: boolean;
|
|
1714
|
+
}
|
|
1715
|
+
interface RequestPlanChangeRequest {
|
|
1716
|
+
target_plan: "free" | "developer" | "startup";
|
|
1717
|
+
/** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
|
|
1718
|
+
idempotency_key: string;
|
|
1719
|
+
rationale?: string;
|
|
1720
|
+
}
|
|
1721
|
+
interface ListCommerceRequestsParams {
|
|
1722
|
+
limit?: number;
|
|
1723
|
+
page?: string;
|
|
1724
|
+
}
|
|
1725
|
+
/** Durable poll shape for an agent-initiated financial request. */
|
|
1726
|
+
interface CommerceRequest {
|
|
1727
|
+
object: "commerce_request";
|
|
1728
|
+
id: string;
|
|
1729
|
+
project_id?: string;
|
|
1730
|
+
agent_id?: string;
|
|
1731
|
+
kind: CommerceRequestKind;
|
|
1732
|
+
state: string;
|
|
1733
|
+
domain?: string;
|
|
1734
|
+
domain_scope?: DomainScope;
|
|
1735
|
+
target_plan?: string;
|
|
1736
|
+
current_plan?: string;
|
|
1737
|
+
rationale?: string;
|
|
1738
|
+
currency: string;
|
|
1739
|
+
quote_cents: number;
|
|
1740
|
+
renewal_cents: number;
|
|
1741
|
+
approved_max_cents?: number;
|
|
1742
|
+
quote_expires_at?: IsoTimestamp;
|
|
1743
|
+
auto_renew: boolean;
|
|
1744
|
+
required_plan?: string;
|
|
1745
|
+
required_plan_price_cents?: number;
|
|
1746
|
+
blocker_code?: string;
|
|
1747
|
+
blockers: CommerceBlocker[];
|
|
1748
|
+
approval_url?: string;
|
|
1749
|
+
payment_action_url?: string;
|
|
1750
|
+
external_job_id?: string;
|
|
1751
|
+
effective_at?: IsoTimestamp;
|
|
1752
|
+
notification_state?: string;
|
|
1753
|
+
notification_last_error?: string;
|
|
1754
|
+
agent_next_action: string;
|
|
1755
|
+
retry_safe: boolean;
|
|
1756
|
+
poll_after_seconds: number;
|
|
1757
|
+
version: number;
|
|
1758
|
+
created_at: IsoTimestamp;
|
|
1759
|
+
updated_at: IsoTimestamp;
|
|
1760
|
+
}
|
|
1597
1761
|
/**
|
|
1598
1762
|
* One event from the SSE stream (`GET /v1/inboxes/{addr}/stream` or `GET
|
|
1599
1763
|
* /v1/events`). It is the SAME envelope a webhook delivers, so a stream consumer
|
|
@@ -1630,12 +1794,12 @@ interface StreamOptions {
|
|
|
1630
1794
|
interface SignUpRequest {
|
|
1631
1795
|
/** Human email that receives the one-time verification code. */
|
|
1632
1796
|
human_email: string;
|
|
1633
|
-
/** Desired local
|
|
1797
|
+
/** Desired local part on `free.extrovertmail.com`. It must normalize to at least 5 characters and cannot use a reserved name. */
|
|
1634
1798
|
username?: string;
|
|
1635
1799
|
}
|
|
1636
1800
|
/**
|
|
1637
1801
|
* Response from `POST /v1/agent/sign-up`. The `agent_key` is a LIMITED-scope key
|
|
1638
|
-
* (
|
|
1802
|
+
* (verification-only, with no inbox read or send permission) that expires with the emailed code. Successful verification revokes
|
|
1639
1803
|
* it and returns a replacement full-scope key. The OTP itself is never returned.
|
|
1640
1804
|
*/
|
|
1641
1805
|
interface SignUpResponse {
|
|
@@ -1645,7 +1809,7 @@ interface SignUpResponse {
|
|
|
1645
1809
|
agent_key: string;
|
|
1646
1810
|
key_prefix: string;
|
|
1647
1811
|
scopes: Scope[];
|
|
1648
|
-
/** The first inbox
|
|
1812
|
+
/** The first inbox created for the agent. */
|
|
1649
1813
|
address: string;
|
|
1650
1814
|
verified: boolean;
|
|
1651
1815
|
/** Where the verification code was sent. */
|
|
@@ -1694,14 +1858,28 @@ interface VerifyResponse {
|
|
|
1694
1858
|
org_claim_token?: string;
|
|
1695
1859
|
}
|
|
1696
1860
|
/**
|
|
1697
|
-
* Response from `GET /v1/auth/me
|
|
1861
|
+
* Response from `GET /v1/auth/me`: the verified principal behind the key.
|
|
1698
1862
|
*
|
|
1699
1863
|
* `org_id`/`project_id` are the FIXED org/project the key is bound to (resolved from
|
|
1700
1864
|
* the stored key, never client input). There is NO mutable project selector for a
|
|
1701
|
-
* scoped key
|
|
1865
|
+
* scoped key: `whoami` is the canonical project-visibility surface; project
|
|
1702
1866
|
* selection happens when the human/admin issues the enrollment token or agent key.
|
|
1703
1867
|
*/
|
|
1704
1868
|
interface WhoAmI {
|
|
1869
|
+
connection_status?: "connected";
|
|
1870
|
+
summary?: string;
|
|
1871
|
+
agent_name?: string;
|
|
1872
|
+
organization_name?: string;
|
|
1873
|
+
project_name?: string;
|
|
1874
|
+
/** Granted permissions, not a guarantee of plan capacity or review approval. */
|
|
1875
|
+
capabilities?: {
|
|
1876
|
+
read_domain_status: boolean;
|
|
1877
|
+
connect_owned_domains: boolean;
|
|
1878
|
+
create_inboxes: boolean;
|
|
1879
|
+
read_inboxes: boolean;
|
|
1880
|
+
submit_mail_for_review: boolean;
|
|
1881
|
+
request_purchases: boolean;
|
|
1882
|
+
};
|
|
1705
1883
|
customer_id: string;
|
|
1706
1884
|
/**
|
|
1707
1885
|
* The fixed org the key is bound to. Optional to match the OpenAPI contract: a
|
|
@@ -1717,13 +1895,31 @@ interface WhoAmI {
|
|
|
1717
1895
|
key_id: string;
|
|
1718
1896
|
scopes: Scope[];
|
|
1719
1897
|
}
|
|
1898
|
+
/** Learn writing guidance from an authenticated human turn on your review. */
|
|
1899
|
+
interface LearnReviewRuleRequest {
|
|
1900
|
+
client_id: string;
|
|
1901
|
+
source_turn_id: string;
|
|
1902
|
+
rule_text: string;
|
|
1903
|
+
target: "org_house" | "project_general" | "category";
|
|
1904
|
+
category_id?: string;
|
|
1905
|
+
kind?: "soft" | "hard";
|
|
1906
|
+
supersedes_id?: string;
|
|
1907
|
+
}
|
|
1908
|
+
interface LearnedReviewRule {
|
|
1909
|
+
rule: Rule;
|
|
1910
|
+
source_review_id: string;
|
|
1911
|
+
source_turn_id: string;
|
|
1912
|
+
human_id: string;
|
|
1913
|
+
audit_id: string;
|
|
1914
|
+
propagation: "queued";
|
|
1915
|
+
}
|
|
1720
1916
|
|
|
1721
1917
|
/**
|
|
1722
1918
|
* The ONE list envelope + opaque-cursor iteration (redesign §5.2 / §6.2).
|
|
1723
1919
|
*
|
|
1724
1920
|
* Every redesign collection endpoint (the canonical `x.projects.inboxes.*` chain
|
|
1725
1921
|
* and beyond) returns {@link List}: `{ object: "list", data, has_more, next_cursor }`.
|
|
1726
|
-
* `next_cursor` is OPAQUE
|
|
1922
|
+
* `next_cursor` is OPAQUE - treat it as a token and pass it back verbatim as
|
|
1727
1923
|
* `?cursor` to fetch the next page. {@link ListPage} wraps a raw {@link List} with
|
|
1728
1924
|
* ergonomic iteration (`for await … of`) and a `nextPage()` cursor walker so callers
|
|
1729
1925
|
* never thread cursors by hand.
|
|
@@ -1773,7 +1969,7 @@ declare class ListPage<T> implements AsyncIterable<T> {
|
|
|
1773
1969
|
readonly object: "list";
|
|
1774
1970
|
constructor(raw: List<T>, fetcher: PageFetcher<T>);
|
|
1775
1971
|
/**
|
|
1776
|
-
* Fetch the next page. Throws if there is none
|
|
1972
|
+
* Fetch the next page. Throws if there is none - guard with {@link hasMore}.
|
|
1777
1973
|
*/
|
|
1778
1974
|
nextPage(signal?: AbortSignal): Promise<ListPage<T>>;
|
|
1779
1975
|
/**
|
|
@@ -1849,12 +2045,25 @@ interface Transport {
|
|
|
1849
2045
|
precheckSuppression(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
|
|
1850
2046
|
listSuppressions(params: ListSuppressionsParams, signal?: AbortSignal): Promise<Page<SuppressionEntry>>;
|
|
1851
2047
|
revokeSuppression(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
|
|
1852
|
-
listDomains(signal?: AbortSignal
|
|
2048
|
+
listDomains(signal?: AbortSignal, params?: {
|
|
2049
|
+
page?: string;
|
|
2050
|
+
limit?: number;
|
|
2051
|
+
}): Promise<Page<Domain>>;
|
|
2052
|
+
listDomainEvents(domain: string, params: {
|
|
2053
|
+
after?: string;
|
|
2054
|
+
limit?: number;
|
|
2055
|
+
}, signal?: AbortSignal): Promise<DomainStatusEventPage>;
|
|
1853
2056
|
getDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
|
|
1854
2057
|
onboardDomain(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
|
|
1855
2058
|
verifyDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
|
|
1856
2059
|
offboardDomain(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
|
|
1857
2060
|
getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
|
|
2061
|
+
quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
|
|
2062
|
+
requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
2063
|
+
requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
2064
|
+
getCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
2065
|
+
cancelCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
2066
|
+
listCommerceRequests(params: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
|
|
1858
2067
|
submitForReview(address: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
1859
2068
|
submitReplyForReview(address: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
1860
2069
|
listReviews(params: ListReviewsParams, signal?: AbortSignal): Promise<Page<Review>>;
|
|
@@ -1880,6 +2089,7 @@ interface Transport {
|
|
|
1880
2089
|
getScanBacklogStatus(categoryId: string, signal?: AbortSignal): Promise<ScanBacklogStatus>;
|
|
1881
2090
|
getCategoryPacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
|
|
1882
2091
|
getRules(params: GetRulesParams, signal?: AbortSignal): Promise<RuleSnapshot>;
|
|
2092
|
+
learnReviewRule(reviewId: string, req: LearnReviewRuleRequest, signal?: AbortSignal): Promise<LearnedReviewRule>;
|
|
1883
2093
|
saveRule(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
|
|
1884
2094
|
promoteRule(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
|
|
1885
2095
|
retireRule(ruleId: string, signal?: AbortSignal): Promise<Rule>;
|
|
@@ -1903,7 +2113,7 @@ interface Transport {
|
|
|
1903
2113
|
*
|
|
1904
2114
|
* The mock honors the same request/response models as the real API and reproduces the few behaviors
|
|
1905
2115
|
* the SDK ergonomics depend on (enrollment cap, idempotency on `client_id`, wait_for_email returning
|
|
1906
|
-
* an OTP). It is intentionally simple
|
|
2116
|
+
* an OTP). It is intentionally simple - not a full server - and never reaches the network.
|
|
1907
2117
|
*/
|
|
1908
2118
|
|
|
1909
2119
|
/**
|
|
@@ -1931,7 +2141,7 @@ declare class MockBackend {
|
|
|
1931
2141
|
* Normalize an inbox ref (opaque id OR address alias) to the canonical address the
|
|
1932
2142
|
* mock keys its message/thread/contact maps on. The SDK now routes inbox ops by the
|
|
1933
2143
|
* canonical opaque `id` when it holds a full record (matching the contract's
|
|
1934
|
-
* canonical-key semantics), so the mock must resolve an id back to its address
|
|
2144
|
+
* canonical-key semantics), so the mock must resolve an id back to its address -
|
|
1935
2145
|
* both key `state.inboxes` (same object), `state.messages` keys by address only.
|
|
1936
2146
|
* Unknown refs pass through unchanged so the existing not-found paths still fire.
|
|
1937
2147
|
*/
|
|
@@ -1961,8 +2171,8 @@ declare class MockBackend {
|
|
|
1961
2171
|
forward(address: string, messageId: string, req: ForwardRequest): SendOutcome;
|
|
1962
2172
|
/**
|
|
1963
2173
|
* Submit a new message for review (mock). Rides the SAME endpoint as `send` on
|
|
1964
|
-
* the real server, so it is literally the same call here: the resolved policy
|
|
1965
|
-
* not which SDK method you picked
|
|
2174
|
+
* the real server, so it is literally the same call here: the resolved policy -
|
|
2175
|
+
* not which SDK method you picked - decides whether the message is queued
|
|
1966
2176
|
* (`kind:"queued_for_review"`) or delivered.
|
|
1967
2177
|
*/
|
|
1968
2178
|
submitForReview(address: string, req: SendRequest): SendOutcome;
|
|
@@ -1983,9 +2193,9 @@ declare class MockBackend {
|
|
|
1983
2193
|
private setReviewState;
|
|
1984
2194
|
/** Mark a review delivered on an auto-send path and emit its terminal `sent` nudge. */
|
|
1985
2195
|
private markReviewAutoSent;
|
|
1986
|
-
/** Raw delivery for a send
|
|
2196
|
+
/** Raw delivery for a send - no policy, only reachable from submitOutbound. */
|
|
1987
2197
|
private deliverSend;
|
|
1988
|
-
/** Raw delivery for a reply
|
|
2198
|
+
/** Raw delivery for a reply - no policy, only reachable from submitOutbound. */
|
|
1989
2199
|
private deliverReply;
|
|
1990
2200
|
/** Append the outbound message and shape the legacy send result. */
|
|
1991
2201
|
private deliverRaw;
|
|
@@ -2049,7 +2259,7 @@ declare class MockBackend {
|
|
|
2049
2259
|
reviewerDecide(reviewId: string, req: ReviewerDecisionRequest): ReviewerDecisionResult | undefined;
|
|
2050
2260
|
/**
|
|
2051
2261
|
* Browse the registry (mock), newest-first, excluding merged/soft-deleted. `match`
|
|
2052
|
-
* is a pure lexical filter (every token must appear in name+description)
|
|
2262
|
+
* is a pure lexical filter (every token must appear in name+description) - NO LLM,
|
|
2053
2263
|
* mirroring the server.
|
|
2054
2264
|
*/
|
|
2055
2265
|
listCategories(params?: ListCategoriesParams): Page<Category>;
|
|
@@ -2057,14 +2267,14 @@ declare class MockBackend {
|
|
|
2057
2267
|
getCategory(categoryId: string): Category | undefined;
|
|
2058
2268
|
/** Propose a category (mock): stands immediately, author_kind=agent (D9). */
|
|
2059
2269
|
proposeCategory(req: ProposeCategoryRequest): Category;
|
|
2060
|
-
/** Rename / re-describe a category (mock)
|
|
2270
|
+
/** Rename / re-describe a category (mock) - metadata only (D10). */
|
|
2061
2271
|
updateCategory(categoryId: string, req: UpdateCategoryRequest): Category | undefined;
|
|
2062
2272
|
/** The mock account-default risk dial (mirrors the server defaults). */
|
|
2063
2273
|
private accountDial;
|
|
2064
2274
|
/**
|
|
2065
2275
|
* Read the effective risk dial (mock): the account default + every category with an
|
|
2066
2276
|
* inherited (null override) effective dial. The mock category carries no overrides,
|
|
2067
|
-
* so every category inherits
|
|
2277
|
+
* so every category inherits - effective == account.
|
|
2068
2278
|
*/
|
|
2069
2279
|
getRiskDial(): RiskDial;
|
|
2070
2280
|
private nextGraduationState;
|
|
@@ -2076,19 +2286,19 @@ declare class MockBackend {
|
|
|
2076
2286
|
getGraduationStatus(categoryId: string): GraduationStatus | undefined;
|
|
2077
2287
|
/**
|
|
2078
2288
|
* Propose graduating a category (mock): returns the current gate status without
|
|
2079
|
-
* changing the category state (D16
|
|
2289
|
+
* changing the category state (D16 - an agent can never flip the bit).
|
|
2080
2290
|
*/
|
|
2081
2291
|
proposeGraduation(categoryId: string, _req: ProposeGraduationRequest): GraduationStatus | undefined;
|
|
2082
2292
|
/**
|
|
2083
2293
|
* Read the D19/§8 backlog-reconciliation status (mock): counts the QUEUED drafts in a
|
|
2084
2294
|
* category that are stale vs current-enough against the current rules-version. The
|
|
2085
2295
|
* mock has no per-draft composed_* stamps on its Review fixtures, so every queued
|
|
2086
|
-
* draft reads as current-enough (composed 0 vs current 0)
|
|
2296
|
+
* draft reads as current-enough (composed 0 vs current 0) - the contract shape is
|
|
2087
2297
|
* exercised; the integer-compare logic is covered by the Go tests.
|
|
2088
2298
|
*/
|
|
2089
2299
|
getScanBacklogStatus(categoryId: string): ScanBacklogStatus | undefined;
|
|
2090
2300
|
/**
|
|
2091
|
-
* Read the demand-driven pacing state (mock
|
|
2301
|
+
* Read the demand-driven pacing state (mock - M7 Slice B/§8): the cursor + effective
|
|
2092
2302
|
* window/ceiling/interval + each queued draft's classification. The mock has no cursor
|
|
2093
2303
|
* (nothing reviewed) and no composed_* stamps, so every queued draft reads in-window-
|
|
2094
2304
|
* fresh until the window fills, then ahead; the contract shape is exercised (the
|
|
@@ -2097,17 +2307,19 @@ declare class MockBackend {
|
|
|
2097
2307
|
getCategoryPacingState(categoryId: string): CategoryPacingState | undefined;
|
|
2098
2308
|
/** rank a rule for the §7 ladder (mock mirror of the server's deterministic order). */
|
|
2099
2309
|
private ruleRank;
|
|
2100
|
-
/** Get the ORDERED active rule set (mock)
|
|
2310
|
+
/** Get the ORDERED active rule set (mock) - §7 ladder + category-before-general. */
|
|
2101
2311
|
getRules(params?: GetRulesParams): RuleSnapshot;
|
|
2102
|
-
/** Save / edit a rule (mock)
|
|
2312
|
+
/** Save / edit a rule (mock) - append-only by supersession (D11). */
|
|
2313
|
+
private learnedRules;
|
|
2314
|
+
learnReviewRule(reviewId: string, req: LearnReviewRuleRequest): LearnedReviewRule;
|
|
2103
2315
|
saveRule(req: SaveRuleRequest): Rule;
|
|
2104
2316
|
/** Promote a rule between layers (mock, via supersession), or undefined when unknown. */
|
|
2105
2317
|
promoteRule(ruleId: string, toScope: "general" | "category"): Rule | undefined;
|
|
2106
|
-
/** Retire a rule (mock)
|
|
2318
|
+
/** Retire a rule (mock) - soft delete, or undefined when unknown. */
|
|
2107
2319
|
retireRule(ruleId: string): Rule | undefined;
|
|
2108
2320
|
/** Read the rule/category change audit log (mock). */
|
|
2109
2321
|
getRuleAudit(params?: GetRuleAuditParams): Page<RuleAuditEntry>;
|
|
2110
|
-
/** Undo a rule change (mock)
|
|
2322
|
+
/** Undo a rule change (mock) - restore the prior version; idempotent (re-undo 409). */
|
|
2111
2323
|
undoRuleChange(udoId: string): Rule;
|
|
2112
2324
|
/** recordRuleAudit appends one change/undo audit row (mock). */
|
|
2113
2325
|
private recordRuleAudit;
|
|
@@ -2124,7 +2336,7 @@ declare class MockBackend {
|
|
|
2124
2336
|
*/
|
|
2125
2337
|
private enqueueTerminalNudge;
|
|
2126
2338
|
/**
|
|
2127
|
-
* Enqueue `front_run_next`
|
|
2339
|
+
* Enqueue `front_run_next` - the signal that the review reached a terminal state
|
|
2128
2340
|
* while the agent was still trying to act on it.
|
|
2129
2341
|
*
|
|
2130
2342
|
* Deduped on (review, terminal state, parent revision) so a retry loop hitting
|
|
@@ -2142,8 +2354,8 @@ declare class MockBackend {
|
|
|
2142
2354
|
}): Review | undefined;
|
|
2143
2355
|
/**
|
|
2144
2356
|
* Mock-only: mirror an approved draft whose delivery then FAILED at the provider.
|
|
2145
|
-
* This is the case the composing agent was previously never told about
|
|
2146
|
-
* console showed the error and the agent's queue stayed silent
|
|
2357
|
+
* This is the case the composing agent was previously never told about - the
|
|
2358
|
+
* console showed the error and the agent's queue stayed silent - so the loop test
|
|
2147
2359
|
* that matters most drives this path.
|
|
2148
2360
|
*/
|
|
2149
2361
|
simulateSendFailed(reviewId: string, error?: string): Review | undefined;
|
|
@@ -2171,7 +2383,7 @@ declare class MockBackend {
|
|
|
2171
2383
|
listReviewEvents(params?: ListReviewEventsParams): ReviewEventsResult;
|
|
2172
2384
|
/**
|
|
2173
2385
|
* Long-poll for a review event (mock). Offline there is nothing to wait FOR, so it
|
|
2174
|
-
* returns the immediate drain (empty when caught up)
|
|
2386
|
+
* returns the immediate drain (empty when caught up) - the server's "empty on
|
|
2175
2387
|
* timeout" contract.
|
|
2176
2388
|
*/
|
|
2177
2389
|
waitForReviewEvent(params?: WaitForReviewEventParams): ReviewEventsResult;
|
|
@@ -2194,9 +2406,10 @@ declare class MockBackend {
|
|
|
2194
2406
|
getMessageRaw(messageId: string): string;
|
|
2195
2407
|
/** Full-text search scoped to one inbox. */
|
|
2196
2408
|
searchMessages(address: string, params: SearchMessagesParams): Page<Message>;
|
|
2197
|
-
listThreads(address: string): Page<Thread>;
|
|
2409
|
+
listThreads(address: string, params?: ListThreadsParams): Page<Thread>;
|
|
2198
2410
|
/** Thread-level search (subject / snippet / participant substring). */
|
|
2199
2411
|
searchThreads(address: string, params: SearchMessagesParams): Page<Thread>;
|
|
2412
|
+
private paginateThreads;
|
|
2200
2413
|
/** Fetch one thread (with messages, oldest-first) by id under an inbox. */
|
|
2201
2414
|
getThread(address: string, threadId: string): ThreadDetail;
|
|
2202
2415
|
/**
|
|
@@ -2251,7 +2464,7 @@ declare class MockBackend {
|
|
|
2251
2464
|
listContactLists(address: string): Page<ContactListEntry> | undefined;
|
|
2252
2465
|
/** Delete a contact-list entry by id; returns false when it was not found. */
|
|
2253
2466
|
deleteContactListEntry(_address: string, entryId: string): boolean;
|
|
2254
|
-
/**
|
|
2467
|
+
/** Add a delegated domain and return only the customer-published nameservers. */
|
|
2255
2468
|
onboardDomain(req: OnboardDomainRequest): Domain;
|
|
2256
2469
|
/** List onboarded domains (records omitted on the summary, mirroring the server). */
|
|
2257
2470
|
listDomains(): Page<Domain>;
|
|
@@ -2268,6 +2481,12 @@ declare class MockBackend {
|
|
|
2268
2481
|
offboardDomain(domain: string): boolean;
|
|
2269
2482
|
/** Get one async job's poll status; undefined when the id is unknown. */
|
|
2270
2483
|
getJob(jobId: string): Job | undefined;
|
|
2484
|
+
quoteDomain(req: QuoteDomainRequest): DomainQuote;
|
|
2485
|
+
requestDomainPurchase(req: RequestDomainPurchaseRequest): CommerceRequest;
|
|
2486
|
+
requestPlanChange(req: RequestPlanChangeRequest): CommerceRequest;
|
|
2487
|
+
getCommerceRequest(requestId: string): CommerceRequest | undefined;
|
|
2488
|
+
cancelCommerceRequest(requestId: string): CommerceRequest | undefined;
|
|
2489
|
+
listCommerceRequests(params?: ListCommerceRequestsParams): Page<CommerceRequest>;
|
|
2271
2490
|
/**
|
|
2272
2491
|
* Pre-check whether the caller's org suppresses a recipient (mirrors
|
|
2273
2492
|
* `GET /v1/suppressions?recipient=…`). Returns `{recipient, suppressed, rows}`
|
|
@@ -2285,7 +2504,7 @@ declare class MockBackend {
|
|
|
2285
2504
|
/**
|
|
2286
2505
|
* Reject the WHOLE send if ANY recipient has an active org-scope suppression,
|
|
2287
2506
|
* naming exactly the suppressed addresses (never the scope/origin) so the caller
|
|
2288
|
-
* can drop them and retry
|
|
2507
|
+
* can drop them and retry - mirroring the live `recipient_suppressed` (422) path.
|
|
2289
2508
|
*/
|
|
2290
2509
|
private enforceSuppression;
|
|
2291
2510
|
/**
|
|
@@ -2296,19 +2515,25 @@ declare class MockBackend {
|
|
|
2296
2515
|
private enforceSendPolicy;
|
|
2297
2516
|
}
|
|
2298
2517
|
|
|
2518
|
+
interface DomainWaitResult {
|
|
2519
|
+
domain: Domain;
|
|
2520
|
+
outcome: "ready" | "action_required" | "needs_attention" | "timed_out" | "status_unavailable";
|
|
2521
|
+
resume_after_seconds: number;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2299
2524
|
/**
|
|
2300
2525
|
* Key-tier awareness (redesign §3.1).
|
|
2301
2526
|
*
|
|
2302
2527
|
* An agent key encodes its CEILING tier in its raw prefix. The SDK never trusts
|
|
2303
|
-
* client input for scope
|
|
2528
|
+
* client input for scope - the tier is derived from the key the caller already
|
|
2304
2529
|
* holds, purely as a client-side hint so an app can branch (e.g. an org-tier key
|
|
2305
2530
|
* MUST pick a project breadth on a list; a project/inbox key may use the bare
|
|
2306
2531
|
* sugar). The server remains the source of truth; this is advisory only.
|
|
2307
2532
|
*
|
|
2308
2533
|
* Prefix scheme (the secret tail is unchanged across tiers):
|
|
2309
|
-
* - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console
|
|
2534
|
+
* - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console issuance only)
|
|
2310
2535
|
* - `pk_agent_proj_…` → {@link KeyTier.Project} (enrollment redeem + console)
|
|
2311
|
-
* - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console
|
|
2536
|
+
* - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console issuance only)
|
|
2312
2537
|
* - legacy `pk_agent_…` (no tier segment) → {@link KeyTier.Project}
|
|
2313
2538
|
*/
|
|
2314
2539
|
/** The ceiling tier encoded in an agent key's prefix. */
|
|
@@ -2316,7 +2541,7 @@ type KeyTier = "org" | "project" | "inbox" | "unknown";
|
|
|
2316
2541
|
/**
|
|
2317
2542
|
* Derive the {@link KeyTier} from a raw agent key by peeking the segment after the
|
|
2318
2543
|
* `pk_agent_` head. A legacy bare `pk_agent_…` key (no tier segment) maps to
|
|
2319
|
-
* `"project"`
|
|
2544
|
+
* `"project"` - exactly today's behavior. A non-agent credential (enrollment
|
|
2320
2545
|
* token, Clerk session, empty) returns `"unknown"`.
|
|
2321
2546
|
*/
|
|
2322
2547
|
declare function parseKeyTier(apiKey: string | undefined): KeyTier;
|
|
@@ -2334,7 +2559,7 @@ declare function tierAllowsOrgWildcard(tier: KeyTier): boolean;
|
|
|
2334
2559
|
declare function tierNeedsExplicitBreadth(tier: KeyTier): boolean;
|
|
2335
2560
|
|
|
2336
2561
|
/**
|
|
2337
|
-
* InboxHandle
|
|
2562
|
+
* InboxHandle: an ergonomic, bound handle to a single inbox.
|
|
2338
2563
|
*
|
|
2339
2564
|
* Returned by `extrovert.inboxes.create(...)` and `extrovert.inbox(address)`, it scopes every operation
|
|
2340
2565
|
* to one address so agent code reads naturally: `inbox.send(...)`, `inbox.waitForEmail(...)`. This
|
|
@@ -2348,7 +2573,7 @@ interface InboxHandleOptions {
|
|
|
2348
2573
|
declare class InboxHandle {
|
|
2349
2574
|
private readonly transport;
|
|
2350
2575
|
private readonly options;
|
|
2351
|
-
/** The canonical address, e.g. `agent7@
|
|
2576
|
+
/** The canonical address, e.g. `agent7@extrovertmail.com`. */
|
|
2352
2577
|
readonly address: string;
|
|
2353
2578
|
/** The full inbox record this handle was created from (absent when constructed by address). */
|
|
2354
2579
|
readonly record: Inbox | undefined;
|
|
@@ -2394,8 +2619,8 @@ declare class InboxHandle {
|
|
|
2394
2619
|
* Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
|
|
2395
2620
|
* human has to approve it and NOTHING has been delivered yet; anything else was
|
|
2396
2621
|
* delivered. Under the default `require_review` policy a call WITHOUT an
|
|
2397
|
-
* `intent` raises `IntentRequiredError` (422) instead
|
|
2398
|
-
* queued
|
|
2622
|
+
* `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
|
|
2623
|
+
* queued: so pass one, or read `inbox.record.effective_review_policy` first.
|
|
2399
2624
|
*/
|
|
2400
2625
|
send(req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
2401
2626
|
/**
|
|
@@ -2403,14 +2628,14 @@ declare class InboxHandle {
|
|
|
2403
2628
|
* the latest message) or `message_id` (reply to that message); the server
|
|
2404
2629
|
* derives To / Subject / In-Reply-To / References. Set `reply_all` to reply to
|
|
2405
2630
|
* every thread recipient. Returns the same three-way {@link SendOutcome} as
|
|
2406
|
-
* {@link send}
|
|
2631
|
+
* {@link send}: a reply is governed by the review policy too.
|
|
2407
2632
|
*/
|
|
2408
2633
|
reply(req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
2409
2634
|
/**
|
|
2410
2635
|
* Forward a message in this inbox to new recipients, preserving the original.
|
|
2411
2636
|
*
|
|
2412
2637
|
* A forward is an outbound message to arbitrary NEW recipients that quotes an
|
|
2413
|
-
* inbound thread, so it is governed by the review policy exactly like a send
|
|
2638
|
+
* inbound thread, so it is governed by the review policy exactly like a send :
|
|
2414
2639
|
* same {@link SendOutcome} union, same `intent` requirement.
|
|
2415
2640
|
*/
|
|
2416
2641
|
forward(messageId: string, req: ForwardRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
@@ -2511,7 +2736,7 @@ declare class InboxHandle {
|
|
|
2511
2736
|
}
|
|
2512
2737
|
|
|
2513
2738
|
/**
|
|
2514
|
-
* `extrovert.projects
|
|
2739
|
+
* `extrovert.projects`: the CANONICAL project-scoped resource chain (redesign §4).
|
|
2515
2740
|
*
|
|
2516
2741
|
* Scope lives in the KEY; a broad (org-tier) key narrows to one project by PATH.
|
|
2517
2742
|
* The headline chain is `x.projects.inboxes.*`, mirroring
|
|
@@ -2526,7 +2751,7 @@ declare class InboxHandle {
|
|
|
2526
2751
|
*
|
|
2527
2752
|
* Operations are keyed by the OPAQUE `inbox_id` (the inbox's email address is also
|
|
2528
2753
|
* accepted as a within-project alias). `projectId` may be `"-"` for the org-wide
|
|
2529
|
-
* wildcard
|
|
2754
|
+
* wildcard: only an org-tier key may use it (others get 403 `forbidden_scope`).
|
|
2530
2755
|
*
|
|
2531
2756
|
* The bare `x.inboxes.*` / `x.inbox(address)` surface is curl-style sugar that
|
|
2532
2757
|
* resolves to the key's default project; this chain is the contract-canonical one.
|
|
@@ -2538,7 +2763,7 @@ interface ProjectsContext {
|
|
|
2538
2763
|
handleOptions: InboxHandleOptions;
|
|
2539
2764
|
}
|
|
2540
2765
|
/**
|
|
2541
|
-
* `x.projects.inboxes
|
|
2766
|
+
* `x.projects.inboxes`: create / list / get / update / delete inboxes, plus the
|
|
2542
2767
|
* send / reply / message / thread / wait operations, all scoped to one project (or
|
|
2543
2768
|
* the `-` org wildcard for an org-tier key). List returns a {@link ListPage} that
|
|
2544
2769
|
* auto-paginates over the opaque-cursor {@link import("../pagination.js").List} envelope.
|
|
@@ -2574,8 +2799,8 @@ declare class ProjectInboxes {
|
|
|
2574
2799
|
* Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
|
|
2575
2800
|
* human has to approve it and NOTHING has been delivered yet; anything else was
|
|
2576
2801
|
* delivered. Under the default `require_review` policy a call WITHOUT an
|
|
2577
|
-
* `intent` raises `IntentRequiredError` (422) instead
|
|
2578
|
-
* queued
|
|
2802
|
+
* `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
|
|
2803
|
+
* queued: so pass one, or read `inbox.record.effective_review_policy` first.
|
|
2579
2804
|
*/
|
|
2580
2805
|
send(projectId: string, inboxId: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
2581
2806
|
/** Reply within a thread from an inbox in `projectId`. See {@link send} on the return union. */
|
|
@@ -2610,14 +2835,14 @@ declare class ProjectInboxes {
|
|
|
2610
2835
|
*
|
|
2611
2836
|
* The frozen contract project-prefixes ONLY the inbox collection/item/credentials
|
|
2612
2837
|
* routes (`/v1/projects/{project_id}/inboxes[/{inbox_id}][/credentials]`); the
|
|
2613
|
-
* send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path
|
|
2838
|
+
* send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path :
|
|
2614
2839
|
* they address the inbox by its opaque id directly (`/v1/inboxes/{inbox_id}/…`),
|
|
2615
2840
|
* where the project is implicit in (and enforced by) the inbox id server-side.
|
|
2616
2841
|
*
|
|
2617
2842
|
* So for these sub-ops `projectId` cannot be carried on the URL and is NOT a URL
|
|
2618
2843
|
* selector. The adversarial review flagged that silently discarding it makes the
|
|
2619
2844
|
* signature misleading. CHOICE: keep the arg (dropping it would break the chain's
|
|
2620
|
-
* symmetry with create/list/get/update/delete
|
|
2845
|
+
* symmetry with create/list/get/update/delete: the more disruptive option) but
|
|
2621
2846
|
* VALIDATE it rather than ignore it. We reject the two client mistakes we can catch
|
|
2622
2847
|
* without a round-trip:
|
|
2623
2848
|
* - a blank / whitespace-only `projectId` (a required selector everywhere else in
|
|
@@ -2629,12 +2854,12 @@ declare class ProjectInboxes {
|
|
|
2629
2854
|
private ref;
|
|
2630
2855
|
}
|
|
2631
2856
|
/**
|
|
2632
|
-
* `extrovert.projects
|
|
2857
|
+
* `extrovert.projects`: the canonical project-scoped resource namespace. Today it
|
|
2633
2858
|
* exposes the `inboxes` chain (`x.projects.inboxes.*`); future project-scoped
|
|
2634
2859
|
* resources (domains, agents) hang off the same namespace.
|
|
2635
2860
|
*/
|
|
2636
2861
|
declare class Projects {
|
|
2637
|
-
/** `x.projects.inboxes
|
|
2862
|
+
/** `x.projects.inboxes.*`: the canonical inbox chain. */
|
|
2638
2863
|
readonly inboxes: ProjectInboxes;
|
|
2639
2864
|
constructor(ctx: ProjectsContext);
|
|
2640
2865
|
}
|
|
@@ -2655,25 +2880,26 @@ interface ResourceContext {
|
|
|
2655
2880
|
*/
|
|
2656
2881
|
keyTier: KeyTier;
|
|
2657
2882
|
}
|
|
2658
|
-
/** `extrovert.inboxes
|
|
2883
|
+
/** `extrovert.inboxes`: create, list, get, update, delete inboxes. */
|
|
2659
2884
|
declare class Inboxes {
|
|
2660
2885
|
private readonly ctx;
|
|
2661
2886
|
constructor(ctx: ResourceContext);
|
|
2662
2887
|
/**
|
|
2663
|
-
* Create an inbox. The default path
|
|
2664
|
-
* `
|
|
2888
|
+
* Create an inbox. The default path creates an address on `extrovertmail.com`
|
|
2889
|
+
* for paid accounts or `free.extrovertmail.com` for free signups, so it returns
|
|
2890
|
+
* a live inbox in one call.
|
|
2665
2891
|
*
|
|
2666
2892
|
* Pass `metadata` to attach arbitrary key-value data, and `client_id` for idempotent creation
|
|
2667
2893
|
* (re-calling with the same id returns the same inbox, with its metadata replayed verbatim).
|
|
2668
2894
|
*/
|
|
2669
2895
|
create(req?: CreateInboxRequest, signal?: AbortSignal): Promise<InboxHandle>;
|
|
2670
2896
|
/**
|
|
2671
|
-
* List inboxes visible to the calling key (the bare curl-sugar surface
|
|
2897
|
+
* List inboxes visible to the calling key (the bare curl-sugar surface: resolves
|
|
2672
2898
|
* to the key's default project). An org-tier key has no single default project, so
|
|
2673
2899
|
* the bare list is ambiguous: fail fast client-side with a BreadthRequiredError that
|
|
2674
2900
|
* names the next call, matching the MCP surface, instead of round-tripping to a 400.
|
|
2675
2901
|
* Use `extrovert.projects.inboxes.list("<project_id>")` or `"-"` (org subtree) for
|
|
2676
|
-
* an org key. The check is advisory
|
|
2902
|
+
* an org key. The check is advisory: the server stays authoritative.
|
|
2677
2903
|
*/
|
|
2678
2904
|
list(params?: ListInboxesParams, signal?: AbortSignal): Promise<Page<Inbox>>;
|
|
2679
2905
|
/** Fetch a single inbox and return an ergonomic handle bound to it. */
|
|
@@ -2694,7 +2920,7 @@ declare class Inboxes {
|
|
|
2694
2920
|
delete(address: string, signal?: AbortSignal): Promise<void>;
|
|
2695
2921
|
}
|
|
2696
2922
|
/**
|
|
2697
|
-
* `extrovert.messages
|
|
2923
|
+
* `extrovert.messages`: read a message, fetch its raw bytes, mark it read.
|
|
2698
2924
|
*
|
|
2699
2925
|
* Reply and forward are inbox-scoped (the server resolves the parent and derives
|
|
2700
2926
|
* recipients), so they live on the {@link InboxHandle} (`inbox.reply(...)`,
|
|
@@ -2739,21 +2965,27 @@ declare class Messages {
|
|
|
2739
2965
|
getAttachment(inbox: string, messageId: string, attachmentId: string, signal?: AbortSignal): Promise<AttachmentDownload>;
|
|
2740
2966
|
}
|
|
2741
2967
|
/**
|
|
2742
|
-
* `extrovert.threads
|
|
2743
|
-
* scoped to
|
|
2968
|
+
* `extrovert.threads`: list, search, read, reply to, and delete conversations,
|
|
2969
|
+
* scoped to their owning inbox.
|
|
2744
2970
|
*/
|
|
2745
2971
|
declare class Threads {
|
|
2746
2972
|
private readonly ctx;
|
|
2747
2973
|
constructor(ctx: ResourceContext);
|
|
2974
|
+
/** List conversations newest-active first. Pass `next_cursor` back as `cursor` for the next page. */
|
|
2975
|
+
list(inbox: string, params?: ListThreadsParams, signal?: AbortSignal): Promise<Page<Thread>>;
|
|
2976
|
+
/** Search thread subjects, snippets, and participants. Cursor pagination matches {@link list}. */
|
|
2977
|
+
search(inbox: string, params: SearchMessagesParams, signal?: AbortSignal): Promise<Page<Thread>>;
|
|
2748
2978
|
/** Fetch one thread (+ its messages, oldest-first) by id under its owning inbox address. */
|
|
2749
2979
|
get(inbox: string, threadId: string, signal?: AbortSignal): Promise<ThreadDetail>;
|
|
2980
|
+
/** Reply in a thread; recipients and RFC reply headers are derived server-side. */
|
|
2981
|
+
reply(inbox: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
|
|
2750
2982
|
/**
|
|
2751
2983
|
* Delete an entire thread (every message): move to Trash (default) or
|
|
2752
2984
|
* permanently remove when `expunge` is true. `inbox` is the owning address.
|
|
2753
2985
|
*/
|
|
2754
2986
|
delete(inbox: string, threadId: string, expunge?: boolean, signal?: AbortSignal): Promise<DeleteResult>;
|
|
2755
2987
|
}
|
|
2756
|
-
/** `extrovert.webhooks
|
|
2988
|
+
/** `extrovert.webhooks`: register / list / get / update / delete HMAC-signed inbound webhooks. */
|
|
2757
2989
|
declare class Webhooks {
|
|
2758
2990
|
private readonly ctx;
|
|
2759
2991
|
constructor(ctx: ResourceContext);
|
|
@@ -2774,7 +3006,7 @@ declare class Webhooks {
|
|
|
2774
3006
|
delete(webhookId: string, signal?: AbortSignal): Promise<void>;
|
|
2775
3007
|
}
|
|
2776
3008
|
/**
|
|
2777
|
-
* `extrovert.contactLists
|
|
3009
|
+
* `extrovert.contactLists`: per-inbox allow/block lists of addresses/domains.
|
|
2778
3010
|
* A `block` entry rejects a send to a matching recipient; once an `allow` entry
|
|
2779
3011
|
* exists for an inbox, sends from it are restricted to matching recipients
|
|
2780
3012
|
* (allowlist mode). Entries are addressable by their opaque id (`lst_…`).
|
|
@@ -2790,12 +3022,12 @@ declare class ContactLists {
|
|
|
2790
3022
|
delete(inbox: string, entryId: string, signal?: AbortSignal): Promise<void>;
|
|
2791
3023
|
}
|
|
2792
3024
|
/**
|
|
2793
|
-
* `extrovert.suppressions
|
|
3025
|
+
* `extrovert.suppressions`: recipient opt-outs (list-unsubscribe). A recipient
|
|
2794
3026
|
* that has unsubscribed cannot be mailed by this org: a send to them is rejected
|
|
2795
3027
|
* with `recipient_suppressed` ({@link RecipientSuppressedError}). Use `precheck`
|
|
2796
3028
|
* before composing to skip a would-be-rejected recipient, `list` to browse the
|
|
2797
3029
|
* org's opt-outs, and `revoke` (reason required, audit-logged) to re-enable a
|
|
2798
|
-
* recipient. All reads/writes are scoped to the caller's OWN org
|
|
3030
|
+
* recipient. All reads/writes are scoped to the caller's OWN org: a
|
|
2799
3031
|
* platform-global or shared-domain opt-out is never surfaced here.
|
|
2800
3032
|
*/
|
|
2801
3033
|
declare class Suppressions {
|
|
@@ -2803,7 +3035,7 @@ declare class Suppressions {
|
|
|
2803
3035
|
constructor(ctx: ResourceContext);
|
|
2804
3036
|
/**
|
|
2805
3037
|
* Pre-check whether the caller's org already suppresses a recipient, BEFORE
|
|
2806
|
-
* composing. `suppressed: true` means a send to them would be rejected
|
|
3038
|
+
* composing. `suppressed: true` means a send to them would be rejected: skip
|
|
2807
3039
|
* that recipient. Returns the matching org rows too (never a global/shared row).
|
|
2808
3040
|
*/
|
|
2809
3041
|
precheck(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
|
|
@@ -2817,25 +3049,36 @@ declare class Suppressions {
|
|
|
2817
3049
|
revoke(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
|
|
2818
3050
|
}
|
|
2819
3051
|
/**
|
|
2820
|
-
* `extrovert.domains
|
|
2821
|
-
*
|
|
2822
|
-
*
|
|
2823
|
-
* verification, and offboard.
|
|
2824
|
-
*
|
|
2825
|
-
*
|
|
2826
|
-
* bind the domain to the key's project; it defaults to `org` (org-shared).
|
|
3052
|
+
* `extrovert.domains`: read with domain:read or domain:manage; changes require
|
|
3053
|
+
* domain:manage. Add delegated inbox domains the customer
|
|
3054
|
+
* controls, read status + nameserver records inline, trigger/refresh
|
|
3055
|
+
* verification, and offboard. New registrations use `extrovert.commerce`: quote
|
|
3056
|
+
* first, create a request, then poll its status. Set `scope: "project"` to bind a
|
|
3057
|
+
* customer-controlled domain to the key's project; it defaults to `org`.
|
|
2827
3058
|
*/
|
|
2828
3059
|
declare class Domains {
|
|
2829
3060
|
private readonly ctx;
|
|
2830
3061
|
constructor(ctx: ResourceContext);
|
|
2831
3062
|
/** List the customer's onboarded domains and their status. */
|
|
2832
|
-
list(
|
|
2833
|
-
|
|
3063
|
+
list(paramsOrSignal?: {
|
|
3064
|
+
page?: string;
|
|
3065
|
+
limit?: number;
|
|
3066
|
+
} | AbortSignal, signal?: AbortSignal): Promise<Page<Domain>>;
|
|
3067
|
+
/** Get one domain's detail, verification status, and nameserver records. */
|
|
2834
3068
|
get(domain: string, signal?: AbortSignal): Promise<Domain>;
|
|
2835
|
-
/**
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
3069
|
+
/** Wait up to 50 seconds, then return an explicit resumable outcome. No DNS writes. */
|
|
3070
|
+
wait(domain: string, options?: {
|
|
3071
|
+
timeout_seconds?: number;
|
|
3072
|
+
signal?: AbortSignal;
|
|
3073
|
+
}): Promise<DomainWaitResult>;
|
|
3074
|
+
/** Resume durable updates for this domain using the previous next_cursor as after. */
|
|
3075
|
+
events(domain: string, params?: {
|
|
3076
|
+
after?: string;
|
|
3077
|
+
limit?: number;
|
|
3078
|
+
}, signal?: AbortSignal): Promise<DomainStatusEventPage>;
|
|
3079
|
+
/**
|
|
3080
|
+
* Add a delegated inbox domain the customer controls. Returns the nameserver
|
|
3081
|
+
* records to publish and never spends money.
|
|
2839
3082
|
*/
|
|
2840
3083
|
onboard(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
|
|
2841
3084
|
/** Trigger or refresh verification for a domain; returns its (possibly advanced) status. */
|
|
@@ -2849,7 +3092,29 @@ declare class Domains {
|
|
|
2849
3092
|
offboard(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
|
|
2850
3093
|
}
|
|
2851
3094
|
/**
|
|
2852
|
-
* `extrovert.
|
|
3095
|
+
* `extrovert.commerce`: quote, request, cancel, and poll financial operations. Agents
|
|
3096
|
+
* can never approve a request through this resource; approval is a human console
|
|
3097
|
+
* action. Every create requires a stable idempotency key.
|
|
3098
|
+
*/
|
|
3099
|
+
declare class Commerce {
|
|
3100
|
+
private readonly ctx;
|
|
3101
|
+
constructor(ctx: ResourceContext);
|
|
3102
|
+
private requireIdempotencyKey;
|
|
3103
|
+
/** Quote a domain without purchasing, reserving, or approving it. */
|
|
3104
|
+
quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
|
|
3105
|
+
/** Create a durable domain-purchase request for human approval. */
|
|
3106
|
+
requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
3107
|
+
/** Create a durable plan-upgrade or downgrade request for human approval. */
|
|
3108
|
+
requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
3109
|
+
/** Poll one request's exact blockers, approval URL, and next-action guidance. */
|
|
3110
|
+
get(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
3111
|
+
/** Withdraw this agent's request while its durable state still permits cancellation. */
|
|
3112
|
+
cancel(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
|
|
3113
|
+
/** List visible commerce requests using the API's opaque page token. */
|
|
3114
|
+
list(params?: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
|
|
3115
|
+
}
|
|
3116
|
+
/**
|
|
3117
|
+
* `extrovert.reviews`: the Review Loop (HITL) agent-plane reads. A sending agent
|
|
2853
3118
|
* monitors its submissions in the human-review queue: list/get a review request and
|
|
2854
3119
|
* read its append-only thread of turns (intent, drafts, human comments/edits/
|
|
2855
3120
|
* decisions, captured diffs). Submitting FOR review rides `inbox.send` /
|
|
@@ -2859,7 +3124,7 @@ declare class Domains {
|
|
|
2859
3124
|
declare class Reviews {
|
|
2860
3125
|
private readonly ctx;
|
|
2861
3126
|
/**
|
|
2862
|
-
* `extrovert.reviews.events
|
|
3127
|
+
* `extrovert.reviews.events`: the Review Loop (HITL) realtime plane: drain,
|
|
2863
3128
|
* long-poll, and ack the durable nudge queue (the AUTHORITATIVE liveness source;
|
|
2864
3129
|
* SSE/webhook are best-effort fast paths on top of it).
|
|
2865
3130
|
*/
|
|
@@ -2874,20 +3139,20 @@ declare class Reviews {
|
|
|
2874
3139
|
/**
|
|
2875
3140
|
* Get the human's assembled feedback (M5): the diff + comments + decision + the
|
|
2876
3141
|
* rules born from this review. Read it after a rejected/edited nudge to learn what
|
|
2877
|
-
* the human wanted. $0 LLM
|
|
3142
|
+
* the human wanted. $0 LLM: pure assembly on our side.
|
|
2878
3143
|
*/
|
|
2879
3144
|
feedback(reviewId: string, signal?: AbortSignal): Promise<ReviewFeedback>;
|
|
2880
3145
|
/**
|
|
2881
3146
|
* Post a chat turn on a review's thread (M5): an agent question to the human
|
|
2882
3147
|
* reviewer; flips in_review -> chatting on the first turn. Idempotent on the
|
|
2883
|
-
* optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM
|
|
3148
|
+
* optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM: you compose it.
|
|
2884
3149
|
*/
|
|
2885
3150
|
chat(reviewId: string, req: PostReviewChatRequest, idempotencyKey?: string, signal?: AbortSignal): Promise<Review>;
|
|
2886
3151
|
/**
|
|
2887
3152
|
* Post a new agent draft under a parent_revision CAS (M5; D17). parent_revision
|
|
2888
3153
|
* must equal the draft's current revision, else a 409 STALE with NO mutation (the
|
|
2889
|
-
* human always wins
|
|
2890
|
-
* in place (revision++) and returns to needs_review. $0 LLM
|
|
3154
|
+
* human always wins: re-read, re-apply, retry). On success the draft is re-rendered
|
|
3155
|
+
* in place (revision++) and returns to needs_review. $0 LLM: you compose the redraft.
|
|
2891
3156
|
*/
|
|
2892
3157
|
revise(reviewId: string, req: SubmitRevisionRequest, signal?: AbortSignal): Promise<Review>;
|
|
2893
3158
|
/**
|
|
@@ -2900,9 +3165,9 @@ declare class Reviews {
|
|
|
2900
3165
|
* assert "I reviewed this against rules vX and no change is needed", advancing the
|
|
2901
3166
|
* draft's composed_* versions with no new draft, no revision bump, no nudge. A
|
|
2902
3167
|
* born-stale draft re-stamped to the current version becomes current-enough and
|
|
2903
|
-
* releasable on the next reconciliation sweep
|
|
3168
|
+
* releasable on the next reconciliation sweep: the cheap counterpart to revise().
|
|
2904
3169
|
* against_version above the category's current rules-version is 400; a terminal draft
|
|
2905
|
-
* 409s. $0 LLM
|
|
3170
|
+
* 409s. $0 LLM: you judged.
|
|
2906
3171
|
*/
|
|
2907
3172
|
restamp(reviewId: string, req: RestampReviewRequest, signal?: AbortSignal): Promise<Review>;
|
|
2908
3173
|
/**
|
|
@@ -2917,22 +3182,22 @@ declare class Reviews {
|
|
|
2917
3182
|
decisionContext(reviewId: string, signal?: AbortSignal): Promise<ReviewDecisionContext>;
|
|
2918
3183
|
/**
|
|
2919
3184
|
* Submit a reviewer decision (M8 Slice B; reviewer_decide, D5/§9). approve/edit → the
|
|
2920
|
-
* PLATFORM
|
|
2921
|
-
* mailbox:send on an inbox it doesn't own
|
|
3185
|
+
* PLATFORM sends with the COMPOSER's credentials (the reviewer NEVER holds
|
|
3186
|
+
* mailbox:send on an inbox it doesn't own: the credential boundary); reject → back to
|
|
2922
3187
|
* the composer (needs_review, hop_count++); escalate → the human queue. revision/
|
|
2923
|
-
* version are the CAS (409 STALE on mismatch, NO mutation
|
|
3188
|
+
* version are the CAS (409 STALE on mismatch, NO mutation: the human always wins,
|
|
2924
3189
|
* D17). The two circuit breakers (hop_count ≥ max_hops, or the hard review_deadline)
|
|
2925
|
-
* FORCE a reject to the human regardless of intent
|
|
2926
|
-
* LLM
|
|
3190
|
+
* FORCE a reject to the human regardless of intent: `forced_by_breaker` names it. $0
|
|
3191
|
+
* LLM: you judged; we route, send, and enforce the breakers.
|
|
2927
3192
|
*/
|
|
2928
3193
|
decide(reviewId: string, req: ReviewerDecisionRequest, signal?: AbortSignal): Promise<ReviewerDecisionResult>;
|
|
2929
3194
|
}
|
|
2930
3195
|
/**
|
|
2931
|
-
* `extrovert.reviews.events
|
|
3196
|
+
* `extrovert.reviews.events`: drain / long-poll / ack the durable review nudge
|
|
2932
3197
|
* queue (spec §5.9). `list` is a non-blocking, side-effect-free drain of the next
|
|
2933
3198
|
* un-acked nudges in FIFO seq order (strict per review); `wait` long-polls
|
|
2934
3199
|
* (~25–55s) for the next one; `ack` advances the per-(agent, review) cursor
|
|
2935
|
-
* monotonically (idempotent
|
|
3200
|
+
* monotonically (idempotent: re-acking an older seq is a no-op).
|
|
2936
3201
|
*/
|
|
2937
3202
|
declare class ReviewEvents {
|
|
2938
3203
|
private readonly ctx;
|
|
@@ -2945,10 +3210,10 @@ declare class ReviewEvents {
|
|
|
2945
3210
|
ack(req: AckReviewEventRequest, signal?: AbortSignal): Promise<AckReviewEventResult>;
|
|
2946
3211
|
}
|
|
2947
3212
|
/**
|
|
2948
|
-
* `extrovert.categories
|
|
3213
|
+
* `extrovert.categories`: the Review Loop category registry (D9/D10). Browse and
|
|
2949
3214
|
* MATCH an existing category before composing (like a skills registry), or propose
|
|
2950
3215
|
* a new one. Categories are CUSTOMER-scoped and agent-attributed (the deliberate
|
|
2951
|
-
* cross-agent-404 exception); identity is opaque cat_ ids
|
|
3216
|
+
* cross-agent-404 exception); identity is opaque cat_ ids: nothing keys on the
|
|
2952
3217
|
* name, so renames never break a reference. `match` is a pure lexical filter (NO
|
|
2953
3218
|
* LLM on our side); the agent does the semantic matching. Merging / deleting a
|
|
2954
3219
|
* category is a human (console) action, not exposed here (D17).
|
|
@@ -2962,12 +3227,12 @@ declare class Categories {
|
|
|
2962
3227
|
get(categoryId: string, signal?: AbortSignal): Promise<Category>;
|
|
2963
3228
|
/** Propose a new category; it stands immediately and writes a create audit row. */
|
|
2964
3229
|
propose(req: ProposeCategoryRequest, signal?: AbortSignal): Promise<Category>;
|
|
2965
|
-
/** Rename / re-describe a category
|
|
3230
|
+
/** Rename / re-describe a category: metadata only (D10). */
|
|
2966
3231
|
update(categoryId: string, req: UpdateCategoryRequest, signal?: AbortSignal): Promise<Category>;
|
|
2967
3232
|
/**
|
|
2968
3233
|
* Read the effective risk dial (D4/D12): the account default + every category's
|
|
2969
3234
|
* overrides (each with its resolved effective value; null override = inherit).
|
|
2970
|
-
* Read-only
|
|
3235
|
+
* Read-only: agents read but NEVER flip the dial; setting it is a human (console)
|
|
2971
3236
|
* action (D16).
|
|
2972
3237
|
*/
|
|
2973
3238
|
riskDial(signal?: AbortSignal): Promise<RiskDial>;
|
|
@@ -2979,14 +3244,14 @@ declare class Categories {
|
|
|
2979
3244
|
graduationStatus(categoryId: string, signal?: AbortSignal): Promise<GraduationStatus>;
|
|
2980
3245
|
/**
|
|
2981
3246
|
* Propose graduating a category (D16/D6): RECORDS the request (durable evidence) and
|
|
2982
|
-
* returns the current gate status. It does NOT change the category state
|
|
3247
|
+
* returns the current gate status. It does NOT change the category state: flipping
|
|
2983
3248
|
* the bit is a human (console) action; an agent only proposes.
|
|
2984
3249
|
*/
|
|
2985
3250
|
proposeGraduation(categoryId: string, req?: ProposeGraduationRequest, signal?: AbortSignal): Promise<GraduationStatus>;
|
|
2986
3251
|
/**
|
|
2987
3252
|
* Read the D19/§8 backlog-reconciliation status: how many of the category's QUEUED
|
|
2988
3253
|
* drafts are stale vs current-enough against the current rules-version (a pure
|
|
2989
|
-
* integer compare, $0 LLM). Read-only
|
|
3254
|
+
* integer compare, $0 LLM). Read-only: you READ the picture; the human (console
|
|
2990
3255
|
* scan-backlog) or the graduate/rule-change hooks TRIGGER the actual reconciliation
|
|
2991
3256
|
* sweep that releases current-enough drafts and nudges stale ones to redraft.
|
|
2992
3257
|
*/
|
|
@@ -3002,39 +3267,41 @@ declare class Categories {
|
|
|
3002
3267
|
pacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
|
|
3003
3268
|
}
|
|
3004
3269
|
/**
|
|
3005
|
-
* `extrovert.rules
|
|
3270
|
+
* `extrovert.rules`: the Review Loop writing-rule store + house-style + the §7
|
|
3006
3271
|
* precedence ladder + audit/undo (D2/D11). ANY agent in the customer may write,
|
|
3007
|
-
* edit, promote, retire, and undo rules (the deliberate cross-agent exception
|
|
3272
|
+
* edit, promote, retire, and undo rules (the deliberate cross-agent exception: the
|
|
3008
3273
|
* shared house-style is the whole pitch). `get()` returns the ORDERED active rule
|
|
3009
3274
|
* set with the precedence ladder applied SERVER-SIDE (NO LLM on our side); the agent
|
|
3010
3275
|
* reconciles the list semantically. Rules are append-only by supersession; undo
|
|
3011
3276
|
* restores the prior version as a forward 'restore' supersession. Identity is opaque
|
|
3012
|
-
* rule_/rln_/udo_ ids
|
|
3277
|
+
* rule_/rln_/udo_ ids: nothing keys on a name.
|
|
3013
3278
|
*/
|
|
3014
3279
|
declare class Rules {
|
|
3015
3280
|
private readonly ctx;
|
|
3281
|
+
/** Learn category or organization house rules from verified human review feedback. */
|
|
3282
|
+
learnFromReview(reviewId: string, req: LearnReviewRuleRequest, signal?: AbortSignal): Promise<LearnedReviewRule>;
|
|
3016
3283
|
constructor(ctx: ResourceContext);
|
|
3017
3284
|
/** Get the ORDERED active rule set (precedence ladder applied; NO LLM). */
|
|
3018
3285
|
get(params?: GetRulesParams, signal?: AbortSignal): Promise<RuleSnapshot>;
|
|
3019
3286
|
/**
|
|
3020
3287
|
* Save / edit a rule (append-only by supersession; D11). An agent-plane save is
|
|
3021
3288
|
* ALWAYS project-layer: the saved rule's `rule_layer` is `project`, bound to the
|
|
3022
|
-
* key's project.
|
|
3023
|
-
* rules in v1
|
|
3289
|
+
* key's project. For org-layer house rules use learnFromReview with an authenticated human source; this method cannot author (`rule_layer:"org"`)
|
|
3290
|
+
* rules in v1: that is a console/admin action.
|
|
3024
3291
|
*/
|
|
3025
3292
|
save(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
|
|
3026
3293
|
/** Promote a rule between the category and general/house-style layers. */
|
|
3027
3294
|
promote(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
|
|
3028
|
-
/** Retire a rule
|
|
3295
|
+
/** Retire a rule: soft delete; the history survives as training data. */
|
|
3029
3296
|
retire(ruleId: string, signal?: AbortSignal): Promise<Rule>;
|
|
3030
3297
|
/** Read the rule/category change audit log (the safety net, D11). */
|
|
3031
3298
|
audit(params?: GetRuleAuditParams, signal?: AbortSignal): Promise<Page<RuleAuditEntry>>;
|
|
3032
|
-
/** Undo a rule change by its audit-row id (udo_…)
|
|
3299
|
+
/** Undo a rule change by its audit-row id (udo_…): restore the prior version. */
|
|
3033
3300
|
undo(udoId: string, signal?: AbortSignal): Promise<Rule>;
|
|
3034
3301
|
}
|
|
3035
3302
|
|
|
3036
3303
|
/**
|
|
3037
|
-
* ExtrovertClient
|
|
3304
|
+
* ExtrovertClient - the entry point.
|
|
3038
3305
|
*
|
|
3039
3306
|
* ```ts
|
|
3040
3307
|
* import { Extrovert } from "@extrovert.dev/sdk";
|
|
@@ -3085,28 +3352,30 @@ interface ExtrovertClientOptions {
|
|
|
3085
3352
|
mockBackend?: MockBackend;
|
|
3086
3353
|
}
|
|
3087
3354
|
declare class ExtrovertClient {
|
|
3088
|
-
/** `extrovert.inboxes`
|
|
3355
|
+
/** `extrovert.inboxes` - create / list / get / update / delete inboxes. */
|
|
3089
3356
|
readonly inboxes: Inboxes;
|
|
3090
|
-
/** `extrovert.messages`
|
|
3357
|
+
/** `extrovert.messages` - read a message, reply to it (threaded). */
|
|
3091
3358
|
readonly messages: Messages;
|
|
3092
|
-
/** `extrovert.threads`
|
|
3359
|
+
/** `extrovert.threads` - fetch a conversation thread. */
|
|
3093
3360
|
readonly threads: Threads;
|
|
3094
|
-
/** `extrovert.webhooks`
|
|
3361
|
+
/** `extrovert.webhooks` - register HMAC-signed inbound webhooks. */
|
|
3095
3362
|
readonly webhooks: Webhooks;
|
|
3096
|
-
/** `extrovert.contactLists`
|
|
3363
|
+
/** `extrovert.contactLists` - per-inbox allow/block lists of addresses/domains. */
|
|
3097
3364
|
readonly contactLists: ContactLists;
|
|
3098
|
-
/** `extrovert.suppressions`
|
|
3365
|
+
/** `extrovert.suppressions` - recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
|
|
3099
3366
|
readonly suppressions: Suppressions;
|
|
3100
|
-
/** `extrovert.domains`
|
|
3367
|
+
/** `extrovert.domains` - domain readiness and setup (domain:read or domain:manage to read; domain:manage to change). */
|
|
3101
3368
|
readonly domains: Domains;
|
|
3102
|
-
/** `extrovert.
|
|
3369
|
+
/** `extrovert.commerce` - quote/request/cancel/poll financial actions; no agent approval methods. */
|
|
3370
|
+
readonly commerce: Commerce;
|
|
3371
|
+
/** `extrovert.reviews` - the Review Loop (HITL) agent-plane reads. */
|
|
3103
3372
|
readonly reviews: Reviews;
|
|
3104
|
-
/** `extrovert.categories`
|
|
3373
|
+
/** `extrovert.categories` - the Review Loop category registry (browse/propose/curate). */
|
|
3105
3374
|
readonly categories: Categories;
|
|
3106
|
-
/** `extrovert.rules`
|
|
3375
|
+
/** `extrovert.rules` - the Review Loop writing-rule store + house-style + audit/undo. */
|
|
3107
3376
|
readonly rules: Rules;
|
|
3108
3377
|
/**
|
|
3109
|
-
* `extrovert.projects`
|
|
3378
|
+
* `extrovert.projects` - the CANONICAL project-scoped chain. The headline is
|
|
3110
3379
|
* `extrovert.projects.inboxes.*` (create/list/get/update/delete/send/...), keyed by
|
|
3111
3380
|
* the opaque `inbox_id` and scoped to a `{project_id}` path (or `-` for the org
|
|
3112
3381
|
* wildcard on an org-tier key). The bare `extrovert.inboxes` surface is curl sugar
|
|
@@ -3122,7 +3391,7 @@ declare class ExtrovertClient {
|
|
|
3122
3391
|
readonly apiVersion: string;
|
|
3123
3392
|
/**
|
|
3124
3393
|
* The CEILING tier derived from the configured agent key prefix (`org` | `project`
|
|
3125
|
-
* | `inbox` | `unknown`). Advisory client-side hint only
|
|
3394
|
+
* | `inbox` | `unknown`). Advisory client-side hint only - the server is the source
|
|
3126
3395
|
* of truth. Lets an app branch (e.g. require a project pick for an org-tier key).
|
|
3127
3396
|
*/
|
|
3128
3397
|
readonly keyTier: KeyTier;
|
|
@@ -3130,18 +3399,20 @@ declare class ExtrovertClient {
|
|
|
3130
3399
|
private readonly handleOptions;
|
|
3131
3400
|
constructor(options?: ExtrovertClientOptions);
|
|
3132
3401
|
/**
|
|
3133
|
-
* Redeem an enrollment token (`pk_enroll_...`) and
|
|
3402
|
+
* Redeem an enrollment token (`pk_enroll_...`) and issue a scoped agent key.
|
|
3134
3403
|
*
|
|
3135
3404
|
* Idempotent on `agent_handle`: redeeming twice with the same handle returns the same agent.
|
|
3136
|
-
* Returns the raw `EnrollResponse`
|
|
3405
|
+
* Returns the raw `EnrollResponse` - to immediately use the issued key, prefer
|
|
3137
3406
|
* {@link ExtrovertClient.enrolled}.
|
|
3138
3407
|
*/
|
|
3139
3408
|
enroll(req: EnrollRequest, signal?: AbortSignal): Promise<EnrollResponse>;
|
|
3140
3409
|
/**
|
|
3141
|
-
*
|
|
3142
|
-
*
|
|
3143
|
-
*
|
|
3144
|
-
*
|
|
3410
|
+
* Request a free account in one unauthenticated call. When free signup is
|
|
3411
|
+
* enabled, this provisions a tenant plus a first inbox and returns a
|
|
3412
|
+
* verification-only agent key. That key can only call {@link verify}; it cannot
|
|
3413
|
+
* read or send mail. A one-time code is emailed to `human_email`. Call
|
|
3414
|
+
* {@link verify} with the code to activate the account and receive full scopes.
|
|
3415
|
+
* Idempotent on `human_email`: re-calling rotates the key and resends the code.
|
|
3145
3416
|
* When free signup is paused, this throws an `ApiError` with status 403 and
|
|
3146
3417
|
* code `signup_disabled` without creating account state.
|
|
3147
3418
|
*/
|
|
@@ -3158,15 +3429,15 @@ declare class ExtrovertClient {
|
|
|
3158
3429
|
/** Introspect the principal behind the current key (`GET /v1/auth/me`). */
|
|
3159
3430
|
whoami(signal?: AbortSignal): Promise<WhoAmI>;
|
|
3160
3431
|
/**
|
|
3161
|
-
* Poll the status of an async job (`GET /v1/jobs/{job_id}`)
|
|
3432
|
+
* Poll the status of an async job (`GET /v1/jobs/{job_id}`) - currently only
|
|
3162
3433
|
* the domain-offboard teardown started by {@link Domains.offboard} enqueues
|
|
3163
3434
|
* one. `status` is terminal on succeeded/failed/cancelled; keep polling
|
|
3164
3435
|
* otherwise. An unknown or foreign job id is a {@link NotFoundError}.
|
|
3165
3436
|
*/
|
|
3166
3437
|
getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
|
|
3167
3438
|
/**
|
|
3168
|
-
* Redeem an enrollment token and return a *new* client already authenticated with the
|
|
3169
|
-
* agent key
|
|
3439
|
+
* Redeem an enrollment token and return a *new* client already authenticated with the issued
|
|
3440
|
+
* agent key - the natural "redeem then act" flow for an agent.
|
|
3170
3441
|
*
|
|
3171
3442
|
* ```ts
|
|
3172
3443
|
* const bootstrap = new Extrovert({ apiKey: enrollmentToken });
|
|
@@ -3182,7 +3453,7 @@ declare class ExtrovertClient {
|
|
|
3182
3453
|
enrollment: EnrollResponse;
|
|
3183
3454
|
}>;
|
|
3184
3455
|
/**
|
|
3185
|
-
* Get an ergonomic handle to an existing inbox by address
|
|
3456
|
+
* Get an ergonomic handle to an existing inbox by address - without an extra round-trip. Use this
|
|
3186
3457
|
* when you already know the address (e.g. from a previous create) and want to send/wait/reply.
|
|
3187
3458
|
* Call {@link InboxHandle.refresh} to load the full record.
|
|
3188
3459
|
*/
|
|
@@ -3225,7 +3496,7 @@ declare class ExtrovertClient {
|
|
|
3225
3496
|
*/
|
|
3226
3497
|
/**
|
|
3227
3498
|
* The CLOSED problem code enum (mirrors `components.schemas.Problem.code` in the
|
|
3228
|
-
* frozen OpenAPI). Adding a member is a contract change
|
|
3499
|
+
* frozen OpenAPI). Adding a member is a contract change - keep it in lockstep with
|
|
3229
3500
|
* the Go `ProblemCode` enum.
|
|
3230
3501
|
*/
|
|
3231
3502
|
type ProblemCode = "bad_request" | "unauthorized" | "forbidden_scope" | "not_found" | "conflict" | "idempotency_conflict" | "breadth_required" | "quota_exceeded" | "rate_limited" | "domain_not_allowed" | "recipient_blocked" | "recipient_suppressed" | "not_configured" | "domain_unavailable" | "internal" | "intent_required" | "wrong_state" | "terminal" | "stale" | "born_stale" | "send_needs_reconciliation" | "graduation_locked" | "maturity_gate_unmet" | "scope_taken" | "unavailable";
|
|
@@ -3238,11 +3509,11 @@ declare const PROBLEM_CODES: readonly ProblemCode[];
|
|
|
3238
3509
|
* compare-and-set (`stale`) and a redraft built against an older rule high-water
|
|
3239
3510
|
* (`born_stale`) describe a situation a retry can fix, and each only a bounded
|
|
3240
3511
|
* number of times (re-read, re-apply on top of the other party's change,
|
|
3241
|
-
* resubmit). `wrong_state` means the verb is wrong, not the timing
|
|
3512
|
+
* resubmit). `wrong_state` means the verb is wrong, not the timing - read the
|
|
3242
3513
|
* `allowed_action` hints and pick another one. `terminal` means the review is
|
|
3243
3514
|
* finished forever; a `front_run_next` nudge is already waiting on the queue
|
|
3244
3515
|
* with the outcome. `send_needs_reconciliation` means a delivery attempt is
|
|
3245
|
-
* unconfirmed
|
|
3516
|
+
* unconfirmed - resending is precisely how a message goes out twice.
|
|
3246
3517
|
*
|
|
3247
3518
|
* `intent_required` is listed false because retrying the SAME bytes fails
|
|
3248
3519
|
* identically: the fix is to ADD an `intent` and send a different request. The
|
|
@@ -3347,38 +3618,38 @@ declare class ApiError extends Error {
|
|
|
3347
3618
|
/** True for 5xx responses (server errors that may succeed on retry). */
|
|
3348
3619
|
get isServerError(): boolean;
|
|
3349
3620
|
}
|
|
3350
|
-
/** 401
|
|
3621
|
+
/** 401 - the agent key / enrollment token was missing, malformed, expired, or revoked. */
|
|
3351
3622
|
declare class AuthenticationError extends ApiError {
|
|
3352
3623
|
}
|
|
3353
|
-
/** 403
|
|
3624
|
+
/** 403 - authenticated, but the key's scopes don't permit this action (capability denied). */
|
|
3354
3625
|
declare class PermissionError extends ApiError {
|
|
3355
3626
|
}
|
|
3356
3627
|
/**
|
|
3357
|
-
* 403 `forbidden_scope`
|
|
3358
|
-
* on the org-wide wildcard, or
|
|
3628
|
+
* 403 `forbidden_scope` - the call is outside the key's CEILING (e.g. a non-org key
|
|
3629
|
+
* on the org-wide wildcard, or an issuance that would escalate). A redesign-specific
|
|
3359
3630
|
* subclass of {@link PermissionError} so existing `instanceof PermissionError`
|
|
3360
3631
|
* branches keep working.
|
|
3361
3632
|
*/
|
|
3362
3633
|
declare class ForbiddenScopeError extends PermissionError {
|
|
3363
3634
|
}
|
|
3364
3635
|
/**
|
|
3365
|
-
* 400 `breadth_required`
|
|
3636
|
+
* 400 `breadth_required` - an org-tier key/operator issued a bare list that needs a
|
|
3366
3637
|
* breadth pick; the problem `errors`/`detail` name the next call
|
|
3367
3638
|
* (`/v1/projects/{id}/inboxes` or `/v1/projects/-/inboxes`).
|
|
3368
3639
|
*/
|
|
3369
3640
|
declare class BreadthRequiredError extends ApiError {
|
|
3370
3641
|
}
|
|
3371
|
-
/** 404
|
|
3642
|
+
/** 404 - the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
|
|
3372
3643
|
declare class NotFoundError extends ApiError {
|
|
3373
3644
|
}
|
|
3374
|
-
/** 409
|
|
3645
|
+
/** 409 - a conflicting state, e.g. an enrollment token that already created its maximum number of inboxes. */
|
|
3375
3646
|
declare class ConflictError extends ApiError {
|
|
3376
3647
|
}
|
|
3377
|
-
/** 422
|
|
3648
|
+
/** 422 - the request body failed validation; see `body.error.details`. */
|
|
3378
3649
|
declare class ValidationError extends ApiError {
|
|
3379
3650
|
}
|
|
3380
3651
|
/**
|
|
3381
|
-
* 422 `recipient_suppressed`
|
|
3652
|
+
* 422 `recipient_suppressed` - a send/reply/forward was rejected because one or
|
|
3382
3653
|
* more recipients have opted out (list-unsubscribe / suppression). The whole send
|
|
3383
3654
|
* is rejected (never a silent partial drop). {@link suppressedRecipients} lists the
|
|
3384
3655
|
* exact addresses to drop; retry the send without them. The scope/origin of the
|
|
@@ -3386,12 +3657,12 @@ declare class ValidationError extends ApiError {
|
|
|
3386
3657
|
* existing `instanceof ValidationError` branches keep working.
|
|
3387
3658
|
*/
|
|
3388
3659
|
declare class RecipientSuppressedError extends ValidationError {
|
|
3389
|
-
/** The recipient addresses that are suppressed
|
|
3660
|
+
/** The recipient addresses that are suppressed - drop these and retry. */
|
|
3390
3661
|
readonly suppressedRecipients: string[];
|
|
3391
3662
|
constructor(args: ConstructorParameters<typeof ApiError>[0]);
|
|
3392
3663
|
}
|
|
3393
3664
|
/**
|
|
3394
|
-
* 422 `intent_required`
|
|
3665
|
+
* 422 `intent_required` - the inbox's resolved review policy requires a human to
|
|
3395
3666
|
* see this message before it goes out, and the request carried no `intent`.
|
|
3396
3667
|
*
|
|
3397
3668
|
* **Nothing was sent and nothing was queued.** The server checks this before it
|
|
@@ -3400,7 +3671,7 @@ declare class RecipientSuppressedError extends ValidationError {
|
|
|
3400
3671
|
* splice in, and the human-readable remediation (the full recipe, including how
|
|
3401
3672
|
* to monitor the resulting review) is on `.message` / `.problem.detail`.
|
|
3402
3673
|
*
|
|
3403
|
-
* Under `require_review`
|
|
3674
|
+
* Under `require_review` - the default for every account - this is the FIRST
|
|
3404
3675
|
* thing most agents hit. Read `effective_review_policy` on
|
|
3405
3676
|
* `GET /v1/inboxes/{id}` once at start-up and compose an intent up front instead
|
|
3406
3677
|
* of learning the policy by being refused. A subclass of {@link ValidationError}
|
|
@@ -3409,7 +3680,7 @@ declare class RecipientSuppressedError extends ValidationError {
|
|
|
3409
3680
|
declare class IntentRequiredError extends ValidationError {
|
|
3410
3681
|
/** The resolved review policy, e.g. `require_review`. */
|
|
3411
3682
|
readonly policy: string | undefined;
|
|
3412
|
-
/** Where the policy came from
|
|
3683
|
+
/** Where the policy came from - a per-inbox override or the account default. */
|
|
3413
3684
|
readonly policySource: string | undefined;
|
|
3414
3685
|
/** Literal JSON to merge into the original request body, then retry once. */
|
|
3415
3686
|
readonly retryWith: string | undefined;
|
|
@@ -3427,7 +3698,7 @@ declare class IntentRequiredError extends ValidationError {
|
|
|
3427
3698
|
declare class ReviewConflictError extends ConflictError {
|
|
3428
3699
|
/** The review's CURRENT state (`needs_review`, `approved`, `sent`, …). */
|
|
3429
3700
|
readonly currentState: string | undefined;
|
|
3430
|
-
/** The current revision
|
|
3701
|
+
/** The current revision - pass it as `parent_revision` on a legal retry. */
|
|
3431
3702
|
readonly currentRevision: number | undefined;
|
|
3432
3703
|
/** The current row version (the optional belt-and-braces CAS). */
|
|
3433
3704
|
readonly currentVersion: number | undefined;
|
|
@@ -3436,13 +3707,13 @@ declare class ReviewConflictError extends ConflictError {
|
|
|
3436
3707
|
constructor(args: ConstructorParameters<typeof ApiError>[0]);
|
|
3437
3708
|
/**
|
|
3438
3709
|
* Whether retrying the same call could ever succeed. False for every subclass
|
|
3439
|
-
* except {@link StaleError} and {@link BornStaleError}
|
|
3710
|
+
* except {@link StaleError} and {@link BornStaleError} - and true there only
|
|
3440
3711
|
* after re-reading and re-applying on top of the other party's change.
|
|
3441
3712
|
*/
|
|
3442
3713
|
get isRetryable(): boolean;
|
|
3443
3714
|
}
|
|
3444
3715
|
/**
|
|
3445
|
-
* 409 `stale`
|
|
3716
|
+
* 409 `stale` - the `(revision[, version])` you named is no longer current
|
|
3446
3717
|
* because a human or reviewer moved the draft. **Nothing was mutated.**
|
|
3447
3718
|
*
|
|
3448
3719
|
* The one genuinely retryable conflict, and bounded (≤3): re-read the draft and
|
|
@@ -3455,7 +3726,7 @@ declare class StaleError extends ReviewConflictError {
|
|
|
3455
3726
|
get isRetryable(): boolean;
|
|
3456
3727
|
}
|
|
3457
3728
|
/**
|
|
3458
|
-
* 409 `wrong_state`
|
|
3729
|
+
* 409 `wrong_state` - this VERB is illegal from the review's current state, but
|
|
3459
3730
|
* the draft is still live.
|
|
3460
3731
|
*
|
|
3461
3732
|
* **Never retry the same verb**; the timing is not the problem, the choice of
|
|
@@ -3464,7 +3735,7 @@ declare class StaleError extends ReviewConflictError {
|
|
|
3464
3735
|
declare class WrongStateError extends ReviewConflictError {
|
|
3465
3736
|
}
|
|
3466
3737
|
/**
|
|
3467
|
-
* 409 `terminal`
|
|
3738
|
+
* 409 `terminal` - the review has already finished (sent / auto_sent /
|
|
3468
3739
|
* cancelled). Nothing will EVER succeed on it.
|
|
3469
3740
|
*
|
|
3470
3741
|
* **Stop.** A `front_run_next` review event is waiting on the durable queue with
|
|
@@ -3478,12 +3749,12 @@ declare class TerminalError extends ReviewConflictError {
|
|
|
3478
3749
|
constructor(args: ConstructorParameters<typeof ApiError>[0]);
|
|
3479
3750
|
}
|
|
3480
3751
|
/**
|
|
3481
|
-
* 409 `born_stale`
|
|
3752
|
+
* 409 `born_stale` - the redraft was composed against an OLDER writing-rule
|
|
3482
3753
|
* high-water than the one now in force. **Nothing was mutated** and the composer
|
|
3483
3754
|
* has been re-nudged.
|
|
3484
3755
|
*
|
|
3485
3756
|
* Retryable at most once per rule high-water: re-read the rules, re-apply them,
|
|
3486
|
-
* resubmit
|
|
3757
|
+
* resubmit - or `restamp_review` when re-reading shows nothing genuinely needed
|
|
3487
3758
|
* to change. Restamping when the body DID need to change makes the draft lie to
|
|
3488
3759
|
* the born-stale accounting, so do it only for a true no-op.
|
|
3489
3760
|
*/
|
|
@@ -3491,7 +3762,7 @@ declare class BornStaleError extends ReviewConflictError {
|
|
|
3491
3762
|
get isRetryable(): boolean;
|
|
3492
3763
|
}
|
|
3493
3764
|
/**
|
|
3494
|
-
* 409 `send_needs_reconciliation`
|
|
3765
|
+
* 409 `send_needs_reconciliation` - a delivery attempt reached (or may have
|
|
3495
3766
|
* reached) the mail provider and the process died before recording the outcome,
|
|
3496
3767
|
* so the review is parked for recover-by-Message-ID.
|
|
3497
3768
|
*
|
|
@@ -3502,17 +3773,17 @@ declare class BornStaleError extends ReviewConflictError {
|
|
|
3502
3773
|
declare class SendNeedsReconciliationError extends ReviewConflictError {
|
|
3503
3774
|
}
|
|
3504
3775
|
/**
|
|
3505
|
-
* 409 `idempotency_conflict`
|
|
3776
|
+
* 409 `idempotency_conflict` - the same `Idempotency-Key` was replayed with a
|
|
3506
3777
|
* DIFFERENT request body within the same scope. The replay key is a hash of the
|
|
3507
3778
|
* raw bytes, so "same message, different spelling" counts as different.
|
|
3508
3779
|
*
|
|
3509
3780
|
* A caller bug, not a race: do not retry under that key. Either send the byte-
|
|
3510
|
-
* identical body, or
|
|
3781
|
+
* identical body, or use a new key for the genuinely new message.
|
|
3511
3782
|
*/
|
|
3512
3783
|
declare class IdempotencyConflictError extends ConflictError {
|
|
3513
3784
|
}
|
|
3514
3785
|
/**
|
|
3515
|
-
* 503 `unavailable`
|
|
3786
|
+
* 503 `unavailable` - a dependency could not be read, so the request was failed
|
|
3516
3787
|
* CLOSED rather than served on a guess. On the send path this specifically means
|
|
3517
3788
|
* the account's review policy was unreadable: relaying unsupervised mail for a
|
|
3518
3789
|
* customer whose stated policy we could not see is the failure that would be
|
|
@@ -3528,7 +3799,7 @@ declare class UnavailableError extends ApiError {
|
|
|
3528
3799
|
retryAfter?: number;
|
|
3529
3800
|
});
|
|
3530
3801
|
}
|
|
3531
|
-
/** 402
|
|
3802
|
+
/** 402 - payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
|
|
3532
3803
|
declare class PaymentRequiredError extends ApiError {
|
|
3533
3804
|
/** The raw `PAYMENT-REQUIRED` header challenge to sign + retry (EIP-3009, Base Sepolia). */
|
|
3534
3805
|
readonly paymentRequired: string | undefined;
|
|
@@ -3536,7 +3807,7 @@ declare class PaymentRequiredError extends ApiError {
|
|
|
3536
3807
|
paymentRequired?: string;
|
|
3537
3808
|
});
|
|
3538
3809
|
}
|
|
3539
|
-
/** 429
|
|
3810
|
+
/** 429 - rate limited. `retryAfter` is the server's hint in seconds, when provided. */
|
|
3540
3811
|
declare class RateLimitError extends ApiError {
|
|
3541
3812
|
/** Seconds to wait before retrying, parsed from the `Retry-After` header. */
|
|
3542
3813
|
readonly retryAfter: number | undefined;
|
|
@@ -3554,7 +3825,7 @@ declare class TimeoutError extends ApiError {
|
|
|
3554
3825
|
}
|
|
3555
3826
|
|
|
3556
3827
|
/**
|
|
3557
|
-
* Narrowing helpers for {@link SendOutcome}
|
|
3828
|
+
* Narrowing helpers for {@link SendOutcome} - the three shapes a send can answer.
|
|
3558
3829
|
*
|
|
3559
3830
|
* `inbox.send()` used to be typed as one struct with a REQUIRED `thread_id`, which
|
|
3560
3831
|
* the direct-send response has never carried. The type checked; the value was
|
|
@@ -3565,7 +3836,7 @@ declare class TimeoutError extends ApiError {
|
|
|
3565
3836
|
* has been delivered**. A human has to approve it first, and the delivery outcome
|
|
3566
3837
|
* arrives later as a `sent` / `send_failed` review event. Code that treats every
|
|
3567
3838
|
* 2xx from `send()` as "the mail went out" is wrong under the default
|
|
3568
|
-
* `require_review` policy
|
|
3839
|
+
* `require_review` policy - which is every account that has not changed it.
|
|
3569
3840
|
*/
|
|
3570
3841
|
|
|
3571
3842
|
/**
|
|
@@ -3575,14 +3846,14 @@ declare class TimeoutError extends ApiError {
|
|
|
3575
3846
|
*/
|
|
3576
3847
|
declare function isQueuedForReview(res: SendOutcome): res is QueuedForReviewResult;
|
|
3577
3848
|
/**
|
|
3578
|
-
* True when the message was delivered immediately
|
|
3849
|
+
* True when the message was delivered immediately - either the review-loop
|
|
3579
3850
|
* `{kind:"sent"}` body or the legacy body a bare send gets under `allow_direct`.
|
|
3580
3851
|
*/
|
|
3581
3852
|
declare function isSentImmediately(res: SendOutcome): res is SendResult | SentResult;
|
|
3582
3853
|
/**
|
|
3583
3854
|
* The delivered message id, or `undefined` when the message was queued instead.
|
|
3584
3855
|
*
|
|
3585
|
-
* `undefined` here is NOT an error
|
|
3856
|
+
* `undefined` here is NOT an error - it is the normal answer under
|
|
3586
3857
|
* `require_review`. Pair it with {@link reviewIdOf} to follow the message to its
|
|
3587
3858
|
* outcome.
|
|
3588
3859
|
*/
|
|
@@ -3690,7 +3961,7 @@ declare function verifyWebhookSignature(options: VerifyWebhookOptions): Promise<
|
|
|
3690
3961
|
*/
|
|
3691
3962
|
declare function parseWebhook(options: VerifyWebhookOptions): Promise<WebhookPayload | null>;
|
|
3692
3963
|
/**
|
|
3693
|
-
* Produce the canonical `X-Extrovert-Signature` header value for a body
|
|
3964
|
+
* Produce the canonical `X-Extrovert-Signature` header value for a body - the exact format the Go
|
|
3694
3965
|
* delivery engine emits: `t=<unix>,v1=<hex hmac-sha256("<t>.<rawbody>")>`. Mainly useful for tests
|
|
3695
3966
|
* and self-hosted senders; the platform signs deliveries server-side. The Go `SignWebhook` and this
|
|
3696
3967
|
* helper are pinned to the same fixed conformance vector across languages.
|
|
@@ -3701,7 +3972,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
|
|
|
3701
3972
|
* The Extrovert Review-Loop **open contract** (HITL D14, spec §11).
|
|
3702
3973
|
*
|
|
3703
3974
|
* This module is the single, documented, *versioned* publication of the stable
|
|
3704
|
-
* agent-facing JSON shapes that the Review Loop exposes
|
|
3975
|
+
* agent-facing JSON shapes that the Review Loop exposes - the shapes agents and
|
|
3705
3976
|
* third-party harnesses code against. It does **not** redesign any types: it
|
|
3706
3977
|
* re-exports the canonical models built across M1–M8 (see `./models`) under one
|
|
3707
3978
|
* named contract surface, stamps a {@link CONTRACT_VERSION}, and publishes a
|
|
@@ -3711,7 +3982,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
|
|
|
3711
3982
|
* ## This is a contract, NOT a protocol (D14)
|
|
3712
3983
|
*
|
|
3713
3984
|
* Per resolved decision **D14**, the open surface is published **now** as an open,
|
|
3714
|
-
* documented **skill + SDK contract**
|
|
3985
|
+
* documented **skill + SDK contract** - explicitly **not** a wire protocol and
|
|
3715
3986
|
* **not** a standalone `/v1/contract` endpoint. The contract is exactly: these SDK
|
|
3716
3987
|
* types + the agent skills (`extrovert-send-email`, `extrovert-writing-rules`) + the
|
|
3717
3988
|
* docs, **versioned with the SDK** (this package). Formal protocol
|
|
@@ -3719,7 +3990,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
|
|
|
3719
3990
|
*
|
|
3720
3991
|
* ## Provisional, pre-1.0 (0.x)
|
|
3721
3992
|
*
|
|
3722
|
-
* {@link CONTRACT_VERSION} is **`0.1.0-pre.
|
|
3993
|
+
* {@link CONTRACT_VERSION} is **`0.1.0-pre.8`** - a deliberately **provisional**, pre-1.0
|
|
3723
3994
|
* contract. It is open and documented, but it MAY still evolve before 1.0: there
|
|
3724
3995
|
* are no external users yet, and the **D20 shared-pool auto-send governor** is a
|
|
3725
3996
|
* hard prerequisite before onboarding external users. Pin the version; expect
|
|
@@ -3729,11 +4000,11 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
|
|
|
3729
4000
|
*
|
|
3730
4001
|
* Every shape keys on **opaque, typed ids** (`rr_`, `turn_`, `cat_`, `rule_`,
|
|
3731
4002
|
* `rln_`, `ndg_`, …) and never on names. Names/descriptions are mutable display
|
|
3732
|
-
* metadata; renaming never breaks a reference. $0-LLM on our side
|
|
4003
|
+
* metadata; renaming never breaks a reference. $0-LLM on our side - the contract
|
|
3733
4004
|
* is pure deterministic JSON; all judgment lives in the agent skills.
|
|
3734
4005
|
*
|
|
3735
4006
|
* The canonical example payloads for the §11 core shapes (Intent, ReviewFeedback,
|
|
3736
|
-
* DiffJson, Rule, Nudge) are the conformance golden fixtures
|
|
4007
|
+
* DiffJson, Rule, Nudge) are the conformance golden fixtures - see
|
|
3737
4008
|
* `golang/internal/extrovertapi/testdata/contract/` and the SDK
|
|
3738
4009
|
* `contract.test.ts` (both assert these examples parse/validate without loss).
|
|
3739
4010
|
*
|
|
@@ -3776,24 +4047,24 @@ interface DiffJson {
|
|
|
3776
4047
|
/**
|
|
3777
4048
|
* The published version of the Extrovert Review-Loop open contract (D14).
|
|
3778
4049
|
*
|
|
3779
|
-
* **`0.1.0-pre.
|
|
4050
|
+
* **`0.1.0-pre.8` - PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
|
|
3780
4051
|
* `package.json` version) and aligned to the openapi `info.version`. Open and
|
|
3781
4052
|
* documented, but MAY still evolve before 1.0 (no external users yet; the D20
|
|
3782
4053
|
* shared-pool governor is required before external users). Pin it.
|
|
3783
4054
|
*/
|
|
3784
|
-
declare const CONTRACT_VERSION: "0.1.0-pre.
|
|
4055
|
+
declare const CONTRACT_VERSION: "0.1.0-pre.8";
|
|
3785
4056
|
/** The stability posture of a published contract version. */
|
|
3786
4057
|
type ContractStability = "provisional" | "stable";
|
|
3787
4058
|
/**
|
|
3788
|
-
* The machine-readable manifest of the open contract (D14)
|
|
4059
|
+
* The machine-readable manifest of the open contract (D14) - what a harness pins.
|
|
3789
4060
|
*
|
|
3790
4061
|
* It enumerates the canonical §11 **core** shapes and the **full** M1–M8 surface
|
|
3791
4062
|
* by name, stamps {@link CONTRACT_VERSION}, and marks the {@link ContractStability}
|
|
3792
4063
|
* posture so a consumer can reason about evolution risk. It carries no runtime
|
|
3793
|
-
* behavior (M9 adds none
|
|
4064
|
+
* behavior (M9 adds none - types + a version + a test + docs) and no LLM.
|
|
3794
4065
|
*/
|
|
3795
4066
|
interface ContractManifest {
|
|
3796
|
-
/** Stable contract name (NOT a protocol name
|
|
4067
|
+
/** Stable contract name (NOT a protocol name - D14). */
|
|
3797
4068
|
readonly name: "extrovert.review-loop";
|
|
3798
4069
|
/** The published contract version (== {@link CONTRACT_VERSION}). */
|
|
3799
4070
|
readonly version: string;
|
|
@@ -3803,7 +4074,7 @@ interface ContractManifest {
|
|
|
3803
4074
|
*/
|
|
3804
4075
|
readonly stability: ContractStability;
|
|
3805
4076
|
/**
|
|
3806
|
-
* D14: this is an SDK + skill contract, versioned WITH the SDK
|
|
4077
|
+
* D14: this is an SDK + skill contract, versioned WITH the SDK - never a wire
|
|
3807
4078
|
* protocol or a standalone protocol endpoint.
|
|
3808
4079
|
*/
|
|
3809
4080
|
readonly kind: "sdk+skill-contract";
|
|
@@ -3813,15 +4084,15 @@ interface ContractManifest {
|
|
|
3813
4084
|
readonly core_shapes: readonly string[];
|
|
3814
4085
|
/** The full published M1–M8 agent-facing contract surface (one 0.x contract; no tiering). */
|
|
3815
4086
|
readonly shapes: readonly string[];
|
|
3816
|
-
/** The agent skills that are part of the contract (D14
|
|
4087
|
+
/** The agent skills that are part of the contract (D14 - "skill + SDK"). */
|
|
3817
4088
|
readonly skills: readonly string[];
|
|
3818
4089
|
}
|
|
3819
4090
|
/**
|
|
3820
4091
|
* The published manifest instance. Frozen so a harness can compare it
|
|
3821
4092
|
* structurally. The `core_shapes` are the five §11 canonical shapes; `shapes` is
|
|
3822
4093
|
* the full provisional-0.x surface. Keep this list in sync with the re-exports
|
|
3823
|
-
* above
|
|
4094
|
+
* above - the `contract.test.ts` drift test asserts every named shape resolves.
|
|
3824
4095
|
*/
|
|
3825
4096
|
declare const CONTRACT_MANIFEST: ContractManifest;
|
|
3826
4097
|
|
|
3827
|
-
export { API_VERSION_HEADER, type AccountRiskDial, type AckReviewEventEntry, type AckReviewEventRequest, type AckReviewEventResult, type AddContactListRequest, type Agent, type AgentStatus, ApiError, type ApiErrorBody, type Attachment, type AttachmentDownload, type AttachmentInput, AuthenticationError, type BatchUpdateMessagesRequest, type BatchUpdateResult, BornStaleError, BreadthRequiredError, CONTRACT_MANIFEST, CONTRACT_VERSION, CURRENT_API_VERSION, Categories, type Category, type CategoryPacingState, type CategoryRiskDial, ConflictError, ConnectionError, type ContactListDirection, type ContactListEntry, type ContactListKind, ContactLists, type ContractManifest, type ContractStability, type CreateInboxRequest, type Cursor, DEFAULT_BASE_URL, type DeleteResult, type DiffHunk, type DiffJson, type Domain, type DomainOffboard, type DomainRecord, type DomainScope, Domains, type EffectiveRiskDial, type EmailAddress, type EnrollRequest, type EnrollResponse, type ExtractedCredentials, ExtrovertClient as Extrovert, ExtrovertClient, type ExtrovertClientOptions, ForbiddenScopeError, type ForwardRequest, type GetInboxParams, type GetRuleAuditParams, type GetRulesParams, type GraduationStatus, IdempotencyConflictError, type Inbox, type InboxCredentials, InboxHandle, type InboxInclude, type InboxMetadata, type InboxMetadataPatch, type InboxMetadataValue, type InboxStatus, Inboxes, IntentRequiredError, type IsoTimestamp, type Job, type KeyTier, type List, type ListCategoriesParams, type ListInboxesParams, type ListMessagesParams, ListPage, type ListParams, type ListReviewEventsParams, type ListReviewsParams, type ListSuppressionsParams, type ListThreadsParams, MOCK_BASE_URL, type MailFolder, type MailboxQuickstart, type MailboxQuickstartCall, type MarkReadRequest, type Message, type MessageDirection, Messages, MockBackend, NotFoundError, type OnboardDomainRequest, type OnboardingMode, PROBLEM_CODES, type PacingItem, type Page, type PageFetcher, PaymentRequiredError, PermissionError, type PostReviewChatRequest, type Problem, type ProblemCode, type ProblemField, type ProjectInboxListParams, ProjectInboxes, Projects, type ProposeCategoryRequest, type ProposeGraduationRequest, type QueuedForReviewResult, REVIEW_PROBLEM_RETRYABLE, RateLimitError, RecipientSuppressedError, type RegisterWebhookRequest, type ReplyRequest, type RestampReviewRequest, type Review, ReviewConflictError, type ReviewDecisionContext, type ReviewEvent, type ReviewEventCursor, type ReviewEventReason, ReviewEvents, type ReviewEventsResult, type ReviewFeedback, type ReviewFeedbackComment, type ReviewInclude, type ReviewIntent, type ReviewMode, type ReviewPolicy, type ReviewState, type ReviewTurn, type ReviewerAction, type ReviewerDecisionRequest, type ReviewerDecisionResult, Reviews, type RiskDial, type Rule, type RuleAuditEntry, type RuleLayer, type RuleSnapshot, Rules, SDK_VERSION, type SaveRuleRequest, type ScanBacklogStatus, type Scope, type SearchMessagesParams, SendNeedsReconciliationError, type SendOutcome, type SendRequest, type SendResult, type SentResult, type SignUpRequest, type SignUpResponse, StaleError, type StreamEvent, type StreamOptions, type SubmitForReviewResult, type SubmitRevisionRequest, type SuppressionEntry, type SuppressionPrecheck, type SuppressionScope, type SuppressionSource, Suppressions, TerminalError, type Thread, type ThreadDetail, Threads, TimeoutError, UnavailableError, type UpdateCategoryRequest, type UpdateInboxRequest, type UpdateWebhookRequest, ValidationError, type VerifyRequest, type VerifyResponse, type VerifyWebhookOptions, type WaitForEmailRequest, type WaitForEmailResult, type WaitForReviewEventParams, type Webhook, type WebhookEvent, type WebhookPayload, Webhooks, type WhoAmI, WrongStateError, extractCredentials, extractLink, extractOtp, isProblemCode, isQueuedForReview, isSentImmediately, listPage, parseKeyTier, parseProblem, parseWebhook, reviewIdOf, sentMessageIdOf, serializeInclude, signWebhook, threadIdOf, tierAllowsOrgWildcard, tierNeedsExplicitBreadth, verifyWebhookSignature };
|
|
4098
|
+
export { API_VERSION_HEADER, type AccountRiskDial, type AckReviewEventEntry, type AckReviewEventRequest, type AckReviewEventResult, type AddContactListRequest, type Agent, type AgentStatus, ApiError, type ApiErrorBody, type Attachment, type AttachmentDownload, type AttachmentInput, AuthenticationError, type BatchUpdateMessagesRequest, type BatchUpdateResult, BornStaleError, BreadthRequiredError, CONTRACT_MANIFEST, CONTRACT_VERSION, CURRENT_API_VERSION, Categories, type Category, type CategoryPacingState, type CategoryRiskDial, Commerce, type CommerceBlocker, type CommerceRequest, type CommerceRequestKind, ConflictError, ConnectionError, type ContactListDirection, type ContactListEntry, type ContactListKind, ContactLists, type ContractManifest, type ContractStability, type CreateInboxRequest, type Cursor, DEFAULT_BASE_URL, type DeleteResult, type DiffHunk, type DiffJson, type Domain, type DomainOffboard, type DomainQuote, type DomainReadiness, type DomainRecord, type DomainScope, type DomainStatusEvent, type DomainStatusEventPage, type DomainWaitResult, Domains, type EffectiveRiskDial, type EmailAddress, type EnrollRequest, type EnrollResponse, type ExtractedCredentials, ExtrovertClient as Extrovert, ExtrovertClient, type ExtrovertClientOptions, ForbiddenScopeError, type ForwardRequest, type GetInboxParams, type GetRuleAuditParams, type GetRulesParams, type GraduationStatus, IdempotencyConflictError, type Inbox, type InboxCredentials, InboxHandle, type InboxInclude, type InboxMetadata, type InboxMetadataPatch, type InboxMetadataValue, type InboxStatus, Inboxes, IntentRequiredError, type IsoTimestamp, type Job, type KeyTier, type LearnReviewRuleRequest, type LearnedReviewRule, type List, type ListCategoriesParams, type ListCommerceRequestsParams, type ListInboxesParams, type ListMessagesParams, ListPage, type ListParams, type ListReviewEventsParams, type ListReviewsParams, type ListSuppressionsParams, type ListThreadsParams, MOCK_BASE_URL, type MailFolder, type MailboxQuickstart, type MailboxQuickstartCall, type MarkReadRequest, type Message, type MessageDirection, Messages, MockBackend, NotFoundError, type OnboardDomainRequest, type OnboardingMode, PROBLEM_CODES, type PacingItem, type Page, type PageFetcher, PaymentRequiredError, PermissionError, type PostReviewChatRequest, type Problem, type ProblemCode, type ProblemField, type ProjectInboxListParams, ProjectInboxes, Projects, type ProposeCategoryRequest, type ProposeGraduationRequest, type QueuedForReviewResult, type QuoteDomainRequest, REVIEW_PROBLEM_RETRYABLE, RateLimitError, RecipientSuppressedError, type RegisterWebhookRequest, type ReplyRequest, type RequestDomainPurchaseRequest, type RequestPlanChangeRequest, type RestampReviewRequest, type Review, ReviewConflictError, type ReviewDecisionContext, type ReviewEvent, type ReviewEventCursor, type ReviewEventReason, ReviewEvents, type ReviewEventsResult, type ReviewFeedback, type ReviewFeedbackComment, type ReviewInclude, type ReviewIntent, type ReviewMode, type ReviewPolicy, type ReviewState, type ReviewTurn, type ReviewerAction, type ReviewerDecisionRequest, type ReviewerDecisionResult, Reviews, type RiskDial, type Rule, type RuleAuditEntry, type RuleLayer, type RuleSnapshot, Rules, SDK_VERSION, type SaveRuleRequest, type ScanBacklogStatus, type Scope, type SearchMessagesParams, SendNeedsReconciliationError, type SendOutcome, type SendRequest, type SendResult, type SentResult, type SignUpRequest, type SignUpResponse, StaleError, type StreamEvent, type StreamOptions, type SubmitForReviewResult, type SubmitRevisionRequest, type SuppressionEntry, type SuppressionPrecheck, type SuppressionScope, type SuppressionSource, Suppressions, TerminalError, type Thread, type ThreadDetail, Threads, TimeoutError, UnavailableError, type UpdateCategoryRequest, type UpdateInboxRequest, type UpdateWebhookRequest, ValidationError, type VerifyRequest, type VerifyResponse, type VerifyWebhookOptions, type WaitForEmailRequest, type WaitForEmailResult, type WaitForReviewEventParams, type Webhook, type WebhookEvent, type WebhookPayload, Webhooks, type WhoAmI, WrongStateError, extractCredentials, extractLink, extractOtp, isProblemCode, isQueuedForReview, isSentImmediately, listPage, parseKeyTier, parseProblem, parseWebhook, reviewIdOf, sentMessageIdOf, serializeInclude, signWebhook, threadIdOf, tierAllowsOrgWildcard, tierNeedsExplicitBreadth, verifyWebhookSignature };
|