@dench.com/cli 2.1.5 → 2.2.1

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.
@@ -178,51 +178,808 @@ const crmOp = z
178
178
  .describe("A single CRM batch/transaction operation.");
179
179
 
180
180
  // ---------------------------------------------------------------------------
181
- // Response fragments (representative; not exhaustive)
181
+ // Email fragments (mirror convex/functions/emailCampaigns*.ts + gateway SES)
182
+ // ---------------------------------------------------------------------------
183
+
184
+ const emailAddress = z.object({
185
+ email: z.string().describe("Recipient email address."),
186
+ name: z.string().optional().describe("Optional display name."),
187
+ });
188
+
189
+ const emailIdentityType = z
190
+ .enum(["domain", "email"])
191
+ .describe(
192
+ "Identity scope. `domain` verifies via DNS (DKIM); `email` verifies a single mailbox via a confirmation email.",
193
+ );
194
+
195
+ const rawMessageStatus = z
196
+ .enum([
197
+ "queued",
198
+ "sent",
199
+ "failed",
200
+ "delivered",
201
+ "opened",
202
+ "clicked",
203
+ "bounced",
204
+ "complained",
205
+ ])
206
+ .describe("Raw email message lifecycle status.");
207
+
208
+ const templateStatus = z
209
+ .enum(["draft", "active", "archived"])
210
+ .describe("Template lifecycle status. Defaults to `active`.");
211
+
212
+ const campaignRecipientInput = z.object({
213
+ email: z.string().describe("Recipient email address."),
214
+ displayName: z.string().optional(),
215
+ personEntryId: z
216
+ .string()
217
+ .optional()
218
+ .describe("Optional CRM people entry to link the send to."),
219
+ companyEntryId: z.string().optional(),
220
+ personalization: z
221
+ .record(z.string(), z.unknown())
222
+ .optional()
223
+ .describe("Values for {{variable}} placeholders in the template."),
224
+ });
225
+
226
+ // ---------------------------------------------------------------------------
227
+ // Response fragments. These mirror the real backend return shapes (Convex
228
+ // `returns` validators / handler code / gateway response mapping). Objects
229
+ // built with `.passthrough()` may carry additional fields at runtime.
182
230
  // ---------------------------------------------------------------------------
183
231
 
184
232
  const okResponse = z.object({ ok: z.boolean() });
185
233
 
186
- const crmObjectShape = z
234
+ const fieldsMap = z
235
+ .record(z.string(), z.unknown())
236
+ .describe("Field-name -> cell value map.");
237
+
238
+ // -- auth / workspace ----------------------------------------------------
239
+
240
+ const organizationRef = z.object({
241
+ id: z.string(),
242
+ name: z.string(),
243
+ slug: z.string(),
244
+ });
245
+
246
+ const agentRef = z.object({
247
+ id: z.string(),
248
+ name: z.string(),
249
+ kind: z.string(),
250
+ });
251
+
252
+ const artifactRow = z.object({
253
+ id: z.string(),
254
+ runId: z.string(),
255
+ title: z.string(),
256
+ type: z.enum([
257
+ "note",
258
+ "draft",
259
+ "report",
260
+ "task_suggestion",
261
+ "patch",
262
+ "other",
263
+ ]),
264
+ status: z.enum(["draft", "approved", "rejected", "applied", "archived"]),
265
+ content: z.string(),
266
+ createdAt: z.number(),
267
+ updatedAt: z.number(),
268
+ });
269
+
270
+ const workspaceStatusPayload = z
187
271
  .object({
188
- id: z.string(),
272
+ workspace: z.object({
273
+ id: z.string(),
274
+ name: z.string(),
275
+ slug: z.string().optional(),
276
+ }),
277
+ agent: agentRef,
278
+ rules: z.array(
279
+ z.object({
280
+ id: z.string(),
281
+ title: z.string(),
282
+ body: z.string(),
283
+ scope: z.enum(["organization", "project"]),
284
+ }),
285
+ ),
286
+ activeAgents: z.array(
287
+ agentRef.extend({ lastSeenAt: z.number().optional() }),
288
+ ),
289
+ pendingApprovals: z.array(
290
+ z
291
+ .object({
292
+ id: z.string(),
293
+ title: z.string(),
294
+ reason: z.string(),
295
+ kind: z.string().optional(),
296
+ risk: riskLevel,
297
+ agentId: z.string().optional(),
298
+ createdAt: z.number(),
299
+ })
300
+ .passthrough(),
301
+ ),
302
+ recentArtifacts: z.array(artifactRow),
303
+ suggestedWork: z.array(
304
+ artifactRow.extend({ nextCommands: z.array(z.string()) }),
305
+ ),
306
+ memory: z.array(
307
+ z.object({
308
+ id: z.string(),
309
+ key: z.string(),
310
+ kind: memoryKind,
311
+ text: z.string(),
312
+ tags: z.array(z.string()),
313
+ status: z.enum(["active", "needs_review", "archived"]),
314
+ updatedAt: z.number(),
315
+ }),
316
+ ),
317
+ chatAgents: z.object({
318
+ nextCommands: z.array(z.string()),
319
+ activeRuns: z.array(
320
+ z
321
+ .object({
322
+ id: z.string(),
323
+ goal: z.string(),
324
+ status: z.string(),
325
+ model: z.string(),
326
+ createdAt: z.number(),
327
+ })
328
+ .passthrough(),
329
+ ),
330
+ templates: z.array(z.string()),
331
+ }),
332
+ tools: z.object({
333
+ discovery: z.array(z.string()),
334
+ cli: z.array(z.string()),
335
+ approvalPolicy: z.string(),
336
+ }),
337
+ nextActions: z.array(z.string()),
338
+ })
339
+ .describe(
340
+ "Workspace orientation payload shared by /context, /status, /agents, and /approvals.",
341
+ );
342
+
343
+ const memoryDoc = z
344
+ .object({
345
+ _id: z.string(),
346
+ _creationTime: z.number(),
347
+ key: z.string(),
348
+ kind: memoryKind,
349
+ text: z.string(),
350
+ tags: z.array(z.string()),
351
+ status: z.enum(["active", "needs_review", "archived"]),
352
+ source: z.string(),
353
+ visibility: memoryVisibility.optional(),
354
+ confidence: z.number().optional(),
355
+ importance: z.number().optional(),
356
+ createdAt: z.number(),
357
+ updatedAt: z.number(),
358
+ })
359
+ .passthrough()
360
+ .describe("A workspace memory document.");
361
+
362
+ // -- billing ---------------------------------------------------------------
363
+
364
+ const billingStatusResponse = z
365
+ .object({
366
+ workspace: organizationRef,
367
+ availableCreditsCents: z.number(),
368
+ creditConsumedCents: z.number(),
369
+ billedCents: z.number(),
370
+ onDemandSpendCents: z.number(),
371
+ monthlySpendLimitCents: z.number(),
372
+ spendLimitRemainingCents: z.number(),
373
+ subscriptionStatus: z.string().nullable(),
374
+ stripeCustomerId: z.string().nullable(),
375
+ grants: z.array(
376
+ z.object({
377
+ id: z.string(),
378
+ source: z.enum([
379
+ "starter",
380
+ "trial",
381
+ "monthly",
382
+ "topup",
383
+ "manual",
384
+ "referral",
385
+ ]),
386
+ category: z.enum(["promotional", "paid"]),
387
+ status: z.enum(["pending", "granted", "depleted", "expired", "voided"]),
388
+ amountCents: z.number(),
389
+ usedCents: z.number(),
390
+ remainingCents: z.number(),
391
+ effectiveAt: z.number(),
392
+ expiresAt: z.number().nullable(),
393
+ }),
394
+ ),
395
+ nextCommands: z.array(z.string()),
396
+ })
397
+ .passthrough();
398
+
399
+ // -- chat --------------------------------------------------------------------
400
+
401
+ const chatThreadRow = z.object({
402
+ threadId: z.string(),
403
+ title: z.string(),
404
+ lastMessageAt: z.number(),
405
+ createdAt: z.number(),
406
+ status: z.enum(["idle", "streaming", "error"]),
407
+ visibility: z.enum(["private", "shared"]),
408
+ createdByUserId: z.string(),
409
+ archivedAt: z.number().nullable(),
410
+ fileContextPath: z.string().nullable(),
411
+ parentThreadId: z
412
+ .string()
413
+ .nullable()
414
+ .describe("Parent thread when this is a spawned sub-agent."),
415
+ nestingDepth: z.number().nullable(),
416
+ summary: z.string().nullable(),
417
+ activeRunId: z.string().nullable(),
418
+ });
419
+
420
+ const chatSpawnResponse = z.object({
421
+ threadId: z.string(),
422
+ runId: z.string(),
423
+ workflowRunId: z.string().nullable(),
424
+ threadUrl: z.string().describe("Web URL of the thread."),
425
+ streamUrl: z.string().describe("SSE stream URL for the live response."),
426
+ yolo: z.boolean(),
427
+ });
428
+
429
+ // -- crm ---------------------------------------------------------------------
430
+
431
+ const crmObjectDoc = z
432
+ .object({
433
+ _id: z.string(),
434
+ _creationTime: z.number(),
435
+ organizationId: z.string(),
189
436
  name: z.string(),
190
- description: z.string().nullable().optional(),
191
- icon: z.string().nullable().optional(),
192
- immutable: z.boolean().optional(),
437
+ description: z.string().optional(),
438
+ defaultView: viewKind,
439
+ sortOrder: z.number(),
440
+ immutable: z.boolean(),
441
+ icon: z.string().optional(),
442
+ viewSettings: z.record(z.string(), z.unknown()).optional(),
443
+ savedViews: z.array(z.record(z.string(), z.unknown())).optional(),
444
+ entryCount: z.number().optional(),
445
+ createdAt: z.number(),
446
+ updatedAt: z.number(),
193
447
  })
194
- .describe("A CRM object (table).");
448
+ .passthrough()
449
+ .describe("A CRM object (table) document.");
195
450
 
196
- const crmFieldShape = z
451
+ const crmFieldDoc = z
197
452
  .object({
198
- id: z.string(),
453
+ _id: z.string(),
454
+ _creationTime: z.number(),
455
+ organizationId: z.string(),
456
+ objectId: z.string(),
199
457
  name: z.string(),
200
- type: z.enum(FIELD_TYPES),
201
- required: z.boolean().optional(),
202
- enum_values: z.array(z.string()).nullable().optional(),
203
- enum_colors: z.array(z.string()).nullable().optional(),
458
+ description: z.string().optional(),
459
+ type: fieldType,
460
+ required: z.boolean(),
461
+ defaultValue: z.string().optional(),
462
+ relatedObjectId: z.string().optional(),
463
+ relationshipType: relationshipType.optional(),
464
+ enumValues: z.array(z.string()).optional(),
465
+ enumColors: z.array(z.string()).optional(),
466
+ enumMultiple: z.boolean().optional(),
467
+ sortOrder: z.number(),
204
468
  indexed: z.boolean().optional(),
469
+ createdAt: z.number(),
470
+ updatedAt: z.number(),
205
471
  })
206
- .describe("A CRM field (column).");
472
+ .passthrough()
473
+ .describe("A CRM field (column) document.");
207
474
 
208
475
  const crmEntryShape = z
209
476
  .object({
210
477
  id: z.string(),
211
- fields: dataMap,
212
- createdAt: z.number().nullable().optional(),
213
- updatedAt: z.number().nullable().optional(),
478
+ objectId: z.string(),
479
+ fields: fieldsMap,
480
+ createdAt: z.number(),
481
+ updatedAt: z.number(),
482
+ updatedBy: z.string(),
483
+ sortOrder: z.number(),
214
484
  })
215
485
  .describe("A materialized CRM entry (row).");
216
486
 
487
+ const entryWriteResponse = z.object({ entryId: z.string() });
488
+
489
+ const crmBatchResults = z.object({
490
+ results: z.array(
491
+ z
492
+ .object({
493
+ entryId: z.string(),
494
+ deleted: z.boolean().optional(),
495
+ })
496
+ .passthrough(),
497
+ ),
498
+ count: z.number(),
499
+ });
500
+
217
501
  const memberShape = z.object({
218
502
  userId: z.string(),
219
- name: z.string().nullable().optional(),
220
- email: z.string().nullable().optional(),
221
- image: z.string().nullable().optional(),
222
- role: z.string().optional(),
223
- joinedAt: z.number().optional(),
503
+ name: z.string().nullable(),
504
+ email: z.string().nullable(),
505
+ image: z.string().nullable(),
506
+ role: z.string(),
507
+ joinedAt: z.number(),
508
+ });
509
+
510
+ // -- routines ------------------------------------------------------------------
511
+
512
+ const cronJobShape = z
513
+ .object({
514
+ id: z.string(),
515
+ name: z.string(),
516
+ description: z.string().optional(),
517
+ enabled: z.boolean(),
518
+ deleteAfterRun: z.boolean(),
519
+ createdAtMs: z.number(),
520
+ updatedAtMs: z.number(),
521
+ schedule: scheduleSpec.optional(),
522
+ sessionTarget: z.string(),
523
+ wakeMode: z.string(),
524
+ payload: z.union([
525
+ z.object({ kind: z.literal("agentTurn"), message: z.string() }),
526
+ z.object({ kind: z.literal("systemEvent"), text: z.string() }),
527
+ ]),
528
+ state: z.object({
529
+ nextRunAtMs: z.number().optional(),
530
+ runningAtMs: z.number().optional(),
531
+ lastRunAtMs: z.number().optional(),
532
+ lastStatus: z.enum(["ok", "error", "skipped"]).optional(),
533
+ lastError: z.string().optional(),
534
+ lastDurationMs: z.number().optional(),
535
+ }),
536
+ })
537
+ .passthrough()
538
+ .describe("A routine (cron trigger).");
539
+
540
+ const cronRunEntry = z
541
+ .object({
542
+ ts: z.number(),
543
+ jobId: z.string(),
544
+ action: z.string(),
545
+ status: z.enum(["ok", "error", "skipped", "running"]).optional(),
546
+ error: z.string().optional(),
547
+ summary: z.string().optional(),
548
+ sessionId: z.string().optional(),
549
+ runAtMs: z.number().optional(),
550
+ durationMs: z.number().optional(),
551
+ nextRunAtMs: z.number().optional(),
552
+ })
553
+ .passthrough();
554
+
555
+ const cronWriteResponse = z.object({
556
+ jobId: z.string(),
557
+ nextFireAt: z.number().nullable().optional(),
558
+ });
559
+
560
+ // -- files -----------------------------------------------------------------
561
+
562
+ const fileTreeRow = z
563
+ .object({
564
+ _id: z.string(),
565
+ _creationTime: z.number(),
566
+ path: z.string(),
567
+ parentPath: z.string(),
568
+ isDir: z.boolean(),
569
+ size: z.number().optional(),
570
+ mtime: z.number().optional(),
571
+ contentHash: z.string().optional(),
572
+ storageId: z.string().optional(),
573
+ lastModifiedBy: z.string().optional(),
574
+ virtual: z
575
+ .boolean()
576
+ .optional()
577
+ .describe("True for synthesized magic files (IDENTITY.md etc.)."),
578
+ })
579
+ .passthrough()
580
+ .describe("A workspace file-tree row.");
581
+
582
+ // -- email -------------------------------------------------------------------
583
+
584
+ const campaignStatusEnum = z
585
+ .enum([
586
+ "draft",
587
+ "pending_approval",
588
+ "scheduled",
589
+ "sending",
590
+ "paused",
591
+ "completed",
592
+ "cancelled",
593
+ "failed",
594
+ ])
595
+ .describe("Campaign lifecycle status.");
596
+
597
+ const deliveryVerificationStatus = z
598
+ .enum(["pending", "verified", "failed", "disabled"])
599
+ .describe("Provider-side (DNS/mailbox) verification status.");
600
+
601
+ const denchVerificationStatus = z
602
+ .enum(["pending", "verified", "expired", "disabled"])
603
+ .describe("Workspace-side sender verification status.");
604
+
605
+ const dnsRecordShape = z.object({
606
+ type: z.string().describe("Record type, e.g. CNAME or TXT."),
607
+ name: z.string(),
608
+ value: z.string(),
609
+ purpose: z.string().describe("Why the record is needed (DKIM/SPF/DMARC)."),
610
+ });
611
+
612
+ const emailIdentityRow = z.object({
613
+ identityId: z.string(),
614
+ type: emailIdentityType,
615
+ domain: z.string().optional(),
616
+ fromEmail: z.string(),
617
+ fromName: z.string().optional(),
618
+ deliveryVerificationStatus,
619
+ denchVerificationStatus,
620
+ disabled: z.boolean(),
621
+ disabledAt: z.number().optional(),
622
+ createdAt: z.number(),
623
+ });
624
+
625
+ const identitySummaryShape = z.object({
626
+ identityId: z.string(),
627
+ fromEmail: z.string(),
628
+ domain: z.string().optional(),
629
+ disabled: z.boolean(),
630
+ });
631
+
632
+ const emailMessageShape = z
633
+ .object({
634
+ messageId: z.string(),
635
+ status: rawMessageStatus,
636
+ fromEmail: z.string(),
637
+ fromName: z.string().optional(),
638
+ to: z.array(emailAddress),
639
+ cc: z.array(emailAddress).optional(),
640
+ bcc: z.array(emailAddress).optional(),
641
+ subject: z.string(),
642
+ inReplyTo: z.string().optional(),
643
+ references: z.array(z.string()).optional(),
644
+ providerMessageId: z.string().optional(),
645
+ rfcMessageId: z.string().optional(),
646
+ recipientCount: z.number(),
647
+ openCount: z.number(),
648
+ clickCount: z.number(),
649
+ sentAt: z.number().optional(),
650
+ deliveredAt: z.number().optional(),
651
+ firstOpenedAt: z.number().optional(),
652
+ lastOpenedAt: z.number().optional(),
653
+ firstClickedAt: z.number().optional(),
654
+ bouncedAt: z.number().optional(),
655
+ complainedAt: z.number().optional(),
656
+ lastError: z.string().optional(),
657
+ createdAt: z.number(),
658
+ })
659
+ .describe("A raw email message with delivery + engagement counters.");
660
+
661
+ const campaignSummaryShape = z.object({
662
+ campaignId: z.string(),
663
+ status: campaignStatusEnum,
664
+ totalRecipients: z.number(),
665
+ queuedCount: z.number(),
666
+ sendingCount: z.number(),
667
+ sentCount: z.number(),
668
+ deliveredCount: z.number(),
669
+ openedCount: z.number(),
670
+ clickedCount: z.number(),
671
+ bouncedCount: z.number(),
672
+ complainedCount: z.number(),
673
+ failedCount: z.number(),
674
+ suppressedCount: z.number(),
675
+ unsubscribedCount: z.number(),
676
+ });
677
+
678
+ const campaignDoc = z
679
+ .object({
680
+ _id: z.string(),
681
+ _creationTime: z.number(),
682
+ organizationId: z.string(),
683
+ name: z.string(),
684
+ status: campaignStatusEnum,
685
+ sendingIdentityId: z.string(),
686
+ templateId: z.string(),
687
+ subjectSnapshot: z.string(),
688
+ htmlSnapshot: z.string(),
689
+ textSnapshot: z.string().optional(),
690
+ fromEmailSnapshot: z.string(),
691
+ fromNameSnapshot: z.string().optional(),
692
+ replyToEmailSnapshot: z.string().optional(),
693
+ scheduledAt: z.number().optional(),
694
+ submittedAt: z.number().optional(),
695
+ startedAt: z.number().optional(),
696
+ completedAt: z.number().optional(),
697
+ cancelledAt: z.number().optional(),
698
+ createdBy: z.string(),
699
+ totalRecipients: z.number(),
700
+ queuedCount: z.number(),
701
+ sendingCount: z.number(),
702
+ sentCount: z.number(),
703
+ deliveredCount: z.number(),
704
+ openedCount: z.number(),
705
+ clickedCount: z.number(),
706
+ bouncedCount: z.number(),
707
+ complainedCount: z.number(),
708
+ failedCount: z.number(),
709
+ suppressedCount: z.number(),
710
+ unsubscribedCount: z.number(),
711
+ maxRecipients: z.number(),
712
+ batchSize: z.number(),
713
+ lastError: z.string().optional(),
714
+ createdAt: z.number(),
715
+ updatedAt: z.number(),
716
+ })
717
+ .passthrough()
718
+ .describe("The full campaign document with counters.");
719
+
720
+ // -- gateway (Exa, images, Composio, enrichment) ----------------------------
721
+
722
+ const exaResultItem = z
723
+ .object({
724
+ url: z.string(),
725
+ title: z.string().optional(),
726
+ publishedDate: z.string().optional(),
727
+ author: z.string().optional(),
728
+ score: z.number().optional(),
729
+ text: z.string().optional(),
730
+ summary: z.string().optional(),
731
+ highlights: z.array(z.string()).optional(),
732
+ image: z.string().optional(),
733
+ favicon: z.string().optional(),
734
+ id: z.string().optional(),
735
+ })
736
+ .passthrough()
737
+ .describe("An Exa search/contents result (provider passthrough).");
738
+
739
+ const exaSearchResponse = z
740
+ .object({
741
+ results: z.array(exaResultItem),
742
+ resolvedSearchType: z.string().optional(),
743
+ autopromptString: z.string().optional(),
744
+ requestId: z.string().optional(),
745
+ costDollars: z.record(z.string(), z.unknown()).optional(),
746
+ })
747
+ .passthrough()
748
+ .describe("Exa response passed through unchanged.");
749
+
750
+ const exaAnswerResponse = z
751
+ .object({
752
+ answer: z.string(),
753
+ citations: z.array(exaResultItem).optional(),
754
+ costDollars: z.record(z.string(), z.unknown()).optional(),
755
+ })
756
+ .passthrough()
757
+ .describe(
758
+ "Exa /answer response (provider passthrough). With stream: true the response is text/event-stream instead.",
759
+ );
760
+
761
+ const imageEnvelope = z
762
+ .object({
763
+ ok: z.boolean(),
764
+ model: z.string(),
765
+ endpoint: z.enum(["generations", "edits"]),
766
+ prompt: z.string(),
767
+ revisedPrompt: z.string().optional(),
768
+ quality: z.string().optional(),
769
+ requestedSize: z.string().optional(),
770
+ format: z.string().optional(),
771
+ mimeType: z.string().optional(),
772
+ estimatedCostUsd: z.number().optional(),
773
+ b64_json: z.string().describe("Base64-encoded image bytes."),
774
+ storageId: z.string().optional(),
775
+ path: z.string().describe("Workspace path where the image was saved."),
776
+ signedUrl: z.string().nullable(),
777
+ contentHash: z.string().optional(),
778
+ sizeBytes: z.number().optional(),
779
+ usage: z
780
+ .object({
781
+ inputTokens: z.number().optional(),
782
+ outputTokens: z.number().optional(),
783
+ totalTokens: z.number().optional(),
784
+ })
785
+ .passthrough()
786
+ .optional(),
787
+ })
788
+ .passthrough()
789
+ .describe("Gateway image envelope wrapping the OpenAI image result.");
790
+
791
+ const composioConnection = z
792
+ .object({
793
+ id: z.string().nullable(),
794
+ connectionId: z.string().nullable(),
795
+ toolkit: z
796
+ .object({
797
+ slug: z.string().nullable(),
798
+ name: z.string().nullable(),
799
+ })
800
+ .passthrough(),
801
+ status: z.string().nullable().describe('e.g. "ACTIVE".'),
802
+ createdAt: z.string().nullable(),
803
+ updatedAt: z.string().nullable(),
804
+ account: z
805
+ .record(z.string(), z.unknown())
806
+ .describe("Normalized account identity (stableId, label, email, ...)."),
807
+ reconnect: z.record(z.string(), z.unknown()).optional(),
808
+ })
809
+ .passthrough()
810
+ .describe("A normalized Composio connection.");
811
+
812
+ const composioConnectionsResponse = z
813
+ .object({
814
+ items: z.array(composioConnection),
815
+ connections: z
816
+ .array(composioConnection)
817
+ .describe("Alias of items for older clients."),
818
+ raw: z.unknown().describe("Raw Composio payload."),
819
+ })
820
+ .passthrough();
821
+
822
+ const toolSearchResponse = z
823
+ .object({
824
+ success: z.boolean().optional(),
825
+ error: z.string().nullable().optional(),
826
+ results: z
827
+ .array(
828
+ z
829
+ .object({
830
+ use_case: z.string(),
831
+ primary_tool_slugs: z.array(z.string()).optional(),
832
+ related_tool_slugs: z.array(z.string()).optional(),
833
+ toolkits: z.array(z.string()).optional(),
834
+ execution_guidance: z.string().optional(),
835
+ recommended_plan_steps: z.array(z.string()).optional(),
836
+ known_pitfalls: z.array(z.string()).optional(),
837
+ })
838
+ .passthrough(),
839
+ )
840
+ .optional(),
841
+ toolkit_connection_statuses: z
842
+ .array(
843
+ z
844
+ .object({
845
+ toolkit: z.string(),
846
+ has_active_connection: z.boolean(),
847
+ status_message: z.string().nullable().optional(),
848
+ accounts: z.array(z.record(z.string(), z.unknown())).optional(),
849
+ })
850
+ .passthrough(),
851
+ )
852
+ .optional(),
853
+ tool_schemas: z
854
+ .record(z.string(), z.record(z.string(), z.unknown()))
855
+ .optional()
856
+ .describe(
857
+ "Tool slug -> schema with gateway-added execution_ref for tool.run.",
858
+ ),
859
+ session: z
860
+ .object({ id: z.string() })
861
+ .passthrough()
862
+ .describe("Tool-router session; reuse session.id for follow-up calls."),
863
+ execution_ref_version: z.number().optional(),
864
+ })
865
+ .passthrough()
866
+ .describe("Composio tool-router search response with gateway enrichments.");
867
+
868
+ const toolRunResponse = z
869
+ .object({
870
+ data: z
871
+ .unknown()
872
+ .optional()
873
+ .describe("Tool output (provider passthrough)."),
874
+ error: z.unknown().nullable().optional(),
875
+ log_id: z.string().optional(),
876
+ execution_mode: z.string().optional(),
877
+ tool_slug: z.string().optional(),
878
+ tool_router_session_id: z.string().optional(),
879
+ toolkit: z.string().optional(),
880
+ account: z.string().optional(),
881
+ })
882
+ .passthrough()
883
+ .describe("Composio execution result with gateway metadata.");
884
+
885
+ const enrichmentMetadata = z
886
+ .object({
887
+ total: z.number().optional(),
888
+ offset: z.number().optional(),
889
+ })
890
+ .passthrough()
891
+ .optional();
892
+
893
+ const enrichedPeopleResponse = z
894
+ .object({
895
+ source: z.enum(["fullenrich", "cache"]),
896
+ people: z
897
+ .array(
898
+ z
899
+ .object({
900
+ fullName: z.string().optional(),
901
+ firstName: z.string().optional(),
902
+ lastName: z.string().optional(),
903
+ headline: z.string().optional(),
904
+ seniority: z.string().optional(),
905
+ jobFunctions: z.array(z.string()).optional(),
906
+ currentCompanyName: z.string().optional(),
907
+ currentCompanyWebsite: z.string().optional(),
908
+ linkedinID: z.string().optional(),
909
+ emails: z.array(z.record(z.string(), z.unknown())).optional(),
910
+ phones: z.array(z.record(z.string(), z.unknown())).optional(),
911
+ })
912
+ .passthrough(),
913
+ )
914
+ .describe("Provider results normalized to the CRM upsert shape."),
915
+ resolvedPersonIds: z.array(z.string()),
916
+ creditsCharged: z.number(),
917
+ metadata: enrichmentMetadata,
918
+ })
919
+ .passthrough();
920
+
921
+ const enrichedCompaniesResponse = z
922
+ .object({
923
+ source: z.enum(["fullenrich", "cache"]),
924
+ companies: z
925
+ .array(
926
+ z
927
+ .object({
928
+ name: z.string().optional(),
929
+ website: z.string().optional(),
930
+ description: z.string().optional(),
931
+ founded: z.number().optional(),
932
+ headcount: z.number().optional(),
933
+ industry: z.string().optional(),
934
+ linkedinUrl: z.string().optional(),
935
+ linkedinID: z.string().optional(),
936
+ })
937
+ .passthrough(),
938
+ )
939
+ .describe("Provider results normalized to the CRM upsert shape."),
940
+ resolvedCompanyIds: z.array(z.string()),
941
+ creditsCharged: z.number(),
942
+ metadata: enrichmentMetadata,
943
+ })
944
+ .passthrough();
945
+
946
+ // -- agent config -------------------------------------------------------------
947
+
948
+ const timedContent = z.object({
949
+ content: z.string(),
950
+ updatedAt: z.number(),
951
+ });
952
+
953
+ const agentConfigBlock = z.object({
954
+ identity: timedContent.nullable(),
955
+ organisation: timedContent.nullable(),
956
+ memoryAggregate: timedContent.nullable(),
957
+ toolsNotes: timedContent.nullable(),
958
+ bootstrap: z.object({
959
+ completed: z.boolean(),
960
+ completedAt: z.number().optional(),
961
+ template: z.string().optional(),
962
+ }),
224
963
  });
225
964
 
965
+ const agentConfigPayload = z
966
+ .object({
967
+ agentConfig: agentConfigBlock,
968
+ userProfile: timedContent.nullable(),
969
+ userTimezone: z
970
+ .object({
971
+ value: z.string(),
972
+ source: z.enum(["auto", "manual", "agent"]),
973
+ updatedAt: z.number(),
974
+ })
975
+ .nullable(),
976
+ organizationId: z.string(),
977
+ })
978
+ .passthrough()
979
+ .describe(
980
+ "Agent harness config payload shared by every /agent-config GET endpoint.",
981
+ );
982
+
226
983
  // ---------------------------------------------------------------------------
227
984
  // Gateway request shapes (re-declared without refine/transform)
228
985
  // ---------------------------------------------------------------------------
@@ -369,7 +1126,18 @@ const companySearch = z.object({
369
1126
  // Request schemas keyed by operation id
370
1127
  // ---------------------------------------------------------------------------
371
1128
 
1129
+ /**
1130
+ * Strict no-input request schema. Used for operations whose backend takes
1131
+ * no caller-supplied fields (auth args are injected by the dispatcher).
1132
+ * Strict parsing drops stray query params / body keys so Convex argument
1133
+ * validators never see unexpected args.
1134
+ */
1135
+ const noInput = z.object({});
1136
+
372
1137
  export const requestSchemas: Record<string, ZodTypeAny> = {
1138
+ // Meta
1139
+ "commands.list": noInput,
1140
+
373
1141
  // Auth
374
1142
  "auth.signin.create": z.object({
375
1143
  codeHash: z.string(),
@@ -414,6 +1182,10 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
414
1182
  }),
415
1183
 
416
1184
  // Workspace
1185
+ "workspace.context": noInput,
1186
+ "workspace.status": noInput,
1187
+ "workspace.agents": noInput,
1188
+ "workspace.approvals.list": noInput,
417
1189
  "workspace.artifacts.list": z.object({
418
1190
  limit: z.coerce.number().int().min(1).max(100).optional(),
419
1191
  }),
@@ -455,6 +1227,7 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
455
1227
  }),
456
1228
 
457
1229
  // Billing
1230
+ "billing.status": noInput,
458
1231
  "billing.topup": z.object({
459
1232
  requestId: z
460
1233
  .string()
@@ -489,7 +1262,13 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
489
1262
  limit: z.coerce.number().int().min(1).max(200).optional(),
490
1263
  }),
491
1264
  "chat.tree": z.object({
1265
+ titleQuery: z.string().optional().describe("Filter threads by title."),
492
1266
  limit: z.coerce.number().int().min(1).max(100).optional(),
1267
+ includeArchived: z.coerce.boolean().optional(),
1268
+ includeAutomated: z.coerce
1269
+ .boolean()
1270
+ .optional()
1271
+ .describe("Include routine-spawned threads. Defaults false."),
493
1272
  }),
494
1273
  "chat.rename": z.object({
495
1274
  items: z
@@ -521,6 +1300,7 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
521
1300
  "chat.follow": z.object({ threadId: z.string() }),
522
1301
 
523
1302
  // CRM objects
1303
+ "crm.objects.list": noInput,
524
1304
  "crm.objects.get": z.object({ name: z.string() }),
525
1305
  "crm.objects.create": z.object({
526
1306
  name: z.string().describe("Object name (lowercased, singular)."),
@@ -770,6 +1550,8 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
770
1550
  "crm.transaction.inspect": z.object({ txnId: z.string() }),
771
1551
 
772
1552
  // CRM docs / actions / reports / enrich / members
1553
+ "crm.docs.list": noInput,
1554
+ "crm.members.list": noInput,
773
1555
  "crm.docs.create": z.object({
774
1556
  title: z.string(),
775
1557
  filePath: z.string(),
@@ -815,29 +1597,169 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
815
1597
  "crm.people.search": peopleSearch,
816
1598
  "crm.companies.search": companySearch,
817
1599
 
818
- // Routines
819
- "cron.list": z.object({ enabledOnly: z.coerce.boolean().optional() }),
820
- "cron.history": z.object({
821
- limit: z.coerce.number().int().min(1).max(200).optional(),
1600
+ // Email (sender identities, raw sends, templates, campaigns)
1601
+ "email.identity.verify": z.object({
1602
+ type: emailIdentityType,
1603
+ identity: z
1604
+ .string()
1605
+ .describe("Domain (example.com) or mailbox (founder@example.com)."),
1606
+ configurationSetName: z
1607
+ .string()
1608
+ .optional()
1609
+ .describe("Optional provider configuration set override."),
822
1610
  }),
823
- "cron.get": z.object({ jobId: z.string() }),
824
- "cron.create": z.object({
825
- name: z.string(),
826
- prompt: z.string().describe("Agent goal/message for each run."),
827
- schedule: scheduleSpec,
828
- description: z.string().optional(),
829
- overlapPolicy: overlapPolicy.optional(),
830
- enabled: z.boolean().optional(),
831
- deleteAfterRun: z.boolean().optional(),
832
- target: cronTarget.optional(),
1611
+ "email.identity.create": z.object({
1612
+ type: emailIdentityType,
1613
+ domain: z
1614
+ .string()
1615
+ .optional()
1616
+ .describe("Lowercase domain; required when type is `domain`."),
1617
+ fromEmail: z.string().describe("Sender mailbox, e.g. founder@example.com."),
1618
+ fromName: z
1619
+ .string()
1620
+ .optional()
1621
+ .describe("Default display name for the sender."),
1622
+ replyToEmail: z.string().optional(),
1623
+ configurationSetName: z.string().optional(),
833
1624
  }),
834
- "cron.update": z.object({
835
- jobId: z.string(),
836
- name: z.string().optional(),
837
- prompt: z.string().optional(),
838
- schedule: scheduleSpec.optional(),
839
- description: z.string().optional(),
840
- overlapPolicy: overlapPolicy.optional(),
1625
+ "email.identity.refresh": z.object({
1626
+ identityId: z.string().describe("Sending identity id."),
1627
+ }),
1628
+ "email.identity.beginVerification": z.object({
1629
+ identityId: z
1630
+ .string()
1631
+ .describe("Sending identity id from `POST /email/sending-identities`."),
1632
+ }),
1633
+ "email.identity.status": z.object({
1634
+ identity: z.string().describe("Email address or domain to check."),
1635
+ }),
1636
+ "email.identity.list": z.object({
1637
+ domain: z.string().optional().describe("Filter identities by domain."),
1638
+ }),
1639
+ "email.identity.dns": z.object({
1640
+ identityId: z.string().describe("Sending identity id."),
1641
+ }),
1642
+ "email.identity.disable": z.object({
1643
+ identity: z
1644
+ .string()
1645
+ .describe(
1646
+ "Identity id, sender email, or domain (disables every sender on the domain).",
1647
+ ),
1648
+ }),
1649
+ "email.identity.restore": z.object({
1650
+ identity: z.string().describe("Identity id, sender email, or domain."),
1651
+ }),
1652
+ "email.send": z.object({
1653
+ fromEmail: z.string().describe("Verified sender mailbox."),
1654
+ fromName: z.string().optional().describe("Display name override."),
1655
+ to: z
1656
+ .array(emailAddress)
1657
+ .min(1)
1658
+ .describe("Primary recipients. to+cc+bcc is capped at 50."),
1659
+ cc: z.array(emailAddress).optional(),
1660
+ bcc: z.array(emailAddress).optional(),
1661
+ replyToEmail: z.string().optional(),
1662
+ subject: z.string(),
1663
+ htmlBody: z
1664
+ .string()
1665
+ .optional()
1666
+ .describe("HTML body. Provide htmlBody and/or textBody."),
1667
+ textBody: z.string().optional(),
1668
+ replyToMessageId: z
1669
+ .string()
1670
+ .optional()
1671
+ .describe(
1672
+ "Dench messageId or RFC 5322 Message-ID to thread this send as a reply.",
1673
+ ),
1674
+ configurationSetName: z.string().optional(),
1675
+ }),
1676
+ "email.message.get": z.object({
1677
+ messageId: z.string().describe("Raw email message id."),
1678
+ }),
1679
+ "email.message.list": z.object({
1680
+ limit: z.coerce.number().int().min(1).max(100).optional(),
1681
+ status: rawMessageStatus.optional(),
1682
+ }),
1683
+ "email.template.create": z.object({
1684
+ name: z.string(),
1685
+ subject: z.string().describe("Supports {{variable}} placeholders."),
1686
+ htmlBody: z.string().describe("HTML body with {{variable}} placeholders."),
1687
+ textBody: z.string().optional(),
1688
+ status: templateStatus.optional(),
1689
+ }),
1690
+ "email.template.preview": z.object({
1691
+ templateId: z.string(),
1692
+ data: z
1693
+ .record(z.string(), z.unknown())
1694
+ .optional()
1695
+ .describe("Personalization data for {{variable}} placeholders."),
1696
+ }),
1697
+ "email.campaign.create": z.object({
1698
+ name: z.string(),
1699
+ identityId: z
1700
+ .string()
1701
+ .describe("Sending identity id OR a verified from-email."),
1702
+ templateId: z.string(),
1703
+ scheduledAt: z
1704
+ .number()
1705
+ .optional()
1706
+ .describe("Epoch ms to start sending; omit to send on submit."),
1707
+ maxRecipients: z.number().optional(),
1708
+ batchSize: z.number().optional(),
1709
+ metadata: z.record(z.string(), z.unknown()).optional(),
1710
+ }),
1711
+ "email.campaign.get": z.object({ campaignId: z.string() }),
1712
+ "email.campaign.recipients.add": z.object({
1713
+ campaignId: z.string(),
1714
+ recipients: z
1715
+ .array(campaignRecipientInput)
1716
+ .max(500)
1717
+ .describe("Up to 500 recipients per call."),
1718
+ }),
1719
+ "email.campaign.preview": z.object({
1720
+ campaignId: z.string(),
1721
+ sample: z
1722
+ .number()
1723
+ .int()
1724
+ .optional()
1725
+ .describe("Number of rendered previews to return (default 5)."),
1726
+ }),
1727
+ "email.campaign.submit": z.object({
1728
+ campaignId: z.string(),
1729
+ approvalId: z
1730
+ .string()
1731
+ .optional()
1732
+ .describe(
1733
+ "Approval request id when workspace policy requires human sign-off.",
1734
+ ),
1735
+ }),
1736
+ "email.campaign.pause": z.object({ campaignId: z.string() }),
1737
+ "email.campaign.resume": z.object({ campaignId: z.string() }),
1738
+ "email.campaign.cancel": z.object({ campaignId: z.string() }),
1739
+
1740
+ // Routines
1741
+ "cron.list": z.object({ enabledOnly: z.coerce.boolean().optional() }),
1742
+ "cron.history": z.object({
1743
+ limit: z.coerce.number().int().min(1).max(200).optional(),
1744
+ }),
1745
+ "cron.get": z.object({ jobId: z.string() }),
1746
+ "cron.create": z.object({
1747
+ name: z.string(),
1748
+ prompt: z.string().describe("Agent goal/message for each run."),
1749
+ schedule: scheduleSpec,
1750
+ description: z.string().optional(),
1751
+ overlapPolicy: overlapPolicy.optional(),
1752
+ enabled: z.boolean().optional(),
1753
+ deleteAfterRun: z.boolean().optional(),
1754
+ target: cronTarget.optional(),
1755
+ }),
1756
+ "cron.update": z.object({
1757
+ jobId: z.string(),
1758
+ name: z.string().optional(),
1759
+ prompt: z.string().optional(),
1760
+ schedule: scheduleSpec.optional(),
1761
+ description: z.string().optional(),
1762
+ overlapPolicy: overlapPolicy.optional(),
841
1763
  enabled: z.boolean().optional(),
842
1764
  deleteAfterRun: z.boolean().optional(),
843
1765
  target: cronTarget.optional(),
@@ -880,6 +1802,13 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
880
1802
  }),
881
1803
 
882
1804
  // Agent config
1805
+ "agentConfig.identity.show": noInput,
1806
+ "agentConfig.organisation.show": noInput,
1807
+ "agentConfig.user.show": noInput,
1808
+ "agentConfig.tools.show": noInput,
1809
+ "agentConfig.mem.show": noInput,
1810
+ "agentConfig.bootstrap.show": noInput,
1811
+ "agentConfig.daily.today": noInput,
883
1812
  "agentConfig.identity.edit": z.object({ content: z.string() }),
884
1813
  "agentConfig.organisation.edit": z.object({ content: z.string() }),
885
1814
  "agentConfig.user.edit": z.object({ content: z.string() }),
@@ -899,11 +1828,14 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
899
1828
  threadId: z.string(),
900
1829
  modelId: z.string().nullable(),
901
1830
  }),
902
- "agentConfig.daily.show": z.object({
903
- date: z.string().describe("YYYY-MM-DD."),
904
- }),
1831
+ // `{date}` in the path is decorative: the backend returns the full agent
1832
+ // config and the caller derives the daily file path for that date. Strict
1833
+ // parsing must drop the segment so getAgentConfig never sees it.
1834
+ "agentConfig.daily.show": z.object({}),
905
1835
 
906
1836
  // Gateway: search + images + tools
1837
+ "apps.list": noInput,
1838
+ "tool.status": noInput,
907
1839
  "search.web": exaSearch,
908
1840
  "search.contents": exaContents,
909
1841
  "search.answer": exaAnswer,
@@ -920,32 +1852,244 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
920
1852
  // ---------------------------------------------------------------------------
921
1853
 
922
1854
  export const responseSchemas: Record<string, ZodTypeAny> = {
923
- "crm.objects.list": z.array(crmObjectShape),
924
- "crm.objects.get": crmObjectShape.nullable(),
1855
+ // Meta
1856
+ "commands.list": z.object({
1857
+ operations: z.array(
1858
+ z.object({
1859
+ id: z.string(),
1860
+ group: z.string(),
1861
+ summary: z.string(),
1862
+ cli: z.string(),
1863
+ aliases: z.array(z.string()),
1864
+ method: z.string(),
1865
+ path: z.string(),
1866
+ backend: z.enum(["convex", "gateway", "custom", "local"]),
1867
+ deprecated: z.boolean(),
1868
+ }),
1869
+ ),
1870
+ }),
1871
+
1872
+ // Auth
1873
+ "auth.signin.create": z.object({
1874
+ status: z.literal("pending"),
1875
+ expiresAt: z.number().describe("Epoch ms when the sign-in code expires."),
1876
+ }),
1877
+ "auth.signin.poll": z.object({
1878
+ status: z.enum(["pending", "approved", "rejected", "expired"]),
1879
+ organization: organizationRef.optional().describe("Present once approved."),
1880
+ agent: agentRef.optional(),
1881
+ sessionExpiresAt: z.number().optional(),
1882
+ }),
1883
+ "auth.otp.start": okResponse,
1884
+ "auth.otp.verify": z.object({
1885
+ ok: z.boolean(),
1886
+ result: z.union([
1887
+ z.object({
1888
+ kind: z.literal("completed"),
1889
+ organization: organizationRef.optional(),
1890
+ sessionExpiresAt: z.number().optional(),
1891
+ }),
1892
+ z.object({
1893
+ kind: z.literal("requiresOrgChoice"),
1894
+ authToken: z
1895
+ .string()
1896
+ .describe("Pass to /auth/otp/finalize with the chosen org."),
1897
+ organizations: z.array(organizationRef),
1898
+ expiresAt: z.number(),
1899
+ }),
1900
+ ]),
1901
+ }),
1902
+ "auth.otp.finalize": z.object({
1903
+ ok: z.boolean(),
1904
+ result: z.object({
1905
+ organization: organizationRef.optional(),
1906
+ sessionExpiresAt: z.number().optional(),
1907
+ }),
1908
+ }),
1909
+
1910
+ // Workspace orientation
1911
+ "workspace.context": workspaceStatusPayload,
1912
+ "workspace.status": workspaceStatusPayload,
1913
+ "workspace.agents": workspaceStatusPayload,
1914
+ "workspace.approvals.list": workspaceStatusPayload,
1915
+ "workspace.artifacts.list": z.array(artifactRow),
1916
+ "workspace.suggestedWork.list": z.array(artifactRow),
1917
+
1918
+ // Memory + approvals
1919
+ "memory.search": z.array(memoryDoc),
1920
+ "memory.save": z.object({
1921
+ ok: z.boolean(),
1922
+ memoryId: z.string(),
1923
+ status: z.enum(["active", "needs_review", "archived"]),
1924
+ }),
1925
+ "approval.request": z.object({ ok: z.boolean(), approvalId: z.string() }),
1926
+ "approval.decide": z.union([
1927
+ z.object({
1928
+ ok: z.literal(true),
1929
+ status: approvalDecision,
1930
+ }),
1931
+ z.object({
1932
+ ok: z.literal(false),
1933
+ code: z.string().describe("e.g. approval_not_pending."),
1934
+ error: z.string(),
1935
+ }),
1936
+ ]),
1937
+
1938
+ // Billing
1939
+ "billing.status": billingStatusResponse,
1940
+ "billing.topup": z.union([
1941
+ z
1942
+ .object({ charged: z.literal(true), amountCents: z.number() })
1943
+ .describe("Saved card charged directly."),
1944
+ z
1945
+ .object({ url: z.string().nullable() })
1946
+ .describe("Stripe Checkout link to complete the top-up."),
1947
+ ]),
1948
+ "billing.upgrade": z.union([
1949
+ z
1950
+ .object({
1951
+ updated: z.literal(true),
1952
+ tier: z.string(),
1953
+ billingCycle: z.string().optional(),
1954
+ stripeSubscriptionId: z.string(),
1955
+ })
1956
+ .describe("Existing subscription updated in place."),
1957
+ z
1958
+ .object({ url: z.string().nullable() })
1959
+ .describe("Stripe Checkout link to complete the upgrade."),
1960
+ ]),
1961
+
1962
+ // Chat
1963
+ "chat.list": z.array(chatThreadRow),
1964
+ "chat.search": z.array(
1965
+ z.object({
1966
+ threadId: z.string(),
1967
+ threadTitle: z.string(),
1968
+ messageId: z.string(),
1969
+ role: z.enum(["user", "assistant", "system"]),
1970
+ snippet: z.string(),
1971
+ createdAt: z.number(),
1972
+ runId: z.string().nullable(),
1973
+ }),
1974
+ ),
1975
+ "chat.read": z.object({
1976
+ thread: chatThreadRow,
1977
+ messages: z.array(
1978
+ z.object({
1979
+ id: z.string(),
1980
+ role: z.enum(["user", "assistant", "system"]),
1981
+ createdAt: z.number(),
1982
+ text: z.string(),
1983
+ runId: z.string().nullable(),
1984
+ }),
1985
+ ),
1986
+ }),
1987
+ "chat.tree": z
1988
+ .array(chatThreadRow)
1989
+ .describe("Flat thread rows; parentThreadId encodes the hierarchy."),
1990
+ "chat.rename": z.object({
1991
+ results: z.array(
1992
+ z.object({
1993
+ threadId: z.string(),
1994
+ ok: z.boolean(),
1995
+ error: z.string().optional(),
1996
+ }),
1997
+ ),
1998
+ succeeded: z.number(),
1999
+ failed: z.number(),
2000
+ }),
2001
+ "chat.delete": z.object({
2002
+ scheduled: z.number(),
2003
+ rejected: z.array(
2004
+ z.object({
2005
+ threadId: z.string(),
2006
+ reason: z.string().describe("e.g. automated_thread_protected."),
2007
+ message: z.string().optional(),
2008
+ }),
2009
+ ),
2010
+ total: z.number(),
2011
+ }),
2012
+ "chat.new": chatSpawnResponse,
2013
+ "chat.send": chatSpawnResponse,
2014
+ "chat.follow": z
2015
+ .string()
2016
+ .describe(
2017
+ "text/event-stream of UI message chunks (text-delta, tool calls, finish).",
2018
+ ),
2019
+
2020
+ // CRM objects
2021
+ "crm.objects.list": z.array(crmObjectDoc),
2022
+ "crm.objects.get": crmObjectDoc.nullable(),
925
2023
  "crm.objects.create": z.object({ id: z.string() }),
926
2024
  "crm.objects.update": okResponse,
927
2025
  "crm.objects.rename": okResponse,
928
2026
  "crm.objects.delete": okResponse,
929
- "crm.fields.list": z.array(crmFieldShape),
2027
+
2028
+ // CRM fields
2029
+ "crm.fields.list": z.array(crmFieldDoc),
930
2030
  "crm.fields.create": z.object({ id: z.string() }),
2031
+ "crm.fields.update": okResponse,
2032
+ "crm.fields.delete": okResponse,
2033
+ "crm.fields.reorder": okResponse,
2034
+ "crm.fields.enum.reorder": z.object({
2035
+ ok: z.boolean(),
2036
+ enumValues: z.array(z.string()),
2037
+ enumColors: z.array(z.string()).nullable(),
2038
+ }),
931
2039
  "crm.fields.enum.add": z.object({
932
2040
  ok: z.boolean(),
933
2041
  enumValues: z.array(z.string()),
934
2042
  enumColors: z.array(z.string()),
935
2043
  inserted: z.boolean(),
936
2044
  }),
2045
+ "crm.fields.enum.remove": z.object({
2046
+ ok: z.boolean(),
2047
+ enumValues: z.array(z.string()),
2048
+ enumColors: z.array(z.string()).nullable(),
2049
+ removed: z.boolean(),
2050
+ }),
2051
+ "crm.fields.enum.rename": z.object({
2052
+ ok: z.boolean(),
2053
+ enumValues: z.array(z.string()),
2054
+ enumColors: z.array(z.string()),
2055
+ entriesUpdated: z.number(),
2056
+ }),
937
2057
  "crm.fields.enum.color": z.object({
938
2058
  ok: z.boolean(),
939
2059
  enumColors: z.array(z.string()),
940
2060
  }),
2061
+
2062
+ // CRM entries + cells
941
2063
  "crm.entries.list": z.array(crmEntryShape),
942
2064
  "crm.entries.get": crmEntryShape.nullable(),
943
- "crm.entries.create": z.object({ entryId: z.string() }),
2065
+ "crm.entries.create": entryWriteResponse,
944
2066
  "crm.entries.createMany": z.object({
945
2067
  results: z.array(z.object({ entryId: z.string() })),
946
2068
  count: z.number(),
947
2069
  }),
2070
+ "crm.entries.update": entryWriteResponse,
2071
+ "crm.entries.updateMany": crmBatchResults,
2072
+ "crm.entries.delete": okResponse,
2073
+ "crm.entries.bulkDelete": z.object({ count: z.number() }),
948
2074
  "crm.cells.get": cellValue,
2075
+ "crm.cells.set": entryWriteResponse,
2076
+ "crm.cells.setMany": z.object({
2077
+ results: z.array(z.object({ entryId: z.string() })),
2078
+ count: z.number(),
2079
+ }),
2080
+ "crm.cells.append": entryWriteResponse,
2081
+
2082
+ // CRM query + search
2083
+ "crm.query": z
2084
+ .array(crmEntryShape)
2085
+ .describe(
2086
+ "Entry rows. With dsl.select the rows are flat {_id, ...selectedFields} objects instead.",
2087
+ ),
2088
+ "crm.sql": z
2089
+ .array(crmEntryShape)
2090
+ .describe(
2091
+ "Entry rows. With dsl.select the rows are flat {_id, ...selectedFields} objects instead.",
2092
+ ),
949
2093
  "crm.aggregate": z.array(
950
2094
  z.object({
951
2095
  key: z.string(),
@@ -953,27 +2097,401 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
953
2097
  sumNumber: z.number().optional(),
954
2098
  }),
955
2099
  ),
2100
+ "crm.search": z.array(
2101
+ z
2102
+ .object({
2103
+ _id: z.string(),
2104
+ _creationTime: z.number(),
2105
+ objectId: z.string(),
2106
+ data: fieldsMap,
2107
+ searchableText: z.string(),
2108
+ sortOrder: z.number(),
2109
+ createdAt: z.number(),
2110
+ updatedAt: z.number(),
2111
+ updatedBy: z.string(),
2112
+ })
2113
+ .passthrough(),
2114
+ ),
2115
+
2116
+ // CRM statuses, batch, transactions
2117
+ "crm.statuses.list": z.array(
2118
+ z
2119
+ .object({
2120
+ _id: z.string(),
2121
+ _creationTime: z.number(),
2122
+ objectId: z.string(),
2123
+ name: z.string(),
2124
+ color: z.string(),
2125
+ sortOrder: z.number(),
2126
+ isDefault: z.boolean(),
2127
+ })
2128
+ .passthrough(),
2129
+ ),
2130
+ "crm.statuses.set": okResponse,
2131
+ "crm.batch": crmBatchResults,
2132
+ "crm.transaction.begin": z.object({ txnId: z.string() }),
2133
+ "crm.transaction.add": okResponse,
2134
+ "crm.transaction.commit": crmBatchResults,
2135
+ "crm.transaction.abort": okResponse,
2136
+ "crm.transaction.inspect": z
2137
+ .object({
2138
+ _id: z.string(),
2139
+ _creationTime: z.number(),
2140
+ status: z.enum(["open", "committed", "aborted"]),
2141
+ ops: z.array(z.record(z.string(), z.unknown())).optional(),
2142
+ results: z.array(z.record(z.string(), z.unknown())).optional(),
2143
+ committedAt: z.number().optional(),
2144
+ createdAt: z.number(),
2145
+ updatedAt: z.number(),
2146
+ })
2147
+ .passthrough()
2148
+ .nullable(),
2149
+
2150
+ // CRM docs, actions, members, reports, enrichment
2151
+ "crm.docs.list": z.array(
2152
+ z
2153
+ .object({
2154
+ _id: z.string(),
2155
+ _creationTime: z.number(),
2156
+ title: z.string(),
2157
+ icon: z.string().optional(),
2158
+ coverImage: z.string().optional(),
2159
+ filePath: z.string(),
2160
+ parentId: z.string().optional(),
2161
+ parentObjectId: z.string().optional(),
2162
+ entryId: z.string().optional(),
2163
+ sortOrder: z.number(),
2164
+ isPublished: z.boolean(),
2165
+ createdAt: z.number(),
2166
+ updatedAt: z.number(),
2167
+ })
2168
+ .passthrough(),
2169
+ ),
2170
+ "crm.docs.create": z.object({ id: z.string() }),
2171
+ "crm.docs.link": okResponse,
2172
+ "crm.actions.list": z.array(
2173
+ z
2174
+ .object({
2175
+ _id: z.string(),
2176
+ _creationTime: z.number(),
2177
+ actionId: z.string(),
2178
+ fieldId: z.string(),
2179
+ entryId: z.string(),
2180
+ objectId: z.string(),
2181
+ runId: z.string().optional(),
2182
+ status: z.enum(["pending", "running", "completed", "failed"]),
2183
+ startedAt: z.number(),
2184
+ completedAt: z.number().optional(),
2185
+ result: z.string().optional(),
2186
+ error: z.string().optional(),
2187
+ })
2188
+ .passthrough(),
2189
+ ),
2190
+ "crm.actions.run": z.object({ id: z.string() }),
956
2191
  "crm.members.list": z.object({
957
2192
  members: z.array(memberShape),
958
2193
  organizationId: z.string(),
959
- organizationSlug: z.string(),
2194
+ organizationSlug: z.string().nullable(),
960
2195
  organizationName: z.string(),
961
2196
  }),
962
- "billing.status": z.object({
963
- availableCreditsCents: z.number(),
964
- billedCents: z.number().optional(),
965
- subscriptionStatus: z.string().optional(),
2197
+ "crm.reports.generate": z.object({
2198
+ spec: z.object({
2199
+ objectName: z.string(),
2200
+ type: reportType,
2201
+ groupByField: z.string(),
2202
+ metric: reportMetric,
2203
+ metricField: z.string().optional(),
2204
+ }),
2205
+ buckets: z.array(
2206
+ z.object({
2207
+ key: z.string(),
2208
+ label: z.string(),
2209
+ count: z.number(),
2210
+ sum: z.number().optional(),
2211
+ avg: z.number().optional(),
2212
+ }),
2213
+ ),
2214
+ totalCount: z.number(),
966
2215
  }),
967
- "approval.request": z.object({ ok: z.boolean(), approvalId: z.string() }),
968
- "memory.save": z.object({
2216
+ "crm.enrich.cell": z.object({
2217
+ enqueued: z.boolean(),
2218
+ provider: z.string(),
2219
+ hint: z.string(),
2220
+ }),
2221
+ "crm.enrich.object": z.object({
2222
+ enqueued: z.number().describe("Number of cells queued for enrichment."),
2223
+ provider: z.string(),
2224
+ }),
2225
+ "crm.people.search": enrichedPeopleResponse,
2226
+ "crm.companies.search": enrichedCompaniesResponse,
2227
+
2228
+ // Email
2229
+ "email.identity.verify": z
2230
+ .object({
2231
+ ok: z.boolean(),
2232
+ identity: z.string(),
2233
+ type: emailIdentityType,
2234
+ identityType: z
2235
+ .string()
2236
+ .nullable()
2237
+ .describe('Provider identity type, e.g. "DOMAIN" or "EMAIL_ADDRESS".'),
2238
+ verifiedForSendingStatus: z.boolean(),
2239
+ messageId: z
2240
+ .string()
2241
+ .nullable()
2242
+ .optional()
2243
+ .describe("Verification email id (email identities only)."),
2244
+ dkimTokens: z
2245
+ .array(z.string())
2246
+ .describe("DKIM tokens for DNS records (domain identities)."),
2247
+ })
2248
+ .passthrough(),
2249
+ "email.identity.create": z.object({ identityId: z.string() }),
2250
+ "email.identity.refresh": z
2251
+ .object({
2252
+ identityId: z.string(),
2253
+ identity: z.string(),
2254
+ deliveryVerificationStatus,
2255
+ deliveryVerified: z.boolean(),
2256
+ domain: z.string().optional(),
2257
+ domainVerified: z.boolean(),
2258
+ emailVerified: z.boolean(),
2259
+ denchVerificationStatus,
2260
+ disabled: z.boolean(),
2261
+ dnsRecords: z.array(dnsRecordShape).optional(),
2262
+ domainVerificationInfo: z
2263
+ .object({
2264
+ errorType: z.string().optional(),
2265
+ lastCheckedAt: z.string().optional(),
2266
+ lastSuccessAt: z.string().optional(),
2267
+ })
2268
+ .optional()
2269
+ .describe("Provider DNS poll info for pending domains."),
2270
+ message: z.string().optional(),
2271
+ })
2272
+ .passthrough(),
2273
+ "email.identity.beginVerification": z.object({
2274
+ identityId: z.string(),
2275
+ fromEmail: z.string(),
2276
+ denchVerificationStatus: z.enum(["pending", "verified"]),
2277
+ deliveryVerificationStatus: z.enum(["pending", "verified"]),
2278
+ action: z.enum([
2279
+ "already_verified",
2280
+ "mailbox_verification_sent",
2281
+ "domain_dns_ready",
2282
+ "workspace_verification_sent",
2283
+ ]),
2284
+ dkimTokens: z.array(z.string()).optional(),
2285
+ dnsRecords: z.array(dnsRecordShape).optional(),
2286
+ message: z.string(),
2287
+ }),
2288
+ "email.identity.status": z
2289
+ .object({
2290
+ ok: z.boolean(),
2291
+ identity: z.string(),
2292
+ verifiedForSendingStatus: z.boolean(),
2293
+ verificationStatus: z
2294
+ .string()
2295
+ .describe('Provider status, e.g. "PENDING" | "SUCCESS" | "FAILED".'),
2296
+ dkimAttributes: z
2297
+ .record(z.string(), z.unknown())
2298
+ .nullable()
2299
+ .describe("Provider DKIM attributes (Tokens, Status, ...)."),
2300
+ mailFromAttributes: z.record(z.string(), z.unknown()).nullable(),
2301
+ verificationInfo: z
2302
+ .object({
2303
+ errorType: z.string().nullable(),
2304
+ lastCheckedAt: z.string().nullable(),
2305
+ lastSuccessAt: z.string().nullable(),
2306
+ })
2307
+ .nullable(),
2308
+ })
2309
+ .passthrough(),
2310
+ "email.identity.list": z.array(emailIdentityRow),
2311
+ "email.identity.dns": z
2312
+ .object({
2313
+ identityId: z.string(),
2314
+ identity: z.string(),
2315
+ deliveryVerificationStatus,
2316
+ deliveryVerified: z.boolean(),
2317
+ domain: z.string().optional(),
2318
+ domainVerified: z.boolean(),
2319
+ emailVerified: z.boolean(),
2320
+ denchVerificationStatus,
2321
+ disabled: z.boolean(),
2322
+ dnsRecords: z
2323
+ .array(dnsRecordShape)
2324
+ .optional()
2325
+ .describe("DKIM/SPF/DMARC records to add for a pending domain."),
2326
+ message: z.string().optional(),
2327
+ })
2328
+ .passthrough(),
2329
+ "email.identity.disable": z.object({
969
2330
  ok: z.boolean(),
970
- memoryId: z.string(),
971
- status: z.enum(["active", "needs_review"]),
2331
+ disabled: z.array(identitySummaryShape),
972
2332
  }),
973
- "cron.create": z.object({
974
- jobId: z.string(),
975
- nextFireAt: z.number().optional(),
2333
+ "email.identity.restore": z.object({
2334
+ ok: z.boolean(),
2335
+ restored: z.array(identitySummaryShape),
976
2336
  }),
2337
+ "email.send": z.object({
2338
+ ok: z.boolean(),
2339
+ messageId: z
2340
+ .string()
2341
+ .describe("Dench message id for `dench email message status`."),
2342
+ providerMessageId: z.string(),
2343
+ rfcMessageId: z
2344
+ .string()
2345
+ .optional()
2346
+ .describe("RFC 5322 Message-ID usable for reply threading."),
2347
+ recipients: z.number(),
2348
+ status: z.literal("sent"),
2349
+ inReplyTo: z.string().optional(),
2350
+ message: z.string(),
2351
+ }),
2352
+ "email.message.get": emailMessageShape,
2353
+ "email.message.list": z.array(emailMessageShape),
2354
+ "email.template.create": z.object({ templateId: z.string() }),
2355
+ "email.template.preview": z.object({
2356
+ subject: z.string(),
2357
+ htmlBody: z.string(),
2358
+ textBody: z.string().optional(),
2359
+ variableNames: z.array(z.string()),
2360
+ }),
2361
+ "email.campaign.create": z.object({ campaignId: z.string() }),
2362
+ "email.campaign.get": campaignDoc,
2363
+ "email.campaign.recipients.add": z.object({
2364
+ added: z.number(),
2365
+ duplicates: z.number(),
2366
+ suppressed: z.number(),
2367
+ invalid: z.number(),
2368
+ totalRecipients: z.number(),
2369
+ }),
2370
+ "email.campaign.preview": z.object({
2371
+ campaignId: z.string(),
2372
+ previews: z.array(
2373
+ z.object({
2374
+ recipientId: z.string(),
2375
+ to: z.string(),
2376
+ subject: z.string(),
2377
+ htmlBody: z.string(),
2378
+ textBody: z.string().optional(),
2379
+ }),
2380
+ ),
2381
+ }),
2382
+ "email.campaign.submit": z.object({
2383
+ ok: z.boolean(),
2384
+ summary: campaignSummaryShape,
2385
+ }),
2386
+ "email.campaign.pause": campaignSummaryShape,
2387
+ "email.campaign.resume": campaignSummaryShape,
2388
+ "email.campaign.cancel": campaignSummaryShape,
2389
+
2390
+ // Routines
2391
+ "cron.list": z.object({
2392
+ jobs: z.array(cronJobShape),
2393
+ cronStatus: z.object({
2394
+ enabled: z.boolean(),
2395
+ nextWakeAtMs: z.number().nullable(),
2396
+ }),
2397
+ }),
2398
+ "cron.history": z.object({ entries: z.array(cronRunEntry) }),
2399
+ "cron.get": cronJobShape,
2400
+ "cron.create": cronWriteResponse,
2401
+ "cron.update": cronWriteResponse,
2402
+ "cron.delete": okResponse,
2403
+ "cron.enable": cronWriteResponse,
2404
+ "cron.disable": cronWriteResponse,
2405
+ "cron.run": z.object({
2406
+ runId: z.string(),
2407
+ threadId: z.string(),
2408
+ target: z.literal("chat_turn"),
2409
+ }),
2410
+ "cron.runs": z.object({ entries: z.array(cronRunEntry) }),
2411
+
2412
+ // Files
2413
+ "files.list": z.array(fileTreeRow),
2414
+ "files.downloadUrl": z
2415
+ .string()
2416
+ .nullable()
2417
+ .describe("Signed download URL, or null when the file has no blob."),
2418
+ "files.delete": z
2419
+ .object({ path: z.string() })
2420
+ .nullable()
2421
+ .describe("Deleted path, or null when nothing existed at the path."),
2422
+ "files.move": z.object({
2423
+ ok: z.boolean(),
2424
+ from: z.string(),
2425
+ to: z.string(),
2426
+ moved: z.array(z.object({ from: z.string(), to: z.string() })),
2427
+ }),
2428
+ "files.stage": z.object({
2429
+ ok: z.boolean(),
2430
+ staged: z.array(
2431
+ z.object({
2432
+ path: z.string(),
2433
+ size: z.number(),
2434
+ result: z
2435
+ .object({
2436
+ path: z.string(),
2437
+ contentHash: z.string(),
2438
+ })
2439
+ .passthrough(),
2440
+ }),
2441
+ ),
2442
+ }),
2443
+
2444
+ // Gateway: search, images, apps, tools
2445
+ "search.web": exaSearchResponse,
2446
+ "search.contents": exaSearchResponse,
2447
+ "search.answer": exaAnswerResponse,
2448
+ "image.generate": imageEnvelope,
2449
+ "image.edit": imageEnvelope,
2450
+ "apps.list": composioConnectionsResponse,
2451
+ "tool.status": composioConnectionsResponse,
2452
+ "tool.connect": z
2453
+ .object({
2454
+ redirect_url: z
2455
+ .string()
2456
+ .optional()
2457
+ .describe("OAuth URL the user opens to finish connecting."),
2458
+ connection_id: z.string().optional(),
2459
+ })
2460
+ .passthrough()
2461
+ .describe("Composio connect-link response (provider passthrough)."),
2462
+ "tool.search": toolSearchResponse,
2463
+ "tool.run": toolRunResponse,
2464
+ "tool.disconnect": z
2465
+ .object({
2466
+ id: z.string().optional(),
2467
+ deleted: z.boolean().optional(),
2468
+ })
2469
+ .passthrough()
2470
+ .describe("Composio delete response (provider passthrough)."),
2471
+
2472
+ // Agent config
2473
+ "agentConfig.identity.show": agentConfigPayload,
2474
+ "agentConfig.identity.edit": agentConfigBlock,
2475
+ "agentConfig.organisation.show": agentConfigPayload,
2476
+ "agentConfig.organisation.edit": agentConfigBlock,
2477
+ "agentConfig.user.show": agentConfigPayload,
2478
+ "agentConfig.user.edit": timedContent,
2479
+ "agentConfig.tools.show": agentConfigPayload,
2480
+ "agentConfig.tools.edit": agentConfigBlock,
2481
+ "agentConfig.mem.show": agentConfigPayload,
2482
+ "agentConfig.mem.edit": agentConfigBlock,
2483
+ "agentConfig.bootstrap.show": agentConfigPayload,
2484
+ "agentConfig.bootstrap.complete": agentConfigBlock,
2485
+ "agentConfig.bootstrap.template": agentConfigBlock,
2486
+ "agentConfig.model.default": z.object({
2487
+ defaultChatModelId: z.string().nullable(),
2488
+ }),
2489
+ "agentConfig.model.thread": z.object({
2490
+ threadId: z.string(),
2491
+ modelOverride: z.string().nullable(),
2492
+ }),
2493
+ "agentConfig.daily.today": agentConfigPayload,
2494
+ "agentConfig.daily.show": agentConfigPayload,
977
2495
  };
978
2496
 
979
2497
  // ---------------------------------------------------------------------------
@@ -1040,9 +2558,17 @@ export const requestExamples: Record<string, unknown> = {
1040
2558
  },
1041
2559
  "crm.cells.set": { value: "In progress" },
1042
2560
  "crm.query": {
2561
+ objectName: "lead",
1043
2562
  dslJson:
1044
2563
  '{"filter":{"Status":"Qualified","Score":{"$gt":50}},"sort":"-Score","limit":50}',
1045
2564
  },
2565
+ "crm.transaction.add": {
2566
+ op: {
2567
+ type: "entries.update",
2568
+ entryId: "ent_lead99",
2569
+ data: { Status: "Qualified" },
2570
+ },
2571
+ },
1046
2572
  "crm.statuses.set": {
1047
2573
  statuses: [
1048
2574
  { name: "New", color: "#94a3b8" },
@@ -1072,6 +2598,10 @@ export const requestExamples: Record<string, unknown> = {
1072
2598
  evidence: "User said yes in chat",
1073
2599
  },
1074
2600
  "chat.new": { prompt: "Summarize the latest CRM changes." },
2601
+ "chat.rename": {
2602
+ items: [{ threadId: "th_abc123", title: "Deploy checklist" }],
2603
+ },
2604
+ "chat.delete": { threadIds: ["th_abc123"] },
1075
2605
  "cron.create": {
1076
2606
  name: "Daily digest",
1077
2607
  prompt: "Summarize open CRM tasks.",
@@ -1082,6 +2612,13 @@ export const requestExamples: Record<string, unknown> = {
1082
2612
  prompt: "A minimal flat-vector app icon",
1083
2613
  size: "1024x1024",
1084
2614
  },
2615
+ "image.edit": {
2616
+ prompt: "Make the background transparent",
2617
+ input_images_base64: ["iVBORw0KGgoAAAANSUhEUg..."],
2618
+ },
2619
+ "tool.search": {
2620
+ queries: [{ use_case: "fetch the 10 most recent emails" }],
2621
+ },
1085
2622
  "tool.run": {
1086
2623
  tool_slug: "GMAIL_FETCH_EMAILS",
1087
2624
  arguments: { max_results: 10 },
@@ -1092,4 +2629,1308 @@ export const requestExamples: Record<string, unknown> = {
1092
2629
  limit: 10,
1093
2630
  },
1094
2631
  "crm.companies.search": { domain: "example.com" },
2632
+ "email.identity.verify": { type: "email", identity: "founder@example.com" },
2633
+ "email.identity.create": {
2634
+ type: "domain",
2635
+ domain: "example.com",
2636
+ fromEmail: "founder@example.com",
2637
+ fromName: "Ada at Example",
2638
+ },
2639
+ "email.send": {
2640
+ fromEmail: "founder@example.com",
2641
+ to: [{ email: "ada@lovelace.dev", name: "Ada" }],
2642
+ subject: "Quick intro",
2643
+ htmlBody: "<p>Hi Ada — great meeting you!</p>",
2644
+ },
2645
+ "email.template.create": {
2646
+ name: "Intro outreach",
2647
+ subject: "Hi {{firstName}}",
2648
+ htmlBody: "<p>Hi {{firstName}}, saw your work at {{company}}.</p>",
2649
+ },
2650
+ "email.template.preview": {
2651
+ data: { firstName: "Ada", company: "Lovelace Labs" },
2652
+ },
2653
+ "email.campaign.create": {
2654
+ name: "Q2 outreach",
2655
+ identityId: "founder@example.com",
2656
+ templateId: "etpl_abc123",
2657
+ },
2658
+ "email.campaign.recipients.add": {
2659
+ recipients: [
2660
+ {
2661
+ email: "ada@lovelace.dev",
2662
+ displayName: "Ada Lovelace",
2663
+ personalization: { firstName: "Ada", company: "Lovelace Labs" },
2664
+ },
2665
+ ],
2666
+ },
2667
+ "email.campaign.preview": { sample: 5 },
2668
+ };
2669
+
2670
+ // ---------------------------------------------------------------------------
2671
+ // Curated 200-response examples keyed by operation id (for the playground).
2672
+ // Mirror real backend outputs; ids are illustrative opaque strings.
2673
+ // ---------------------------------------------------------------------------
2674
+
2675
+ /** /context, /status, /agents, and /approvals all return this payload. */
2676
+ const workspaceStatusExample = {
2677
+ workspace: { id: "org_abc123", name: "Acme", slug: "acme" },
2678
+ agent: { id: "ag_xyz789", name: "Cursor", kind: "cursor" },
2679
+ rules: [],
2680
+ activeAgents: [
2681
+ {
2682
+ id: "ag_xyz789",
2683
+ name: "Cursor",
2684
+ kind: "cursor",
2685
+ lastSeenAt: 1765526400000,
2686
+ },
2687
+ ],
2688
+ pendingApprovals: [],
2689
+ recentArtifacts: [],
2690
+ suggestedWork: [],
2691
+ memory: [],
2692
+ chatAgents: {
2693
+ nextCommands: ['dench agent new "Find useful work" --follow --json'],
2694
+ activeRuns: [],
2695
+ templates: [],
2696
+ },
2697
+ tools: {
2698
+ discovery: ["dench_list_apps", "dench_search_tools"],
2699
+ cli: ["dench apps --json"],
2700
+ approvalPolicy: "Read-only tools can run by default.",
2701
+ },
2702
+ nextActions: ["Ask for a goal or start a chat agent"],
2703
+ };
2704
+
2705
+ export const responseExamples: Record<string, unknown> = {
2706
+ "commands.list": {
2707
+ operations: [
2708
+ {
2709
+ id: "crm.entries.create",
2710
+ group: "crm",
2711
+ summary: "Create a CRM entry.",
2712
+ cli: "dench crm entries create",
2713
+ aliases: [],
2714
+ method: "POST",
2715
+ path: "/crm/objects/{objectName}/entries",
2716
+ backend: "convex",
2717
+ deprecated: false,
2718
+ },
2719
+ ],
2720
+ },
2721
+ "auth.signin.create": { status: "pending", expiresAt: 1765526400000 },
2722
+ "auth.signin.poll": {
2723
+ status: "approved",
2724
+ organization: { id: "org_abc123", name: "Acme", slug: "acme" },
2725
+ agent: { id: "ag_xyz789", name: "Cursor", kind: "cursor" },
2726
+ sessionExpiresAt: 1773302400000,
2727
+ },
2728
+ "auth.otp.start": { ok: true },
2729
+ "auth.otp.verify": {
2730
+ ok: true,
2731
+ result: {
2732
+ kind: "completed",
2733
+ organization: { id: "org_abc123", name: "Acme", slug: "acme" },
2734
+ sessionExpiresAt: 1773302400000,
2735
+ },
2736
+ },
2737
+ "auth.otp.finalize": {
2738
+ ok: true,
2739
+ result: {
2740
+ organization: { id: "org_abc123", name: "Acme", slug: "acme" },
2741
+ sessionExpiresAt: 1773302400000,
2742
+ },
2743
+ },
2744
+ "workspace.context": workspaceStatusExample,
2745
+ "workspace.status": workspaceStatusExample,
2746
+ "workspace.agents": workspaceStatusExample,
2747
+ "workspace.approvals.list": workspaceStatusExample,
2748
+ "workspace.artifacts.list": [
2749
+ {
2750
+ id: "ra_def456",
2751
+ runId: "rn_ghi789",
2752
+ title: "Research summary",
2753
+ type: "report",
2754
+ status: "draft",
2755
+ content: "Key findings...",
2756
+ createdAt: 1765526400000,
2757
+ updatedAt: 1765526400000,
2758
+ },
2759
+ ],
2760
+ "workspace.suggestedWork.list": [
2761
+ {
2762
+ id: "ra_def456",
2763
+ runId: "rn_ghi789",
2764
+ title: "Follow up with 3 stale leads",
2765
+ type: "task_suggestion",
2766
+ status: "draft",
2767
+ content: "These leads have not been contacted in 30 days...",
2768
+ createdAt: 1765526400000,
2769
+ updatedAt: 1765526400000,
2770
+ },
2771
+ ],
2772
+ "memory.search": [
2773
+ {
2774
+ _id: "wm_jkl012",
2775
+ _creationTime: 1765526400000,
2776
+ key: "deployment-policy",
2777
+ kind: "decision",
2778
+ text: "Never deploy without human approval.",
2779
+ tags: ["deployment", "policy"],
2780
+ status: "active",
2781
+ source: "agent",
2782
+ createdAt: 1765526400000,
2783
+ updatedAt: 1765526400000,
2784
+ },
2785
+ ],
2786
+ "memory.save": { ok: true, memoryId: "wm_jkl012", status: "active" },
2787
+ "approval.request": { ok: true, approvalId: "ap_mno345" },
2788
+ "approval.decide": { ok: true, status: "approved" },
2789
+ "billing.status": {
2790
+ workspace: { id: "org_abc123", name: "Acme", slug: "acme" },
2791
+ availableCreditsCents: 500,
2792
+ creditConsumedCents: 120,
2793
+ billedCents: 120,
2794
+ onDemandSpendCents: 0,
2795
+ monthlySpendLimitCents: 5000,
2796
+ spendLimitRemainingCents: 4880,
2797
+ subscriptionStatus: "active",
2798
+ stripeCustomerId: "cus_abc123",
2799
+ grants: [
2800
+ {
2801
+ id: "gr_pqr678",
2802
+ source: "starter",
2803
+ category: "promotional",
2804
+ status: "granted",
2805
+ amountCents: 500,
2806
+ usedCents: 120,
2807
+ remainingCents: 380,
2808
+ effectiveAt: 1765526400000,
2809
+ expiresAt: null,
2810
+ },
2811
+ ],
2812
+ nextCommands: ["dench billing topup --amount 20"],
2813
+ },
2814
+ "billing.topup": { url: "https://checkout.stripe.com/c/pay/cs_test_abc123" },
2815
+ "billing.upgrade": {
2816
+ url: "https://checkout.stripe.com/c/pay/cs_test_xyz789",
2817
+ },
2818
+ "chat.list": [
2819
+ {
2820
+ threadId: "th_abc123",
2821
+ title: "Deploy checklist",
2822
+ lastMessageAt: 1765526400000,
2823
+ createdAt: 1765526000000,
2824
+ status: "idle",
2825
+ visibility: "private",
2826
+ createdByUserId: "us_xyz789",
2827
+ archivedAt: null,
2828
+ fileContextPath: null,
2829
+ parentThreadId: null,
2830
+ nestingDepth: null,
2831
+ summary: null,
2832
+ activeRunId: null,
2833
+ },
2834
+ ],
2835
+ "chat.search": [
2836
+ {
2837
+ threadId: "th_abc123",
2838
+ threadTitle: "Deploy checklist",
2839
+ messageId: "cm_def456",
2840
+ role: "user",
2841
+ snippet: "How do we deploy to prod?",
2842
+ createdAt: 1765526400000,
2843
+ runId: null,
2844
+ },
2845
+ ],
2846
+ "chat.read": {
2847
+ thread: {
2848
+ threadId: "th_abc123",
2849
+ title: "Deploy checklist",
2850
+ lastMessageAt: 1765526400000,
2851
+ createdAt: 1765526000000,
2852
+ status: "idle",
2853
+ visibility: "private",
2854
+ createdByUserId: "us_xyz789",
2855
+ archivedAt: null,
2856
+ fileContextPath: null,
2857
+ parentThreadId: null,
2858
+ nestingDepth: null,
2859
+ summary: null,
2860
+ activeRunId: null,
2861
+ },
2862
+ messages: [
2863
+ {
2864
+ id: "cm_def456",
2865
+ role: "user",
2866
+ createdAt: 1765526400000,
2867
+ text: "How do we deploy?",
2868
+ runId: null,
2869
+ },
2870
+ {
2871
+ id: "cm_ghi789",
2872
+ role: "assistant",
2873
+ createdAt: 1765526460000,
2874
+ text: "Push to main; Vercel auto-deploys.",
2875
+ runId: "rn_jkl012",
2876
+ },
2877
+ ],
2878
+ },
2879
+ "chat.tree": [
2880
+ {
2881
+ threadId: "th_abc123",
2882
+ title: "Deploy checklist",
2883
+ lastMessageAt: 1765526400000,
2884
+ createdAt: 1765526000000,
2885
+ status: "idle",
2886
+ visibility: "private",
2887
+ createdByUserId: "us_xyz789",
2888
+ archivedAt: null,
2889
+ fileContextPath: null,
2890
+ parentThreadId: null,
2891
+ nestingDepth: null,
2892
+ summary: null,
2893
+ activeRunId: null,
2894
+ },
2895
+ ],
2896
+ "chat.rename": {
2897
+ results: [{ threadId: "th_abc123", ok: true }],
2898
+ succeeded: 1,
2899
+ failed: 0,
2900
+ },
2901
+ "chat.delete": { scheduled: 2, rejected: [], total: 2 },
2902
+ "chat.new": {
2903
+ threadId: "th_abc123",
2904
+ runId: "rn_def456",
2905
+ workflowRunId: "wrun_01HX9",
2906
+ threadUrl: "https://www.dench.com/acme/chat/th_abc123",
2907
+ streamUrl: "https://www.dench.com/api/chat/stream?sessionId=th_abc123",
2908
+ yolo: false,
2909
+ },
2910
+ "chat.send": {
2911
+ threadId: "th_abc123",
2912
+ runId: "rn_ghi789",
2913
+ workflowRunId: "wrun_01HXA",
2914
+ threadUrl: "https://www.dench.com/acme/chat/th_abc123",
2915
+ streamUrl: "https://www.dench.com/api/chat/stream?sessionId=th_abc123",
2916
+ yolo: false,
2917
+ },
2918
+ "chat.follow":
2919
+ 'data: {"type":"start","messageId":"msg_01"}\n\ndata: {"type":"text-delta","id":"t1","delta":"Hello"}\n\ndata: {"type":"finish"}\n\n',
2920
+ "crm.objects.list": [
2921
+ {
2922
+ _id: "obj_lead01",
2923
+ _creationTime: 1765526400000,
2924
+ organizationId: "org_abc123",
2925
+ name: "lead",
2926
+ description: "Sales leads",
2927
+ defaultView: "kanban",
2928
+ sortOrder: 100,
2929
+ immutable: false,
2930
+ icon: "target",
2931
+ entryCount: 42,
2932
+ createdAt: 1765526400000,
2933
+ updatedAt: 1765612800000,
2934
+ },
2935
+ ],
2936
+ "crm.objects.get": {
2937
+ _id: "obj_lead01",
2938
+ _creationTime: 1765526400000,
2939
+ organizationId: "org_abc123",
2940
+ name: "lead",
2941
+ description: "Sales leads",
2942
+ defaultView: "kanban",
2943
+ sortOrder: 100,
2944
+ immutable: false,
2945
+ icon: "target",
2946
+ entryCount: 42,
2947
+ createdAt: 1765526400000,
2948
+ updatedAt: 1765612800000,
2949
+ },
2950
+ "crm.objects.create": { id: "obj_lead01" },
2951
+ "crm.objects.update": { ok: true },
2952
+ "crm.objects.rename": { ok: true },
2953
+ "crm.objects.delete": { ok: true },
2954
+ "crm.fields.list": [
2955
+ {
2956
+ _id: "fld_status01",
2957
+ _creationTime: 1765526400000,
2958
+ organizationId: "org_abc123",
2959
+ objectId: "obj_lead01",
2960
+ name: "Status",
2961
+ type: "enum",
2962
+ required: false,
2963
+ enumValues: ["New", "Working", "Qualified", "Lost"],
2964
+ enumColors: ["#94a3b8", "#3b82f6", "#22c55e", "#ef4444"],
2965
+ enumMultiple: false,
2966
+ sortOrder: 200,
2967
+ indexed: true,
2968
+ createdAt: 1765526400000,
2969
+ updatedAt: 1765612800000,
2970
+ },
2971
+ ],
2972
+ "crm.fields.create": { id: "fld_score01" },
2973
+ "crm.fields.update": { ok: true },
2974
+ "crm.fields.delete": { ok: true },
2975
+ "crm.fields.reorder": { ok: true },
2976
+ "crm.fields.enum.reorder": {
2977
+ ok: true,
2978
+ enumValues: ["New", "Qualified", "Working", "Lost"],
2979
+ enumColors: ["#94a3b8", "#22c55e", "#3b82f6", "#ef4444"],
2980
+ },
2981
+ "crm.fields.enum.add": {
2982
+ ok: true,
2983
+ enumValues: ["New", "Working", "Nurturing", "Qualified", "Lost"],
2984
+ enumColors: ["#94a3b8", "#3b82f6", "#eab308", "#22c55e", "#ef4444"],
2985
+ inserted: true,
2986
+ },
2987
+ "crm.fields.enum.remove": {
2988
+ ok: true,
2989
+ enumValues: ["New", "Working", "Qualified"],
2990
+ enumColors: ["#94a3b8", "#3b82f6", "#22c55e"],
2991
+ removed: true,
2992
+ },
2993
+ "crm.fields.enum.rename": {
2994
+ ok: true,
2995
+ enumValues: ["New", "Working", "Closed Won", "Lost"],
2996
+ enumColors: ["#94a3b8", "#3b82f6", "#22c55e", "#ef4444"],
2997
+ entriesUpdated: 7,
2998
+ },
2999
+ "crm.fields.enum.color": {
3000
+ ok: true,
3001
+ enumColors: ["#94a3b8", "#3b82f6", "#22c55e", "#ef4444"],
3002
+ },
3003
+ "crm.entries.list": [
3004
+ {
3005
+ id: "ent_lead99",
3006
+ objectId: "obj_lead01",
3007
+ fields: { Name: "Ada Lovelace", Email: "ada@example.com", Status: "New" },
3008
+ createdAt: 1765526400000,
3009
+ updatedAt: 1765612800000,
3010
+ updatedBy: "user:us_xyz789",
3011
+ sortOrder: 0,
3012
+ },
3013
+ ],
3014
+ "crm.entries.get": {
3015
+ id: "ent_lead99",
3016
+ objectId: "obj_lead01",
3017
+ fields: { Name: "Ada Lovelace", Email: "ada@example.com", Status: "New" },
3018
+ createdAt: 1765526400000,
3019
+ updatedAt: 1765612800000,
3020
+ updatedBy: "user:us_xyz789",
3021
+ sortOrder: 0,
3022
+ },
3023
+ "crm.entries.create": { entryId: "ent_lead99" },
3024
+ "crm.entries.createMany": {
3025
+ results: [{ entryId: "ent_lead99" }, { entryId: "ent_lead100" }],
3026
+ count: 2,
3027
+ },
3028
+ "crm.entries.update": { entryId: "ent_lead99" },
3029
+ "crm.entries.updateMany": {
3030
+ results: [{ entryId: "ent_lead99" }, { entryId: "ent_lead100" }],
3031
+ count: 2,
3032
+ },
3033
+ "crm.entries.delete": { ok: true },
3034
+ "crm.entries.bulkDelete": { count: 3 },
3035
+ "crm.cells.get": "Qualified",
3036
+ "crm.cells.set": { entryId: "ent_lead99" },
3037
+ "crm.cells.setMany": {
3038
+ results: [{ entryId: "ent_lead99" }, { entryId: "ent_lead100" }],
3039
+ count: 2,
3040
+ },
3041
+ "crm.cells.append": { entryId: "ent_lead99" },
3042
+ "crm.query": [
3043
+ {
3044
+ id: "ent_lead99",
3045
+ objectId: "obj_lead01",
3046
+ fields: { Name: "Ada Lovelace", Status: "Qualified", Score: 85 },
3047
+ createdAt: 1765526400000,
3048
+ updatedAt: 1765612800000,
3049
+ updatedBy: "user:us_xyz789",
3050
+ sortOrder: 0,
3051
+ },
3052
+ ],
3053
+ "crm.sql": [
3054
+ {
3055
+ id: "ent_lead99",
3056
+ objectId: "obj_lead01",
3057
+ fields: { Name: "Ada Lovelace", Status: "Qualified", Score: 85 },
3058
+ createdAt: 1765526400000,
3059
+ updatedAt: 1765612800000,
3060
+ updatedBy: "user:us_xyz789",
3061
+ sortOrder: 0,
3062
+ },
3063
+ ],
3064
+ "crm.aggregate": [
3065
+ { key: "New", count: 12 },
3066
+ { key: "Qualified", count: 8, sumNumber: 640 },
3067
+ ],
3068
+ "crm.search": [
3069
+ {
3070
+ _id: "ent_lead99",
3071
+ _creationTime: 1765526400000,
3072
+ objectId: "obj_lead01",
3073
+ data: { Name: "Acme Corp", Status: "Qualified" },
3074
+ searchableText: "Acme Corp Qualified",
3075
+ sortOrder: 0,
3076
+ createdAt: 1765526400000,
3077
+ updatedAt: 1765612800000,
3078
+ updatedBy: "user:us_xyz789",
3079
+ },
3080
+ ],
3081
+ "crm.statuses.list": [
3082
+ {
3083
+ _id: "sts_new01",
3084
+ _creationTime: 1765526400000,
3085
+ objectId: "obj_lead01",
3086
+ name: "New",
3087
+ color: "#94a3b8",
3088
+ sortOrder: 100,
3089
+ isDefault: true,
3090
+ },
3091
+ ],
3092
+ "crm.statuses.set": { ok: true },
3093
+ "crm.batch": {
3094
+ results: [
3095
+ { entryId: "ent_lead101" },
3096
+ { entryId: "ent_lead99", deleted: true },
3097
+ ],
3098
+ count: 2,
3099
+ },
3100
+ "crm.transaction.begin": { txnId: "txn_abc01" },
3101
+ "crm.transaction.add": { ok: true },
3102
+ "crm.transaction.commit": {
3103
+ results: [{ entryId: "ent_deal01" }],
3104
+ count: 1,
3105
+ },
3106
+ "crm.transaction.abort": { ok: true },
3107
+ "crm.transaction.inspect": {
3108
+ _id: "txn_abc01",
3109
+ _creationTime: 1765526400000,
3110
+ status: "open",
3111
+ ops: [
3112
+ {
3113
+ type: "entries.create",
3114
+ objectName: "lead",
3115
+ data: { Name: "Beta Inc" },
3116
+ },
3117
+ ],
3118
+ createdAt: 1765526400000,
3119
+ updatedAt: 1765526400000,
3120
+ },
3121
+ "crm.docs.list": [
3122
+ {
3123
+ _id: "doc_q2notes",
3124
+ _creationTime: 1765526400000,
3125
+ title: "Q2 Pipeline Notes",
3126
+ filePath: "/docs/q2-pipeline.md",
3127
+ sortOrder: 1765526400000,
3128
+ isPublished: false,
3129
+ createdAt: 1765526400000,
3130
+ updatedAt: 1765612800000,
3131
+ },
3132
+ ],
3133
+ "crm.docs.create": { id: "doc_q2notes" },
3134
+ "crm.docs.link": { ok: true },
3135
+ "crm.actions.list": [
3136
+ {
3137
+ _id: "arun_01",
3138
+ _creationTime: 1765526400000,
3139
+ actionId: "enrich_company",
3140
+ fieldId: "fld_action01",
3141
+ entryId: "ent_lead99",
3142
+ objectId: "obj_lead01",
3143
+ status: "completed",
3144
+ startedAt: 1765526400000,
3145
+ completedAt: 1765526460000,
3146
+ result: "Enriched 4 fields",
3147
+ },
3148
+ ],
3149
+ "crm.actions.run": { id: "arun_02" },
3150
+ "crm.members.list": {
3151
+ members: [
3152
+ {
3153
+ userId: "us_xyz789",
3154
+ name: "Jane Doe",
3155
+ email: "jane@acme.com",
3156
+ image: null,
3157
+ role: "ADMIN",
3158
+ joinedAt: 1765440000000,
3159
+ },
3160
+ ],
3161
+ organizationId: "org_abc123",
3162
+ organizationSlug: "acme",
3163
+ organizationName: "Acme",
3164
+ },
3165
+ "crm.reports.generate": {
3166
+ spec: {
3167
+ objectName: "lead",
3168
+ type: "bar",
3169
+ groupByField: "Status",
3170
+ metric: "count",
3171
+ },
3172
+ buckets: [
3173
+ { key: "New", label: "New", count: 12, sum: 0, avg: 0 },
3174
+ { key: "Qualified", label: "Qualified", count: 8, sum: 640, avg: 80 },
3175
+ ],
3176
+ totalCount: 20,
3177
+ },
3178
+ "crm.enrich.cell": {
3179
+ enqueued: true,
3180
+ provider: "auto",
3181
+ hint: "Enrichment queued; the cell fills in once the provider responds.",
3182
+ },
3183
+ "crm.enrich.object": { enqueued: 37, provider: "auto" },
3184
+ "crm.people.search": {
3185
+ source: "fullenrich",
3186
+ people: [
3187
+ {
3188
+ fullName: "Jane Doe",
3189
+ firstName: "Jane",
3190
+ lastName: "Doe",
3191
+ headline: "VP Engineering",
3192
+ currentCompanyName: "Acme",
3193
+ currentCompanyWebsite: "acme.com",
3194
+ linkedinID: "janedoe",
3195
+ },
3196
+ ],
3197
+ resolvedPersonIds: ["per_abc123"],
3198
+ creditsCharged: 1,
3199
+ metadata: { total: 1, offset: 0 },
3200
+ },
3201
+ "crm.companies.search": {
3202
+ source: "fullenrich",
3203
+ companies: [
3204
+ {
3205
+ name: "Acme",
3206
+ website: "acme.com",
3207
+ description: "An example company",
3208
+ linkedinUrl: "https://linkedin.com/company/acme",
3209
+ linkedinID: "acme",
3210
+ },
3211
+ ],
3212
+ resolvedCompanyIds: ["com_abc123"],
3213
+ creditsCharged: 1,
3214
+ metadata: { total: 1, offset: 0 },
3215
+ },
3216
+ "email.identity.verify": {
3217
+ ok: true,
3218
+ identity: "example.com",
3219
+ type: "domain",
3220
+ identityType: "DOMAIN",
3221
+ verifiedForSendingStatus: false,
3222
+ dkimTokens: ["abc123token", "def456token", "ghi789token"],
3223
+ },
3224
+ "email.identity.create": { identityId: "esi_abc123" },
3225
+ "email.identity.refresh": {
3226
+ identityId: "esi_abc123",
3227
+ identity: "example.com",
3228
+ deliveryVerificationStatus: "pending",
3229
+ deliveryVerified: false,
3230
+ domain: "example.com",
3231
+ domainVerified: false,
3232
+ emailVerified: true,
3233
+ denchVerificationStatus: "verified",
3234
+ disabled: false,
3235
+ dnsRecords: [
3236
+ {
3237
+ type: "CNAME",
3238
+ name: "abc123token._domainkey.example.com",
3239
+ value: "abc123token.dkim.amazonses.com",
3240
+ purpose: "DKIM (required for domain verification)",
3241
+ },
3242
+ ],
3243
+ message: "Domain example.com is pending DNS verification.",
3244
+ },
3245
+ "email.identity.beginVerification": {
3246
+ identityId: "esi_abc123",
3247
+ fromEmail: "founder@example.com",
3248
+ denchVerificationStatus: "pending",
3249
+ deliveryVerificationStatus: "pending",
3250
+ action: "mailbox_verification_sent",
3251
+ message:
3252
+ "Verification email sent. Open the link in that mailbox, then check sender status again.",
3253
+ },
3254
+ "email.identity.status": {
3255
+ ok: true,
3256
+ identity: "example.com",
3257
+ verifiedForSendingStatus: false,
3258
+ verificationStatus: "PENDING",
3259
+ dkimAttributes: { Tokens: ["abc123token"], Status: "PENDING" },
3260
+ mailFromAttributes: null,
3261
+ verificationInfo: {
3262
+ errorType: null,
3263
+ lastCheckedAt: "2026-06-12T10:00:00.000Z",
3264
+ lastSuccessAt: null,
3265
+ },
3266
+ },
3267
+ "email.identity.list": [
3268
+ {
3269
+ identityId: "esi_abc123",
3270
+ type: "email",
3271
+ fromEmail: "founder@example.com",
3272
+ fromName: "Ada at Example",
3273
+ deliveryVerificationStatus: "verified",
3274
+ denchVerificationStatus: "verified",
3275
+ disabled: false,
3276
+ createdAt: 1765526400000,
3277
+ },
3278
+ ],
3279
+ "email.identity.dns": {
3280
+ identityId: "esi_abc123",
3281
+ identity: "example.com",
3282
+ deliveryVerificationStatus: "pending",
3283
+ deliveryVerified: false,
3284
+ domain: "example.com",
3285
+ domainVerified: false,
3286
+ emailVerified: false,
3287
+ denchVerificationStatus: "verified",
3288
+ disabled: false,
3289
+ dnsRecords: [
3290
+ {
3291
+ type: "CNAME",
3292
+ name: "abc123token._domainkey.example.com",
3293
+ value: "abc123token.dkim.amazonses.com",
3294
+ purpose: "DKIM (required for domain verification)",
3295
+ },
3296
+ {
3297
+ type: "TXT",
3298
+ name: "example.com",
3299
+ value: "v=spf1 include:amazonses.com ~all",
3300
+ purpose: "SPF (recommended)",
3301
+ },
3302
+ ],
3303
+ },
3304
+ "email.identity.disable": {
3305
+ ok: true,
3306
+ disabled: [
3307
+ {
3308
+ identityId: "esi_abc123",
3309
+ fromEmail: "founder@example.com",
3310
+ disabled: true,
3311
+ },
3312
+ ],
3313
+ },
3314
+ "email.identity.restore": {
3315
+ ok: true,
3316
+ restored: [
3317
+ {
3318
+ identityId: "esi_abc123",
3319
+ fromEmail: "founder@example.com",
3320
+ disabled: false,
3321
+ },
3322
+ ],
3323
+ },
3324
+ "email.send": {
3325
+ ok: true,
3326
+ messageId: "emsg_abc123",
3327
+ providerMessageId: "0100018abc-provider-id",
3328
+ rfcMessageId: "<0100018abc@email.amazonses.com>",
3329
+ recipients: 1,
3330
+ status: "sent",
3331
+ message:
3332
+ "Email sent. Track opens/clicks with `dench email message status`.",
3333
+ },
3334
+ "email.message.get": {
3335
+ messageId: "emsg_abc123",
3336
+ status: "opened",
3337
+ fromEmail: "founder@example.com",
3338
+ to: [{ email: "ada@lovelace.dev", name: "Ada" }],
3339
+ subject: "Quick intro",
3340
+ providerMessageId: "0100018abc-provider-id",
3341
+ rfcMessageId: "<0100018abc@email.amazonses.com>",
3342
+ recipientCount: 1,
3343
+ openCount: 2,
3344
+ clickCount: 1,
3345
+ sentAt: 1765526400000,
3346
+ deliveredAt: 1765526410000,
3347
+ firstOpenedAt: 1765529700000,
3348
+ createdAt: 1765526395000,
3349
+ },
3350
+ "email.message.list": [
3351
+ {
3352
+ messageId: "emsg_abc123",
3353
+ status: "sent",
3354
+ fromEmail: "founder@example.com",
3355
+ to: [{ email: "ada@lovelace.dev" }],
3356
+ subject: "Quick intro",
3357
+ recipientCount: 1,
3358
+ openCount: 0,
3359
+ clickCount: 0,
3360
+ sentAt: 1765526400000,
3361
+ createdAt: 1765526395000,
3362
+ },
3363
+ ],
3364
+ "email.template.create": { templateId: "etpl_abc123" },
3365
+ "email.template.preview": {
3366
+ subject: "Hi Ada",
3367
+ htmlBody: "<p>Hi Ada, saw your work at Lovelace Labs.</p>",
3368
+ variableNames: ["company", "firstName"],
3369
+ },
3370
+ "email.campaign.create": { campaignId: "ecmp_abc123" },
3371
+ "email.campaign.get": {
3372
+ _id: "ecmp_abc123",
3373
+ _creationTime: 1765526395000,
3374
+ organizationId: "org_abc123",
3375
+ name: "Q2 outreach",
3376
+ status: "sending",
3377
+ sendingIdentityId: "esi_abc123",
3378
+ templateId: "etpl_abc123",
3379
+ subjectSnapshot: "Hi {{firstName}}",
3380
+ htmlSnapshot: "<p>Hi {{firstName}}, saw your work at {{company}}.</p>",
3381
+ fromEmailSnapshot: "founder@example.com",
3382
+ createdBy: "user:us_xyz789",
3383
+ totalRecipients: 120,
3384
+ queuedCount: 70,
3385
+ sendingCount: 0,
3386
+ sentCount: 50,
3387
+ deliveredCount: 48,
3388
+ openedCount: 12,
3389
+ clickedCount: 3,
3390
+ bouncedCount: 1,
3391
+ complainedCount: 0,
3392
+ failedCount: 0,
3393
+ suppressedCount: 2,
3394
+ unsubscribedCount: 0,
3395
+ maxRecipients: 0,
3396
+ batchSize: 50,
3397
+ createdAt: 1765526395000,
3398
+ updatedAt: 1765526460000,
3399
+ },
3400
+ "email.campaign.recipients.add": {
3401
+ added: 47,
3402
+ duplicates: 2,
3403
+ suppressed: 1,
3404
+ invalid: 0,
3405
+ totalRecipients: 120,
3406
+ },
3407
+ "email.campaign.preview": {
3408
+ campaignId: "ecmp_abc123",
3409
+ previews: [
3410
+ {
3411
+ recipientId: "ecr_abc123",
3412
+ to: "ada@lovelace.dev",
3413
+ subject: "Hi Ada",
3414
+ htmlBody: "<p>Hi Ada, saw your work at Lovelace Labs.</p>",
3415
+ },
3416
+ ],
3417
+ },
3418
+ "email.campaign.submit": {
3419
+ ok: true,
3420
+ summary: {
3421
+ campaignId: "ecmp_abc123",
3422
+ status: "sending",
3423
+ totalRecipients: 120,
3424
+ queuedCount: 120,
3425
+ sendingCount: 0,
3426
+ sentCount: 0,
3427
+ deliveredCount: 0,
3428
+ openedCount: 0,
3429
+ clickedCount: 0,
3430
+ bouncedCount: 0,
3431
+ complainedCount: 0,
3432
+ failedCount: 0,
3433
+ suppressedCount: 2,
3434
+ unsubscribedCount: 0,
3435
+ },
3436
+ },
3437
+ "email.campaign.pause": {
3438
+ campaignId: "ecmp_abc123",
3439
+ status: "paused",
3440
+ totalRecipients: 120,
3441
+ queuedCount: 70,
3442
+ sendingCount: 0,
3443
+ sentCount: 50,
3444
+ deliveredCount: 48,
3445
+ openedCount: 12,
3446
+ clickedCount: 3,
3447
+ bouncedCount: 1,
3448
+ complainedCount: 0,
3449
+ failedCount: 0,
3450
+ suppressedCount: 2,
3451
+ unsubscribedCount: 0,
3452
+ },
3453
+ "email.campaign.resume": {
3454
+ campaignId: "ecmp_abc123",
3455
+ status: "sending",
3456
+ totalRecipients: 120,
3457
+ queuedCount: 70,
3458
+ sendingCount: 0,
3459
+ sentCount: 50,
3460
+ deliveredCount: 48,
3461
+ openedCount: 12,
3462
+ clickedCount: 3,
3463
+ bouncedCount: 1,
3464
+ complainedCount: 0,
3465
+ failedCount: 0,
3466
+ suppressedCount: 2,
3467
+ unsubscribedCount: 0,
3468
+ },
3469
+ "email.campaign.cancel": {
3470
+ campaignId: "ecmp_abc123",
3471
+ status: "cancelled",
3472
+ totalRecipients: 120,
3473
+ queuedCount: 70,
3474
+ sendingCount: 0,
3475
+ sentCount: 50,
3476
+ deliveredCount: 48,
3477
+ openedCount: 12,
3478
+ clickedCount: 3,
3479
+ bouncedCount: 1,
3480
+ complainedCount: 0,
3481
+ failedCount: 0,
3482
+ suppressedCount: 2,
3483
+ unsubscribedCount: 0,
3484
+ },
3485
+ "cron.list": {
3486
+ jobs: [
3487
+ {
3488
+ id: "trg_cron001",
3489
+ name: "Daily digest",
3490
+ enabled: true,
3491
+ deleteAfterRun: false,
3492
+ createdAtMs: 1765526400000,
3493
+ updatedAtMs: 1765526400000,
3494
+ schedule: { kind: "cron", expr: "0 9 * * *", tz: "America/New_York" },
3495
+ sessionTarget: "isolated",
3496
+ wakeMode: "now",
3497
+ payload: { kind: "agentTurn", message: "Summarize open CRM tasks." },
3498
+ state: { nextRunAtMs: 1765612800000, lastStatus: "ok" },
3499
+ },
3500
+ ],
3501
+ cronStatus: { enabled: true, nextWakeAtMs: 1765612800000 },
3502
+ },
3503
+ "cron.history": {
3504
+ entries: [
3505
+ {
3506
+ ts: 1765526400000,
3507
+ jobId: "trg_cron001",
3508
+ action: "finished",
3509
+ status: "ok",
3510
+ summary: "Summarized 3 open tasks.",
3511
+ sessionId: "th_abc123",
3512
+ runAtMs: 1765526350000,
3513
+ durationMs: 45000,
3514
+ nextRunAtMs: 1765612800000,
3515
+ },
3516
+ ],
3517
+ },
3518
+ "cron.get": {
3519
+ id: "trg_cron001",
3520
+ name: "Daily digest",
3521
+ enabled: true,
3522
+ deleteAfterRun: false,
3523
+ createdAtMs: 1765526400000,
3524
+ updatedAtMs: 1765526400000,
3525
+ schedule: { kind: "every", everyMs: 86400000 },
3526
+ sessionTarget: "isolated",
3527
+ wakeMode: "now",
3528
+ payload: { kind: "agentTurn", message: "Summarize open CRM tasks." },
3529
+ state: { nextRunAtMs: 1765612800000 },
3530
+ },
3531
+ "cron.create": { jobId: "trg_cron001", nextFireAt: 1765612800000 },
3532
+ "cron.update": { jobId: "trg_cron001", nextFireAt: 1765612800000 },
3533
+ "cron.delete": { ok: true },
3534
+ "cron.enable": { jobId: "trg_cron001", nextFireAt: 1765612800000 },
3535
+ "cron.disable": { jobId: "trg_cron001" },
3536
+ "cron.run": {
3537
+ runId: "rn_def456",
3538
+ threadId: "th_abc123",
3539
+ target: "chat_turn",
3540
+ },
3541
+ "cron.runs": {
3542
+ entries: [
3543
+ {
3544
+ ts: 1765526400000,
3545
+ jobId: "trg_cron001",
3546
+ action: "finished",
3547
+ status: "ok",
3548
+ runAtMs: 1765526350000,
3549
+ durationMs: 45000,
3550
+ },
3551
+ ],
3552
+ },
3553
+ "files.list": [
3554
+ {
3555
+ _id: "ft_abc123",
3556
+ _creationTime: 1765526400000,
3557
+ path: "/prospects",
3558
+ parentPath: "/",
3559
+ isDir: true,
3560
+ mtime: 1765526400000,
3561
+ lastModifiedBy: "user:us_xyz789",
3562
+ },
3563
+ {
3564
+ _id: "ft_def456",
3565
+ _creationTime: 1765526400000,
3566
+ path: "/README.md",
3567
+ parentPath: "/",
3568
+ isDir: false,
3569
+ size: 2048,
3570
+ mtime: 1765526400000,
3571
+ contentHash: "9f86d081884c7d65",
3572
+ lastModifiedBy: "api-v1",
3573
+ },
3574
+ ],
3575
+ "files.downloadUrl":
3576
+ "https://happy-animal-123.convex.cloud/api/storage/abc123?download=README.md",
3577
+ "files.delete": { path: "/README.md" },
3578
+ "files.move": {
3579
+ ok: true,
3580
+ from: "/drafts/report.md",
3581
+ to: "/reports/q2.md",
3582
+ moved: [{ from: "/drafts/report.md", to: "/reports/q2.md" }],
3583
+ },
3584
+ "files.stage": {
3585
+ ok: true,
3586
+ staged: [
3587
+ {
3588
+ path: "/prospects/leads.csv",
3589
+ size: 1024,
3590
+ result: {
3591
+ path: "/prospects/leads.csv",
3592
+ contentHash: "9f86d081884c7d65",
3593
+ },
3594
+ },
3595
+ ],
3596
+ },
3597
+ "search.web": {
3598
+ results: [
3599
+ {
3600
+ url: "https://example.com/ai-crm",
3601
+ title: "AI CRM workflows in 2026",
3602
+ publishedDate: "2026-05-01T00:00:00.000Z",
3603
+ author: "Jane Doe",
3604
+ id: "https://example.com/ai-crm",
3605
+ },
3606
+ ],
3607
+ resolvedSearchType: "neural",
3608
+ requestId: "req_abc123",
3609
+ costDollars: { total: 0.005 },
3610
+ },
3611
+ "search.contents": {
3612
+ results: [
3613
+ {
3614
+ url: "https://example.com/ai-crm",
3615
+ title: "AI CRM workflows in 2026",
3616
+ text: "The article content...",
3617
+ summary: "AI CRMs automate lead routing.",
3618
+ },
3619
+ ],
3620
+ costDollars: { total: 0.002 },
3621
+ },
3622
+ "search.answer": {
3623
+ answer: "Dench is an AI agent workspace with a built-in CRM.",
3624
+ citations: [
3625
+ {
3626
+ url: "https://www.dench.com",
3627
+ title: "Dench",
3628
+ id: "https://www.dench.com",
3629
+ },
3630
+ ],
3631
+ costDollars: { total: 0.005 },
3632
+ },
3633
+ "image.generate": {
3634
+ ok: true,
3635
+ model: "gpt-image-2",
3636
+ endpoint: "generations",
3637
+ prompt: "A minimal flat-vector app icon",
3638
+ quality: "auto",
3639
+ requestedSize: "1024x1024",
3640
+ format: "png",
3641
+ mimeType: "image/png",
3642
+ estimatedCostUsd: 0.053,
3643
+ b64_json: "iVBORw0KGgoAAAANS...",
3644
+ path: "/image-generations/20260612-app-icon.png",
3645
+ signedUrl: "https://happy-animal-123.convex.cloud/api/storage/img123",
3646
+ sizeBytes: 245760,
3647
+ usage: { inputTokens: 12, outputTokens: 1056, totalTokens: 1068 },
3648
+ },
3649
+ "image.edit": {
3650
+ ok: true,
3651
+ model: "gpt-image-2",
3652
+ endpoint: "edits",
3653
+ prompt: "Make the background transparent",
3654
+ quality: "auto",
3655
+ requestedSize: "1024x1024",
3656
+ format: "png",
3657
+ mimeType: "image/png",
3658
+ estimatedCostUsd: 0.066,
3659
+ b64_json: "iVBORw0KGgoAAAANS...",
3660
+ path: "/image-generations/20260612-app-icon-edit.png",
3661
+ signedUrl: "https://happy-animal-123.convex.cloud/api/storage/img124",
3662
+ sizeBytes: 198432,
3663
+ },
3664
+ "apps.list": {
3665
+ items: [
3666
+ {
3667
+ id: "ca_github01",
3668
+ connectionId: "ca_github01",
3669
+ toolkit: { slug: "github", name: "GitHub" },
3670
+ status: "ACTIVE",
3671
+ createdAt: "2026-06-01T12:00:00.000Z",
3672
+ updatedAt: "2026-06-01T12:00:00.000Z",
3673
+ account: {
3674
+ stableId: "octocat",
3675
+ label: "octocat",
3676
+ email: "octo@github.com",
3677
+ },
3678
+ },
3679
+ ],
3680
+ connections: [
3681
+ {
3682
+ id: "ca_github01",
3683
+ connectionId: "ca_github01",
3684
+ toolkit: { slug: "github", name: "GitHub" },
3685
+ status: "ACTIVE",
3686
+ createdAt: "2026-06-01T12:00:00.000Z",
3687
+ updatedAt: "2026-06-01T12:00:00.000Z",
3688
+ account: {
3689
+ stableId: "octocat",
3690
+ label: "octocat",
3691
+ email: "octo@github.com",
3692
+ },
3693
+ },
3694
+ ],
3695
+ raw: [],
3696
+ },
3697
+ "tool.status": {
3698
+ items: [
3699
+ {
3700
+ id: "ca_gmail01",
3701
+ connectionId: "ca_gmail01",
3702
+ toolkit: { slug: "gmail", name: "Gmail" },
3703
+ status: "ACTIVE",
3704
+ createdAt: "2026-06-01T12:00:00.000Z",
3705
+ updatedAt: "2026-06-01T12:00:00.000Z",
3706
+ account: { stableId: "ada@example.com", label: "ada@example.com" },
3707
+ },
3708
+ ],
3709
+ connections: [
3710
+ {
3711
+ id: "ca_gmail01",
3712
+ connectionId: "ca_gmail01",
3713
+ toolkit: { slug: "gmail", name: "Gmail" },
3714
+ status: "ACTIVE",
3715
+ createdAt: "2026-06-01T12:00:00.000Z",
3716
+ updatedAt: "2026-06-01T12:00:00.000Z",
3717
+ account: { stableId: "ada@example.com", label: "ada@example.com" },
3718
+ },
3719
+ ],
3720
+ raw: [],
3721
+ },
3722
+ "tool.connect": {
3723
+ redirect_url: "https://backend.composio.dev/s/abc123",
3724
+ connection_id: "ca_github01",
3725
+ },
3726
+ "tool.search": {
3727
+ success: true,
3728
+ error: null,
3729
+ results: [
3730
+ {
3731
+ use_case: "fetch recent emails",
3732
+ primary_tool_slugs: ["GMAIL_FETCH_EMAILS"],
3733
+ toolkits: ["gmail"],
3734
+ },
3735
+ ],
3736
+ toolkit_connection_statuses: [
3737
+ { toolkit: "gmail", has_active_connection: true },
3738
+ ],
3739
+ tool_schemas: {
3740
+ GMAIL_FETCH_EMAILS: {
3741
+ toolkit: "gmail",
3742
+ tool_slug: "GMAIL_FETCH_EMAILS",
3743
+ execution_ref: "eyJzZXNzaW9uIjoi...",
3744
+ execution_ref_version: 1,
3745
+ },
3746
+ },
3747
+ session: { id: "trs_abc123", generate_id: true },
3748
+ execution_ref_version: 1,
3749
+ },
3750
+ "tool.run": {
3751
+ data: { messages: [{ id: "msg01", subject: "Quick intro" }] },
3752
+ error: null,
3753
+ log_id: "log_exec_01",
3754
+ execution_mode: "gateway_tool_router",
3755
+ tool_slug: "GMAIL_FETCH_EMAILS",
3756
+ tool_router_session_id: "trs_abc123",
3757
+ },
3758
+ "tool.disconnect": { id: "ca_github01", deleted: true },
3759
+ "agentConfig.identity.show": {
3760
+ agentConfig: {
3761
+ identity: {
3762
+ content: "# IDENTITY\nYou are Atlas...",
3763
+ updatedAt: 1765526400000,
3764
+ },
3765
+ organisation: null,
3766
+ memoryAggregate: null,
3767
+ toolsNotes: null,
3768
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3769
+ },
3770
+ userProfile: { content: "Name: Alex", updatedAt: 1765526400000 },
3771
+ userTimezone: {
3772
+ value: "America/New_York",
3773
+ source: "manual",
3774
+ updatedAt: 1765526400000,
3775
+ },
3776
+ organizationId: "org_abc123",
3777
+ },
3778
+ "agentConfig.identity.edit": {
3779
+ identity: {
3780
+ content: "# IDENTITY\nYou are Atlas...",
3781
+ updatedAt: 1765526400000,
3782
+ },
3783
+ organisation: null,
3784
+ memoryAggregate: null,
3785
+ toolsNotes: null,
3786
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3787
+ },
3788
+ "agentConfig.organisation.show": {
3789
+ agentConfig: {
3790
+ identity: null,
3791
+ organisation: {
3792
+ content: "Acme builds widgets.",
3793
+ updatedAt: 1765526400000,
3794
+ },
3795
+ memoryAggregate: null,
3796
+ toolsNotes: null,
3797
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3798
+ },
3799
+ userProfile: null,
3800
+ userTimezone: null,
3801
+ organizationId: "org_abc123",
3802
+ },
3803
+ "agentConfig.organisation.edit": {
3804
+ identity: null,
3805
+ organisation: { content: "Acme builds widgets.", updatedAt: 1765526400000 },
3806
+ memoryAggregate: null,
3807
+ toolsNotes: null,
3808
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3809
+ },
3810
+ "agentConfig.user.show": {
3811
+ agentConfig: {
3812
+ identity: null,
3813
+ organisation: null,
3814
+ memoryAggregate: null,
3815
+ toolsNotes: null,
3816
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3817
+ },
3818
+ userProfile: {
3819
+ content: "Name: Alex\nRole: Engineer",
3820
+ updatedAt: 1765526400000,
3821
+ },
3822
+ userTimezone: null,
3823
+ organizationId: "org_abc123",
3824
+ },
3825
+ "agentConfig.user.edit": {
3826
+ content: "Name: Alex\nRole: Engineer",
3827
+ updatedAt: 1765526400000,
3828
+ },
3829
+ "agentConfig.tools.show": {
3830
+ agentConfig: {
3831
+ identity: null,
3832
+ organisation: null,
3833
+ memoryAggregate: null,
3834
+ toolsNotes: {
3835
+ content: "Prefer dench tool run for Stripe.",
3836
+ updatedAt: 1765526400000,
3837
+ },
3838
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3839
+ },
3840
+ userProfile: null,
3841
+ userTimezone: null,
3842
+ organizationId: "org_abc123",
3843
+ },
3844
+ "agentConfig.tools.edit": {
3845
+ identity: null,
3846
+ organisation: null,
3847
+ memoryAggregate: null,
3848
+ toolsNotes: {
3849
+ content: "Prefer dench tool run for Stripe.",
3850
+ updatedAt: 1765526400000,
3851
+ },
3852
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3853
+ },
3854
+ "agentConfig.mem.show": {
3855
+ agentConfig: {
3856
+ identity: null,
3857
+ organisation: null,
3858
+ memoryAggregate: {
3859
+ content: "Deploys go through Vercel.",
3860
+ updatedAt: 1765526400000,
3861
+ },
3862
+ toolsNotes: null,
3863
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3864
+ },
3865
+ userProfile: null,
3866
+ userTimezone: null,
3867
+ organizationId: "org_abc123",
3868
+ },
3869
+ "agentConfig.mem.edit": {
3870
+ identity: null,
3871
+ organisation: null,
3872
+ memoryAggregate: {
3873
+ content: "Deploys go through Vercel.",
3874
+ updatedAt: 1765526400000,
3875
+ },
3876
+ toolsNotes: null,
3877
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3878
+ },
3879
+ "agentConfig.bootstrap.show": {
3880
+ agentConfig: {
3881
+ identity: null,
3882
+ organisation: null,
3883
+ memoryAggregate: null,
3884
+ toolsNotes: null,
3885
+ bootstrap: { completed: false, template: "Welcome! Let's set up." },
3886
+ },
3887
+ userProfile: null,
3888
+ userTimezone: null,
3889
+ organizationId: "org_abc123",
3890
+ },
3891
+ "agentConfig.bootstrap.complete": {
3892
+ identity: null,
3893
+ organisation: null,
3894
+ memoryAggregate: null,
3895
+ toolsNotes: null,
3896
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3897
+ },
3898
+ "agentConfig.bootstrap.template": {
3899
+ identity: null,
3900
+ organisation: null,
3901
+ memoryAggregate: null,
3902
+ toolsNotes: null,
3903
+ bootstrap: { completed: false, template: "Welcome! Let's set up." },
3904
+ },
3905
+ "agentConfig.model.default": {
3906
+ defaultChatModelId: "anthropic/claude-sonnet-4",
3907
+ },
3908
+ "agentConfig.model.thread": {
3909
+ threadId: "th_abc123",
3910
+ modelOverride: "anthropic/claude-opus-4",
3911
+ },
3912
+ "agentConfig.daily.today": {
3913
+ agentConfig: {
3914
+ identity: null,
3915
+ organisation: null,
3916
+ memoryAggregate: null,
3917
+ toolsNotes: null,
3918
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3919
+ },
3920
+ userProfile: null,
3921
+ userTimezone: null,
3922
+ organizationId: "org_abc123",
3923
+ },
3924
+ "agentConfig.daily.show": {
3925
+ agentConfig: {
3926
+ identity: null,
3927
+ organisation: null,
3928
+ memoryAggregate: null,
3929
+ toolsNotes: null,
3930
+ bootstrap: { completed: true, completedAt: 1765526400000 },
3931
+ },
3932
+ userProfile: null,
3933
+ userTimezone: null,
3934
+ organizationId: "org_abc123",
3935
+ },
1095
3936
  };