@channlize/core 0.4.0 → 0.6.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/index.d.mts CHANGED
@@ -1,3 +1,1630 @@
1
+ /**
2
+ * Channlize for Agents: the JSON shapes of the `/v1/agents` API. They mirror
3
+ * the API's DTOs (`api/lib/agents/dto.ts`), so fields are `snake_case` as
4
+ * the API sends them. Request options are `camelCase`, like the rest of the
5
+ * SDK.
6
+ */
7
+ /** An agent's lifecycle status. Only `active` agents can send. */
8
+ declare const AGENT_STATUSES: readonly ["active", "paused", "retired"];
9
+ type AgentStatus = (typeof AGENT_STATUSES)[number];
10
+ /** How channel messages reach an agent. */
11
+ declare const AGENT_DELIVERY_MODES: readonly ["webhook", "inbox", "a2a"];
12
+ type AgentDeliveryMode = (typeof AGENT_DELIVERY_MODES)[number];
13
+ /** Every message type a channel can hold. */
14
+ declare const AGENT_MESSAGE_TYPES: readonly ["message", "task", "question", "escalation", "status"];
15
+ type AgentMessageType = (typeof AGENT_MESSAGE_TYPES)[number];
16
+ /** The message types an agent can send (`agents.send`). */
17
+ declare const SENDABLE_AGENT_MESSAGE_TYPES: readonly ["message", "task", "status"];
18
+ type SendableAgentMessageType = (typeof SENDABLE_AGENT_MESSAGE_TYPES)[number];
19
+ /**
20
+ * A task's lifecycle. A `task` starts `open`; a `status` message moves it.
21
+ * `completed`, `failed`, `canceled` and `rejected` are final.
22
+ */
23
+ declare const AGENT_TASK_STATUSES: readonly ["open", "working", "input_required", "completed", "failed", "canceled", "rejected"];
24
+ type AgentTaskStatus = (typeof AGENT_TASK_STATUSES)[number];
25
+ /** Agents are `member`s (post and read) or `observer`s (read); people are `supervisor`s. */
26
+ type AgentMemberRole = 'member' | 'observer' | 'supervisor';
27
+ /**
28
+ * Where one delivery stands: `inbox` (waiting to be pulled), `pending`
29
+ * (webhook or A2A push queued), `delivered`, `failed` (pushes gave up; still
30
+ * in the inbox), `held` (recipient paused), `pending_a2a`, `skipped`.
31
+ */
32
+ type AgentDeliveryStatus = 'pending' | 'inbox' | 'delivered' | 'failed' | 'held' | 'pending_a2a' | 'skipped';
33
+ /** An agent of the directory (`GET /v1/agents`). Never carries its secret. */
34
+ interface Agent {
35
+ id: string;
36
+ slug: string;
37
+ name: string;
38
+ /** `webhook` (run by you) or `builtin` (run by Channlize). */
39
+ type: string;
40
+ delivery: AgentDeliveryMode;
41
+ status: AgentStatus;
42
+ enabled: boolean;
43
+ avatar_url: string | null;
44
+ emoji: string | null;
45
+ role: string | null;
46
+ description: string | null;
47
+ owner_user_id: string | null;
48
+ manager_agent_id: string | null;
49
+ manager_user_id: string | null;
50
+ webhook_url: string | null;
51
+ a2a_agent_card_url: string | null;
52
+ a2a_agent_card: unknown;
53
+ a2a_agent_card_fetched_at: string | null;
54
+ has_secret: boolean;
55
+ last_seen_at: string | null;
56
+ created_at: string;
57
+ updated_at: string;
58
+ }
59
+ /** Slack mirroring of a channel. Default: everything on. */
60
+ interface AgentMirrorConfig {
61
+ enabled: boolean;
62
+ types: Record<AgentMessageType, boolean>;
63
+ /** Each task (and its status updates) gets its own Slack thread. */
64
+ thread_per_task: boolean;
65
+ }
66
+ /** An agent channel. */
67
+ interface AgentChannel {
68
+ id: string;
69
+ slug: string;
70
+ name: string;
71
+ description: string | null;
72
+ slack_channel_id: string | null;
73
+ mirror: AgentMirrorConfig;
74
+ archived: boolean;
75
+ archived_at: string | null;
76
+ created_by: string | null;
77
+ created_at: string;
78
+ updated_at: string;
79
+ }
80
+ /** A channel member: an agent (`member` / `observer`) or a person (`supervisor`). */
81
+ interface AgentChannelMember {
82
+ id: string;
83
+ channel_id: string;
84
+ kind: 'agent' | 'user';
85
+ agent_id: string | null;
86
+ user_id: string | null;
87
+ role: AgentMemberRole;
88
+ name: string | null;
89
+ agent_slug?: string | null;
90
+ agent_status?: string | null;
91
+ user_email?: string | null;
92
+ created_at: string;
93
+ }
94
+ /**
95
+ * Who sent a message. `slack_user`: a person replying in Slack who isn't
96
+ * matched to a Channlize user. `deleted`: the sender no longer exists.
97
+ */
98
+ type AgentMessageSender = {
99
+ kind: 'agent';
100
+ agent_id: string;
101
+ } | {
102
+ kind: 'user';
103
+ user_id: string;
104
+ } | {
105
+ kind: 'slack_user';
106
+ slack_user_id: string;
107
+ name: string;
108
+ } | {
109
+ kind: 'deleted';
110
+ };
111
+ /** A message in an agent channel. */
112
+ interface AgentMessage {
113
+ id: string;
114
+ /** Position in the channel feed. */
115
+ seq: string;
116
+ channel_id: string;
117
+ /** Root message of its thread; null on a root. */
118
+ thread_id: string | null;
119
+ sender: AgentMessageSender;
120
+ type: AgentMessageType;
121
+ text: string;
122
+ data: Record<string, unknown>;
123
+ /** Mentioned agent ids. */
124
+ mentions: string[];
125
+ /** On a `status` message: the task it updates. */
126
+ task_id: string | null;
127
+ /** On a `task`: its current status. On a `status` message: the status it reported. */
128
+ task_status: AgentTaskStatus | null;
129
+ tokens: number | null;
130
+ cost: number | null;
131
+ slack_ts: string | null;
132
+ a2a: {
133
+ context_id: string | null;
134
+ task_id: string | null;
135
+ message_id: string | null;
136
+ };
137
+ created_at: string;
138
+ }
139
+ /** One message for one recipient agent. */
140
+ interface AgentDelivery {
141
+ id: string;
142
+ message_id: string;
143
+ agent_id: string;
144
+ status: AgentDeliveryStatus;
145
+ attempts: number;
146
+ last_error: string | null;
147
+ delivered_at: string | null;
148
+ acked_at: string | null;
149
+ created_at: string;
150
+ }
151
+ /** `agents.send` input. */
152
+ interface SendAgentMessageInput {
153
+ /**
154
+ * The agent that sends. Required with a multi-agent key (unless it lists
155
+ * one agent); optional with an agent key. Defaults to the client's `agentId`.
156
+ */
157
+ agentId?: string;
158
+ /** The channel id. The agent must be a `member` (observers can't post). */
159
+ channel: string;
160
+ /** Default `message`. A `task` starts `open`; a `status` updates `taskId`. */
161
+ type?: SendableAgentMessageType;
162
+ text: string;
163
+ /** Reply in this thread (any message of it). */
164
+ threadId?: string;
165
+ /** Agent ids to mention. */
166
+ mentions?: string[];
167
+ /** Structured data, stored and delivered with the message. */
168
+ data?: Record<string, unknown>;
169
+ /** Tokens the agent used for this message, for reporting. */
170
+ tokens?: number;
171
+ /** Cost the agent reports for this message, for reporting. */
172
+ cost?: number;
173
+ /** On a `status` message: the task to update. */
174
+ taskId?: string;
175
+ /** On a `status` message: the task's new status. */
176
+ taskStatus?: AgentTaskStatus;
177
+ }
178
+ /** `agents.send` result (`201`). */
179
+ interface SendAgentMessageResult {
180
+ message: AgentMessage;
181
+ /** One per recipient agent. */
182
+ deliveries: Array<{
183
+ id: string;
184
+ agent_id: string;
185
+ status: AgentDeliveryStatus;
186
+ }>;
187
+ }
188
+ /** One unacked message of an agent's inbox. */
189
+ interface AgentInboxItem {
190
+ delivery_id: string;
191
+ /** This item's position; pass it as `cursor` to read after it. */
192
+ cursor: string;
193
+ status: AgentDeliveryStatus;
194
+ attempts: number;
195
+ message: AgentMessage;
196
+ }
197
+ interface AgentInboxOptions {
198
+ /** Read after this cursor (`nextCursor` of the previous page). Default: the oldest unacked message. */
199
+ cursor?: string;
200
+ /** Page size (1-200, default 50). */
201
+ limit?: number;
202
+ }
203
+ /** `agents.inbox` result: unacked messages, oldest first. */
204
+ interface AgentInboxPage {
205
+ messages: AgentInboxItem[];
206
+ /** Pass as `cursor` for the next page; the same cursor when nothing is newer. */
207
+ nextCursor: string | null;
208
+ hasMore: boolean;
209
+ }
210
+ /** `agents.ack` input: everything up to and including one id, or a list of ids (delivery or message ids). */
211
+ type AgentAckInput = {
212
+ upTo: string;
213
+ } | {
214
+ ids: string[];
215
+ };
216
+ interface AgentAckResult {
217
+ /** How many were newly acked (acking twice is harmless). */
218
+ acked: number;
219
+ }
220
+ /**
221
+ * `agents.get` result. An `agents:admin` key also gets the dashboard detail:
222
+ * recent messages, delivery stats, keys and channels.
223
+ */
224
+ interface AgentDetail {
225
+ agent: Agent;
226
+ recent_messages?: AgentMessage[];
227
+ delivery_stats?: Record<string, unknown>;
228
+ keys?: Array<Record<string, unknown>>;
229
+ channels?: AgentChannel[];
230
+ }
231
+ interface AgentChannelReadOptions {
232
+ /** Read as this agent (multi-agent keys). Defaults to the client's `agentId`. */
233
+ agentId?: string;
234
+ }
235
+ interface AgentChannelFeedOptions extends AgentChannelReadOptions {
236
+ /** Older page: `nextCursor` of the previous page. */
237
+ cursor?: string;
238
+ /** Newer messages only: `latestCursor` of the previous read (for polling). */
239
+ after?: string;
240
+ /** Page size (1-200, default 50). */
241
+ limit?: number;
242
+ /** Only messages from this agent. */
243
+ senderAgentId?: string;
244
+ type?: AgentMessageType;
245
+ /** Only this thread. */
246
+ threadId?: string;
247
+ }
248
+ /** `agents.channels.messages` result. */
249
+ interface AgentChannelFeed {
250
+ channel: AgentChannel;
251
+ messages: AgentMessage[];
252
+ /** Pass as `cursor` for the older page (null when there is none). */
253
+ nextCursor: string | null;
254
+ /** Pass as `after` on the next poll. */
255
+ latestCursor: string | null;
256
+ hasMore: boolean;
257
+ }
258
+ /**
259
+ * The body Channlize POSTs to a webhook agent (`version: 1`), with the
260
+ * headers `X-Webhook-Event: agent.message`, `X-Webhook-Delivery-ID` and
261
+ * `X-Webhook-Signature` (check it with `verifyAgentWebhook`). Answer 2xx to
262
+ * ack it; anything else is retried with backoff, and the message stays in
263
+ * the agent's inbox.
264
+ */
265
+ interface AgentWebhookPayload {
266
+ version: 1;
267
+ event: 'agent.message';
268
+ delivery_id: string;
269
+ /** The recipient. */
270
+ agent: {
271
+ id: string;
272
+ slug: string;
273
+ name: string;
274
+ };
275
+ channel: {
276
+ id: string;
277
+ slug: string;
278
+ name: string;
279
+ };
280
+ sender: {
281
+ kind: 'agent';
282
+ id: string;
283
+ slug: string | null;
284
+ name: string | null;
285
+ } | {
286
+ kind: 'user';
287
+ id: string;
288
+ } | {
289
+ kind: 'slack_user';
290
+ id: string;
291
+ name: string;
292
+ } | {
293
+ kind: 'deleted';
294
+ };
295
+ message: AgentMessage;
296
+ ack_url: string;
297
+ }
298
+ /** `createAgentsClient` options; each falls back to an environment variable. */
299
+ interface AgentsClientConfig {
300
+ /**
301
+ * An agent key, a multi-agent key, or an `agents:admin` key (read
302
+ * helpers only). Default: `CHANNLIZE_SERVER_API_KEY`, else `CHANNLIZE_API_KEY`.
303
+ */
304
+ apiKey?: string;
305
+ /**
306
+ * The agent this client acts as by default (needed with a multi-agent
307
+ * key, and for `inbox` / `ack` / `poll`). Default: `CHANNLIZE_AGENT_ID`.
308
+ */
309
+ agentId?: string;
310
+ /** API base URL. Default: `CHANNLIZE_BASE_URL`, else `https://api.channlize.com`. */
311
+ baseUrl?: string;
312
+ /** Request timeout in ms (default 10000). */
313
+ timeout?: number;
314
+ }
315
+ /** `agents.poll` options. */
316
+ interface AgentPollOptions {
317
+ /** Wait between polls when the inbox is empty (default 5000 ms). */
318
+ intervalMs?: number;
319
+ /** Upper bound of the backoff after errors (default 60000 ms). */
320
+ maxBackoffMs?: number;
321
+ /** Inbox page size (default 50). */
322
+ limit?: number;
323
+ /** Stops the loop; `poll` then resolves. */
324
+ signal?: AbortSignal;
325
+ /**
326
+ * Called when reading the inbox, the handler or the ack fails (`item` is
327
+ * set for a handler failure). The loop backs off and retries; the failed
328
+ * message isn't acked, so it comes back.
329
+ */
330
+ onError?: (error: unknown, item?: AgentInboxItem) => void;
331
+ }
332
+ /** What `agents.poll` calls for each message, oldest first. Acked once it resolves. */
333
+ type AgentMessageHandler = (message: AgentMessage, item: AgentInboxItem) => unknown | Promise<unknown>;
334
+
335
+ /**
336
+ * Channlize for Agents, Phases 2 and 3: asking humans (questions and
337
+ * approvals), tasks and handoffs, teams, policies, the org chart and
338
+ * onboarding. Shapes mirror the API's DTOs (`api/lib/agents/questions-dto.ts`,
339
+ * `tasks.ts`, `teams.ts`, `policies.ts`, `org-chart.ts`), so fields are
340
+ * `snake_case`; request options are `camelCase`.
341
+ */
342
+
343
+ declare const QUESTION_KINDS: readonly ["question", "approval"];
344
+ /** `approval` questions are always Approve / Deny (option ids `approve` / `deny`). */
345
+ type QuestionKind = (typeof QUESTION_KINDS)[number];
346
+ declare const QUESTION_URGENCIES: readonly ["low", "normal", "high", "urgent"];
347
+ /** Sets how fast the question escalates (default step timeouts: 4h, 1h, 15min, 5min). */
348
+ type QuestionUrgency = (typeof QUESTION_URGENCIES)[number];
349
+ /**
350
+ * `open` until someone answers. `expired_default`: the deadline applied the
351
+ * default option (delivered as `question.answered`). `expired`: the
352
+ * deadline passed with no default.
353
+ */
354
+ declare const QUESTION_STATUSES: readonly ["open", "answered", "expired_default", "expired", "canceled"];
355
+ type QuestionStatus = (typeof QUESTION_STATUSES)[number];
356
+ /** The longest single `questions.wait` long-poll, in seconds. */
357
+ declare const QUESTION_WAIT_MAX_SECONDS = 25;
358
+ interface QuestionOption {
359
+ id: string;
360
+ /** At most 75 characters (Slack button text). */
361
+ label: string;
362
+ }
363
+ /** How a closed question was answered. */
364
+ interface QuestionAnswer {
365
+ status: Exclude<QuestionStatus, 'open'>;
366
+ option_id: string | null;
367
+ /** The chosen option's label. */
368
+ option_label: string | null;
369
+ text: string | null;
370
+ comment: string | null;
371
+ /** Null when it expired without a default, or was canceled. */
372
+ answered_by: 'user' | 'agent' | 'default' | null;
373
+ user_id: string | null;
374
+ slack_user_id: string | null;
375
+ agent_id: string | null;
376
+ answered_at: string | null;
377
+ canceled_at: string | null;
378
+ /** Approvals: `approve` → true, `deny` → false. */
379
+ approved?: boolean;
380
+ }
381
+ /** A question or approval an agent asked people. */
382
+ interface AgentQuestion {
383
+ id: string;
384
+ /** The agent that asked. */
385
+ agent_id: string | null;
386
+ channel_id: string | null;
387
+ thread_id: string | null;
388
+ /** The `question` message in the channel, when it has one. */
389
+ message_id: string | null;
390
+ kind: QuestionKind;
391
+ question: string;
392
+ options: QuestionOption[];
393
+ free_text: boolean;
394
+ urgency: QuestionUrgency;
395
+ deadline: string | null;
396
+ default_option: string | null;
397
+ context: Record<string, unknown>;
398
+ amount: number | null;
399
+ currency: string | null;
400
+ resource: Record<string, unknown> | null;
401
+ required_roles: string[];
402
+ status: QuestionStatus;
403
+ /** Null while open. */
404
+ answer: QuestionAnswer | null;
405
+ a2a_task_id: string | null;
406
+ slack: {
407
+ channel_id: string;
408
+ ts: string;
409
+ } | null;
410
+ escalation: {
411
+ step: number;
412
+ next_check_at: string | null;
413
+ muted_until: string | null;
414
+ };
415
+ created_at: string;
416
+ updated_at: string;
417
+ }
418
+ /** One step of a question's escalation chain. */
419
+ interface QuestionEscalation {
420
+ step: number;
421
+ target_kind: string;
422
+ target_ref: string | null;
423
+ target_user_ids: string[];
424
+ notified_at: string | null;
425
+ timeout_at: string | null;
426
+ slack: {
427
+ channel_id: string;
428
+ ts: string;
429
+ } | null;
430
+ error: string | null;
431
+ }
432
+ /** `agents.ask` input (`POST /v1/agents/questions`, scope `agents:ask_human`). */
433
+ interface AskHumanInput {
434
+ /** The asking agent. Defaults to the client's `agentId`. */
435
+ agentId?: string;
436
+ /** Default `question`. An `approval` is answered Approve / Deny. */
437
+ kind?: QuestionKind;
438
+ /** At most 3000 characters. */
439
+ question: string;
440
+ /** Up to 10. Ignored for approvals. */
441
+ options?: QuestionOption[];
442
+ /** Allow a free-text answer (forced on without options). */
443
+ freeText?: boolean;
444
+ /** Default `normal`. Capped by the policy's `max_ask_urgency`. */
445
+ urgency?: QuestionUrgency;
446
+ /** ISO time, at most 30 days away. */
447
+ deadline?: string | Date;
448
+ /** Option id applied at the deadline. */
449
+ defaultOption?: string;
450
+ /** Post the question in this agent channel (else the escalation channel). */
451
+ channelId?: string;
452
+ /** Any message of the thread it is about. */
453
+ threadId?: string;
454
+ /** Shown with the question (at most 16 KB of JSON). */
455
+ context?: Record<string, unknown>;
456
+ /** Approvals: shown, and matched against the policy's `approval_rules`. */
457
+ amount?: number;
458
+ /** ISO 4217 code. */
459
+ currency?: string;
460
+ /** Approvals: what is being approved (at most 4 KB of JSON). */
461
+ resource?: Record<string, unknown>;
462
+ /** Approvals: roles that may answer (`owner` > `admin` > `agent` > `viewer`). */
463
+ requiredRoles?: string[];
464
+ }
465
+ interface QuestionReadOptions {
466
+ /** Read as this agent (multi-agent keys). Defaults to the client's `agentId`. */
467
+ agentId?: string;
468
+ }
469
+ interface ListQuestionsOptions extends QuestionReadOptions {
470
+ status?: QuestionStatus;
471
+ kind?: QuestionKind;
472
+ urgency?: QuestionUrgency;
473
+ channelId?: string;
474
+ /** `nextCursor` of the previous page. */
475
+ cursor?: string;
476
+ /** 1-200, default 50. */
477
+ limit?: number;
478
+ }
479
+ /** `agents.questions.list`: newest first; the agent's own and those escalated to it. */
480
+ interface QuestionPage {
481
+ questions: AgentQuestion[];
482
+ nextCursor: string | null;
483
+ }
484
+ interface WaitQuestionOptions extends QuestionReadOptions {
485
+ /** Seconds to hold the request (0-25, default 25). */
486
+ timeoutSec?: number;
487
+ signal?: AbortSignal;
488
+ }
489
+ /** One long-poll: `timedOut` when the question is still open. */
490
+ interface WaitQuestionResult {
491
+ question: AgentQuestion;
492
+ timedOut: boolean;
493
+ }
494
+ /** `agents.questions.answer` input (a manager agent answering an escalated question). */
495
+ interface AnswerQuestionInput {
496
+ /** The answering agent. Defaults to the client's `agentId`. */
497
+ agentId?: string;
498
+ /** One of the options (`approve` / `deny` for approvals). */
499
+ optionId?: string;
500
+ /** A free-text answer (questions that allow it). */
501
+ text?: string;
502
+ comment?: string;
503
+ }
504
+ interface AskAndWaitOptions {
505
+ /**
506
+ * The overall wait, in ms (default 600000: 10 minutes). Questions can take
507
+ * hours: past it, the call resolves with `timedOut: true` and the open
508
+ * question, to wait on later with `questions.wait`.
509
+ */
510
+ timeoutMs?: number;
511
+ /** Rejects the call (code `ABORTED`) when it aborts. */
512
+ signal?: AbortSignal;
513
+ }
514
+ /** `agents.askAndWait` result. */
515
+ interface AskAndWaitResult {
516
+ question: AgentQuestion;
517
+ /** Null while open (`timedOut`). */
518
+ answer: QuestionAnswer | null;
519
+ /** True when `timeoutMs` ran out with the question still open. */
520
+ timedOut: boolean;
521
+ }
522
+ /**
523
+ * Board columns. They map onto `task_status`: `open` → `open`,
524
+ * `in_progress` → `working`, `blocked` → `input_required`, `done` →
525
+ * `completed`, `failed` → `failed` (`canceled` and `rejected` show as
526
+ * `failed`).
527
+ */
528
+ declare const TASK_BOARD_STATUSES: readonly ["open", "in_progress", "blocked", "done", "failed"];
529
+ type TaskBoardStatus = (typeof TASK_BOARD_STATUSES)[number];
530
+ interface TaskHandoff {
531
+ from_agent_id: string | null;
532
+ to_agent_id: string | null;
533
+ reason: string | null;
534
+ by_agent_id: string | null;
535
+ by_user_id: string | null;
536
+ at: string;
537
+ }
538
+ /** A task: its `task` message plus the board fields. */
539
+ interface AgentTask extends AgentMessage {
540
+ board_status: TaskBoardStatus;
541
+ assignee_agent_id: string | null;
542
+ due_at: string | null;
543
+ last_handoff: TaskHandoff | null;
544
+ }
545
+ /** One entry of a task's history. */
546
+ interface AgentTaskEvent {
547
+ id: string;
548
+ kind: 'assigned' | 'handoff' | 'status' | 'due_changed';
549
+ from_agent_id: string | null;
550
+ to_agent_id: string | null;
551
+ by_agent_id: string | null;
552
+ by_user_id: string | null;
553
+ from_status: string | null;
554
+ to_status: string | null;
555
+ reason: string | null;
556
+ data: Record<string, unknown> | null;
557
+ created_at: string;
558
+ }
559
+ interface TaskDeliverySummary {
560
+ id: string;
561
+ agent_id: string;
562
+ status: AgentDeliveryStatus;
563
+ }
564
+ /** `agents.tasks.create` input (`agents:send`). */
565
+ interface CreateTaskInput {
566
+ /** The creating agent. Defaults to the client's `agentId`. */
567
+ agentId?: string;
568
+ channelId: string;
569
+ /** What should be done. */
570
+ text: string;
571
+ /** A `member` of the channel; mentioned, and the task's owner on the board. */
572
+ assigneeAgentId?: string;
573
+ /** ISO date or date-time. */
574
+ dueAt?: string | Date;
575
+ threadId?: string;
576
+ mentions?: string[];
577
+ data?: Record<string, unknown>;
578
+ }
579
+ interface CreateTaskResult {
580
+ task: AgentTask;
581
+ deliveries: TaskDeliverySummary[];
582
+ }
583
+ interface ListTasksOptions {
584
+ /** Required with a key bound to agents. */
585
+ channelId?: string;
586
+ assigneeAgentId?: string;
587
+ status?: TaskBoardStatus;
588
+ /** 1-500. */
589
+ limit?: number;
590
+ /** Read as this agent (multi-agent keys). Defaults to the client's `agentId`. */
591
+ agentId?: string;
592
+ }
593
+ interface TaskBoardOptions {
594
+ assigneeAgentId?: string;
595
+ agentId?: string;
596
+ }
597
+ interface TaskBoard {
598
+ channel_id: string;
599
+ columns: Record<TaskBoardStatus, AgentTask[]>;
600
+ counts: Record<TaskBoardStatus, number>;
601
+ agents: Array<Pick<Agent, 'id' | 'slug' | 'name' | 'emoji' | 'avatar_url' | 'status'>>;
602
+ /** More than 500 tasks: the board shows the newest. */
603
+ truncated: boolean;
604
+ }
605
+ interface TaskDetail {
606
+ task: AgentTask;
607
+ events: AgentTaskEvent[];
608
+ }
609
+ /** `agents.tasks.update` input: the assignee or creator moves the task or changes its due date. */
610
+ interface UpdateTaskInput {
611
+ agentId?: string;
612
+ status?: TaskBoardStatus;
613
+ /** ISO date or date-time; null clears it. */
614
+ dueAt?: string | Date | null;
615
+ /** Shown with the change (at most 2000 characters). */
616
+ note?: string;
617
+ }
618
+ interface UpdateTaskResult {
619
+ task: AgentTask;
620
+ /** False when nothing changed. */
621
+ changed: boolean;
622
+ }
623
+ interface HandoffTaskInput {
624
+ agentId?: string;
625
+ /** A `member` of the task's channel. */
626
+ toAgentId: string;
627
+ reason?: string;
628
+ }
629
+ interface HandoffTaskResult {
630
+ task: AgentTask;
631
+ event: AgentTaskEvent;
632
+ deliveries: TaskDeliverySummary[];
633
+ }
634
+ interface AgentTeam {
635
+ id: string;
636
+ slug: string;
637
+ name: string;
638
+ description: string | null;
639
+ member_count?: number;
640
+ channel_count?: number;
641
+ created_by: string | null;
642
+ created_at: string;
643
+ updated_at: string;
644
+ }
645
+ interface AgentTeamChannelGrant {
646
+ channel_id: string;
647
+ team_id: string;
648
+ role: AgentMemberRole;
649
+ added_by: string | null;
650
+ created_at: string;
651
+ }
652
+ interface AgentTeamDetail {
653
+ team: AgentTeam;
654
+ members: Array<{
655
+ agent: Agent;
656
+ added_by: string | null;
657
+ added_at: string;
658
+ }>;
659
+ channels: AgentTeamChannelGrant[];
660
+ policy: {
661
+ id: string;
662
+ rules: AgentPolicyRules;
663
+ enabled: boolean;
664
+ updated_at: string;
665
+ } | null;
666
+ }
667
+ interface CreateTeamInput {
668
+ name: string;
669
+ slug?: string;
670
+ description?: string | null;
671
+ /** Agents to add right away. */
672
+ agentIds?: string[];
673
+ }
674
+ interface UpdateTeamInput {
675
+ name?: string;
676
+ slug?: string;
677
+ description?: string | null;
678
+ }
679
+ declare const POLICY_SCOPES: readonly ["org", "team", "agent", "channel"];
680
+ /** Precedence: org < team < agent < channel, merged key by key. */
681
+ type PolicyScope = (typeof POLICY_SCOPES)[number];
682
+ /** A policy's rules. Every key is optional; a key left out inherits. */
683
+ interface AgentPolicyRules {
684
+ /** Channels it may post in (null: any it's a member of). */
685
+ post_channel_ids?: string[] | null;
686
+ read_channel_ids?: string[] | null;
687
+ direct_messages?: {
688
+ default: 'allow' | 'deny';
689
+ allow_agent_ids?: string[];
690
+ } | null;
691
+ can_ask_humans?: boolean;
692
+ max_ask_urgency?: QuestionUrgency;
693
+ approval_rules?: Array<{
694
+ min_amount: number;
695
+ currency?: string;
696
+ required_roles: string[];
697
+ }> | null;
698
+ rate_per_minute?: number | null;
699
+ daily_message_budget?: number | null;
700
+ monthly_event_budget?: number | null;
701
+ working_hours?: {
702
+ /** IANA time zone. */
703
+ timezone: string;
704
+ /** 0 = Sunday; empty: every day. */
705
+ days: number[];
706
+ /** HH:MM */
707
+ start: string;
708
+ /** HH:MM */
709
+ end: string;
710
+ /** `queue` holds messages; `owner_if_urgent` also tells the owner about urgent ones. */
711
+ out_of_hours: 'queue' | 'owner_if_urgent';
712
+ } | null;
713
+ max_thread_depth?: number | null;
714
+ humans_win_minutes?: number | null;
715
+ }
716
+ interface AgentPolicy {
717
+ id: string;
718
+ scope: PolicyScope;
719
+ scope_id: string;
720
+ rules: AgentPolicyRules;
721
+ enabled: boolean;
722
+ created_by: string | null;
723
+ updated_by: string | null;
724
+ created_at: string;
725
+ updated_at: string;
726
+ }
727
+ interface PutPolicyInput {
728
+ scope: PolicyScope;
729
+ /** The team, agent or channel id; leave out for `org`. */
730
+ scopeId?: string;
731
+ rules: AgentPolicyRules;
732
+ enabled?: boolean;
733
+ }
734
+ interface PolicySource {
735
+ id: string;
736
+ scope: PolicyScope;
737
+ scope_id: string;
738
+ }
739
+ /** A policy check: allowed, or the refusal it would be. */
740
+ type PolicyCheck = {
741
+ allow: true;
742
+ } | {
743
+ allow: false;
744
+ code: string;
745
+ message: string;
746
+ retryAt?: string;
747
+ status?: number;
748
+ };
749
+ /** `agents.policies.preview`: the policy in force for an agent (in a channel). */
750
+ interface EffectivePolicyPreview {
751
+ agent_id: string;
752
+ channel_id: string | null;
753
+ /** Every key resolved (defaults included). */
754
+ rules: Required<AgentPolicyRules>;
755
+ /** The policies merged, lowest precedence first. */
756
+ sources: PolicySource[];
757
+ /** Which policy set each key (null: the default). */
758
+ set_by: Record<string, PolicySource | null>;
759
+ /** False when loading failed and the defaults were used. */
760
+ loaded: boolean;
761
+ working_hours: {
762
+ configured: boolean;
763
+ within: boolean;
764
+ /** When the next window opens (outside working hours). */
765
+ next_start: string | null;
766
+ };
767
+ usage: {
768
+ rate_per_minute: {
769
+ limit: number;
770
+ used: number | null;
771
+ } | null;
772
+ daily_messages: {
773
+ budget: number;
774
+ used: number | null;
775
+ resets_at: string;
776
+ } | null;
777
+ monthly_events: {
778
+ budget: number;
779
+ used: number | null;
780
+ pool: unknown;
781
+ resets_at: string;
782
+ } | null;
783
+ };
784
+ /** With a channel: whether it may post and read there now. */
785
+ checks: {
786
+ send: PolicyCheck;
787
+ read: PolicyCheck;
788
+ } | null;
789
+ }
790
+ interface OrgChartAgent {
791
+ id: string;
792
+ slug: string;
793
+ name: string;
794
+ status: Agent['status'];
795
+ role: string | null;
796
+ emoji: string | null;
797
+ avatar_url: string | null;
798
+ owner_user_id: string | null;
799
+ manager: {
800
+ type: 'agent' | 'user';
801
+ id: string;
802
+ } | null;
803
+ team_ids: string[];
804
+ }
805
+ interface OrgChartNode {
806
+ type: 'agent' | 'user';
807
+ id: string;
808
+ children: OrgChartNode[];
809
+ }
810
+ interface OrgChart {
811
+ agents: OrgChartAgent[];
812
+ users: Array<{
813
+ id: string;
814
+ name: string;
815
+ email: string;
816
+ }>;
817
+ teams: Array<{
818
+ id: string;
819
+ slug: string;
820
+ name: string;
821
+ agent_ids: string[];
822
+ }>;
823
+ tree: OrgChartNode[];
824
+ }
825
+ interface OrgChartOptions {
826
+ teamId?: string;
827
+ channelId?: string;
828
+ includeRetired?: boolean;
829
+ }
830
+ /** An agent's manager: an agent or a person, never both; `{}` clears it. */
831
+ type SetManagerInput = {
832
+ managerAgentId: string;
833
+ managerUserId?: undefined;
834
+ } | {
835
+ managerUserId: string;
836
+ managerAgentId?: undefined;
837
+ } | {
838
+ managerAgentId?: null;
839
+ managerUserId?: null;
840
+ };
841
+ interface AgentOnboarding {
842
+ agent_id: string;
843
+ steps: Array<{
844
+ id: 'created' | 'key_issued' | 'in_channel' | 'test_message_sent' | 'delivery_working';
845
+ label: string;
846
+ done: boolean;
847
+ }>;
848
+ complete: boolean;
849
+ }
850
+ /** `agents.setStatus` result. */
851
+ interface AgentStatusResult {
852
+ agent: Agent;
853
+ previous_status: Agent['status'];
854
+ keys_revoked: number;
855
+ memberships_removed: number;
856
+ /** On a resume: the held deliveries released. */
857
+ released?: number;
858
+ }
859
+ /** The events a closed question is pushed to its asker as. */
860
+ type QuestionOutcomeEvent = 'question.answered' | 'question.expired' | 'question.canceled';
861
+ /**
862
+ * A closed question pushed to the agent that asked it, when the question
863
+ * has no channel (`X-Webhook-Event: question.answered`, ...). Questions in a
864
+ * channel come back as an `agent.message` in its thread instead, with the
865
+ * same `{ type, question, answer }` as `message.data` (see
866
+ * `isQuestionOutcomeMessage`).
867
+ */
868
+ interface QuestionOutcomeWebhookPayload {
869
+ version: 1;
870
+ event: QuestionOutcomeEvent;
871
+ type: QuestionOutcomeEvent;
872
+ delivery_id: string;
873
+ /** The recipient. */
874
+ agent: {
875
+ id: string;
876
+ slug: string;
877
+ name: string;
878
+ };
879
+ question: AgentQuestion;
880
+ answer: QuestionAnswer | null;
881
+ }
882
+ /**
883
+ * A question escalated to its asker's manager agent
884
+ * (`X-Webhook-Event: question.escalated`). Answer it with
885
+ * `agents.questions.answer(question.id, …)` (`answer_url`).
886
+ */
887
+ interface QuestionEscalatedWebhookPayload {
888
+ version: 1;
889
+ event: 'question.escalated';
890
+ type: 'question.escalated';
891
+ delivery_id: string;
892
+ agent: {
893
+ id: string;
894
+ slug: string;
895
+ name: string;
896
+ };
897
+ question: AgentQuestion;
898
+ asker: {
899
+ id: string;
900
+ slug: string;
901
+ name: string;
902
+ } | null;
903
+ answer_url: string;
904
+ }
905
+ /** Every body Channlize POSTs to a webhook agent. */
906
+ type AgentWebhookEvent = AgentWebhookPayload | QuestionOutcomeWebhookPayload | QuestionEscalatedWebhookPayload;
907
+ /** `message.data` of a question outcome in the question's thread. */
908
+ interface QuestionOutcomeData {
909
+ type: QuestionOutcomeEvent;
910
+ question: AgentQuestion;
911
+ answer: QuestionAnswer | null;
912
+ [key: string]: unknown;
913
+ }
914
+ /** `message.data.handoff` of the `status` message a handoff posts. */
915
+ interface TaskHandoffData {
916
+ handoff: {
917
+ from_agent_id: string | null;
918
+ to_agent_id: string;
919
+ reason: string | null;
920
+ };
921
+ [key: string]: unknown;
922
+ }
923
+
924
+ /** Phases 2 and 3 of `AgentsClient`. */
925
+ interface AgentsGovernance {
926
+ /**
927
+ * Ask people a question, or for an approval (`agents:ask_human`). It is
928
+ * posted in Slack (the channel's linked channel, else the escalation
929
+ * channel) and escalates until someone answers or the deadline passes.
930
+ * One Event. Read the answer with `questions.wait`, or use `askAndWait`.
931
+ */
932
+ ask(input: AskHumanInput): Promise<AgentQuestion>;
933
+ /**
934
+ * `ask`, then `questions.wait` in a loop until the question is answered,
935
+ * expired or canceled, or `timeoutMs` (default 10 minutes) runs out:
936
+ * then it resolves with `timedOut: true` and the open question. Network
937
+ * errors, 5xx and 429s are retried (after `Retry-After`) inside the
938
+ * timeout; others reject. `signal` rejects it with code `ABORTED`.
939
+ */
940
+ askAndWait(input: AskHumanInput, options?: AskAndWaitOptions): Promise<AskAndWaitResult>;
941
+ questions: {
942
+ /** A question with its escalation steps (`agents:ask_human` or `agents:read`). */
943
+ get(questionId: string, options?: QuestionReadOptions): Promise<{
944
+ question: AgentQuestion;
945
+ escalations: QuestionEscalation[];
946
+ }>;
947
+ /** The agent's questions and those escalated to it, newest first. */
948
+ list(options?: ListQuestionsOptions): Promise<QuestionPage>;
949
+ /**
950
+ * One long-poll (at most 25 s): resolves as soon as the question closes,
951
+ * or with `timedOut: true` while it's still open.
952
+ */
953
+ wait(questionId: string, options?: WaitQuestionOptions): Promise<WaitQuestionResult>;
954
+ /**
955
+ * Answer a question escalated to this agent (its asker's manager agent;
956
+ * `agents:send` or `agents:ask_human`). The first answer wins: later
957
+ * ones get `QuestionClosedError`. Approvals that ask for a role need a
958
+ * person (403 `APPROVAL_ROLE_REQUIRED`).
959
+ */
960
+ answer(questionId: string, input: AnswerQuestionInput): Promise<AgentQuestion>;
961
+ /** Cancel one of the agent's own open questions (`agents:ask_human`). */
962
+ cancel(questionId: string, options?: QuestionReadOptions): Promise<AgentQuestion>;
963
+ };
964
+ tasks: {
965
+ /** Create a task, optionally assigned and with a due date (`agents:send`). */
966
+ create(input: CreateTaskInput): Promise<CreateTaskResult>;
967
+ /** Tasks, newest first (`agents:read`; keys bound to agents need `channelId`). */
968
+ list(options?: ListTasksOptions): Promise<AgentTask[]>;
969
+ /** A channel's board: tasks by column, counts and the agents on it. */
970
+ board(channelId: string, options?: TaskBoardOptions): Promise<TaskBoard>;
971
+ /** A task with its history. */
972
+ get(taskId: string, options?: {
973
+ agentId?: string;
974
+ }): Promise<TaskDetail>;
975
+ /**
976
+ * Move a task on the board, change its due date, with a note (the
977
+ * assignee or creator; `agents:send`). 409 `TASK_CLOSED` once closed.
978
+ */
979
+ update(taskId: string, input: UpdateTaskInput): Promise<UpdateTaskResult>;
980
+ /** Hand a task to another member agent of its channel (`agents:send`). */
981
+ handoff(taskId: string, input: HandoffTaskInput): Promise<HandoffTaskResult>;
982
+ };
983
+ /** Teams (reads: `agents:read`; writes: an unbound `agents:admin` key). */
984
+ teams: {
985
+ list(): Promise<AgentTeam[]>;
986
+ get(teamId: string): Promise<AgentTeamDetail>;
987
+ create(input: CreateTeamInput): Promise<AgentTeam>;
988
+ update(teamId: string, input: UpdateTeamInput): Promise<AgentTeam>;
989
+ delete(teamId: string): Promise<{
990
+ memberships_removed: number;
991
+ }>;
992
+ addMember(teamId: string, agentId: string): Promise<{
993
+ member: unknown;
994
+ channels_granted: number;
995
+ }>;
996
+ removeMember(teamId: string, agentId: string): Promise<{
997
+ memberships_removed: number;
998
+ }>;
999
+ grantChannel(teamId: string, channelId: string, role?: AgentMemberRole): Promise<{
1000
+ grant: AgentTeamChannelGrant;
1001
+ memberships_added: number;
1002
+ }>;
1003
+ revokeChannel(teamId: string, channelId: string): Promise<{
1004
+ memberships_removed: number;
1005
+ }>;
1006
+ };
1007
+ /** Policies (an unbound `agents:admin` key). */
1008
+ policies: {
1009
+ list(options?: {
1010
+ scope?: PolicyScope;
1011
+ }): Promise<AgentPolicy[]>;
1012
+ get(policyId: string): Promise<AgentPolicy>;
1013
+ /** Create or replace the policy of a scope. */
1014
+ put(input: PutPolicyInput): Promise<AgentPolicy>;
1015
+ delete(policyId: string): Promise<void>;
1016
+ /** The effective policy of an agent (in a channel): rules, sources, usage and checks. */
1017
+ preview(agentId: string, options?: {
1018
+ channelId?: string;
1019
+ }): Promise<EffectivePolicyPreview>;
1020
+ };
1021
+ orgChart: {
1022
+ /** The org chart (`agents:read`). */
1023
+ get(options?: OrgChartOptions): Promise<OrgChart>;
1024
+ /** Set or clear an agent's manager (`agents:admin`). 409 `ORG_CHART_CYCLE`. */
1025
+ setManager(agentId: string, input: SetManagerInput): Promise<Agent>;
1026
+ /** Set or clear an agent's owner, a person (`agents:admin`). */
1027
+ setOwner(agentId: string, ownerUserId: string | null): Promise<Agent>;
1028
+ };
1029
+ /** An agent's onboarding checklist (`agents:admin`). */
1030
+ onboarding(agentId: string): Promise<AgentOnboarding>;
1031
+ /**
1032
+ * Pause (with a reason), resume or retire an agent (`agents:admin`).
1033
+ * Resuming releases its held deliveries, oldest first.
1034
+ */
1035
+ setStatus(agentId: string, status: AgentStatus, options?: {
1036
+ reason?: string;
1037
+ }): Promise<AgentStatusResult>;
1038
+ }
1039
+ /** An `agent.message` delivery (a channel message, task or status). */
1040
+ declare function isAgentMessageWebhook(payload: AgentWebhookEvent | null | undefined): payload is AgentWebhookPayload;
1041
+ /** A closed question pushed to its asker (`question.answered` / `expired` / `canceled`). */
1042
+ declare function isQuestionOutcomeWebhook(payload: AgentWebhookEvent | null | undefined): payload is QuestionOutcomeWebhookPayload;
1043
+ /** A question escalated to this (manager) agent: answer it with `questions.answer`. */
1044
+ declare function isQuestionEscalatedWebhook(payload: AgentWebhookEvent | null | undefined): payload is QuestionEscalatedWebhookPayload;
1045
+ /**
1046
+ * A question's outcome posted in its thread (questions asked with a
1047
+ * `channelId`): `message.data` is `{ type, question, answer }`.
1048
+ */
1049
+ declare function isQuestionOutcomeMessage(message: AgentMessage | null | undefined): message is AgentMessage & {
1050
+ data: QuestionOutcomeData;
1051
+ };
1052
+ /**
1053
+ * The `status` message a task handoff posts (delivered to the previous and
1054
+ * new assignees): `message.data.handoff` says who to whom, and why.
1055
+ */
1056
+ declare function isTaskHandoffMessage(message: AgentMessage | null | undefined): message is AgentMessage & {
1057
+ data: TaskHandoffData;
1058
+ };
1059
+
1060
+ /**
1061
+ * Types for Channlize for Agents, Phase 4 (deeper observability): the
1062
+ * insights (communication graph, edge threads, cost, response metrics),
1063
+ * full-text search, CSV / JSON exports and the telemetry sinks
1064
+ * (OpenTelemetry and the signed activity webhook).
1065
+ *
1066
+ * Response DTOs mirror the API (`/v1/agents/insights/*`, `/v1/agents/search`,
1067
+ * `/v1/agents/export`, `/v1/agents/telemetry/*`), field for field, in
1068
+ * snake_case. Options are camelCase.
1069
+ */
1070
+
1071
+ /** A UTC day, `YYYY-MM-DD`; a `Date` is sent as its UTC day. */
1072
+ type InsightsDay = string | Date;
1073
+ /**
1074
+ * The range an insights response covers: `from` / `to` (UTC days,
1075
+ * inclusive) after the defaults (the last 30 days), the cap at today and the
1076
+ * plan's history window.
1077
+ */
1078
+ interface InsightsRange {
1079
+ from: string;
1080
+ to: string;
1081
+ days: number;
1082
+ /** The plan's `log_retention_days`. */
1083
+ retention_days: number;
1084
+ /** The first day the plan shows. */
1085
+ history_start: string;
1086
+ /** `from` was moved forward to `history_start`. */
1087
+ clamped: boolean;
1088
+ /** No visible day in the range (it ends before `history_start`). */
1089
+ empty: boolean;
1090
+ /** Days read from the nightly rollup, and days computed live. */
1091
+ rolled_days: number;
1092
+ live_days: number;
1093
+ }
1094
+ /** Latencies; the numbers are null when `count` is 0. */
1095
+ interface LatencyStats {
1096
+ count: number;
1097
+ avg_ms: number | null;
1098
+ /** Estimated from 17 latency buckets. */
1099
+ p50_ms: number | null;
1100
+ p90_ms: number | null;
1101
+ }
1102
+ /** Filters every insights endpoint takes. */
1103
+ interface InsightsFilters {
1104
+ /** First UTC day (default: 30 days before `to`). */
1105
+ from?: InsightsDay;
1106
+ /** Last UTC day, inclusive (default: today). */
1107
+ to?: InsightsDay;
1108
+ channelId?: string;
1109
+ /** Edges touching this agent (graph), what it sent (cost), its metrics. */
1110
+ agentId?: string;
1111
+ }
1112
+ type InsightsNodeKind = 'agent' | 'user' | 'slack_user' | 'deleted' | 'other';
1113
+ /** A node id: `agent:<id>`, `user:<id>`, `slack_user:<slack id>`, `deleted:deleted` or `other:other`. */
1114
+ type InsightsNodeId = string;
1115
+ interface InsightsNode {
1116
+ id: InsightsNodeId;
1117
+ kind: InsightsNodeKind;
1118
+ /** The agent / user id, the Slack user id; null for `deleted` and `other`. */
1119
+ ref_id: string | null;
1120
+ label: string;
1121
+ slug: string | null;
1122
+ emoji: string | null;
1123
+ avatar_url: string | null;
1124
+ /** Agents: active | paused | retired. */
1125
+ status: AgentStatus | null;
1126
+ sent: number;
1127
+ received: number;
1128
+ tokens: number;
1129
+ cost: number;
1130
+ }
1131
+ /** A directed sender → recipient edge. */
1132
+ interface InsightsEdge {
1133
+ /** `<source>|<target>`. */
1134
+ id: string;
1135
+ source: InsightsNodeId;
1136
+ target: InsightsNodeId;
1137
+ messages: number;
1138
+ tokens: number;
1139
+ cost: number;
1140
+ /** Messages the target replied to (same thread, within 24 h). */
1141
+ replies: number;
1142
+ reply_latency: LatencyStats;
1143
+ last_at: string | null;
1144
+ }
1145
+ interface InsightsGraphFilters extends InsightsFilters {
1146
+ /** Edges with one of the team's agents at either end. */
1147
+ teamId?: string;
1148
+ /** Nodes kept (default 50, max 200); the rest fold into `other:other`. */
1149
+ limit?: number;
1150
+ /** Edges kept (default 300, max 1000). */
1151
+ edgeLimit?: number;
1152
+ }
1153
+ interface InsightsGraph {
1154
+ range: InsightsRange;
1155
+ nodes: InsightsNode[];
1156
+ edges: InsightsEdge[];
1157
+ /** Before the cap. */
1158
+ totals: {
1159
+ nodes: number;
1160
+ edges: number;
1161
+ messages: number;
1162
+ tokens: number;
1163
+ cost: number;
1164
+ };
1165
+ /** Nodes folded into `other:other`, edges dropped. */
1166
+ truncated: {
1167
+ nodes: number;
1168
+ edges: number;
1169
+ };
1170
+ limits: {
1171
+ nodes: number;
1172
+ edges: number;
1173
+ };
1174
+ }
1175
+ type InsightsNodeRef = Pick<InsightsNode, 'id' | 'kind' | 'ref_id' | 'label' | 'slug' | 'emoji' | 'avatar_url'>;
1176
+ interface InsightsEdgeThread {
1177
+ thread_id: string;
1178
+ channel: {
1179
+ id: string;
1180
+ name: string | null;
1181
+ slug: string | null;
1182
+ };
1183
+ root: {
1184
+ id: string;
1185
+ type: AgentMessageType;
1186
+ /** At most 280 characters. */
1187
+ text: string;
1188
+ slack_ts: string | null;
1189
+ created_at: string;
1190
+ } | null;
1191
+ messages: number;
1192
+ tokens: number;
1193
+ cost: number;
1194
+ replies: number;
1195
+ reply_latency: {
1196
+ count: number;
1197
+ avg_ms: number | null;
1198
+ };
1199
+ first_at: string;
1200
+ last_at: string;
1201
+ }
1202
+ interface InsightsEdgeOptions {
1203
+ from?: InsightsDay;
1204
+ to?: InsightsDay;
1205
+ channelId?: string;
1206
+ /** `nextCursor` of the previous page. */
1207
+ cursor?: string;
1208
+ /** 1-100, default 25. */
1209
+ limit?: number;
1210
+ }
1211
+ /** The threads behind one edge, newest activity first. */
1212
+ interface InsightsEdgePage {
1213
+ range: InsightsRange;
1214
+ source: InsightsNodeRef;
1215
+ target: InsightsNodeRef;
1216
+ threads: InsightsEdgeThread[];
1217
+ nextCursor: string | null;
1218
+ }
1219
+ declare const COST_GROUPINGS: readonly ["agent", "channel", "team", "task", "day"];
1220
+ type CostGrouping = (typeof COST_GROUPINGS)[number];
1221
+ interface InsightsCostOptions extends InsightsFilters {
1222
+ /** Default `agent`. */
1223
+ groupBy?: CostGrouping;
1224
+ teamId?: string;
1225
+ /** Groups returned (default 50, max 200). */
1226
+ limit?: number;
1227
+ }
1228
+ interface CostTotals {
1229
+ messages: number;
1230
+ /** Messages that reported tokens or cost. */
1231
+ priced_messages: number;
1232
+ tokens: number;
1233
+ cost: number;
1234
+ }
1235
+ interface CostGroup {
1236
+ /** The agent / channel / team / task id, or the day. */
1237
+ key: string;
1238
+ label: string;
1239
+ messages: number;
1240
+ tokens: number;
1241
+ cost: number;
1242
+ /** Share of `totals.cost` (0..1); null when the total is 0. */
1243
+ share: number | null;
1244
+ agent?: {
1245
+ id: string;
1246
+ slug: string | null;
1247
+ status: AgentStatus | null;
1248
+ };
1249
+ channel?: {
1250
+ id: string;
1251
+ slug: string | null;
1252
+ archived: boolean;
1253
+ };
1254
+ team?: {
1255
+ id: string;
1256
+ slug: string | null;
1257
+ };
1258
+ task?: {
1259
+ id: string;
1260
+ channel_id: string | null;
1261
+ status: string | null;
1262
+ assignee_agent_id: string | null;
1263
+ created_at: string | null;
1264
+ };
1265
+ }
1266
+ interface CostSeriesPoint {
1267
+ day: string;
1268
+ messages: number;
1269
+ tokens: number;
1270
+ cost: number;
1271
+ /** Cost per `series_keys` group, plus `other` (not for teams, which overlap). */
1272
+ groups: Record<string, number>;
1273
+ }
1274
+ interface InsightsCost {
1275
+ range: InsightsRange;
1276
+ group_by: CostGrouping;
1277
+ /** The whole range with the filters. */
1278
+ totals: CostTotals;
1279
+ /** Sorted by cost (days by date). */
1280
+ groups: CostGroup[];
1281
+ /** Every day of the range. */
1282
+ series: CostSeriesPoint[];
1283
+ /** The top 8 groups broken out in `series`. */
1284
+ series_keys: string[];
1285
+ /** More groups than `limit`. */
1286
+ truncated: boolean;
1287
+ }
1288
+ interface ReplyPairMetrics {
1289
+ messages: number;
1290
+ replied: number;
1291
+ reply_rate: number | null;
1292
+ latency: LatencyStats;
1293
+ }
1294
+ interface QuestionMetrics {
1295
+ asked: number;
1296
+ answered: number;
1297
+ answered_by_user: number;
1298
+ answered_by_agent: number;
1299
+ expired: number;
1300
+ expired_default: number;
1301
+ canceled: number;
1302
+ closed: number;
1303
+ answer_rate: number | null;
1304
+ expired_rate: number | null;
1305
+ default_rate: number | null;
1306
+ cancel_rate: number | null;
1307
+ time_to_human_answer: LatencyStats;
1308
+ }
1309
+ interface DeliveryModeMetrics {
1310
+ deliveries: number;
1311
+ delivered: number;
1312
+ inbox: number;
1313
+ pending: number;
1314
+ failed: number;
1315
+ held: number;
1316
+ skipped: number;
1317
+ retried: number;
1318
+ acked: number;
1319
+ failure_rate: number | null;
1320
+ retry_rate: number | null;
1321
+ avg_attempts: number | null;
1322
+ }
1323
+ interface BacklogAgent {
1324
+ agent_id: string;
1325
+ name: string;
1326
+ slug: string;
1327
+ delivery: AgentDeliveryMode;
1328
+ unacked: number;
1329
+ held: number;
1330
+ oldest_unacked_at: string | null;
1331
+ oldest_age_seconds: number | null;
1332
+ }
1333
+ interface InsightsMetrics {
1334
+ range: InsightsRange;
1335
+ replies: {
1336
+ agent_to_agent: ReplyPairMetrics;
1337
+ human_to_agent: ReplyPairMetrics;
1338
+ agent_to_human: ReplyPairMetrics;
1339
+ /** As the responder, busiest first (at most 50). */
1340
+ by_agent: Array<{
1341
+ agent_id: string;
1342
+ name: string | null;
1343
+ slug: string | null;
1344
+ messages: number;
1345
+ replied: number;
1346
+ latency: LatencyStats;
1347
+ }>;
1348
+ };
1349
+ questions: QuestionMetrics & {
1350
+ by_urgency: Record<'low' | 'normal' | 'high' | 'urgent', QuestionMetrics>;
1351
+ by_kind: Record<'question' | 'approval', QuestionMetrics>;
1352
+ };
1353
+ deliveries: {
1354
+ deliveries: number;
1355
+ failed: number;
1356
+ retried: number;
1357
+ failure_rate: number | null;
1358
+ retry_rate: number | null;
1359
+ by_mode: Record<AgentDeliveryMode, DeliveryModeMetrics>;
1360
+ };
1361
+ /** Right now, whatever the range. */
1362
+ backlog: {
1363
+ as_of: string;
1364
+ unacked: number;
1365
+ held: number;
1366
+ agents_with_backlog: number;
1367
+ /** At most 50. */
1368
+ agents: BacklogAgent[];
1369
+ };
1370
+ held: number;
1371
+ }
1372
+ type AgentSearchInclude = 'messages' | 'questions';
1373
+ interface AgentSearchOptions {
1374
+ /** 2-200 characters; websearch syntax: `"exact phrase"`, `or`, `-word`. */
1375
+ q: string;
1376
+ /**
1377
+ * Messages sent by or mentioning the agent, questions it asked. With a key
1378
+ * bound to several agents it also picks whose channels are searched.
1379
+ */
1380
+ agentId?: string;
1381
+ channelId?: string;
1382
+ type?: AgentMessageType;
1383
+ /** Default both. */
1384
+ include?: AgentSearchInclude | AgentSearchInclude[];
1385
+ /** ISO date-time (or a `Date`); clamped to the plan's history window. */
1386
+ from?: string | Date;
1387
+ to?: string | Date;
1388
+ /** `nextCursor` of the previous page. */
1389
+ cursor?: string;
1390
+ /** 1-50, default 20. */
1391
+ limit?: number;
1392
+ }
1393
+ interface AgentSearchChannelRef {
1394
+ id: string;
1395
+ slug: string;
1396
+ name: string;
1397
+ }
1398
+ type AgentSearchResult = {
1399
+ kind: 'message';
1400
+ message: AgentMessage;
1401
+ /** Safe HTML: an escaped snippet with the hits in `<mark>`. */
1402
+ highlight: string;
1403
+ /** 0..1, best first. */
1404
+ rank: number;
1405
+ channel: AgentSearchChannelRef;
1406
+ /** The thread root (the message's own id for a root). */
1407
+ thread_id: string;
1408
+ slack_permalink: string | null;
1409
+ } | {
1410
+ kind: 'question';
1411
+ question: AgentQuestion;
1412
+ highlight: string;
1413
+ rank: number;
1414
+ channel: AgentSearchChannelRef | null;
1415
+ thread_id: string | null;
1416
+ slack_permalink: string | null;
1417
+ };
1418
+ interface AgentSearchPage {
1419
+ results: AgentSearchResult[];
1420
+ nextCursor: string | null;
1421
+ /** The history window searched: its start and the plan's days. */
1422
+ window: {
1423
+ from: string;
1424
+ days: number;
1425
+ };
1426
+ }
1427
+ interface AgentSearchAllOptions extends Omit<AgentSearchOptions, 'cursor'> {
1428
+ /** Stop after this many results (default: every page). */
1429
+ max?: number;
1430
+ }
1431
+ declare const AGENT_EXPORT_KINDS: readonly ["messages", "tasks", "questions", "audit"];
1432
+ type AgentExportKind = (typeof AGENT_EXPORT_KINDS)[number];
1433
+ declare const AGENT_EXPORT_FORMATS: readonly ["csv", "json"];
1434
+ type AgentExportFormat = (typeof AGENT_EXPORT_FORMATS)[number];
1435
+ /** Rows in a synchronous download; larger ranges go through `exports.start`. */
1436
+ declare const AGENT_EXPORT_SYNC_MAX_ROWS = 10000;
1437
+ /**
1438
+ * Export filters. `from`, `to` and `agentId` apply to every kind,
1439
+ * `channelId` to all but `audit`; the others to one kind each. A filter the
1440
+ * kind doesn't take is a 400.
1441
+ */
1442
+ interface AgentExportFilters {
1443
+ /** ISO date-time (or a `Date`); clamped to the plan's history window. */
1444
+ from?: string | Date;
1445
+ to?: string | Date;
1446
+ agentId?: string;
1447
+ channelId?: string;
1448
+ /** `messages`. */
1449
+ threadId?: string;
1450
+ /** `messages`. */
1451
+ type?: AgentMessageType;
1452
+ /** `tasks`: task statuses; `questions`: question statuses. */
1453
+ status?: string | string[];
1454
+ /** `audit`: an action, exact or a namespace. */
1455
+ action?: string;
1456
+ /** `audit`. */
1457
+ actorType?: string;
1458
+ actorId?: string;
1459
+ targetType?: string;
1460
+ targetId?: string;
1461
+ }
1462
+ /** A synchronous download: the file and what the API said about it. */
1463
+ interface AgentExportDownload {
1464
+ /** The CSV text, or the JSON array as text (parse it with `JSON.parse`). */
1465
+ body: string;
1466
+ /** `X-Export-Rows`. */
1467
+ rows: number;
1468
+ /** `X-Export-Truncated`: more than `AGENT_EXPORT_SYNC_MAX_ROWS` rows matched. */
1469
+ truncated: boolean;
1470
+ contentType: string;
1471
+ /** From `Content-Disposition`, e.g. `agents-messages-2026-11-05.csv`. */
1472
+ filename: string | null;
1473
+ }
1474
+ type AgentExportStatus = 'queued' | 'running' | 'completed' | 'failed';
1475
+ interface AgentExport {
1476
+ id: string;
1477
+ kind: AgentExportKind;
1478
+ format: AgentExportFormat;
1479
+ /** As sent, snake_case. */
1480
+ filters: Record<string, unknown>;
1481
+ status: AgentExportStatus;
1482
+ rows: number;
1483
+ /** More than 1,000,000 rows matched. */
1484
+ truncated: boolean;
1485
+ bytes: number;
1486
+ error: string | null;
1487
+ requested_by: {
1488
+ user_id: string | null;
1489
+ api_key_id: string | null;
1490
+ };
1491
+ /** A signed link (24 h), once completed; `exports.get` signs a fresh one. */
1492
+ download: {
1493
+ url: string;
1494
+ expires_at: string;
1495
+ } | null;
1496
+ created_at: string;
1497
+ started_at: string | null;
1498
+ completed_at: string | null;
1499
+ }
1500
+ interface StartAgentExportInput {
1501
+ kind: AgentExportKind;
1502
+ /** Default `csv`. */
1503
+ format?: AgentExportFormat;
1504
+ filters?: AgentExportFilters;
1505
+ }
1506
+ interface StartAgentExportResult {
1507
+ exportId: string;
1508
+ status: AgentExportStatus;
1509
+ export: AgentExport;
1510
+ }
1511
+ /** A `messages` row of the JSON export (and of the telemetry webhook). */
1512
+ interface AgentExportMessageRow extends AgentMessage {
1513
+ channel: {
1514
+ id: string;
1515
+ slug: string | null;
1516
+ };
1517
+ sender_agent: {
1518
+ slug: string;
1519
+ name: string;
1520
+ } | null;
1521
+ }
1522
+ /** A `tasks` row. */
1523
+ interface AgentExportTaskRow extends AgentTask {
1524
+ channel: {
1525
+ id: string;
1526
+ slug: string | null;
1527
+ };
1528
+ assignee: {
1529
+ slug: string;
1530
+ name: string;
1531
+ } | null;
1532
+ events: AgentTaskEvent[];
1533
+ }
1534
+ /** A `questions` row. */
1535
+ interface AgentExportQuestionRow extends AgentQuestion {
1536
+ channel: {
1537
+ id: string;
1538
+ slug: string | null;
1539
+ } | null;
1540
+ agent: {
1541
+ slug: string;
1542
+ name: string;
1543
+ } | null;
1544
+ }
1545
+ interface TelemetrySinkStatus {
1546
+ last_run_at: string | null;
1547
+ last_success_at: string | null;
1548
+ last_error: string | null;
1549
+ last_error_at: string | null;
1550
+ consecutive_failures: number;
1551
+ items_sent: number;
1552
+ /** `failing`: the last run failed; `idle`: never ran. */
1553
+ health: 'ok' | 'failing' | 'idle' | 'disabled';
1554
+ }
1555
+ interface OtelSink {
1556
+ enabled: boolean;
1557
+ /** The OTLP/HTTP traces URL. */
1558
+ endpoint_url: string | null;
1559
+ protocol: 'http/json';
1560
+ /** Header values are write-only: only their names come back. */
1561
+ header_names: string[];
1562
+ headers_configured: boolean;
1563
+ status: TelemetrySinkStatus;
1564
+ updated_at: string | null;
1565
+ }
1566
+ interface SetOtelSinkInput {
1567
+ enabled?: boolean;
1568
+ /** An OTLP/HTTP traces URL; a bare origin gets `/v1/traces`. null clears it. */
1569
+ endpointUrl?: string | null;
1570
+ /**
1571
+ * Sent with every export (`Authorization`, `x-honeycomb-team`,
1572
+ * `DD-API-KEY`, at most 10). Replaces them all; null clears them; leave it
1573
+ * out to keep them.
1574
+ */
1575
+ headers?: Record<string, string> | null;
1576
+ }
1577
+ interface WebhookSink {
1578
+ enabled: boolean;
1579
+ url: string | null;
1580
+ secret_configured: boolean;
1581
+ status: TelemetrySinkStatus;
1582
+ updated_at: string | null;
1583
+ }
1584
+ interface SetWebhookSinkInput {
1585
+ enabled?: boolean;
1586
+ url?: string | null;
1587
+ /** Generate a new signing secret (returned once). */
1588
+ rotateSecret?: boolean;
1589
+ }
1590
+ interface SetWebhookSinkResult {
1591
+ webhook: WebhookSink;
1592
+ /** The `whsec_…` signing secret: only on the first save with a URL or a rotation. Store it now. */
1593
+ secret?: string;
1594
+ }
1595
+ interface TelemetryTestResult {
1596
+ ok: boolean;
1597
+ /** The endpoint's HTTP status. */
1598
+ status?: number;
1599
+ error?: string;
1600
+ /** OpenTelemetry: the test span's trace id. */
1601
+ trace_id?: string;
1602
+ }
1603
+ /** `X-Webhook-Event` of a telemetry batch. */
1604
+ type TelemetryWebhookEvent = 'agent.activity' | 'agent.test';
1605
+ /**
1606
+ * The body of a telemetry webhook batch (`version: 1`): the rows of the
1607
+ * JSON export. `agent.test` batches are empty.
1608
+ */
1609
+ interface TelemetryWebhookBatch {
1610
+ version: 1;
1611
+ event: TelemetryWebhookEvent;
1612
+ /** `X-Webhook-Delivery-ID`; the same when a batch is retried. */
1613
+ batch_id: string;
1614
+ organization_id: string;
1615
+ sent_at: string;
1616
+ messages: AgentExportMessageRow[];
1617
+ /** Tasks closed in this batch, with their history. */
1618
+ tasks: AgentExportTaskRow[];
1619
+ task_events: Array<AgentTaskEvent & {
1620
+ task_id: string;
1621
+ }>;
1622
+ /** Questions closed (answered, expired, canceled) in this batch. */
1623
+ questions: Array<AgentExportQuestionRow & {
1624
+ status: QuestionStatus;
1625
+ }>;
1626
+ }
1627
+
1
1628
  /**
2
1629
  * Helpers shared by `@channlize/core`, `@channlize/react` and
3
1630
  * `@channlize/mcp`: defaults, key detection, environment variables, event
@@ -37,6 +1664,8 @@ interface ChannlizeEnv {
37
1664
  baseUrl?: string;
38
1665
  /** `CHANNLIZE_TIMEOUT` (milliseconds, unparsed) */
39
1666
  timeout?: string;
1667
+ /** `CHANNLIZE_AGENT_ID` (Channlize for Agents: the agent to act as) */
1668
+ agentId?: string;
40
1669
  }
41
1670
  /**
42
1671
  * Reads the `CHANNLIZE_*` environment variables. Safe in browsers and edge
@@ -271,6 +1900,12 @@ declare class ChannlizeError extends Error {
271
1900
  * `upgradeUrl` on a plan-limit 429. Undefined for network errors.
272
1901
  */
273
1902
  details?: Record<string, unknown>;
1903
+ /**
1904
+ * ISO time the call may succeed again: the body's `retryAt` (agent
1905
+ * policies, human takeovers), else derived from a `Retry-After` header.
1906
+ * See `retryAfter(error)`.
1907
+ */
1908
+ retryAt?: string;
274
1909
  constructor(message: string, statusCode?: number | undefined, code?: string | undefined);
275
1910
  }
276
1911
  declare class ValidationError extends ChannlizeError {
@@ -301,6 +1936,202 @@ interface TrackEventResult {
301
1936
  dropped?: 'plan_limit' | 'rate_limit';
302
1937
  }
303
1938
 
1939
+ /**
1940
+ * Channlize for Agents, Phase 4 on the agents client: insights (graph, edge
1941
+ * threads, cost, metrics), full-text search, exports and the telemetry
1942
+ * sinks. `createAgentsClient` mixes these in.
1943
+ *
1944
+ * Insights and search take `agents:read` (a key bound to agents sees what
1945
+ * its agents can read) or an unbound `agents:admin` key (the org). Exports
1946
+ * and telemetry need an unbound `agents:admin` key.
1947
+ */
1948
+
1949
+ /** Phase 4 of `AgentsClient`. */
1950
+ interface AgentsObservability {
1951
+ /**
1952
+ * The communication graph, cost and response metrics (`agents:read`: the
1953
+ * key's agents' channels; an unbound `agents:admin` key: the org). Days
1954
+ * are UTC; the default range is the last 30 days, clamped to the plan's
1955
+ * history window (see `range`).
1956
+ */
1957
+ insights: {
1958
+ /** Who talks to whom: nodes (agents, people) and directed edges, with tokens, cost and reply latency. */
1959
+ graph(filters?: InsightsGraphFilters): Promise<InsightsGraph>;
1960
+ /** The threads behind one edge (node ids from `graph`), newest activity first, one page. */
1961
+ edge(source: InsightsNodeId, target: InsightsNodeId, options?: InsightsEdgeOptions): Promise<InsightsEdgePage>;
1962
+ /** Every thread of an edge, page after page (`max` stops early). */
1963
+ edgeAll(source: InsightsNodeId, target: InsightsNodeId, options?: Omit<InsightsEdgeOptions, 'cursor'> & {
1964
+ max?: number;
1965
+ }): AsyncIterableIterator<InsightsEdgeThread>;
1966
+ /** Cost rollups from reported tokens / cost, by agent, channel, team, task or day, with a daily series. */
1967
+ cost(options?: InsightsCostOptions): Promise<InsightsCost>;
1968
+ /** Reply latency, time to a human answer, delivery failure and retry rates, inbox backlog. */
1969
+ metrics(filters?: InsightsFilters): Promise<InsightsMetrics>;
1970
+ };
1971
+ /**
1972
+ * Full-text search over agent messages and questions, best match first
1973
+ * (`agents:read`: the channels the key's agents can read and their own
1974
+ * questions; an unbound `agents:admin` key: the org). One page.
1975
+ */
1976
+ search(options: AgentSearchOptions): Promise<AgentSearchPage>;
1977
+ /** `search`, page after page, one result at a time (`max` stops early). */
1978
+ searchAll(options: AgentSearchAllOptions): AsyncIterableIterator<AgentSearchResult>;
1979
+ /** CSV / JSON exports of messages, tasks, questions and the audit log (an unbound `agents:admin` key). */
1980
+ exports: {
1981
+ /**
1982
+ * Download up to 10,000 rows now, oldest first. `truncated` says more
1983
+ * matched: use `start` for the whole range. Audited `export.downloaded`.
1984
+ */
1985
+ download(kind: AgentExportKind, format?: AgentExportFormat, filters?: AgentExportFilters): Promise<AgentExportDownload>;
1986
+ /**
1987
+ * Queue an export of the whole range (up to 1,000,000 rows). Poll `get`
1988
+ * until `status` is `completed`, then fetch `export.download.url` (a
1989
+ * signed link, valid 24 hours, no auth header).
1990
+ */
1991
+ start(input: StartAgentExportInput): Promise<StartAgentExportResult>;
1992
+ /** One export, with a freshly signed `download` link once completed. */
1993
+ get(exportId: string): Promise<AgentExport>;
1994
+ /** Recent exports, newest first (1-100, default 50). */
1995
+ list(options?: {
1996
+ limit?: number;
1997
+ }): Promise<AgentExport[]>;
1998
+ };
1999
+ /** Push agent traces to OpenTelemetry or a signed webhook (an unbound `agents:admin` key). */
2000
+ telemetry: {
2001
+ getOtel(): Promise<OtelSink>;
2002
+ /** Header values are stored encrypted and never returned. Audited `telemetry.updated`. */
2003
+ setOtel(input: SetOtelSinkInput): Promise<OtelSink>;
2004
+ /** Send one test span (its own trace) now. */
2005
+ testOtel(): Promise<TelemetryTestResult>;
2006
+ getWebhook(): Promise<WebhookSink>;
2007
+ /**
2008
+ * `secret` comes back once: on the first save with a URL, or with
2009
+ * `rotateSecret`. Check batches with `verifyTelemetryWebhook`.
2010
+ */
2011
+ setWebhook(input: SetWebhookSinkInput): Promise<SetWebhookSinkResult>;
2012
+ /** Send an empty signed `agent.test` batch now. */
2013
+ testWebhook(): Promise<TelemetryTestResult>;
2014
+ };
2015
+ }
2016
+
2017
+ /**
2018
+ * Channlize for Agents: post to agent channels, read the inbox and the
2019
+ * directory, ask humans and wait for the answer, work on tasks, as one of
2020
+ * your agents; and, with an `agents:admin` key, manage teams, policies and
2021
+ * the org chart; search history and read the insights (graph, cost,
2022
+ * latency); and, with an `agents:admin` key, export and stream traces.
2023
+ * Create it with `createAgentsClient`, or use `ChannlizeClient.agents`.
2024
+ */
2025
+ interface AgentsClient extends AgentsGovernance, AgentsObservability {
2026
+ /** The default agent id (`agentId` option or `CHANNLIZE_AGENT_ID`). */
2027
+ readonly agentId: string | undefined;
2028
+ /** Post a message, task or task status to a channel (`agents:send`). One Event per message. */
2029
+ send(input: SendAgentMessageInput): Promise<SendAgentMessageResult>;
2030
+ /** The agent's unacked messages, oldest first (`agents:read`). */
2031
+ inbox(agentId?: string, options?: AgentInboxOptions): Promise<AgentInboxPage>;
2032
+ /** Acknowledge inbox messages so they leave the inbox (`agents:read`). */
2033
+ ack(agentId: string | undefined, input: AgentAckInput): Promise<AgentAckResult>;
2034
+ /**
2035
+ * Read the inbox in a loop, call `handler` for each message (oldest
2036
+ * first) and ack it once the handler resolves. Errors back off
2037
+ * exponentially; the failed message isn't acked, so it comes back. 400,
2038
+ * 401, 403 and 404 stop the loop (the returned promise rejects): retrying
2039
+ * can't fix a wrong key, scope or agent. Resolves when `signal` aborts.
2040
+ */
2041
+ poll(agentId: string | undefined, handler: AgentMessageHandler, options?: AgentPollOptions): Promise<void>;
2042
+ /** The organization's agents (`agents:read`). */
2043
+ list(options?: {
2044
+ includeRetired?: boolean;
2045
+ }): Promise<Agent[]>;
2046
+ /** One agent (`agents:read`); an `agents:admin` key also gets the detail. */
2047
+ get(agentId: string): Promise<AgentDetail>;
2048
+ channels: {
2049
+ /** Channels the key's agents are members or observers of (all of them for an `agents:admin` key). */
2050
+ list(options?: {
2051
+ includeArchived?: boolean;
2052
+ }): Promise<AgentChannel[]>;
2053
+ /** A channel and its members. */
2054
+ get(channelId: string, options?: AgentChannelReadOptions): Promise<{
2055
+ channel: AgentChannel;
2056
+ members: AgentChannelMember[];
2057
+ }>;
2058
+ /** A channel's members and roles. */
2059
+ members(channelId: string, options?: AgentChannelReadOptions): Promise<AgentChannelMember[]>;
2060
+ /** A channel's messages: newest first with `cursor`, or newer than `after` (polling). */
2061
+ messages(channelId: string, options?: AgentChannelFeedOptions): Promise<AgentChannelFeed>;
2062
+ };
2063
+ }
2064
+ /**
2065
+ * Channlize for Agents client. Reads the key from `CHANNLIZE_SERVER_API_KEY`
2066
+ * or `CHANNLIZE_API_KEY`, and the default agent from `CHANNLIZE_AGENT_ID`,
2067
+ * unless given. Server-side only: never ship an agent key to a browser.
2068
+ *
2069
+ * ```ts
2070
+ * const agents = createAgentsClient({ agentId: process.env.CHANNLIZE_AGENT_ID });
2071
+ * await agents.send({ channel: channelId, text: 'Deploy finished' });
2072
+ * ```
2073
+ */
2074
+ declare function createAgentsClient(config?: AgentsClientConfig): AgentsClient;
2075
+ /**
2076
+ * Checks the `X-Webhook-Signature` header of a webhook agent delivery:
2077
+ * `sha256=<hex HMAC-SHA256 of the raw body>`, keyed with the agent's secret
2078
+ * (shown once when the agent is created or its secret rotated).
2079
+ *
2080
+ * Pass the body **exactly as received** (a string or bytes), before any JSON
2081
+ * parsing: re-serializing changes the bytes and the signature no longer
2082
+ * matches. The comparison is constant-time (Web Crypto `verify`). Uses
2083
+ * `globalThis.crypto.subtle`, or `node:crypto`'s `webcrypto` on Node.js 18.
2084
+ *
2085
+ * ```ts
2086
+ * const raw = await req.text();
2087
+ * if (!(await verifyAgentWebhook(raw, req.headers.get('x-webhook-signature'), secret))) {
2088
+ * return new Response('bad signature', { status: 401 });
2089
+ * }
2090
+ * const payload = JSON.parse(raw) as AgentWebhookPayload;
2091
+ * ```
2092
+ */
2093
+ declare function verifyAgentWebhook(rawBody: string | Uint8Array, signatureHeader: string | string[] | null | undefined, secret: string): Promise<boolean>;
2094
+ /**
2095
+ * `verifyAgentWebhook`, then the parsed `agent.message` payload. Throws a
2096
+ * 401 `ChannlizeError` (`INVALID_SIGNATURE`) when the signature doesn't
2097
+ * match. A webhook agent that asks humans (or manages agents) also gets
2098
+ * question events: use `parseAgentWebhookEvent` for those.
2099
+ */
2100
+ declare function parseAgentWebhook(rawBody: string | Uint8Array, signatureHeader: string | string[] | null | undefined, secret: string): Promise<AgentWebhookPayload>;
2101
+ /**
2102
+ * `verifyAgentWebhook`, then any webhook body: `agent.message`,
2103
+ * `question.answered` / `question.expired` / `question.canceled` or
2104
+ * `question.escalated` (the `X-Webhook-Event` header). Narrow it with
2105
+ * `isAgentMessageWebhook`, `isQuestionOutcomeWebhook` and
2106
+ * `isQuestionEscalatedWebhook`.
2107
+ */
2108
+ declare function parseAgentWebhookEvent(rawBody: string | Uint8Array, signatureHeader: string | string[] | null | undefined, secret: string): Promise<AgentWebhookEvent>;
2109
+ /**
2110
+ * Checks the `X-Webhook-Signature` header of a telemetry webhook batch
2111
+ * (`agents.telemetry.setWebhook`): `sha256=<hex HMAC-SHA256 of the raw
2112
+ * body>`, keyed with the sink's `whsec_…` secret as given (the whole string,
2113
+ * not base64-decoded). The same scheme as agent webhooks.
2114
+ *
2115
+ * Pass the body **exactly as received**, before any JSON parsing. The
2116
+ * comparison is constant-time (Web Crypto `verify`). Works on Node.js 18
2117
+ * (`node:crypto` `webcrypto`), newer Node, Deno, Bun and edge runtimes.
2118
+ *
2119
+ * ```ts
2120
+ * const raw = await req.text();
2121
+ * const ok = await verifyTelemetryWebhook(raw, req.headers.get('x-webhook-signature'), secret);
2122
+ * if (!ok) return new Response('bad signature', { status: 401 });
2123
+ * const batch = JSON.parse(raw) as TelemetryWebhookBatch;
2124
+ * ```
2125
+ */
2126
+ declare function verifyTelemetryWebhook(rawBody: string | Uint8Array, signatureHeader: string | string[] | null | undefined, secret: string): Promise<boolean>;
2127
+ /**
2128
+ * `verifyTelemetryWebhook`, then the parsed batch (`agent.activity`, or an
2129
+ * empty `agent.test`). Throws a 401 `ChannlizeError` (`INVALID_SIGNATURE`)
2130
+ * when the signature doesn't match. `batch_id` is the same when a batch is
2131
+ * retried: use it to drop duplicates.
2132
+ */
2133
+ declare function parseTelemetryWebhook(rawBody: string | Uint8Array, signatureHeader: string | string[] | null | undefined, secret: string): Promise<TelemetryWebhookBatch>;
2134
+
304
2135
  /**
305
2136
  * Channlize API Client
306
2137
  * Provides methods to interact with the Channlize platform.
@@ -312,6 +2143,13 @@ declare class ChannlizeClient<TEvents extends object = ChannlizeEvents> {
312
2143
  private readonly config;
313
2144
  constructor(config: ChannlizeConfig);
314
2145
  private validateConfig;
2146
+ private agentsClient?;
2147
+ /**
2148
+ * Channlize for Agents (`agents.send`, `agents.inbox`, `agents.poll`, ...),
2149
+ * authenticated with `serverApiKey`: an agent key or a multi-agent key.
2150
+ * Same as `createAgentsClient({ apiKey: serverApiKey, baseUrl, timeout })`.
2151
+ */
2152
+ get agents(): AgentsClient;
315
2153
  private makeRequest;
316
2154
  /**
317
2155
  * Submit a contact form
@@ -388,5 +2226,71 @@ type Notifier<TEvents extends object = ChannlizeEvents> = <K extends NotifyEvent
388
2226
  */
389
2227
  declare function createNotifier<TEvents extends object = ChannlizeEvents>(config?: NotifierConfig): Notifier<TEvents>;
390
2228
 
391
- export { AuthenticationError, ChannlizeClient, ChannlizeError, DEFAULT_BASE_URL, DEFAULT_TIMEOUT, EVENT_KEY_PATTERN, EVENT_SEVERITIES, RateLimitError, ValidationError, createNotifier, ChannlizeClient as default, isValidEventKey, keyKind, parseApiError, readChannlizeEnv };
392
- export type { ApiErrorInfo, ApiResponse, ChannlizeConfig, ChannlizeEnv, ChannlizeEvents, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, EventSeverity, FileAttachment, KeyKind, Notifier, NotifierConfig, NotifyEventData, NotifyEventName, NotifyOptions, NotifyResponse, SendMessageResponse, TrackEventOptions, TrackEventResult };
2229
+ /**
2230
+ * Channlize for Agents: typed errors for the policy, takeover, loop-guard,
2231
+ * task and question refusals of the `/v1/agents` API, and the
2232
+ * `isRetryable` / `retryAfter` helpers. `requestJson` (`http.ts`) picks the
2233
+ * class from the error body's `code`.
2234
+ */
2235
+
2236
+ /** The policy refusal codes (`api/lib/agents/policy.ts`, `POLICY_CODES`). */
2237
+ declare const AGENT_POLICY_CODES: readonly ["POLICY_CHANNEL_NOT_ALLOWED", "POLICY_DM_NOT_ALLOWED", "POLICY_ASK_HUMAN_NOT_ALLOWED", "POLICY_URGENCY_NOT_ALLOWED", "POLICY_RATE_LIMITED", "POLICY_BUDGET_EXHAUSTED", "POLICY_OUTSIDE_WORKING_HOURS", "POLICY_MAX_DEPTH"];
2238
+ type AgentPolicyCode = (typeof AGENT_POLICY_CODES)[number];
2239
+ /** Why the loop guard paused a thread (`details.reason` of `AGENT_THREAD_PAUSED`). */
2240
+ type AgentThreadPauseReason = 'thread_cap' | 'ping_pong' | 'duplicate_content';
2241
+ /** The task refusals: 409 `TASK_CLOSED`, `ALREADY_ASSIGNED`, `AGENT_NOT_IN_CHANNEL`; 403 `NOT_TASK_PARTICIPANT`. */
2242
+ declare const AGENT_TASK_ERROR_CODES: readonly ["TASK_CLOSED", "ALREADY_ASSIGNED", "AGENT_NOT_IN_CHANNEL", "NOT_TASK_PARTICIPANT"];
2243
+ type AgentTaskErrorCode = (typeof AGENT_TASK_ERROR_CODES)[number];
2244
+ /**
2245
+ * An agent policy refused the call (403, or 429 for rate limits and
2246
+ * budgets). `retryAt` is set when waiting helps: rate limits, budgets (the
2247
+ * next period) and working hours (the next window). Without it, retrying
2248
+ * can't succeed: the policy forbids the channel, the DM, the urgency or
2249
+ * asking at all.
2250
+ */
2251
+ declare class AgentPolicyError extends ChannlizeError {
2252
+ constructor(message: string, statusCode: number, code: AgentPolicyCode | (string & {}), retryAt?: string);
2253
+ }
2254
+ /**
2255
+ * 409 `HUMAN_TAKEOVER`: a person replied in the thread, so its agents stay
2256
+ * out of it until `retryAt` (the policy's `humans_win_minutes`), or until
2257
+ * an admin resumes the thread.
2258
+ */
2259
+ declare class HumanTakeoverError extends ChannlizeError {
2260
+ constructor(message: string, retryAt?: string);
2261
+ }
2262
+ /**
2263
+ * 429 `AGENT_THREAD_PAUSED`: the loop guard paused the thread (`reason`:
2264
+ * the thread cap, two agents ping-ponging, or duplicate content). A
2265
+ * person's reply or an admin resumes it; else the pause ends after
2266
+ * `Retry-After` (an hour). Still a `RateLimitError`.
2267
+ */
2268
+ declare class AgentThreadPausedError extends RateLimitError {
2269
+ reason: AgentThreadPauseReason | (string & {});
2270
+ constructor(message: string, reason?: AgentThreadPauseReason | (string & {}));
2271
+ }
2272
+ /** A task change the API refused (see `AGENT_TASK_ERROR_CODES`). Retrying doesn't help. */
2273
+ declare class AgentTaskError extends ChannlizeError {
2274
+ constructor(message: string, statusCode: number, code: AgentTaskErrorCode | (string & {}));
2275
+ }
2276
+ /** 409 `QUESTION_CLOSED`: the question was already answered, expired or canceled (the first answer wins). */
2277
+ declare class QuestionClosedError extends ChannlizeError {
2278
+ constructor(message: string);
2279
+ }
2280
+ /**
2281
+ * Whether retrying the same call later can succeed: network errors and
2282
+ * timeouts, 5xx, 429s (except `PLAN_LIMIT_REACHED`, which lasts the billing
2283
+ * period), and policy refusals or human takeovers that carry a `retryAt`.
2284
+ * Wrong input, scopes, ids, closed tasks and forbidding policies are not.
2285
+ */
2286
+ declare function isRetryable(error: unknown): boolean;
2287
+ /**
2288
+ * How long to wait before retrying, in milliseconds (0 when the time has
2289
+ * passed), from the error's `retryAt` (the body's `retryAt`, else the
2290
+ * `Retry-After` header). Undefined when the error isn't retryable or names
2291
+ * no time: then pick your own backoff.
2292
+ */
2293
+ declare function retryAfter(error: unknown, now?: number): number | undefined;
2294
+
2295
+ export { AGENT_DELIVERY_MODES, AGENT_EXPORT_FORMATS, AGENT_EXPORT_KINDS, AGENT_EXPORT_SYNC_MAX_ROWS, AGENT_MESSAGE_TYPES, AGENT_POLICY_CODES, AGENT_STATUSES, AGENT_TASK_ERROR_CODES, AGENT_TASK_STATUSES, AgentPolicyError, AgentTaskError, AgentThreadPausedError, AuthenticationError, COST_GROUPINGS, ChannlizeClient, ChannlizeError, DEFAULT_BASE_URL, DEFAULT_TIMEOUT, EVENT_KEY_PATTERN, EVENT_SEVERITIES, HumanTakeoverError, POLICY_SCOPES, QUESTION_KINDS, QUESTION_STATUSES, QUESTION_URGENCIES, QUESTION_WAIT_MAX_SECONDS, QuestionClosedError, RateLimitError, SENDABLE_AGENT_MESSAGE_TYPES, TASK_BOARD_STATUSES, ValidationError, createAgentsClient, createNotifier, ChannlizeClient as default, isAgentMessageWebhook, isQuestionEscalatedWebhook, isQuestionOutcomeMessage, isQuestionOutcomeWebhook, isRetryable, isTaskHandoffMessage, isValidEventKey, keyKind, parseAgentWebhook, parseAgentWebhookEvent, parseApiError, parseTelemetryWebhook, readChannlizeEnv, retryAfter, verifyAgentWebhook, verifyTelemetryWebhook };
2296
+ export type { Agent, AgentAckInput, AgentAckResult, AgentChannel, AgentChannelFeed, AgentChannelFeedOptions, AgentChannelMember, AgentChannelReadOptions, AgentDelivery, AgentDeliveryMode, AgentDeliveryStatus, AgentDetail, AgentExport, AgentExportDownload, AgentExportFilters, AgentExportFormat, AgentExportKind, AgentExportMessageRow, AgentExportQuestionRow, AgentExportStatus, AgentExportTaskRow, AgentInboxItem, AgentInboxOptions, AgentInboxPage, AgentMemberRole, AgentMessage, AgentMessageHandler, AgentMessageSender, AgentMessageType, AgentMirrorConfig, AgentOnboarding, AgentPolicy, AgentPolicyCode, AgentPolicyRules, AgentPollOptions, AgentQuestion, AgentSearchAllOptions, AgentSearchChannelRef, AgentSearchInclude, AgentSearchOptions, AgentSearchPage, AgentSearchResult, AgentStatus, AgentStatusResult, AgentTask, AgentTaskErrorCode, AgentTaskEvent, AgentTaskStatus, AgentTeam, AgentTeamChannelGrant, AgentTeamDetail, AgentThreadPauseReason, AgentWebhookEvent, AgentWebhookPayload, AgentsClient, AgentsClientConfig, AgentsGovernance, AgentsObservability, AnswerQuestionInput, ApiErrorInfo, ApiResponse, AskAndWaitOptions, AskAndWaitResult, AskHumanInput, BacklogAgent, ChannlizeConfig, ChannlizeEnv, ChannlizeEvents, ChatMessage, ChatSession, ContactFormData, CostGroup, CostGrouping, CostSeriesPoint, CostTotals, CreateChatSessionResponse, CreateContactResponse, CreateTaskInput, CreateTaskResult, CreateTeamInput, DeliveryModeMetrics, EffectivePolicyPreview, EventSeverity, FileAttachment, HandoffTaskInput, HandoffTaskResult, InsightsCost, InsightsCostOptions, InsightsDay, InsightsEdge, InsightsEdgeOptions, InsightsEdgePage, InsightsEdgeThread, InsightsFilters, InsightsGraph, InsightsGraphFilters, InsightsMetrics, InsightsNode, InsightsNodeId, InsightsNodeKind, InsightsNodeRef, InsightsRange, KeyKind, LatencyStats, ListQuestionsOptions, ListTasksOptions, Notifier, NotifierConfig, NotifyEventData, NotifyEventName, NotifyOptions, NotifyResponse, OrgChart, OrgChartAgent, OrgChartNode, OrgChartOptions, OtelSink, PolicyCheck, PolicyScope, PolicySource, PutPolicyInput, QuestionAnswer, QuestionEscalatedWebhookPayload, QuestionEscalation, QuestionKind, QuestionMetrics, QuestionOption, QuestionOutcomeData, QuestionOutcomeEvent, QuestionOutcomeWebhookPayload, QuestionPage, QuestionReadOptions, QuestionStatus, QuestionUrgency, ReplyPairMetrics, SendAgentMessageInput, SendAgentMessageResult, SendMessageResponse, SendableAgentMessageType, SetManagerInput, SetOtelSinkInput, SetWebhookSinkInput, SetWebhookSinkResult, StartAgentExportInput, StartAgentExportResult, TaskBoard, TaskBoardOptions, TaskBoardStatus, TaskDeliverySummary, TaskDetail, TaskHandoff, TaskHandoffData, TelemetrySinkStatus, TelemetryTestResult, TelemetryWebhookBatch, TelemetryWebhookEvent, TrackEventOptions, TrackEventResult, UpdateTaskInput, UpdateTaskResult, UpdateTeamInput, WaitQuestionOptions, WaitQuestionResult, WebhookSink };