@band-ai/band-sdk-core 1.2.1 → 2.1.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 +45 -0
- package/band_sdk_core.js +94 -0
- package/band_sdk_core_bg.wasm +0 -0
- package/index.d.ts +145 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,6 +148,51 @@ native `Error` with the same `.issues`/`.traceContext` contract as
|
|
|
148
148
|
`type` are independent issues, both reported when both strings are
|
|
149
149
|
invalid.
|
|
150
150
|
|
|
151
|
+
### One-shot delivery lifecycle
|
|
152
|
+
|
|
153
|
+
`evaluateDeliveryEvent`, `evaluateNextMessage`, `evaluateDrainCandidate`, and
|
|
154
|
+
`evaluateAdapterResult` are the stateless one-shot delivery lifecycle
|
|
155
|
+
decisions — design decisions live as rustdoc in
|
|
156
|
+
`crates/core/src/runtime/delivery.rs`. Each returns a plain tagged object;
|
|
157
|
+
there is no cross-invocation state, so there is no class here to construct.
|
|
158
|
+
Decision fields stay snake_case (message-wire vocabulary: `room_id`,
|
|
159
|
+
`sender_id`, `sender_type`, …), unlike this module's own camelCase
|
|
160
|
+
function/argument names, so the same shape returns identically from both
|
|
161
|
+
bindings.
|
|
162
|
+
|
|
163
|
+
`evaluateDeliveryEvent(eventType, roomId, payload, agentId, traceContext?)`
|
|
164
|
+
routes one inbound event: `"ignored"` for an unrecognized or out-of-scope
|
|
165
|
+
`eventType`; `"cleanup"` for `room_removed`/`room_deleted`; `"skip_self"` or
|
|
166
|
+
`"invocation"` for `message_created`, depending on whether the sender is
|
|
167
|
+
this agent (`sender_type === "Agent"` and `sender_id === agentId`).
|
|
168
|
+
`message_created` delegates to `validateEventPayload` for payload-shape
|
|
169
|
+
validation, so a malformed `payload` throws the same `Error`, and
|
|
170
|
+
additionally rejects an empty `payload.id` — a message with no identity
|
|
171
|
+
cannot be claimed or acknowledged. `room_removed`/`room_deleted` need no
|
|
172
|
+
payload shape and read `id` straight off the raw payload.
|
|
173
|
+
|
|
174
|
+
`roomId` resolves from the caller-supplied `roomId` first, else the payload's
|
|
175
|
+
own `chat_room_id` (message events) or `id` (room events). An empty string
|
|
176
|
+
counts as absent at both steps. Unresolvable throws an `Error` with one issue
|
|
177
|
+
on path `room_id`: code `missing` when the fallback field is absent or empty,
|
|
178
|
+
`wrong_type` when it is present but not a string.
|
|
179
|
+
|
|
180
|
+
`evaluateNextMessage(triggeringMessageId, nextMessageId)` compares the
|
|
181
|
+
triggering message against the platform's authoritative "next open message"
|
|
182
|
+
for a room (already fetched by the caller): `"no_pending"`,
|
|
183
|
+
`"already_processed"`, or `"ready_to_claim"`.
|
|
184
|
+
|
|
185
|
+
`evaluateDrainCandidate(candidate, seenIds, agentId)` classifies one
|
|
186
|
+
already-fetched drain candidate — `candidate` is `{id, sender_id,
|
|
187
|
+
sender_type}`, or `null`/`undefined` when the fetch returned nothing:
|
|
188
|
+
`"no_candidate"`, `"self_echo"` (checked before the snapshot, so an echo
|
|
189
|
+
never halts a drain), `"out_of_snapshot"` (stop), or `"drain"` (continue).
|
|
190
|
+
The caller's own bounded or unbounded loop owns the cap; this function
|
|
191
|
+
classifies one candidate per call.
|
|
192
|
+
|
|
193
|
+
`evaluateAdapterResult(roomId, messageId, succeeded)` maps an adapter
|
|
194
|
+
outcome to `"processed"` or `"failed"`.
|
|
195
|
+
|
|
151
196
|
The public declaration is
|
|
152
197
|
[`index.d.ts`](https://github.com/band-ai/band-sdk-core/blob/main/crates/wasm/index.d.ts).
|
|
153
198
|
|
package/band_sdk_core.js
CHANGED
|
@@ -727,6 +727,13 @@ class SessionPolicy {
|
|
|
727
727
|
const ptr = this.__destroy_into_raw();
|
|
728
728
|
wasm.__wbg_sessionpolicy_free(ptr, 0);
|
|
729
729
|
}
|
|
730
|
+
/**
|
|
731
|
+
* @returns {number}
|
|
732
|
+
*/
|
|
733
|
+
get deadThresholdS() {
|
|
734
|
+
const ret = wasm.sessionpolicy_deadThresholdS(this.__wbg_ptr);
|
|
735
|
+
return ret;
|
|
736
|
+
}
|
|
730
737
|
/**
|
|
731
738
|
* A recommended, not final, default.
|
|
732
739
|
* @returns {SessionPolicy}
|
|
@@ -735,6 +742,13 @@ class SessionPolicy {
|
|
|
735
742
|
const ret = wasm.sessionpolicy_default();
|
|
736
743
|
return SessionPolicy.__wrap(ret);
|
|
737
744
|
}
|
|
745
|
+
/**
|
|
746
|
+
* @returns {number}
|
|
747
|
+
*/
|
|
748
|
+
get heartbeatIntervalS() {
|
|
749
|
+
const ret = wasm.sessionpolicy_heartbeatIntervalS(this.__wbg_ptr);
|
|
750
|
+
return ret;
|
|
751
|
+
}
|
|
738
752
|
/**
|
|
739
753
|
* `config` is any plain object with the fields declared in
|
|
740
754
|
* `index.d.ts`'s `SessionPolicyConfig`; grouped into one value rather
|
|
@@ -1192,6 +1206,82 @@ function classifyUpgrade(status) {
|
|
|
1192
1206
|
}
|
|
1193
1207
|
exports.classifyUpgrade = classifyUpgrade;
|
|
1194
1208
|
|
|
1209
|
+
/**
|
|
1210
|
+
* Adapter outcome -> ack decision. Throws a plain `Error` if `roomId`/
|
|
1211
|
+
* `messageId` is not a string.
|
|
1212
|
+
* @param {any} roomId
|
|
1213
|
+
* @param {any} messageId
|
|
1214
|
+
* @param {boolean} succeeded
|
|
1215
|
+
* @returns {any}
|
|
1216
|
+
*/
|
|
1217
|
+
function evaluateAdapterResult(roomId, messageId, succeeded) {
|
|
1218
|
+
const ret = wasm.evaluateAdapterResult(roomId, messageId, succeeded);
|
|
1219
|
+
if (ret[2]) {
|
|
1220
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
1221
|
+
}
|
|
1222
|
+
return takeFromExternrefTable0(ret[0]);
|
|
1223
|
+
}
|
|
1224
|
+
exports.evaluateAdapterResult = evaluateAdapterResult;
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Evaluate the routing decision for one inbound platform event.
|
|
1228
|
+
*
|
|
1229
|
+
* On failure throws a native `Error` with `.issues` (an array of
|
|
1230
|
+
* `{path, code, message}` objects) and `.traceContext`. A non-string
|
|
1231
|
+
* `eventType`/`roomId`/`agentId`/`traceContext`, or a `payload` that
|
|
1232
|
+
* cannot be converted, throws a plain `Error` without `.issues`.
|
|
1233
|
+
* @param {any} eventType
|
|
1234
|
+
* @param {any} roomId
|
|
1235
|
+
* @param {any} payload
|
|
1236
|
+
* @param {any} agentId
|
|
1237
|
+
* @param {any} traceContext
|
|
1238
|
+
* @returns {any}
|
|
1239
|
+
*/
|
|
1240
|
+
function evaluateDeliveryEvent(eventType, roomId, payload, agentId, traceContext) {
|
|
1241
|
+
const ret = wasm.evaluateDeliveryEvent(eventType, roomId, payload, agentId, traceContext);
|
|
1242
|
+
if (ret[2]) {
|
|
1243
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
1244
|
+
}
|
|
1245
|
+
return takeFromExternrefTable0(ret[0]);
|
|
1246
|
+
}
|
|
1247
|
+
exports.evaluateDeliveryEvent = evaluateDeliveryEvent;
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
* One step of the drain loop. `candidate` is `{id, sender_id,
|
|
1251
|
+
* sender_type}` or `null`/`undefined` when the host's fetch returned no
|
|
1252
|
+
* candidate; a malformed object throws a plain `Error`.
|
|
1253
|
+
* @param {any} candidate
|
|
1254
|
+
* @param {any} seenIds
|
|
1255
|
+
* @param {any} agentId
|
|
1256
|
+
* @returns {any}
|
|
1257
|
+
*/
|
|
1258
|
+
function evaluateDrainCandidate(candidate, seenIds, agentId) {
|
|
1259
|
+
const ret = wasm.evaluateDrainCandidate(candidate, seenIds, agentId);
|
|
1260
|
+
if (ret[2]) {
|
|
1261
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
1262
|
+
}
|
|
1263
|
+
return takeFromExternrefTable0(ret[0]);
|
|
1264
|
+
}
|
|
1265
|
+
exports.evaluateDrainCandidate = evaluateDrainCandidate;
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* Compares the triggering message against the platform's authoritative
|
|
1269
|
+
* "next open message" for a room. Throws a plain `Error` if
|
|
1270
|
+
* `triggeringMessageId`/`nextMessageId` is not a string (or `null`/
|
|
1271
|
+
* `undefined` for `nextMessageId`).
|
|
1272
|
+
* @param {any} triggeringMessageId
|
|
1273
|
+
* @param {any} nextMessageId
|
|
1274
|
+
* @returns {any}
|
|
1275
|
+
*/
|
|
1276
|
+
function evaluateNextMessage(triggeringMessageId, nextMessageId) {
|
|
1277
|
+
const ret = wasm.evaluateNextMessage(triggeringMessageId, nextMessageId);
|
|
1278
|
+
if (ret[2]) {
|
|
1279
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
1280
|
+
}
|
|
1281
|
+
return takeFromExternrefTable0(ret[0]);
|
|
1282
|
+
}
|
|
1283
|
+
exports.evaluateNextMessage = evaluateNextMessage;
|
|
1284
|
+
|
|
1195
1285
|
/**
|
|
1196
1286
|
* This platform's Phoenix Channels topic for a room's `room_participants`
|
|
1197
1287
|
* channel.
|
|
@@ -1372,6 +1462,10 @@ function __wbg_get_imports() {
|
|
|
1372
1462
|
const ret = arg0[arg1 >>> 0];
|
|
1373
1463
|
return ret;
|
|
1374
1464
|
},
|
|
1465
|
+
__wbg_get_with_ref_key_6412cf3094599694: function(arg0, arg1) {
|
|
1466
|
+
const ret = arg0[arg1];
|
|
1467
|
+
return ret;
|
|
1468
|
+
},
|
|
1375
1469
|
__wbg_instanceof_ArrayBuffer_993d02d2d254cad1: function(arg0) {
|
|
1376
1470
|
let result;
|
|
1377
1471
|
try {
|
package/band_sdk_core_bg.wasm
CHANGED
|
Binary file
|
package/index.d.ts
CHANGED
|
@@ -240,21 +240,26 @@ export interface SessionPolicyConfig {
|
|
|
240
240
|
rapidCooldownStepS: number;
|
|
241
241
|
rapidCooldownMaxS: number;
|
|
242
242
|
rapidThreshold: number;
|
|
243
|
+
heartbeatIntervalS: number;
|
|
244
|
+
deadThresholdS: number;
|
|
243
245
|
}
|
|
244
246
|
|
|
245
247
|
/**
|
|
246
248
|
* Reconnect backoff/jitter policy, plus the graduated rapid-disconnect
|
|
247
249
|
* cooldown ladder. A recommended, not final, starting design.
|
|
248
250
|
*
|
|
249
|
-
* Throws a native `Error` with `.issues`/`.traceContext` if `factor < 1.0
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
251
|
+
* Throws a native `Error` with `.issues`/`.traceContext` if `factor < 1.0`,
|
|
252
|
+
* `baseDelayS > maxDelayS`, `heartbeatIntervalS == 0`, or
|
|
253
|
+
* `deadThresholdS <= heartbeatIntervalS`. Throws a plain `Error` if
|
|
254
|
+
* `config` is missing a field or a field is not a finite, non-negative
|
|
255
|
+
* number (`rapidThreshold` must also be an integer).
|
|
253
256
|
*/
|
|
254
257
|
export class SessionPolicy {
|
|
255
258
|
constructor(config: SessionPolicyConfig, traceContext?: string | null);
|
|
256
259
|
/** A recommended, not final, default. */
|
|
257
260
|
static default(): SessionPolicy;
|
|
261
|
+
readonly heartbeatIntervalS: number;
|
|
262
|
+
readonly deadThresholdS: number;
|
|
258
263
|
}
|
|
259
264
|
|
|
260
265
|
/**
|
|
@@ -359,3 +364,139 @@ export class RoomRoster {
|
|
|
359
364
|
reconcile(currentRoomIds: string[]): RoomReconciliation;
|
|
360
365
|
clear(): string[];
|
|
361
366
|
}
|
|
367
|
+
|
|
368
|
+
// The one-shot delivery lifecycle decisions: evaluateDeliveryEvent,
|
|
369
|
+
// evaluateNextMessage, evaluateDrainCandidate, evaluateAdapterResult.
|
|
370
|
+
// Each returns a plain tagged object -- these functions carry no
|
|
371
|
+
// cross-invocation state, so there is no class here to construct. Decision
|
|
372
|
+
// fields stay snake_case (message-wire vocabulary: `room_id`, `sender_id`,
|
|
373
|
+
// `sender_type`, ...), unlike this module's own camelCase function/argument
|
|
374
|
+
// names, so the same shape is returned identically from both bindings.
|
|
375
|
+
|
|
376
|
+
export interface EventIgnored {
|
|
377
|
+
decision: "ignored";
|
|
378
|
+
event_type: string;
|
|
379
|
+
}
|
|
380
|
+
export interface EventCleanup {
|
|
381
|
+
decision: "cleanup";
|
|
382
|
+
room_id: string;
|
|
383
|
+
}
|
|
384
|
+
export interface EventSkipSelf {
|
|
385
|
+
decision: "skip_self";
|
|
386
|
+
room_id: string;
|
|
387
|
+
message_id: string;
|
|
388
|
+
}
|
|
389
|
+
export interface EventInvocation {
|
|
390
|
+
decision: "invocation";
|
|
391
|
+
room_id: string;
|
|
392
|
+
message_id: string;
|
|
393
|
+
sender_id: string;
|
|
394
|
+
sender_type: string;
|
|
395
|
+
}
|
|
396
|
+
export type EventDecision = EventIgnored | EventCleanup | EventSkipSelf | EventInvocation;
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Evaluate the routing decision for one inbound platform event.
|
|
400
|
+
*
|
|
401
|
+
* `message_created` delegates to {@link validateEventPayload}'s own
|
|
402
|
+
* validation; a rejection there throws the same native `Error` with
|
|
403
|
+
* `.issues`/`.traceContext`, as does an empty `payload.id`.
|
|
404
|
+
* `room_removed`/`room_deleted` need no payload shape and read `id` straight
|
|
405
|
+
* off the raw payload. Both event kinds throw that same `Error` shape when
|
|
406
|
+
* `roomId` resolves from neither the envelope nor the payload — an empty
|
|
407
|
+
* string counting as absent — with issue code `missing` when the fallback
|
|
408
|
+
* field is absent or empty and `wrong_type` when it is present but not a
|
|
409
|
+
* string. Throws a plain `Error` without `.issues` if
|
|
410
|
+
* `eventType`/`roomId`/`agentId`/`traceContext` is not a string (or not
|
|
411
|
+
* `null`/`undefined` for `roomId`/`traceContext`), or if `payload` cannot be
|
|
412
|
+
* converted.
|
|
413
|
+
*/
|
|
414
|
+
export function evaluateDeliveryEvent(
|
|
415
|
+
eventType: string,
|
|
416
|
+
roomId: string | null | undefined,
|
|
417
|
+
payload: unknown,
|
|
418
|
+
agentId: string,
|
|
419
|
+
traceContext?: string | null,
|
|
420
|
+
): EventDecision;
|
|
421
|
+
|
|
422
|
+
export interface NextMessageNoPending {
|
|
423
|
+
decision: "no_pending";
|
|
424
|
+
}
|
|
425
|
+
export interface NextMessageAlreadyProcessed {
|
|
426
|
+
decision: "already_processed";
|
|
427
|
+
next_open_id: string;
|
|
428
|
+
}
|
|
429
|
+
export interface NextMessageReadyToClaim {
|
|
430
|
+
decision: "ready_to_claim";
|
|
431
|
+
}
|
|
432
|
+
export type NextMessageDecision =
|
|
433
|
+
| NextMessageNoPending
|
|
434
|
+
| NextMessageAlreadyProcessed
|
|
435
|
+
| NextMessageReadyToClaim;
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Compares the triggering message against the platform's authoritative
|
|
439
|
+
* "next open message" for a room. Throws a plain `Error` if
|
|
440
|
+
* `triggeringMessageId` is not a string, or `nextMessageId` is not a
|
|
441
|
+
* string, `null`, or `undefined`.
|
|
442
|
+
*/
|
|
443
|
+
export function evaluateNextMessage(
|
|
444
|
+
triggeringMessageId: string,
|
|
445
|
+
nextMessageId: string | null | undefined,
|
|
446
|
+
): NextMessageDecision;
|
|
447
|
+
|
|
448
|
+
/** One already-fetched drain candidate, matching `evaluateDeliveryEvent`'s own field names. */
|
|
449
|
+
export interface DrainCandidate {
|
|
450
|
+
id: string;
|
|
451
|
+
sender_id: string;
|
|
452
|
+
sender_type: string;
|
|
453
|
+
}
|
|
454
|
+
export interface DrainNoCandidate {
|
|
455
|
+
decision: "no_candidate";
|
|
456
|
+
}
|
|
457
|
+
export interface DrainOutOfSnapshot {
|
|
458
|
+
decision: "out_of_snapshot";
|
|
459
|
+
message_id: string;
|
|
460
|
+
}
|
|
461
|
+
export interface DrainSelfEcho {
|
|
462
|
+
decision: "self_echo";
|
|
463
|
+
message_id: string;
|
|
464
|
+
}
|
|
465
|
+
export interface DrainMessage {
|
|
466
|
+
decision: "drain";
|
|
467
|
+
message_id: string;
|
|
468
|
+
}
|
|
469
|
+
export type DrainStep = DrainNoCandidate | DrainOutOfSnapshot | DrainSelfEcho | DrainMessage;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* One step of the drain loop. `candidate` is `null`/`undefined` when the
|
|
473
|
+
* host's fetch returned no candidate. Throws a plain `Error` if
|
|
474
|
+
* `candidate` is present but malformed, or if `agentId` is not a string.
|
|
475
|
+
*/
|
|
476
|
+
export function evaluateDrainCandidate(
|
|
477
|
+
candidate: DrainCandidate | null | undefined,
|
|
478
|
+
seenIds: string[],
|
|
479
|
+
agentId: string,
|
|
480
|
+
): DrainStep;
|
|
481
|
+
|
|
482
|
+
export interface AckProcessed {
|
|
483
|
+
decision: "processed";
|
|
484
|
+
room_id: string;
|
|
485
|
+
message_id: string;
|
|
486
|
+
}
|
|
487
|
+
export interface AckFailed {
|
|
488
|
+
decision: "failed";
|
|
489
|
+
room_id: string;
|
|
490
|
+
message_id: string;
|
|
491
|
+
}
|
|
492
|
+
export type AckDecision = AckProcessed | AckFailed;
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Adapter outcome -> ack decision. Throws a plain `Error` if `roomId`/
|
|
496
|
+
* `messageId` is not a string.
|
|
497
|
+
*/
|
|
498
|
+
export function evaluateAdapterResult(
|
|
499
|
+
roomId: string,
|
|
500
|
+
messageId: string,
|
|
501
|
+
succeeded: boolean,
|
|
502
|
+
): AckDecision;
|