@tai42/api-client 1.0.1 → 1.2.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/dist/client.d.ts +282 -42
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +63 -2
- package/dist/client.js.map +1 -1
- package/dist/fleet-report.d.ts +12 -12
- package/dist/fleet-report.d.ts.map +1 -1
- package/dist/fleet-report.js +2 -2
- package/dist/fleet-report.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +1354 -351
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +273 -31
- package/dist/schemas.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +120 -2
- package/src/fleet-report.ts +14 -14
- package/src/index.ts +18 -4
- package/src/schemas.ts +324 -34
package/src/schemas.ts
CHANGED
|
@@ -319,77 +319,117 @@ export type BackendInfo = z.infer<typeof backendInfo>;
|
|
|
319
319
|
|
|
320
320
|
/** The two worker kinds that join the bus: an ASGI `serve` worker or a
|
|
321
321
|
* `backend` runtime process. A drift throws `ApiSchemaError`. */
|
|
322
|
-
export const
|
|
323
|
-
export type
|
|
322
|
+
export const workerKind = z.enum(['serve', 'backend']);
|
|
323
|
+
export type WorkerKind = z.infer<typeof workerKind>;
|
|
324
|
+
|
|
325
|
+
/** The lifecycle state a worker advertises in its presence value: `ready` once its
|
|
326
|
+
* resync has converged, `resyncing` while a boot/reconnect resync runs, `recycling`
|
|
327
|
+
* once it has begun a graceful self-exit. A drift throws `ApiSchemaError`. */
|
|
328
|
+
export const workerState = z.enum(['ready', 'resyncing', 'recycling']);
|
|
329
|
+
export type WorkerState = z.infer<typeof workerState>;
|
|
330
|
+
|
|
331
|
+
/** The last op a worker applied, stamped onto its presence row after the terminal
|
|
332
|
+
* reply. `outcome` is the free op-outcome string; `at` is the ISO instant it landed. */
|
|
333
|
+
export const workerLastOp = z.object({
|
|
334
|
+
op: z.string(),
|
|
335
|
+
outcome: z.string(),
|
|
336
|
+
at: z.string(),
|
|
337
|
+
});
|
|
338
|
+
export type WorkerLastOp = z.infer<typeof workerLastOp>;
|
|
324
339
|
|
|
325
340
|
/**
|
|
326
|
-
* One live worker on the bus — a presence-census
|
|
327
|
-
* `{kind}-{
|
|
328
|
-
*
|
|
341
|
+
* One live worker on the bus — a presence-census row. `name` is the stable slot
|
|
342
|
+
* (`{kind}-{n}`) that doubles as a reload target; `generation` is the monotonic life
|
|
343
|
+
* counter minted with the worker's claim; `kind` tells the two worker kinds apart;
|
|
344
|
+
* `pid` is the process id. `joined_at`/`beat_at` are ISO instants (first-seen and last
|
|
345
|
+
* heartbeat) for the cosmetic seen-since display; `state` is the advertised lifecycle
|
|
346
|
+
* state; `stale` is SERVER-computed from the row's remaining presence TTL against the
|
|
347
|
+
* bus cadence (a quiet row past the freshness bound — reconnecting or dead) and is the
|
|
348
|
+
* only freshness signal a client reads, never a client-side threshold; `last_op` is the
|
|
349
|
+
* worker's last applied op, or `null` before it has applied one.
|
|
329
350
|
*/
|
|
330
|
-
export const
|
|
331
|
-
|
|
332
|
-
kind:
|
|
351
|
+
export const fleetWorker = z.object({
|
|
352
|
+
name: z.string(),
|
|
353
|
+
kind: workerKind,
|
|
333
354
|
pid: z.number(),
|
|
355
|
+
generation: z.number(),
|
|
356
|
+
joined_at: z.string(),
|
|
357
|
+
beat_at: z.string(),
|
|
358
|
+
state: workerState,
|
|
359
|
+
stale: z.boolean(),
|
|
360
|
+
last_op: workerLastOp.nullable(),
|
|
334
361
|
});
|
|
335
|
-
export type
|
|
362
|
+
export type FleetWorker = z.infer<typeof fleetWorker>;
|
|
336
363
|
|
|
337
364
|
/**
|
|
338
365
|
* `GET /api/fleet/workers` — the live worker fleet from the bus presence census.
|
|
339
|
-
* The census lists ALL subscribed
|
|
366
|
+
* The census lists ALL subscribed workers (ASGI `serve` workers and backend-runtime
|
|
340
367
|
* processes alike), not only backend workers. A census read that fails surfaces as a
|
|
341
368
|
* loud 500, never a fabricated empty fleet.
|
|
342
369
|
*/
|
|
343
|
-
export const fleetWorkers = z.object({ workers: z.array(
|
|
370
|
+
export const fleetWorkers = z.object({ workers: z.array(fleetWorker) });
|
|
344
371
|
export type FleetWorkers = z.infer<typeof fleetWorkers>;
|
|
345
372
|
|
|
346
373
|
/**
|
|
347
|
-
* One
|
|
348
|
-
*
|
|
349
|
-
*
|
|
374
|
+
* One worker's outcome within a fleet broadcast. `applied`/`failed` are terminal wire
|
|
375
|
+
* replies from a subscriber; `missing`/`departed`/`timed_out` are publisher-computed
|
|
376
|
+
* from the presence census (a silent worker never sends them); `resyncing`/`recycling`/
|
|
377
|
+
* `stale` are the gap outcomes for a row that failed the ready+fresh gate — reported as
|
|
378
|
+
* its own actual condition rather than dropped (`resyncing` converges on its resync,
|
|
379
|
+
* `recycling` is departing, `stale` is a quiet row past the freshness bound carrying no
|
|
380
|
+
* convergence promise).
|
|
350
381
|
*/
|
|
351
|
-
export const fleetOutcome = z.enum([
|
|
382
|
+
export const fleetOutcome = z.enum([
|
|
383
|
+
'applied',
|
|
384
|
+
'failed',
|
|
385
|
+
'missing',
|
|
386
|
+
'departed',
|
|
387
|
+
'timed_out',
|
|
388
|
+
'resyncing',
|
|
389
|
+
'recycling',
|
|
390
|
+
'stale',
|
|
391
|
+
]);
|
|
352
392
|
export type FleetOutcome = z.infer<typeof fleetOutcome>;
|
|
353
393
|
|
|
354
394
|
/**
|
|
355
|
-
* One
|
|
395
|
+
* One worker's result within a {@link fleetResult}. `payload` carries query-op data
|
|
356
396
|
* (opaque to the UI); `error` carries a failed apply's message; `detail` carries the
|
|
357
|
-
* publisher's report text for a computed `missing`/`departed`/`timed_out
|
|
358
|
-
* throws `ApiSchemaError`.
|
|
397
|
+
* publisher's report text for a computed gap outcome (`missing`/`departed`/`timed_out`/
|
|
398
|
+
* `resyncing`/`recycling`/`stale`). A drift throws `ApiSchemaError`.
|
|
359
399
|
*/
|
|
360
|
-
export const
|
|
361
|
-
|
|
400
|
+
export const fleetWorkerResult = z.object({
|
|
401
|
+
name: z.string(),
|
|
362
402
|
outcome: fleetOutcome,
|
|
363
403
|
payload: jsonValue,
|
|
364
404
|
error: z.string().nullable(),
|
|
365
405
|
detail: z.string().nullable(),
|
|
366
406
|
});
|
|
367
|
-
export type
|
|
407
|
+
export type FleetWorkerResult = z.infer<typeof fleetWorkerResult>;
|
|
368
408
|
|
|
369
409
|
/**
|
|
370
|
-
* The awaited per-
|
|
410
|
+
* The awaited per-worker report of one fleet broadcast. Two honest shapes ride the
|
|
371
411
|
* same schema. Reachable (`reachable: true`): `results` holds one entry per expected
|
|
372
|
-
*
|
|
373
|
-
* visible `failed`/`missing`/`departed`/`timed_out
|
|
374
|
-
* worker. Bus-unreachable (`reachable: false`): the
|
|
375
|
-
*
|
|
376
|
-
* bare body of `POST /api/fleet/reload-config` and the single-MCP
|
|
377
|
-
* the body the mode-wrapped {@link fleetReportFanout} carries under its
|
|
378
|
-
* `unreachable` modes.
|
|
412
|
+
* worker (the serving worker's own entry included) plus the gap rows, so an unconfirmed
|
|
413
|
+
* sibling is a visible `failed`/`missing`/`departed`/`timed_out`/`resyncing`/`recycling`/
|
|
414
|
+
* `stale` entry, never a silent stale worker. Bus-unreachable (`reachable: false`): the
|
|
415
|
+
* transport failed before any worker could reply, so `results` is empty and only `error`
|
|
416
|
+
* is carried. This is the bare body of `POST /api/fleet/reload-config` and the single-MCP
|
|
417
|
+
* reload; it is also the body the mode-wrapped {@link fleetReportFanout} carries under its
|
|
418
|
+
* `fleet` / `unreachable` modes.
|
|
379
419
|
*/
|
|
380
420
|
export const fleetResult = z.object({
|
|
381
421
|
op: z.string(),
|
|
382
422
|
reachable: z.boolean(),
|
|
383
423
|
local_only: z.boolean(),
|
|
384
|
-
results: z.array(
|
|
424
|
+
results: z.array(fleetWorkerResult),
|
|
385
425
|
error: z.string().nullable(),
|
|
386
426
|
});
|
|
387
427
|
export type FleetResult = z.infer<typeof fleetResult>;
|
|
388
428
|
|
|
389
429
|
/**
|
|
390
|
-
* `POST /api/fleet/reload-config` — soft-restart the fleet and report per-
|
|
430
|
+
* `POST /api/fleet/reload-config` — soft-restart the fleet and report per-worker. The
|
|
391
431
|
* serving worker applies its own reload first, then broadcasts; the returned report
|
|
392
|
-
* names every
|
|
432
|
+
* names every worker's outcome. A failed local apply does not abort the broadcast, so
|
|
393
433
|
* the report is embedded even on the convergence-failure path.
|
|
394
434
|
*/
|
|
395
435
|
export const fleetReloadResult = fleetResult;
|
|
@@ -403,7 +443,7 @@ export type FleetReloadResult = z.infer<typeof fleetReloadResult>;
|
|
|
403
443
|
* - `fleet` — a reachable multi-worker broadcast; carries the full {@link
|
|
404
444
|
* fleetResult} so an unconfirmed sibling is visible.
|
|
405
445
|
* - `unreachable` — the bus itself could not be reached; carries the
|
|
406
|
-
* bus-unreachable {@link fleetResult} (no
|
|
446
|
+
* bus-unreachable {@link fleetResult} (no worker list, only `error`).
|
|
407
447
|
*
|
|
408
448
|
* Every mutation whose response embeds this parses it EXPLICITLY: zod's default
|
|
409
449
|
* unknown-key stripping would otherwise silently drop the field, hiding a failed
|
|
@@ -501,7 +541,7 @@ export const mcpStatus = z.object({
|
|
|
501
541
|
|
|
502
542
|
/**
|
|
503
543
|
* `POST /api/mcp-status/{title}/reload` — re-probe a single MCP server and broadcast
|
|
504
|
-
* the reload to the fleet. The response is the bare per-
|
|
544
|
+
* the reload to the fleet. The response is the bare per-worker {@link fleetResult}
|
|
505
545
|
* (the serving worker's re-probe rides its own `results` entry as the payload); there
|
|
506
546
|
* is no local/workers split. A drift throws `ApiSchemaError`.
|
|
507
547
|
*/
|
|
@@ -549,6 +589,123 @@ export const configMode = z.object({
|
|
|
549
589
|
read_only: z.boolean().default(false),
|
|
550
590
|
});
|
|
551
591
|
|
|
592
|
+
// -- settings profiles -------------------------------------------------------
|
|
593
|
+
// The admin-only `/api/config/profiles/*` surface. Secrets ride the wire in the
|
|
594
|
+
// clear (secret/fenced routes); masking is CLIENT-SIDE per the secret-mask union. A drift
|
|
595
|
+
// on any of these throws `ApiSchemaError`.
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* `GET /api/config/profiles` — one row per stored profile. The list is
|
|
599
|
+
* names+descriptions ONLY (action=read); no `env`, no `secret_keys`, no bodies.
|
|
600
|
+
* (No `last_modified`: the list carries identity, not history — version metadata
|
|
601
|
+
* is the `/versions` surface — so the list renders no last-modified column.)
|
|
602
|
+
*/
|
|
603
|
+
export const settingsProfileSummary = z.object({
|
|
604
|
+
name: z.string(),
|
|
605
|
+
description: z.string(),
|
|
606
|
+
});
|
|
607
|
+
export type SettingsProfileSummary = z.infer<typeof settingsProfileSummary>;
|
|
608
|
+
export const settingsProfileList = z.array(settingsProfileSummary);
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* `GET /api/config/profiles/{name}` and each version body — the stored profile
|
|
612
|
+
* document (action=secret). `env` carries REAL values; `secret_keys` is the
|
|
613
|
+
* per-profile secret-marks band folded into the secret-mask union for masking.
|
|
614
|
+
*/
|
|
615
|
+
export const settingsProfileBody = z.object({
|
|
616
|
+
description: z.string(),
|
|
617
|
+
env: z.record(z.string(), z.string()),
|
|
618
|
+
secret_keys: z.array(z.string()),
|
|
619
|
+
});
|
|
620
|
+
export type SettingsProfileBody = z.infer<typeof settingsProfileBody>;
|
|
621
|
+
|
|
622
|
+
/** `PUT /api/config/profiles/{name}` — a minimal save ack; `version` is the new store version. */
|
|
623
|
+
export const settingsProfileSaved = z.object({
|
|
624
|
+
ok: z.literal(true),
|
|
625
|
+
version: z.number().optional(),
|
|
626
|
+
});
|
|
627
|
+
export type SettingsProfileSaved = z.infer<typeof settingsProfileSaved>;
|
|
628
|
+
|
|
629
|
+
/** `DELETE /api/config/profiles/{name}` — a minimal removal ack. */
|
|
630
|
+
export const settingsProfileDeleted = z.object({ ok: z.literal(true) });
|
|
631
|
+
|
|
632
|
+
/** `POST /api/config/profiles/{name}/rollback` — the restore ack; `version` is the resulting active version. */
|
|
633
|
+
export const settingsProfileRollback = z.object({
|
|
634
|
+
ok: z.literal(true),
|
|
635
|
+
version: z.number(),
|
|
636
|
+
});
|
|
637
|
+
export type SettingsProfileRollback = z.infer<typeof settingsProfileRollback>;
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* `POST /api/config/profiles/{name}/diff` — the SAVED profile vs the stored env
|
|
641
|
+
* (action=secret). `changed` carries real `old`/`new` values (UI masks via
|
|
642
|
+
* JsonDiff); `recycle_keys`/`refused_keys` are the diff's recycle-class and
|
|
643
|
+
* boundary-refused key names, called out in the UI before apply.
|
|
644
|
+
*/
|
|
645
|
+
export const settingsProfileDiff = z.object({
|
|
646
|
+
added: z.array(z.string()),
|
|
647
|
+
removed: z.array(z.string()),
|
|
648
|
+
changed: z.array(z.object({ key: z.string(), old: z.string(), new: z.string() })),
|
|
649
|
+
recycle_keys: z.array(z.string()),
|
|
650
|
+
refused_keys: z.array(z.string()),
|
|
651
|
+
});
|
|
652
|
+
export type SettingsProfileDiff = z.infer<typeof settingsProfileDiff>;
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* `POST /api/config/profiles/{name}/apply` — the dedicated `profile_apply_response`
|
|
656
|
+
* (action=fenced, destructive). NAMES-ONLY (no env value in any
|
|
657
|
+
* section): `hot` is the hot-swapped key names; `recycle` is the orchestrator's
|
|
658
|
+
* per-worker section — one `{name, kind, status, generation_before}` row per recycled
|
|
659
|
+
* target, `generation_before` the life that was recycled, the applier's OWN row carrying
|
|
660
|
+
* the `self-deferred` status literal when the diff has serve-affecting recycle keys;
|
|
661
|
+
* `fresh` is the per-kind list of NEW ready lives observed since the pre-apply snapshot
|
|
662
|
+
* (each `{name, kind, generation}`), evidence of fresh capacity and never claimed as any
|
|
663
|
+
* target's successor; `refused` is `[]` on success by construction (populated
|
|
664
|
+
* `{key, reason}` only on a refusal), the populated refusal surfaces being the diff
|
|
665
|
+
* preview and the refusal error report. `fanout` is the mode-wrapped fleet broadcast,
|
|
666
|
+
* parsed EXPLICITLY so a failed propagation reaches the shared fleet-report handler. A
|
|
667
|
+
* drift throws `ApiSchemaError`.
|
|
668
|
+
*/
|
|
669
|
+
export const profileApplyResponse = z.object({
|
|
670
|
+
hot: z.array(z.string()),
|
|
671
|
+
recycle: z.array(
|
|
672
|
+
z.object({
|
|
673
|
+
name: z.string(),
|
|
674
|
+
kind: z.string(),
|
|
675
|
+
status: z.string(),
|
|
676
|
+
generation_before: z.number(),
|
|
677
|
+
}),
|
|
678
|
+
),
|
|
679
|
+
fresh: z.array(z.object({ name: z.string(), kind: z.string(), generation: z.number() })),
|
|
680
|
+
refused: z.array(z.object({ key: z.string(), reason: z.string() })),
|
|
681
|
+
fanout: fleetReportFanout,
|
|
682
|
+
});
|
|
683
|
+
export type ProfileApplyResponse = z.infer<typeof profileApplyResponse>;
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* `GET /api/config/profiles/{name}/versions` — version METADATA only (action=read;
|
|
687
|
+
* no bodies), the generic versioned-store row minus `body`. `is_current` flags the
|
|
688
|
+
* active pointer.
|
|
689
|
+
*/
|
|
690
|
+
export const settingsProfileVersionMeta = z.object({
|
|
691
|
+
version: z.number(),
|
|
692
|
+
tags: z.array(z.string()),
|
|
693
|
+
created_at: z.string(),
|
|
694
|
+
is_current: z.boolean(),
|
|
695
|
+
});
|
|
696
|
+
export type SettingsProfileVersionMeta = z.infer<typeof settingsProfileVersionMeta>;
|
|
697
|
+
export const settingsProfileVersionList = z.array(settingsProfileVersionMeta);
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* `GET /api/config/profiles/{name}/versions/{version}` — one immutable version WITH
|
|
701
|
+
* its `body` (action=secret; body rendered masked per the secret-mask union). The generic
|
|
702
|
+
* versioned-store row shape.
|
|
703
|
+
*/
|
|
704
|
+
export const settingsProfileVersion = settingsProfileVersionMeta.extend({
|
|
705
|
+
body: settingsProfileBody,
|
|
706
|
+
});
|
|
707
|
+
export type SettingsProfileVersion = z.infer<typeof settingsProfileVersion>;
|
|
708
|
+
|
|
552
709
|
// -- connectors --------------------------------------------------------------
|
|
553
710
|
|
|
554
711
|
export const subServiceView = z.object({
|
|
@@ -795,6 +952,139 @@ export const channels = z.object({
|
|
|
795
952
|
});
|
|
796
953
|
export type Channels = z.infer<typeof channels>;
|
|
797
954
|
|
|
955
|
+
// -- conversations -----------------------------------------------------------
|
|
956
|
+
// The cross-channel conversation monitor's READ side: the stored routing rows
|
|
957
|
+
// (the route picker) from `GET /api/conversations`, a route's threads from
|
|
958
|
+
// `GET /api/conversations/{route}/threads`, and one thread's transcript from
|
|
959
|
+
// `GET /api/conversations/{route}/transcript?thread_id=`. Timestamps are float
|
|
960
|
+
// epoch seconds, not ISO strings, and both paged doors carry the same window
|
|
961
|
+
// fields; the transcript adds the direction it was read in.
|
|
962
|
+
|
|
963
|
+
/** The inbound door a route is bound to: the authed API, or a channel medium. */
|
|
964
|
+
export const conversationDoor = z.enum(['api', 'channel']);
|
|
965
|
+
export type ConversationDoor = z.infer<typeof conversationDoor>;
|
|
966
|
+
|
|
967
|
+
/** What a route's turn runs: a registered agent, or a tool dispatch. */
|
|
968
|
+
export const conversationTargetKind = z.enum(['agent', 'tool']);
|
|
969
|
+
export type ConversationTargetKind = z.infer<typeof conversationTargetKind>;
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Where a record sits between intake and a terminal outcome. `failed` is the one
|
|
973
|
+
* the monitor surfaces loudly; `shed` and `silent` are terminal by design and
|
|
974
|
+
* never send.
|
|
975
|
+
*/
|
|
976
|
+
export const conversationDeliveryStatus = z.enum([
|
|
977
|
+
'accepted',
|
|
978
|
+
'pending_delivery',
|
|
979
|
+
'provisional',
|
|
980
|
+
'delivered',
|
|
981
|
+
'failed',
|
|
982
|
+
'shed',
|
|
983
|
+
'silent',
|
|
984
|
+
]);
|
|
985
|
+
export type ConversationDeliveryStatus = z.infer<typeof conversationDeliveryStatus>;
|
|
986
|
+
|
|
987
|
+
/** The nature of a turn's outcome, orthogonal to where its delivery stands. */
|
|
988
|
+
export const conversationAnswerStatus = z.enum(['answered', 'error', 'silent']);
|
|
989
|
+
export type ConversationAnswerStatus = z.infer<typeof conversationAnswerStatus>;
|
|
990
|
+
|
|
991
|
+
/** A stored routing row as a read door returns it, its `callback_secret` withheld. */
|
|
992
|
+
export const conversationRoute = z.object({
|
|
993
|
+
route_name: z.string(),
|
|
994
|
+
door: conversationDoor,
|
|
995
|
+
target_kind: conversationTargetKind,
|
|
996
|
+
target_name: z.string(),
|
|
997
|
+
payload_expr: z.string().nullable(),
|
|
998
|
+
reply_expr: z.string().nullable(),
|
|
999
|
+
execution_key: z.string(),
|
|
1000
|
+
channel: z.string().nullable(),
|
|
1001
|
+
our_identity: z.string().nullable(),
|
|
1002
|
+
callback_url: z.string().nullable(),
|
|
1003
|
+
execution_key_fingerprint: z.string(),
|
|
1004
|
+
});
|
|
1005
|
+
export type ConversationRoute = z.infer<typeof conversationRoute>;
|
|
1006
|
+
|
|
1007
|
+
export const conversationRoutes = z.object({
|
|
1008
|
+
items: z.array(conversationRoute),
|
|
1009
|
+
total: z.number(),
|
|
1010
|
+
});
|
|
1011
|
+
export type ConversationRoutes = z.infer<typeof conversationRoutes>;
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* One thread of a route, summarized from its newest record. A `thread_id` holds
|
|
1015
|
+
* an api-door address (`{principal}/{end user}`, percent-encoded), so it never
|
|
1016
|
+
* goes back into a URL as a path segment — the transcript door takes it as a
|
|
1017
|
+
* query value.
|
|
1018
|
+
*/
|
|
1019
|
+
export const conversationThread = z.object({
|
|
1020
|
+
thread_id: z.string(),
|
|
1021
|
+
client_address: z.string(),
|
|
1022
|
+
last_activity_at: z.number(),
|
|
1023
|
+
message_count: z.number(),
|
|
1024
|
+
last_delivery_status: conversationDeliveryStatus,
|
|
1025
|
+
});
|
|
1026
|
+
export type ConversationThread = z.infer<typeof conversationThread>;
|
|
1027
|
+
|
|
1028
|
+
/** The page window both thread read doors carry; `next_page` is null on the last. */
|
|
1029
|
+
const conversationPageWindow = {
|
|
1030
|
+
total: z.number(),
|
|
1031
|
+
page: z.number(),
|
|
1032
|
+
page_size: z.number(),
|
|
1033
|
+
next_page: z.number().nullable(),
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
export const conversationThreadsPage = z.object({
|
|
1037
|
+
items: z.array(conversationThread),
|
|
1038
|
+
...conversationPageWindow,
|
|
1039
|
+
});
|
|
1040
|
+
export type ConversationThreadsPage = z.infer<typeof conversationThreadsPage>;
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* One exchange: the visitor's `inbound_text` — every record answers a message, so
|
|
1044
|
+
* both projections always carry it — and the agent's `answer`, plus where that
|
|
1045
|
+
* answer's delivery stands. The fields after `updated_at` are ADMIN ONLY —
|
|
1046
|
+
* the same door serves a caller-scoped projection that withholds them — so they
|
|
1047
|
+
* are optional here and absence means "not published to this reader".
|
|
1048
|
+
*/
|
|
1049
|
+
export const conversationMessage = z.object({
|
|
1050
|
+
message_id: z.string(),
|
|
1051
|
+
route_name: z.string(),
|
|
1052
|
+
door: conversationDoor,
|
|
1053
|
+
thread_id: z.string(),
|
|
1054
|
+
client_address: z.string(),
|
|
1055
|
+
caller_principal: z.string().nullable(),
|
|
1056
|
+
inbound_text: z.string(),
|
|
1057
|
+
answer_status: conversationAnswerStatus.nullable(),
|
|
1058
|
+
answer: z.string().nullable(),
|
|
1059
|
+
delivery_status: conversationDeliveryStatus,
|
|
1060
|
+
created_at: z.number(),
|
|
1061
|
+
updated_at: z.number(),
|
|
1062
|
+
channel: z.string().nullable().optional(),
|
|
1063
|
+
our_identity: z.string().nullable().optional(),
|
|
1064
|
+
provider_message_id: z.string().nullable().optional(),
|
|
1065
|
+
callback_url: z.string().nullable().optional(),
|
|
1066
|
+
error: z.string().nullable().optional(),
|
|
1067
|
+
outbound_message_ids: z.array(z.string()).optional(),
|
|
1068
|
+
attempts: z.number().optional(),
|
|
1069
|
+
});
|
|
1070
|
+
export type ConversationMessage = z.infer<typeof conversationMessage>;
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* The direction a transcript page reads in. `asc` is the reading order (oldest
|
|
1074
|
+
* first); `desc` is the live-tail order, where page 1 is always the newest page
|
|
1075
|
+
* and paging forward walks BACKWARDS through the thread's history.
|
|
1076
|
+
*/
|
|
1077
|
+
export const transcriptOrder = z.enum(['asc', 'desc']);
|
|
1078
|
+
export type TranscriptOrder = z.infer<typeof transcriptOrder>;
|
|
1079
|
+
|
|
1080
|
+
/** A transcript page, echoing the order it was read in. */
|
|
1081
|
+
export const conversationTranscriptPage = z.object({
|
|
1082
|
+
items: z.array(conversationMessage),
|
|
1083
|
+
...conversationPageWindow,
|
|
1084
|
+
order: transcriptOrder,
|
|
1085
|
+
});
|
|
1086
|
+
export type ConversationTranscriptPage = z.infer<typeof conversationTranscriptPage>;
|
|
1087
|
+
|
|
798
1088
|
// -- notifications -----------------------------------------------------------
|
|
799
1089
|
// The internal notifications sink: the messages the `notify_user` operation records
|
|
800
1090
|
// with no channel, so they land only in the Studio inbox. Each record carries the
|