@pingroom/sdk 0.7.1 → 0.9.0
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 +288 -44
- package/dist/client.d.ts +27 -312
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +33 -1154
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +40 -6
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +56 -4
- package/dist/errors.js.map +1 -1
- package/dist/http.d.ts +12 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +47 -18
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/async.d.ts +2 -0
- package/dist/internal/async.d.ts.map +1 -1
- package/dist/internal/async.js +6 -0
- package/dist/internal/async.js.map +1 -1
- package/dist/internal/guards.d.ts +16 -0
- package/dist/internal/guards.d.ts.map +1 -1
- package/dist/internal/guards.js +22 -1
- package/dist/internal/guards.js.map +1 -1
- package/dist/internal/request.d.ts +41 -0
- package/dist/internal/request.d.ts.map +1 -0
- package/dist/internal/request.js +78 -0
- package/dist/internal/request.js.map +1 -0
- package/dist/internal/retry.d.ts +65 -0
- package/dist/internal/retry.d.ts.map +1 -0
- package/dist/internal/retry.js +126 -0
- package/dist/internal/retry.js.map +1 -0
- package/dist/internal/url.d.ts +9 -0
- package/dist/internal/url.d.ts.map +1 -1
- package/dist/internal/url.js +25 -0
- package/dist/internal/url.js.map +1 -1
- package/dist/internal/validate.d.ts +13 -0
- package/dist/internal/validate.d.ts.map +1 -0
- package/dist/internal/validate.js +36 -0
- package/dist/internal/validate.js.map +1 -0
- package/dist/linkPing.d.ts.map +1 -1
- package/dist/linkPing.js +6 -2
- package/dist/linkPing.js.map +1 -1
- package/dist/liveStatus.d.ts +106 -11
- package/dist/liveStatus.d.ts.map +1 -1
- package/dist/liveStatus.js +20 -3
- package/dist/liveStatus.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +40 -10
- package/dist/mcp.js.map +1 -1
- package/dist/namespaces/actions.d.ts +50 -0
- package/dist/namespaces/actions.d.ts.map +1 -0
- package/dist/namespaces/actions.js +219 -0
- package/dist/namespaces/actions.js.map +1 -0
- package/dist/namespaces/approvals.d.ts +23 -0
- package/dist/namespaces/approvals.d.ts.map +1 -0
- package/dist/namespaces/approvals.js +78 -0
- package/dist/namespaces/approvals.js.map +1 -0
- package/dist/namespaces/attachments.d.ts +37 -0
- package/dist/namespaces/attachments.d.ts.map +1 -0
- package/dist/namespaces/attachments.js +91 -0
- package/dist/namespaces/attachments.js.map +1 -0
- package/dist/namespaces/auth.d.ts +58 -0
- package/dist/namespaces/auth.d.ts.map +1 -0
- package/dist/namespaces/auth.js +242 -0
- package/dist/namespaces/auth.js.map +1 -0
- package/dist/namespaces/directory.d.ts +10 -0
- package/dist/namespaces/directory.d.ts.map +1 -0
- package/dist/namespaces/directory.js +19 -0
- package/dist/namespaces/directory.js.map +1 -0
- package/dist/namespaces/handoffs.d.ts +47 -0
- package/dist/namespaces/handoffs.d.ts.map +1 -0
- package/dist/namespaces/handoffs.js +126 -0
- package/dist/namespaces/handoffs.js.map +1 -0
- package/dist/namespaces/inbox.d.ts +17 -0
- package/dist/namespaces/inbox.d.ts.map +1 -0
- package/dist/namespaces/inbox.js +192 -0
- package/dist/namespaces/inbox.js.map +1 -0
- package/dist/namespaces/live.d.ts +57 -0
- package/dist/namespaces/live.d.ts.map +1 -0
- package/dist/namespaces/live.js +116 -0
- package/dist/namespaces/live.js.map +1 -0
- package/dist/namespaces/notifications.d.ts +25 -0
- package/dist/namespaces/notifications.d.ts.map +1 -0
- package/dist/namespaces/notifications.js +128 -0
- package/dist/namespaces/notifications.js.map +1 -0
- package/dist/namespaces/profile.d.ts +19 -0
- package/dist/namespaces/profile.d.ts.map +1 -0
- package/dist/namespaces/profile.js +22 -0
- package/dist/namespaces/profile.js.map +1 -0
- package/dist/namespaces/questions.d.ts +41 -0
- package/dist/namespaces/questions.d.ts.map +1 -0
- package/dist/namespaces/questions.js +107 -0
- package/dist/namespaces/questions.js.map +1 -0
- package/dist/namespaces/rooms.d.ts +13 -0
- package/dist/namespaces/rooms.d.ts.map +1 -0
- package/dist/namespaces/rooms.js +41 -0
- package/dist/namespaces/rooms.js.map +1 -0
- package/dist/namespaces/webhooks.d.ts +11 -0
- package/dist/namespaces/webhooks.d.ts.map +1 -0
- package/dist/namespaces/webhooks.js +32 -0
- package/dist/namespaces/webhooks.js.map +1 -0
- package/dist/types/approvals.d.ts +62 -0
- package/dist/types/approvals.d.ts.map +1 -0
- package/dist/types/approvals.js +2 -0
- package/dist/types/approvals.js.map +1 -0
- package/dist/types/auth.d.ts +185 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/common.d.ts +43 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +2 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/handoffs.d.ts +121 -0
- package/dist/types/handoffs.d.ts.map +1 -0
- package/dist/types/handoffs.js +2 -0
- package/dist/types/handoffs.js.map +1 -0
- package/dist/types/inbox.d.ts +51 -0
- package/dist/types/inbox.d.ts.map +1 -0
- package/dist/types/inbox.js +2 -0
- package/dist/types/inbox.js.map +1 -0
- package/dist/types/notifications.d.ts +376 -0
- package/dist/types/notifications.d.ts.map +1 -0
- package/dist/types/notifications.js +2 -0
- package/dist/types/notifications.js.map +1 -0
- package/dist/types/profile.d.ts +30 -0
- package/dist/types/profile.d.ts.map +1 -0
- package/dist/types/profile.js +3 -0
- package/dist/types/profile.js.map +1 -0
- package/dist/types/questions.d.ts +210 -0
- package/dist/types/questions.d.ts.map +1 -0
- package/dist/types/questions.js +2 -0
- package/dist/types/questions.js.map +1 -0
- package/dist/types/rooms.d.ts +163 -0
- package/dist/types/rooms.d.ts.map +1 -0
- package/dist/types/rooms.js +3 -0
- package/dist/types/rooms.js.map +1 -0
- package/dist/types.d.ts +9 -1035
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhooks.d.ts +32 -5
- package/dist/webhooks.d.ts.map +1 -1
- package/dist/webhooks.js +44 -14
- package/dist/webhooks.js.map +1 -1
- package/package.json +4 -2
- package/src/client.ts +115 -0
- package/src/errors.ts +291 -0
- package/src/http.ts +225 -0
- package/src/index.ts +97 -0
- package/src/internal/async.ts +54 -0
- package/src/internal/guards.ts +129 -0
- package/src/internal/request.ts +97 -0
- package/src/internal/retry.ts +157 -0
- package/src/internal/url.ts +78 -0
- package/src/internal/validate.ts +42 -0
- package/src/linkPing.ts +56 -0
- package/src/liveStatus.ts +337 -0
- package/src/locationPing.ts +101 -0
- package/src/mcp.ts +161 -0
- package/src/namespaces/actions.ts +234 -0
- package/src/namespaces/approvals.ts +104 -0
- package/src/namespaces/attachments.ts +106 -0
- package/src/namespaces/auth.ts +284 -0
- package/src/namespaces/directory.ts +21 -0
- package/src/namespaces/handoffs.ts +160 -0
- package/src/namespaces/inbox.ts +253 -0
- package/src/namespaces/live.ts +134 -0
- package/src/namespaces/notifications.ts +152 -0
- package/src/namespaces/profile.ts +24 -0
- package/src/namespaces/questions.ts +133 -0
- package/src/namespaces/rooms.ts +53 -0
- package/src/namespaces/webhooks.ts +38 -0
- package/src/types/approvals.ts +67 -0
- package/src/types/auth.ts +202 -0
- package/src/types/common.ts +74 -0
- package/src/types/handoffs.ts +148 -0
- package/src/types/inbox.ts +64 -0
- package/src/types/notifications.ts +393 -0
- package/src/types/profile.ts +37 -0
- package/src/types/questions.ts +226 -0
- package/src/types/rooms.ts +169 -0
- package/src/types.ts +17 -0
- package/src/version.ts +2 -0
- package/src/webhooks.ts +373 -0
- package/dist/liveActivity.d.ts +0 -101
- package/dist/liveActivity.d.ts.map +0 -1
- package/dist/liveActivity.js +0 -83
- package/dist/liveActivity.js.map +0 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { HttpClient } from '../http.js';
|
|
2
|
+
import type { AskInput, Handoff, ListHandoffsInput, RequestAckInput, WaitHandoffInput, WaitForOutcomeOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The Handoff façade: the Agent → one-human loop. Always DIRECT (exactly one
|
|
5
|
+
* human) and PRIVATE (no other room member can read it). Backed by the ack and
|
|
6
|
+
* question primitives, so its {@link Handoff.state | state} space is their union
|
|
7
|
+
* — kept DISTINCT per {@link Handoff.kind | kind}. A negative answer to a
|
|
8
|
+
* question handoff (e.g. `hold`) is a SUCCESSFUL `answered` result, not an error.
|
|
9
|
+
*
|
|
10
|
+
* const task = await pr.handoffs.requestAck({ prompt, idempotencyKey });
|
|
11
|
+
* const result = await pr.handoffs.waitForResult(task.id);
|
|
12
|
+
*
|
|
13
|
+
* const q = await pr.handoffs.ask({ prompt, options: ['deploy', 'hold'], idempotencyKey });
|
|
14
|
+
*/
|
|
15
|
+
export declare class HandoffsApi {
|
|
16
|
+
private readonly http;
|
|
17
|
+
constructor(http: HttpClient);
|
|
18
|
+
/** Ask a human to acknowledge (an `ack` handoff). Resolves on the first acknowledgement. */
|
|
19
|
+
requestAck(input: RequestAckInput): Promise<Handoff>;
|
|
20
|
+
/**
|
|
21
|
+
* Ask a human a multi-option question (a `question` handoff). Resolves on the
|
|
22
|
+
* first tapped answer. Bare-string options normalize to `{ value, label }`.
|
|
23
|
+
*/
|
|
24
|
+
ask(input: AskInput): Promise<Handoff>;
|
|
25
|
+
/** Fetch a handoff's current state. */
|
|
26
|
+
get(id: string): Promise<Handoff>;
|
|
27
|
+
/**
|
|
28
|
+
* Block until the handoff resolves (or expires/cancels), looping the bounded
|
|
29
|
+
* long-poll under the hood. `expired`/`cancelled` and a negative answer (e.g.
|
|
30
|
+
* `hold`) all surface as normal terminal results — nothing is thrown for them.
|
|
31
|
+
*
|
|
32
|
+
* Polls start at least 2.1 s apart, so a short `timeout` stays under the
|
|
33
|
+
* route's 30-per-minute limit. A response that is not this handoff in a
|
|
34
|
+
* known state rejects with `invalid_response`. Network failures, 429 and 5xx
|
|
35
|
+
* are retried with backoff (honouring `retryAfter`), and reported to
|
|
36
|
+
* `onRetry`, until `signal` aborts or the outage outlasts the handoff's
|
|
37
|
+
* `expires_at` by 5 minutes (15 minutes of failures while no `expires_at` has
|
|
38
|
+
* been read); that rejects with `unavailable`. See {@link WaitForOutcomeOptions}.
|
|
39
|
+
*/
|
|
40
|
+
waitForResult(id: string, input?: WaitHandoffInput & WaitForOutcomeOptions): Promise<Handoff>;
|
|
41
|
+
/** List the agent's open handoffs or bounded recent history. */
|
|
42
|
+
list(input?: ListHandoffsInput): Promise<Handoff[]>;
|
|
43
|
+
/** One bounded long-poll; returns the (possibly still-open) handoff. */
|
|
44
|
+
private wait;
|
|
45
|
+
private create;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=handoffs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoffs.d.ts","sourceRoot":"","sources":["../../src/namespaces/handoffs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO7C,OAAO,KAAK,EACV,QAAQ,EACR,OAAO,EAGP,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AA+BrB;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,4FAA4F;IAC5F,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAMpD;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtC,uCAAuC;IACvC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKjC;;;;;;;;;;;;OAYG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,gBAAgB,GAAG,qBAA0B,GAAG,OAAO,CAAC,OAAO,CAAC;IAevG,gEAAgE;IAC1D,IAAI,CAAC,KAAK,GAAE,iBAAsB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO7D,wEAAwE;IACxE,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,MAAM;CAqBf"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// `pr.handoffs`: the direct, private agent-to-human loop.
|
|
2
|
+
import { PingRoomError } from '../errors.js';
|
|
3
|
+
import { assertStructuredData, normalizeIdempotencyKey, requireNonEmpty, } from '../internal/guards.js';
|
|
4
|
+
import { pollUntilSettled } from '../internal/retry.js';
|
|
5
|
+
import { MIN_HANDOFF_POLL_INTERVAL_MS, enc, assertOnRetry, dropUndefined, waitTimeoutMs, } from '../internal/request.js';
|
|
6
|
+
import { isRecord, sameId, invalidWaitResponse } from '../internal/validate.js';
|
|
7
|
+
const HANDOFF_STATES = new Set(['open', 'acked', 'pending', 'answered', 'expired', 'cancelled']);
|
|
8
|
+
function validateHandoffWait(value, handoffId) {
|
|
9
|
+
const state = isRecord(value) ? value['state'] : undefined;
|
|
10
|
+
if (!isRecord(value) || !sameId(value['id'], handoffId) || typeof state !== 'string' || !HANDOFF_STATES.has(state)) {
|
|
11
|
+
return invalidWaitResponse('handoff', handoffId, value, 'state');
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
/** A bare string option is shorthand for `{ value, label: value }`. */
|
|
16
|
+
function normalizeHandoffOptions(options) {
|
|
17
|
+
return options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));
|
|
18
|
+
}
|
|
19
|
+
/** Terminal states never change again — the wait loop can stop as soon as one lands. */
|
|
20
|
+
function isHandoffTerminal(handoff) {
|
|
21
|
+
const s = handoff.state;
|
|
22
|
+
return s === 'acked' || s === 'answered' || s === 'expired' || s === 'cancelled';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The Handoff façade: the Agent → one-human loop. Always DIRECT (exactly one
|
|
26
|
+
* human) and PRIVATE (no other room member can read it). Backed by the ack and
|
|
27
|
+
* question primitives, so its {@link Handoff.state | state} space is their union
|
|
28
|
+
* — kept DISTINCT per {@link Handoff.kind | kind}. A negative answer to a
|
|
29
|
+
* question handoff (e.g. `hold`) is a SUCCESSFUL `answered` result, not an error.
|
|
30
|
+
*
|
|
31
|
+
* const task = await pr.handoffs.requestAck({ prompt, idempotencyKey });
|
|
32
|
+
* const result = await pr.handoffs.waitForResult(task.id);
|
|
33
|
+
*
|
|
34
|
+
* const q = await pr.handoffs.ask({ prompt, options: ['deploy', 'hold'], idempotencyKey });
|
|
35
|
+
*/
|
|
36
|
+
export class HandoffsApi {
|
|
37
|
+
http;
|
|
38
|
+
constructor(http) {
|
|
39
|
+
this.http = http;
|
|
40
|
+
}
|
|
41
|
+
/** Ask a human to acknowledge (an `ack` handoff). Resolves on the first acknowledgement. */
|
|
42
|
+
requestAck(input) {
|
|
43
|
+
requireNonEmpty(input.prompt, 'prompt');
|
|
44
|
+
assertStructuredData(input.data);
|
|
45
|
+
return this.create('ack', input);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Ask a human a multi-option question (a `question` handoff). Resolves on the
|
|
49
|
+
* first tapped answer. Bare-string options normalize to `{ value, label }`.
|
|
50
|
+
*/
|
|
51
|
+
ask(input) {
|
|
52
|
+
requireNonEmpty(input.prompt, 'prompt');
|
|
53
|
+
assertStructuredData(input.data);
|
|
54
|
+
if (!Array.isArray(input.options) || input.options.length < 2 || input.options.length > 4) {
|
|
55
|
+
throw new PingRoomError('`options` must contain between 2 and 4 entries for a question handoff.', {
|
|
56
|
+
code: 'invalid_request',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return this.create('question', input, normalizeHandoffOptions(input.options));
|
|
60
|
+
}
|
|
61
|
+
/** Fetch a handoff's current state. */
|
|
62
|
+
get(id) {
|
|
63
|
+
requireNonEmpty(id, 'id');
|
|
64
|
+
return this.http.request('GET', `/api/agent/handoffs/${enc(id)}`);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Block until the handoff resolves (or expires/cancels), looping the bounded
|
|
68
|
+
* long-poll under the hood. `expired`/`cancelled` and a negative answer (e.g.
|
|
69
|
+
* `hold`) all surface as normal terminal results — nothing is thrown for them.
|
|
70
|
+
*
|
|
71
|
+
* Polls start at least 2.1 s apart, so a short `timeout` stays under the
|
|
72
|
+
* route's 30-per-minute limit. A response that is not this handoff in a
|
|
73
|
+
* known state rejects with `invalid_response`. Network failures, 429 and 5xx
|
|
74
|
+
* are retried with backoff (honouring `retryAfter`), and reported to
|
|
75
|
+
* `onRetry`, until `signal` aborts or the outage outlasts the handoff's
|
|
76
|
+
* `expires_at` by 5 minutes (15 minutes of failures while no `expires_at` has
|
|
77
|
+
* been read); that rejects with `unavailable`. See {@link WaitForOutcomeOptions}.
|
|
78
|
+
*/
|
|
79
|
+
async waitForResult(id, input = {}) {
|
|
80
|
+
requireNonEmpty(id, 'id');
|
|
81
|
+
assertOnRetry(input.onRetry);
|
|
82
|
+
return pollUntilSettled({
|
|
83
|
+
poll: () => this.wait(id, input),
|
|
84
|
+
validate: (value) => validateHandoffWait(value, id),
|
|
85
|
+
settled: isHandoffTerminal,
|
|
86
|
+
expiresAt: (handoff) => handoff.expires_at,
|
|
87
|
+
what: `handoff ${id}`,
|
|
88
|
+
minIntervalMs: MIN_HANDOFF_POLL_INTERVAL_MS,
|
|
89
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
90
|
+
...(input.onRetry ? { onRetry: input.onRetry } : {}),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/** List the agent's open handoffs or bounded recent history. */
|
|
94
|
+
async list(input = {}) {
|
|
95
|
+
const res = await this.http.request('GET', '/api/agent/handoffs', {
|
|
96
|
+
query: dropUndefined({ state: input.state }),
|
|
97
|
+
});
|
|
98
|
+
return res.handoffs ?? [];
|
|
99
|
+
}
|
|
100
|
+
/** One bounded long-poll; returns the (possibly still-open) handoff. */
|
|
101
|
+
wait(id, input) {
|
|
102
|
+
return this.http.request('GET', `/api/agent/handoffs/${enc(id)}/wait`, {
|
|
103
|
+
query: dropUndefined({ timeout: input.timeout }),
|
|
104
|
+
timeoutMs: waitTimeoutMs(input.timeout),
|
|
105
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
create(kind, input, options) {
|
|
109
|
+
const body = dropUndefined({
|
|
110
|
+
kind,
|
|
111
|
+
prompt: input.prompt,
|
|
112
|
+
audience: { type: 'direct', user_id: input.target ?? 'me' },
|
|
113
|
+
expires_in: input.expiresIn,
|
|
114
|
+
urgency: input.urgency,
|
|
115
|
+
options,
|
|
116
|
+
correlation_id: input.correlationId,
|
|
117
|
+
reply_to: input.replyTo,
|
|
118
|
+
data: input.data,
|
|
119
|
+
});
|
|
120
|
+
return this.http.request('POST', '/api/agent/handoffs', {
|
|
121
|
+
body,
|
|
122
|
+
...(input.idempotencyKey ? { headers: { 'Idempotency-Key': normalizeIdempotencyKey(input.idempotencyKey) } } : {}),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=handoffs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoffs.js","sourceRoot":"","sources":["../../src/namespaces/handoffs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HttpClient } from '../http.js';
|
|
2
|
+
import type { AgentInboxEnsureResult, AgentInboxActivateInput, AgentInboxActivationResult, AgentInboxEnsureInput } from '../types.js';
|
|
3
|
+
/** Setup and activation of the bound human's Agent Inbox delivery room. */
|
|
4
|
+
export declare class InboxApi {
|
|
5
|
+
private readonly http;
|
|
6
|
+
constructor(http: HttpClient);
|
|
7
|
+
/** Replay the viable activation attempt or create its next numbered retry. */
|
|
8
|
+
ensure(input?: AgentInboxEnsureInput): Promise<AgentInboxEnsureResult>;
|
|
9
|
+
/**
|
|
10
|
+
* Ensure the bound human's Agent Inbox, then block on its onboarding
|
|
11
|
+
* Question until the server confirms activation, it expires/cancels, or the
|
|
12
|
+
* overall deadline elapses. Pairing remains a separate operation so adopting
|
|
13
|
+
* a credential never silently waits for a phone response.
|
|
14
|
+
*/
|
|
15
|
+
activate(input?: AgentInboxActivateInput): Promise<AgentInboxActivationResult>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=inbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/namespaces/inbox.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EAEvB,0BAA0B,EAC1B,qBAAqB,EAEtB,MAAM,aAAa,CAAC;AA8GrB,2EAA2E;AAC3E,qBAAa,QAAQ;IACP,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,8EAA8E;IAC9E,MAAM,CAAC,KAAK,GAAE,qBAA0B,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAO1E;;;;;OAKG;IACG,QAAQ,CAAC,KAAK,GAAE,uBAA4B,GAAG,OAAO,CAAC,0BAA0B,CAAC;CA+GzF"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// `pr.inbox`: setting up and activating the human's Agent Inbox.
|
|
2
|
+
import { PingRoomActivationIncompleteError, PingRoomError } from '../errors.js';
|
|
3
|
+
import { combineSignals, sleep, throwIfAborted } from '../internal/async.js';
|
|
4
|
+
import { isTransientError, transientDelayMs } from '../internal/retry.js';
|
|
5
|
+
import { MIN_HANDOFF_POLL_INTERVAL_MS, enc, dropUndefined, waitTimeoutMs, } from '../internal/request.js';
|
|
6
|
+
import { isRecord, isNonEmptyString, isNullableString } from '../internal/validate.js';
|
|
7
|
+
const DEFAULT_INBOX_ACTIVATION_TIMEOUT_MS = 120_000;
|
|
8
|
+
function invalidInboxResponse(message, body = {}) {
|
|
9
|
+
throw new PingRoomError(message, { code: 'inbox_invalid_response', body });
|
|
10
|
+
}
|
|
11
|
+
function validateInboxEnsure(value) {
|
|
12
|
+
if (!isRecord(value) || value['onboarded'] !== true || typeof value['replayed'] !== 'boolean') {
|
|
13
|
+
return invalidInboxResponse('PingRoom returned an invalid Agent Inbox ensure response.');
|
|
14
|
+
}
|
|
15
|
+
const room = value['room'];
|
|
16
|
+
const question = value['question'];
|
|
17
|
+
if (!isRecord(room)
|
|
18
|
+
|| !isNonEmptyString(room['id'])
|
|
19
|
+
|| typeof room['name'] !== 'string'
|
|
20
|
+
|| !isNonEmptyString(room['invite_code'])
|
|
21
|
+
|| typeof room['is_agent_inbox'] !== 'boolean'
|
|
22
|
+
|| !isRecord(question)
|
|
23
|
+
|| !isNonEmptyString(question['id'])
|
|
24
|
+
|| question['kind'] !== 'question'
|
|
25
|
+
|| !isNonEmptyString(question['prompt'])
|
|
26
|
+
|| !Array.isArray(question['options'])
|
|
27
|
+
|| question['options'].some((option) => (!isRecord(option)
|
|
28
|
+
|| !isNonEmptyString(option['value'])
|
|
29
|
+
|| !isNonEmptyString(option['label'])))
|
|
30
|
+
|| (question['state'] !== 'pending'
|
|
31
|
+
&& question['state'] !== 'answered'
|
|
32
|
+
&& question['state'] !== 'expired'
|
|
33
|
+
&& question['state'] !== 'cancelled')
|
|
34
|
+
|| !isNullableString(question['expires_at'])
|
|
35
|
+
|| !isNullableString(question['created_at'])) {
|
|
36
|
+
return invalidInboxResponse('PingRoom returned an incomplete Agent Inbox ensure response.');
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function validateInboxWait(value, expectedId) {
|
|
41
|
+
if (!isRecord(value)) {
|
|
42
|
+
return invalidInboxResponse('PingRoom returned an invalid Agent Inbox wait response.');
|
|
43
|
+
}
|
|
44
|
+
const state = value['state'];
|
|
45
|
+
if (!isNonEmptyString(value['id'])
|
|
46
|
+
|| value['id'] !== expectedId
|
|
47
|
+
|| value['kind'] !== 'question'
|
|
48
|
+
|| (state !== 'pending' && state !== 'answered' && state !== 'expired' && state !== 'cancelled')
|
|
49
|
+
|| (value['activation_completed'] !== undefined && typeof value['activation_completed'] !== 'boolean')
|
|
50
|
+
|| (state !== 'answered' && value['activation_completed'] === true)) {
|
|
51
|
+
return invalidInboxResponse('PingRoom returned a mismatched Agent Inbox wait response.', {
|
|
52
|
+
expected_id: expectedId,
|
|
53
|
+
received_id: typeof value['id'] === 'string' ? value['id'] : null,
|
|
54
|
+
kind: typeof value['kind'] === 'string' ? value['kind'] : null,
|
|
55
|
+
state: typeof state === 'string' ? state : null,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (state === 'answered') {
|
|
59
|
+
const answer = value['answer'];
|
|
60
|
+
if (!isRecord(answer)
|
|
61
|
+
|| !isNullableString(answer['value'])
|
|
62
|
+
|| !isNullableString(answer['label'])
|
|
63
|
+
|| !isNullableString(answer['text'])
|
|
64
|
+
|| (!isNonEmptyString(answer['value']) && !isNonEmptyString(answer['text']))
|
|
65
|
+
|| !isNullableString(answer['answered_at'])
|
|
66
|
+
|| (answer['responder'] !== null && !isRecord(answer['responder']))) {
|
|
67
|
+
return invalidInboxResponse('PingRoom returned an answered activation without a valid answer.', {
|
|
68
|
+
id: expectedId,
|
|
69
|
+
state,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const responder = answer['responder'];
|
|
73
|
+
if (isRecord(responder)
|
|
74
|
+
&& (!isNullableString(responder['id']) || !isNullableString(responder['display_name']))) {
|
|
75
|
+
return invalidInboxResponse('PingRoom returned an invalid activation responder.', {
|
|
76
|
+
id: expectedId,
|
|
77
|
+
state,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else if (value['answer'] !== undefined && value['answer'] !== null) {
|
|
82
|
+
return invalidInboxResponse('PingRoom returned an answer for an unresolved activation.', {
|
|
83
|
+
id: expectedId,
|
|
84
|
+
state,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
/** Setup and activation of the bound human's Agent Inbox delivery room. */
|
|
90
|
+
export class InboxApi {
|
|
91
|
+
http;
|
|
92
|
+
constructor(http) {
|
|
93
|
+
this.http = http;
|
|
94
|
+
}
|
|
95
|
+
/** Replay the viable activation attempt or create its next numbered retry. */
|
|
96
|
+
ensure(input = {}) {
|
|
97
|
+
return this.http.request('POST', '/api/agent/inbox/ensure', {
|
|
98
|
+
body: {},
|
|
99
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Ensure the bound human's Agent Inbox, then block on its onboarding
|
|
104
|
+
* Question until the server confirms activation, it expires/cancels, or the
|
|
105
|
+
* overall deadline elapses. Pairing remains a separate operation so adopting
|
|
106
|
+
* a credential never silently waits for a phone response.
|
|
107
|
+
*/
|
|
108
|
+
async activate(input = {}) {
|
|
109
|
+
const overallTimeoutMs = input.overallTimeoutMs ?? DEFAULT_INBOX_ACTIVATION_TIMEOUT_MS;
|
|
110
|
+
if (!Number.isFinite(overallTimeoutMs) || overallTimeoutMs < 0) {
|
|
111
|
+
throw new PingRoomError('`overallTimeoutMs` must be a non-negative finite number.', {
|
|
112
|
+
code: 'invalid_request',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const deadlineError = () => (new PingRoomActivationIncompleteError('deadline_exceeded', 'Agent Inbox activation did not complete before the overall deadline.', { overall_timeout_ms: overallTimeoutMs }));
|
|
116
|
+
const deadlineController = new AbortController();
|
|
117
|
+
const deadlineTimer = overallTimeoutMs === 0
|
|
118
|
+
? null
|
|
119
|
+
: setTimeout(() => deadlineController.abort(deadlineError()), overallTimeoutMs);
|
|
120
|
+
if (overallTimeoutMs === 0)
|
|
121
|
+
deadlineController.abort(deadlineError());
|
|
122
|
+
const signal = input.signal
|
|
123
|
+
? combineSignals(input.signal, deadlineController.signal)
|
|
124
|
+
: deadlineController.signal;
|
|
125
|
+
try {
|
|
126
|
+
throwIfAborted(signal);
|
|
127
|
+
const ensured = validateInboxEnsure(await this.ensure({ signal }));
|
|
128
|
+
const questionId = ensured.question.id;
|
|
129
|
+
let failures = 0;
|
|
130
|
+
for (;;) {
|
|
131
|
+
throwIfAborted(signal);
|
|
132
|
+
const pollStartedAt = Date.now();
|
|
133
|
+
let question;
|
|
134
|
+
try {
|
|
135
|
+
question = validateInboxWait(await this.http.request('GET', `/api/agent/handoffs/${enc(questionId)}/wait`, {
|
|
136
|
+
query: dropUndefined({ timeout: input.timeout }),
|
|
137
|
+
timeoutMs: waitTimeoutMs(input.timeout),
|
|
138
|
+
signal,
|
|
139
|
+
}), questionId);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
// A dropped connection, a request deadline, a 429 (each wait route
|
|
143
|
+
// has its own 30/min bucket per human) or a 5xx is not an outcome:
|
|
144
|
+
// retry it like every other wait, inside the overall deadline.
|
|
145
|
+
// Anything else is permanent and surfaces.
|
|
146
|
+
throwIfAborted(signal);
|
|
147
|
+
if (!isTransientError(error)) {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
failures += 1;
|
|
151
|
+
await sleep(Math.max(transientDelayMs(error, failures), MIN_HANDOFF_POLL_INTERVAL_MS - (Date.now() - pollStartedAt)), signal);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
failures = 0;
|
|
155
|
+
throwIfAborted(signal);
|
|
156
|
+
if (question.state === 'pending') {
|
|
157
|
+
await sleep(Math.max(0, MIN_HANDOFF_POLL_INTERVAL_MS - (Date.now() - pollStartedAt)), signal);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (question.state === 'answered' && question.activation_completed === true) {
|
|
161
|
+
return {
|
|
162
|
+
...ensured,
|
|
163
|
+
activation_completed: true,
|
|
164
|
+
question: question,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (question.state === 'answered') {
|
|
168
|
+
throw new PingRoomActivationIncompleteError('answered_without_completion', 'The onboarding Question was answered without verified native phone receipt before the answer.', { question_id: questionId, activation_completed: question.activation_completed ?? null });
|
|
169
|
+
}
|
|
170
|
+
if (question.state === 'expired' || question.state === 'cancelled') {
|
|
171
|
+
throw new PingRoomActivationIncompleteError(question.state, `The onboarding Question ${question.state} before Agent Inbox activation completed.`, { question_id: questionId, activation_completed: question.activation_completed ?? null });
|
|
172
|
+
}
|
|
173
|
+
return invalidInboxResponse('PingRoom returned an invalid terminal activation state.', {
|
|
174
|
+
id: questionId,
|
|
175
|
+
state: question.state,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
// A custom fetch implementation may reject with a generic AbortError
|
|
181
|
+
// instead of the signal's richer reason. Preserve caller cancellation
|
|
182
|
+
// and the activation-specific deadline error at this public boundary.
|
|
183
|
+
throwIfAborted(signal);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
if (deadlineTimer !== null)
|
|
188
|
+
clearTimeout(deadlineTimer);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/namespaces/inbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { HttpClient } from '../http.js';
|
|
2
|
+
import type { LiveClaimAction, LiveClaimResult, LiveStatusPing, LiveStatusResult, LiveStatusSnapshot } from '../liveStatus.js';
|
|
3
|
+
/**
|
|
4
|
+
* Live-status streams — a self-updating card on the room members' lock screen.
|
|
5
|
+
*
|
|
6
|
+
* Requires the `pingroom:live:write` scope. Free accounts get a small daily
|
|
7
|
+
* budget of NEW streams; updates and the terminal ping of an open stream are
|
|
8
|
+
* never charged, so a card can never be quota-blocked into hanging open. A
|
|
9
|
+
* first ping that is already `done`/`failed` is a new stream and is charged.
|
|
10
|
+
*/
|
|
11
|
+
export declare class LiveApi {
|
|
12
|
+
private readonly http;
|
|
13
|
+
constructor(http: HttpClient);
|
|
14
|
+
/**
|
|
15
|
+
* Send one stream ping — start, update, or end, chosen by `live_status.state`
|
|
16
|
+
* and whether the correlation already exists.
|
|
17
|
+
*/
|
|
18
|
+
push(inviteCode: string, ping: LiveStatusPing): Promise<LiveStatusResult>;
|
|
19
|
+
/**
|
|
20
|
+
* Read back a stream this credential started, so a restarted producer can
|
|
21
|
+
* reconcile instead of opening a duplicate.
|
|
22
|
+
*
|
|
23
|
+
* Resolves null ONLY for a 404 `stream_not_found` — no stream with that
|
|
24
|
+
* correlation id in the last 24 hours. Every other failure throws: a 404 for
|
|
25
|
+
* an unknown or deleted room code, and a 403 `room_not_granted`
|
|
26
|
+
* ({@link RoomScopedErrorCode}) when the room is outside the grant the human
|
|
27
|
+
* gave this agent, both propagate rather than being reported as "no stream".
|
|
28
|
+
*/
|
|
29
|
+
get(inviteCode: string, correlationId: string): Promise<LiveStatusSnapshot | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Act on a "Who's on it?" request as the human this credential acts for:
|
|
32
|
+
* `claim` takes an open request (anyone but its asker), `release` lets go of
|
|
33
|
+
* one you hold, `done` finishes it (its claimer, or its asker at any time) and
|
|
34
|
+
* `cancel` withdraws it (its asker, or a room owner or admin).
|
|
35
|
+
*
|
|
36
|
+
* `release` returns the request to `open` only while it can still be taken.
|
|
37
|
+
* Past its deadline (or four hours after it was made, when it has none) it
|
|
38
|
+
* ends the request as `expired` instead: a 200 whose `claim.status` is
|
|
39
|
+
* `expired` and whose `state` is `failed`, with `claim.by` and `claim.at`
|
|
40
|
+
* `null`. It is not an error, and the asker hears "No one took it". No other
|
|
41
|
+
* action resolves that way.
|
|
42
|
+
*
|
|
43
|
+
* `notificationId` is the request's `notification_id`, from the `push()`
|
|
44
|
+
* result or `notifications.list()`. It needs only room membership, not room
|
|
45
|
+
* ownership, and the `pingroom:live:write` scope.
|
|
46
|
+
*
|
|
47
|
+
* Repeating your own last action resolves with `idempotent: true`. A refusal
|
|
48
|
+
* throws `PingRoomError`: `claim_conflict` (409), `claim_own_request` (422),
|
|
49
|
+
* `claim_private_rooms_only` (422), `claim_not_found` (404) or `forbidden`
|
|
50
|
+
* (403). On 409 and 422 `error.body` is a `LiveClaimRefusal` carrying the
|
|
51
|
+
* request as it stands, so you can say who got it first.
|
|
52
|
+
* A malformed or mismatched success throws `invalid_response`; the SDK
|
|
53
|
+
* never repeats the transition POST automatically.
|
|
54
|
+
*/
|
|
55
|
+
claim(inviteCode: string, notificationId: string, action: LiveClaimAction): Promise<LiveClaimResult>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/namespaces/live.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAGf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAqC1B;;;;;;;GAOG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C;;;OAGG;IACH,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAOzE;;;;;;;;;OASG;IACG,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAcxF;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;CAYrG"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// `pr.live`: live-status streams.
|
|
2
|
+
import { PingRoomError } from '../errors.js';
|
|
3
|
+
import { assertStructuredData, requireNonEmpty } from '../internal/guards.js';
|
|
4
|
+
import { enc } from '../internal/request.js';
|
|
5
|
+
import { isNonEmptyString, isRecord, sameId } from '../internal/validate.js';
|
|
6
|
+
/**
|
|
7
|
+
* What each action's 200 receipt may say, as `[claim.status, stream state]`
|
|
8
|
+
* pairs. `release` has two: letting go reopens a request that can still be
|
|
9
|
+
* taken, but a request past its deadline (or four hours old with none) ends as
|
|
10
|
+
* `expired` with stream state `failed`, exactly as time ends an open one. That
|
|
11
|
+
* is still a 200, and a retry replays it. Only `release` can end that way.
|
|
12
|
+
*/
|
|
13
|
+
const CLAIM_OUTCOMES = {
|
|
14
|
+
claim: [['claimed', 'running']],
|
|
15
|
+
release: [['open', 'running'], ['expired', 'failed']],
|
|
16
|
+
done: [['done', 'done']],
|
|
17
|
+
cancel: [['cancelled', 'failed']],
|
|
18
|
+
};
|
|
19
|
+
function validateClaimResult(value, notificationId, action) {
|
|
20
|
+
const expected = CLAIM_OUTCOMES[action];
|
|
21
|
+
const claim = isRecord(value) ? value['claim'] : undefined;
|
|
22
|
+
const party = isRecord(claim) ? claim['by'] : undefined;
|
|
23
|
+
if (!isRecord(value) || !sameId(value['notification_id'], notificationId)
|
|
24
|
+
|| !isNonEmptyString(value['correlation_id']) || typeof value['idempotent'] !== 'boolean'
|
|
25
|
+
|| !isRecord(claim) || !expected
|
|
26
|
+
|| !expected.some(([status, state]) => claim['status'] === status && value['state'] === state)
|
|
27
|
+
|| typeof claim['late'] !== 'boolean'
|
|
28
|
+
|| !(party === null || isRecord(party) && isNonEmptyString(party['id']) && typeof party['name'] === 'string')
|
|
29
|
+
|| !(claim['at'] === null || typeof claim['at'] === 'number' && Number.isFinite(claim['at']))) {
|
|
30
|
+
throw new PingRoomError('PingRoom returned an invalid claim transition receipt.', {
|
|
31
|
+
code: 'invalid_response',
|
|
32
|
+
body: { expected_notification_id: notificationId, action },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Live-status streams — a self-updating card on the room members' lock screen.
|
|
39
|
+
*
|
|
40
|
+
* Requires the `pingroom:live:write` scope. Free accounts get a small daily
|
|
41
|
+
* budget of NEW streams; updates and the terminal ping of an open stream are
|
|
42
|
+
* never charged, so a card can never be quota-blocked into hanging open. A
|
|
43
|
+
* first ping that is already `done`/`failed` is a new stream and is charged.
|
|
44
|
+
*/
|
|
45
|
+
export class LiveApi {
|
|
46
|
+
http;
|
|
47
|
+
constructor(http) {
|
|
48
|
+
this.http = http;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Send one stream ping — start, update, or end, chosen by `live_status.state`
|
|
52
|
+
* and whether the correlation already exists.
|
|
53
|
+
*/
|
|
54
|
+
push(inviteCode, ping) {
|
|
55
|
+
requireNonEmpty(inviteCode, 'inviteCode');
|
|
56
|
+
requireNonEmpty(ping.correlation_id, 'correlation_id');
|
|
57
|
+
assertStructuredData(ping.data);
|
|
58
|
+
return this.http.request('POST', `/api/agent/rooms/${enc(inviteCode)}/live`, { body: ping });
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Read back a stream this credential started, so a restarted producer can
|
|
62
|
+
* reconcile instead of opening a duplicate.
|
|
63
|
+
*
|
|
64
|
+
* Resolves null ONLY for a 404 `stream_not_found` — no stream with that
|
|
65
|
+
* correlation id in the last 24 hours. Every other failure throws: a 404 for
|
|
66
|
+
* an unknown or deleted room code, and a 403 `room_not_granted`
|
|
67
|
+
* ({@link RoomScopedErrorCode}) when the room is outside the grant the human
|
|
68
|
+
* gave this agent, both propagate rather than being reported as "no stream".
|
|
69
|
+
*/
|
|
70
|
+
async get(inviteCode, correlationId) {
|
|
71
|
+
requireNonEmpty(inviteCode, 'inviteCode');
|
|
72
|
+
requireNonEmpty(correlationId, 'correlationId');
|
|
73
|
+
try {
|
|
74
|
+
return await this.http.request('GET', `/api/agent/rooms/${enc(inviteCode)}/live/${enc(correlationId)}`);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (error instanceof PingRoomError && error.status === 404 && error.code === 'stream_not_found')
|
|
78
|
+
return null;
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Act on a "Who's on it?" request as the human this credential acts for:
|
|
84
|
+
* `claim` takes an open request (anyone but its asker), `release` lets go of
|
|
85
|
+
* one you hold, `done` finishes it (its claimer, or its asker at any time) and
|
|
86
|
+
* `cancel` withdraws it (its asker, or a room owner or admin).
|
|
87
|
+
*
|
|
88
|
+
* `release` returns the request to `open` only while it can still be taken.
|
|
89
|
+
* Past its deadline (or four hours after it was made, when it has none) it
|
|
90
|
+
* ends the request as `expired` instead: a 200 whose `claim.status` is
|
|
91
|
+
* `expired` and whose `state` is `failed`, with `claim.by` and `claim.at`
|
|
92
|
+
* `null`. It is not an error, and the asker hears "No one took it". No other
|
|
93
|
+
* action resolves that way.
|
|
94
|
+
*
|
|
95
|
+
* `notificationId` is the request's `notification_id`, from the `push()`
|
|
96
|
+
* result or `notifications.list()`. It needs only room membership, not room
|
|
97
|
+
* ownership, and the `pingroom:live:write` scope.
|
|
98
|
+
*
|
|
99
|
+
* Repeating your own last action resolves with `idempotent: true`. A refusal
|
|
100
|
+
* throws `PingRoomError`: `claim_conflict` (409), `claim_own_request` (422),
|
|
101
|
+
* `claim_private_rooms_only` (422), `claim_not_found` (404) or `forbidden`
|
|
102
|
+
* (403). On 409 and 422 `error.body` is a `LiveClaimRefusal` carrying the
|
|
103
|
+
* request as it stands, so you can say who got it first.
|
|
104
|
+
* A malformed or mismatched success throws `invalid_response`; the SDK
|
|
105
|
+
* never repeats the transition POST automatically.
|
|
106
|
+
*/
|
|
107
|
+
claim(inviteCode, notificationId, action) {
|
|
108
|
+
requireNonEmpty(inviteCode, 'inviteCode');
|
|
109
|
+
requireNonEmpty(notificationId, 'notificationId');
|
|
110
|
+
if (typeof action !== 'string' || !Object.hasOwn(CLAIM_OUTCOMES, action)) {
|
|
111
|
+
throw new PingRoomError('`action` must be claim, release, done or cancel.', { code: 'invalid_request' });
|
|
112
|
+
}
|
|
113
|
+
return this.http.request('POST', `/api/agent/rooms/${enc(inviteCode)}/live/${enc(notificationId)}/claim`, { body: { action } }).then((value) => validateClaimResult(value, notificationId, action));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/namespaces/live.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { HttpClient } from '../http.js';
|
|
2
|
+
import type { AcknowledgementWaitResult, AgentNotification, ListNotificationsInput, ListenInput, NotificationDetail, NotificationHistoryEntry, Paginated, WaitForAcknowledgementInput, WaitInput, WaitResult } from '../types.js';
|
|
3
|
+
export declare class NotificationsApi {
|
|
4
|
+
private readonly http;
|
|
5
|
+
constructor(http: HttpClient);
|
|
6
|
+
/** Paginated list (polling fallback). Prefer wait()/listen() for real-time. */
|
|
7
|
+
list(input?: ListNotificationsInput): Promise<Paginated<NotificationHistoryEntry>>;
|
|
8
|
+
/** Fetch one visible notification, including its current acknowledgement state. */
|
|
9
|
+
getNotification(notificationId: string): Promise<NotificationDetail>;
|
|
10
|
+
/**
|
|
11
|
+
* One bounded long-poll for an ack-required ping. The returned state may
|
|
12
|
+
* still be `open` when the hold timeout elapses; call again to keep waiting.
|
|
13
|
+
*/
|
|
14
|
+
waitForAcknowledgement(notificationId: string, input?: WaitForAcknowledgementInput): Promise<AcknowledgementWaitResult>;
|
|
15
|
+
/** One long-poll: resolves as soon as new pings land, or with an empty list at timeout. */
|
|
16
|
+
wait(input?: WaitInput): Promise<WaitResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Continuous real-time inbound: an async iterator that long-polls in a loop,
|
|
19
|
+
* advancing the cursor, yielding each new ping. Stops when `signal` aborts.
|
|
20
|
+
*
|
|
21
|
+
* for await (const ping of pr.notifications.listen({ signal })) { ... }
|
|
22
|
+
*/
|
|
23
|
+
listen(input?: ListenInput): AsyncGenerator<AgentNotification, void, void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/namespaces/notifications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK7C,OAAO,KAAK,EACV,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,kBAAkB,EAClB,wBAAwB,EACxB,SAAS,EACT,2BAA2B,EAC3B,SAAS,EACT,UAAU,EACX,MAAM,aAAa,CAAC;AAsBrB,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,+EAA+E;IACzE,IAAI,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAc5F,mFAAmF;IACnF,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKpE;;;OAGG;IACH,sBAAsB,CACpB,cAAc,EAAE,MAAM,EACtB,KAAK,GAAE,2BAAgC,GACtC,OAAO,CAAC,yBAAyB,CAAC;IASrC,2FAA2F;IAC3F,IAAI,CAAC,KAAK,GAAE,SAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAQhD;;;;;OAKG;IACI,MAAM,CAAC,KAAK,GAAE,WAAgB,GAAG,cAAc,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,CAAC;CAuDtF"}
|