robotrock 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/agent-admin.d.ts +82 -0
  2. package/dist/agent-admin.js +938 -0
  3. package/dist/agent-admin.js.map +1 -0
  4. package/dist/ai/index.d.ts +6 -5
  5. package/dist/ai/index.js +407 -188
  6. package/dist/ai/index.js.map +1 -1
  7. package/dist/ai/trigger.d.ts +4 -3
  8. package/dist/ai/trigger.js +407 -188
  9. package/dist/ai/trigger.js.map +1 -1
  10. package/dist/ai/workflow.d.ts +4 -3
  11. package/dist/ai/workflow.js +404 -185
  12. package/dist/ai/workflow.js.map +1 -1
  13. package/dist/auth-headers-qL-ZeEtd.d.ts +13 -0
  14. package/dist/{client-XTnFHGFE.d.ts → client-YO9Y1rkH.d.ts} +29 -17
  15. package/dist/eve/agent/index.d.ts +11 -35
  16. package/dist/eve/agent/index.js +678 -146
  17. package/dist/eve/agent/index.js.map +1 -1
  18. package/dist/eve/index.d.ts +5 -2
  19. package/dist/eve/index.js +195 -2
  20. package/dist/eve/index.js.map +1 -1
  21. package/dist/eve/tools/admin/assign-tasks.d.ts +39 -0
  22. package/dist/eve/tools/admin/assign-tasks.js +1060 -0
  23. package/dist/eve/tools/admin/assign-tasks.js.map +1 -0
  24. package/dist/eve/tools/admin/manage-groups.d.ts +53 -0
  25. package/dist/eve/tools/admin/manage-groups.js +1218 -0
  26. package/dist/eve/tools/admin/manage-groups.js.map +1 -0
  27. package/dist/eve/tools/admin/manage-team-members.d.ts +45 -0
  28. package/dist/eve/tools/admin/manage-team-members.js +1160 -0
  29. package/dist/eve/tools/admin/manage-team-members.js.map +1 -0
  30. package/dist/eve/tools/admin/query-tasks.d.ts +71 -0
  31. package/dist/eve/tools/admin/query-tasks.js +1161 -0
  32. package/dist/eve/tools/admin/query-tasks.js.map +1 -0
  33. package/dist/eve/tools/catalog/search-products.d.ts +57 -0
  34. package/dist/eve/tools/catalog/search-products.js +94 -0
  35. package/dist/eve/tools/catalog/search-products.js.map +1 -0
  36. package/dist/eve/tools/identity/index.d.ts +2 -0
  37. package/dist/eve/tools/identity/index.js +117 -27
  38. package/dist/eve/tools/identity/index.js.map +1 -1
  39. package/dist/eve/tools/identity/my-access.d.ts +6 -46
  40. package/dist/eve/tools/identity/my-access.js +91 -10
  41. package/dist/eve/tools/identity/my-access.js.map +1 -1
  42. package/dist/eve/tools/identity/whoami.d.ts +7 -8
  43. package/dist/eve/tools/identity/whoami.js +33 -17
  44. package/dist/eve/tools/identity/whoami.js.map +1 -1
  45. package/dist/eve/tools/inbox/create-task.d.ts +5 -4
  46. package/dist/eve/tools/inbox/create-task.js +365 -137
  47. package/dist/eve/tools/inbox/create-task.js.map +1 -1
  48. package/dist/eve/tools/inbox/index.d.ts +1 -0
  49. package/dist/eve/tools/inbox/index.js +365 -137
  50. package/dist/eve/tools/inbox/index.js.map +1 -1
  51. package/dist/eve/tools/index.d.ts +7 -0
  52. package/dist/eve/tools/index.js +1362 -168
  53. package/dist/eve/tools/index.js.map +1 -1
  54. package/dist/{index-BL9qKHA8.d.ts → index-DoQN48Bm.d.ts} +61 -2
  55. package/dist/index.d.ts +6 -3
  56. package/dist/index.js +325 -119
  57. package/dist/index.js.map +1 -1
  58. package/dist/schemas/index.d.ts +6 -1
  59. package/dist/schemas/index.js +177 -48
  60. package/dist/schemas/index.js.map +1 -1
  61. package/dist/{tool-approval-bridge-C4bTm8vu.d.ts → tool-approval-bridge-aMA79Z1B.d.ts} +1 -1
  62. package/dist/tool-reply-guidance-C3qrT1In.d.ts +25 -0
  63. package/dist/trigger/index.d.ts +2 -1
  64. package/dist/trigger/index.js +310 -108
  65. package/dist/trigger/index.js.map +1 -1
  66. package/dist/{trigger-Dn0DFiyU.d.ts → trigger-CXrbKVCL.d.ts} +2 -2
  67. package/dist/workflow/index.d.ts +2 -1
  68. package/dist/workflow/index.js +310 -108
  69. package/dist/workflow/index.js.map +1 -1
  70. package/package.json +28 -4
@@ -1,9 +1,9 @@
1
1
  // src/eve/tools/inbox/create-task.ts
2
2
  import { defineTool } from "eve/tools";
3
- import { z as z4 } from "zod";
3
+ import { z as z6 } from "zod";
4
4
 
5
5
  // src/schemas/index.ts
6
- import { z as z2 } from "zod";
6
+ import { z as z4 } from "zod";
7
7
 
8
8
  // ../core/src/utils/safe-url.ts
9
9
  var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
@@ -390,13 +390,27 @@ var createAgentChatBodySchema = z.object({
390
390
  eveConnectionId: z.string().min(1).optional(),
391
391
  /** Source application id; groups the chat under an inbox section. */
392
392
  app: z.string().min(1).optional(),
393
- assignTo: assignToSchema.optional(),
393
+ /** Email of the user who owns the chat. Required unless `parentChatId` is set. */
394
+ ownerEmail: z.string().email().optional(),
394
395
  title: z.string().min(1),
395
396
  messages: z.array(agentChatSeedMessageSchema).default([]),
396
397
  /** Provenance label stored on the session ("cron" | "agent" | ...). */
397
398
  source: z.string().min(1).optional()
398
399
  }).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
399
400
  message: "Provide either agentIdentifier or parentChatId"
401
+ }).refine((data) => Boolean(data.ownerEmail || data.parentChatId), {
402
+ message: "Provide ownerEmail unless parentChatId is set"
403
+ });
404
+ var agentChatAuditToolBodySchema = z.object({
405
+ eveSessionId: z.string().min(1),
406
+ userId: z.string().min(1),
407
+ toolCallId: z.string().min(1),
408
+ toolName: z.string().min(1),
409
+ input: z.record(z.string(), z.unknown()).default({}),
410
+ success: z.boolean(),
411
+ status: z.enum(["completed", "failed", "rejected"]),
412
+ error: z.string().optional(),
413
+ idempotencyKey: z.string().optional()
400
414
  });
401
415
  var agentChatAuditInputBodySchema = z.object({
402
416
  eveSessionId: z.string().min(1),
@@ -436,62 +450,175 @@ var agentChatLinkTaskBodySchema = z.object({
436
450
  toolCallId: z.string().min(1)
437
451
  });
438
452
 
453
+ // ../core/src/schemas/tool-result-display.ts
454
+ import { z as z2 } from "zod";
455
+ var toolDisplayMetadataSchema = z2.object({
456
+ widget: z2.string().optional(),
457
+ title: z2.string().optional(),
458
+ description: z2.string().optional()
459
+ });
460
+ var toolDisplayEnvelopeSchema = z2.object({
461
+ display: toolDisplayMetadataSchema.optional(),
462
+ data: z2.record(z2.string(), z2.unknown()),
463
+ ui: z2.record(
464
+ z2.string(),
465
+ z2.object({
466
+ "ui:widget": z2.string().optional(),
467
+ "ui:title": z2.string().optional(),
468
+ "ui:description": z2.string().optional(),
469
+ "ui:options": z2.record(z2.string(), z2.unknown()).optional()
470
+ }).passthrough()
471
+ ).optional()
472
+ });
473
+
474
+ // ../core/src/schemas/agent-admin.ts
475
+ import { z as z3 } from "zod";
476
+ var tenantRoleSchema = z3.enum(["admin", "member"]);
477
+ var agentAdminUserSchema = z3.object({
478
+ id: z3.string(),
479
+ email: z3.string().email(),
480
+ name: z3.string()
481
+ });
482
+ var agentAdminMemberSchema = z3.object({
483
+ userId: z3.string(),
484
+ role: z3.string(),
485
+ membershipKind: z3.enum(["team", "assignee"]),
486
+ hasLoggedIn: z3.boolean(),
487
+ user: agentAdminUserSchema
488
+ });
489
+ var agentAdminGroupSchema = z3.object({
490
+ id: z3.string(),
491
+ name: z3.string(),
492
+ slug: z3.string(),
493
+ description: z3.string().nullable(),
494
+ memberCount: z3.number().optional()
495
+ });
496
+ var agentAdminGroupDetailSchema = agentAdminGroupSchema.extend({
497
+ members: z3.array(
498
+ z3.object({
499
+ userId: z3.string(),
500
+ user: agentAdminUserSchema
501
+ })
502
+ )
503
+ });
504
+ var agentAdminTaskSummarySchema = z3.object({
505
+ id: z3.string(),
506
+ convexId: z3.string(),
507
+ status: z3.string(),
508
+ type: z3.string().nullable(),
509
+ name: z3.string().nullable(),
510
+ description: z3.string().nullable(),
511
+ validUntil: z3.number(),
512
+ createdAt: z3.number(),
513
+ threadPriority: z3.string().nullable(),
514
+ handledByUserId: z3.string().nullable()
515
+ });
516
+ var inviteMemberBodySchema = z3.object({
517
+ email: z3.string().email(),
518
+ role: tenantRoleSchema.optional()
519
+ });
520
+ var updateMemberRoleBodySchema = z3.object({
521
+ role: tenantRoleSchema
522
+ });
523
+ var createGroupBodySchema = z3.object({
524
+ name: z3.string().min(1),
525
+ description: z3.string().optional()
526
+ });
527
+ var updateGroupBodySchema = z3.object({
528
+ name: z3.string().min(1).optional(),
529
+ description: z3.string().optional()
530
+ });
531
+ var addGroupMemberBodySchema = z3.object({
532
+ userId: z3.string().min(1).describe("Convex user id or member email.")
533
+ });
534
+ var listTasksQuerySchema = z3.object({
535
+ statusFilter: z3.enum(["all", "open", "handled", "expired"]).optional(),
536
+ typeFilter: z3.string().optional(),
537
+ appFilter: z3.string().optional(),
538
+ sortField: z3.enum(["type", "date", "status", "validUntil"]).optional(),
539
+ sortDirection: z3.enum(["asc", "desc"]).optional(),
540
+ limit: z3.coerce.number().int().positive().max(100).optional(),
541
+ cursor: z3.string().optional()
542
+ });
543
+ var searchTasksQuerySchema = z3.object({
544
+ q: z3.string().min(1),
545
+ limit: z3.coerce.number().int().positive().max(100).optional()
546
+ });
547
+ var assignTasksResultSchema = z3.object({
548
+ taskId: z3.string(),
549
+ success: z3.boolean(),
550
+ message: z3.string().optional(),
551
+ name: z3.string().nullable().optional(),
552
+ description: z3.string().nullable().optional(),
553
+ type: z3.string().nullable().optional()
554
+ });
555
+ var assignTasksResponseSchema = z3.object({
556
+ results: z3.array(assignTasksResultSchema)
557
+ });
558
+ var assignTasksBodySchema = z3.object({
559
+ taskIds: z3.array(z3.string().min(1)).min(1).max(100),
560
+ assignTo: assignToSchema.refine(
561
+ (value) => (value.users?.length ?? 0) > 0 || (value.groups?.length ?? 0) > 0,
562
+ { message: "assignTo needs at least one user email or group slug." }
563
+ )
564
+ });
565
+
439
566
  // src/schemas/index.ts
440
- var handlerUrlSchema2 = z2.string().refine((url) => isAllowedHandlerUrl(url), {
567
+ var handlerUrlSchema2 = z4.string().refine((url) => isAllowedHandlerUrl(url), {
441
568
  message: HANDLER_URL_ERROR
442
569
  });
443
- var jsonSchema7Schema2 = z2.custom(
570
+ var jsonSchema7Schema2 = z4.custom(
444
571
  (val) => typeof val === "object" && val !== null,
445
572
  { message: "Must be a valid JSON Schema object" }
446
573
  );
447
- var uiSchemaSchema2 = z2.custom((val) => typeof val === "object" && val !== null, {
574
+ var uiSchemaSchema2 = z4.custom((val) => typeof val === "object" && val !== null, {
448
575
  message: "Must be a valid UiSchema object"
449
576
  });
450
- var webhookHandlerSchema2 = z2.object({
451
- type: z2.literal("webhook"),
577
+ var webhookHandlerSchema2 = z4.object({
578
+ type: z4.literal("webhook"),
452
579
  url: handlerUrlSchema2,
453
- headers: z2.record(z2.string(), z2.string())
580
+ headers: z4.record(z4.string(), z4.string())
454
581
  });
455
582
  var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
456
- type: z2.literal("trigger"),
457
- tokenId: z2.string().min(1)
583
+ type: z4.literal("trigger"),
584
+ tokenId: z4.string().min(1)
458
585
  });
459
- var handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
460
- var taskActionInputSchema2 = z2.object({
461
- id: z2.string().min(1),
462
- title: z2.string().min(1),
463
- description: z2.string().optional(),
586
+ var handlerSchema2 = z4.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
587
+ var taskActionInputSchema2 = z4.object({
588
+ id: z4.string().min(1),
589
+ title: z4.string().min(1),
590
+ description: z4.string().optional(),
464
591
  schema: jsonSchema7Schema2.optional(),
465
592
  ui: uiSchemaSchema2.optional(),
466
- data: z2.record(z2.string(), z2.unknown()).optional()
593
+ data: z4.record(z4.string(), z4.unknown()).optional()
467
594
  });
468
595
  var taskActionSchema2 = taskActionInputSchema2.extend({
469
- handlers: z2.array(handlerSchema2).min(1).optional()
596
+ handlers: z4.array(handlerSchema2).min(1).optional()
470
597
  });
471
- var uiFieldSchemaSchema2 = z2.object({
472
- "ui:widget": z2.string().optional(),
473
- "ui:title": z2.string().optional(),
474
- "ui:description": z2.string().optional(),
475
- "ui:options": z2.record(z2.string(), z2.unknown()).optional(),
476
- items: z2.lazy(() => z2.record(z2.string(), uiFieldSchemaSchema2)).optional()
598
+ var uiFieldSchemaSchema2 = z4.object({
599
+ "ui:widget": z4.string().optional(),
600
+ "ui:title": z4.string().optional(),
601
+ "ui:description": z4.string().optional(),
602
+ "ui:options": z4.record(z4.string(), z4.unknown()).optional(),
603
+ items: z4.lazy(() => z4.record(z4.string(), uiFieldSchemaSchema2)).optional()
477
604
  }).passthrough();
478
- var contextUiSchema2 = z2.record(z2.string(), uiFieldSchemaSchema2).optional();
479
- var contextDataSchema2 = z2.object({
480
- data: z2.record(z2.string(), z2.unknown()),
605
+ var contextUiSchema2 = z4.record(z4.string(), uiFieldSchemaSchema2).optional();
606
+ var contextDataSchema2 = z4.object({
607
+ data: z4.record(z4.string(), z4.unknown()),
481
608
  ui: contextUiSchema2
482
609
  }).optional();
483
610
  var TASK_CONTEXT_FORMAT_VERSION2 = 2;
484
- var taskContextObjectBaseSchema2 = z2.object({
485
- app: z2.string().min(1).optional(),
486
- type: z2.string().min(1),
487
- name: z2.string().min(1),
488
- description: z2.string().optional(),
489
- validUntil: z2.string().optional(),
611
+ var taskContextObjectBaseSchema2 = z4.object({
612
+ app: z4.string().min(1).optional(),
613
+ type: z4.string().min(1),
614
+ name: z4.string().min(1),
615
+ description: z4.string().optional(),
616
+ validUntil: z4.string().optional(),
490
617
  context: contextDataSchema2,
491
- contextVersion: z2.literal(2).optional(),
618
+ contextVersion: z4.literal(2).optional(),
492
619
  /** @deprecated Use `contextVersion`. Accepted on ingest only. */
493
- version: z2.literal(2).optional(),
494
- actions: z2.array(taskActionSchema2).min(1, "At least one action is required")
620
+ version: z4.literal(2).optional(),
621
+ actions: z4.array(taskActionSchema2).min(1, "At least one action is required")
495
622
  });
496
623
  function normalizeTaskContextVersion2(data) {
497
624
  const { version: legacyVersion, contextVersion, ...rest } = data;
@@ -507,7 +634,7 @@ function refineContextPublicUrls2(data, ctx) {
507
634
  const error = validateContextPublicUrls(data.context);
508
635
  if (error) {
509
636
  ctx.addIssue({
510
- code: z2.ZodIssueCode.custom,
637
+ code: z4.ZodIssueCode.custom,
511
638
  message: error,
512
639
  path: ["context"]
513
640
  });
@@ -516,9 +643,9 @@ function refineContextPublicUrls2(data, ctx) {
516
643
  var taskContextSchema2 = taskContextObjectSchema2.superRefine(
517
644
  refineContextPublicUrls2
518
645
  );
519
- var assignToSchema2 = z2.object({
520
- users: z2.array(z2.string().email()).optional(),
521
- groups: z2.array(z2.string().min(1)).optional()
646
+ var assignToSchema2 = z4.object({
647
+ users: z4.array(z4.string().email()).optional(),
648
+ groups: z4.array(z4.string().min(1)).optional()
522
649
  }).refine(
523
650
  (data) => {
524
651
  const groups = data.groups ?? [];
@@ -529,7 +656,7 @@ var assignToSchema2 = z2.object({
529
656
  },
530
657
  { message: 'Cannot combine "all" with other group slugs' }
531
658
  );
532
- var threadUpdateMessageSchema2 = z2.string().min(1).max(500);
659
+ var threadUpdateMessageSchema2 = z4.string().min(1).max(500);
533
660
  var threadUpdateStatuses2 = [
534
661
  "info",
535
662
  "queued",
@@ -539,15 +666,15 @@ var threadUpdateStatuses2 = [
539
666
  "failed",
540
667
  "cancelled"
541
668
  ];
542
- var threadUpdateStatusSchema2 = z2.enum(threadUpdateStatuses2);
543
- var threadUpdateInputSchema2 = z2.object({
669
+ var threadUpdateStatusSchema2 = z4.enum(threadUpdateStatuses2);
670
+ var threadUpdateInputSchema2 = z4.object({
544
671
  message: threadUpdateMessageSchema2,
545
672
  status: threadUpdateStatusSchema2.optional()
546
673
  });
547
674
  var taskPriorities2 = ["low", "normal", "high", "urgent"];
548
- var taskPrioritySchema2 = z2.enum(taskPriorities2);
549
- var agentTelemetrySchema2 = z2.object({
550
- version: z2.string().min(1)
675
+ var taskPrioritySchema2 = z4.enum(taskPriorities2);
676
+ var agentTelemetrySchema2 = z4.object({
677
+ version: z4.string().min(1)
551
678
  });
552
679
  var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
553
680
  assignTo: assignToSchema2.optional(),
@@ -555,7 +682,7 @@ var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
555
682
  * Groups related tasks together. When omitted, the server generates one and
556
683
  * returns it so the caller can reuse it on later tasks in the same thread.
557
684
  */
558
- threadId: z2.string().min(1).optional(),
685
+ threadId: z4.string().min(1).optional(),
559
686
  /**
560
687
  * Optional thread priority. When set, applies to the whole thread and
561
688
  * overwrites any previous priority. Omit on later tasks to leave unchanged.
@@ -570,6 +697,65 @@ var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
570
697
  }).transform(normalizeTaskContextVersion2).superRefine(refineContextPublicUrls2);
571
698
  var threadUpdateBodySchema = threadUpdateInputSchema2;
572
699
 
700
+ // ../core/src/handler-retry.ts
701
+ var HANDLER_RETRY_DELAYS_MS = [
702
+ 6e4,
703
+ // 1m
704
+ 3e5,
705
+ // 5m
706
+ 18e5,
707
+ // 30m
708
+ 36e5,
709
+ // 1h
710
+ 216e5,
711
+ // 6h
712
+ 864e5,
713
+ // 24h
714
+ 1728e5
715
+ // 48h
716
+ ];
717
+ var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
718
+
719
+ // ../core/src/attribution/index.ts
720
+ import { z as z5 } from "zod";
721
+
722
+ // ../core/src/app-url.ts
723
+ var PRODUCTION_APP_URL = "https://app.robotrock.io";
724
+ var PRODUCTION_API_URL = "https://api.robotrock.io/v1";
725
+ var DEV_API_URL = "http://localhost:4001/v1";
726
+ var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
727
+ function normalizeRobotRockApiBaseUrl(baseUrl) {
728
+ const trimmed = baseUrl.trim().replace(/\/+$/, "");
729
+ if (trimmed.endsWith("/v1")) {
730
+ return trimmed;
731
+ }
732
+ return `${trimmed}/v1`;
733
+ }
734
+ function getRobotRockApiBaseUrl() {
735
+ const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
736
+ if (explicit) {
737
+ return normalizeRobotRockApiBaseUrl(explicit);
738
+ }
739
+ if (process.env.NODE_ENV === "production") {
740
+ return PRODUCTION_API_URL;
741
+ }
742
+ return DEV_API_URL;
743
+ }
744
+
745
+ // ../core/src/attribution/index.ts
746
+ var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
747
+ var attributionSchema = z5.object({
748
+ utmSource: z5.string().optional(),
749
+ utmMedium: z5.string().optional(),
750
+ utmCampaign: z5.string().optional(),
751
+ utmContent: z5.string().optional(),
752
+ utmTerm: z5.string().optional(),
753
+ gclid: z5.string().optional(),
754
+ landingUrl: z5.string().optional(),
755
+ referrer: z5.string().optional(),
756
+ capturedAt: z5.number()
757
+ });
758
+
573
759
  // src/approval-result.ts
574
760
  var TaskTimeoutError = class extends Error {
575
761
  constructor(message) {
@@ -644,77 +830,27 @@ function getErrorMessage(data, fallback) {
644
830
  return fallback;
645
831
  }
646
832
 
647
- // ../core/src/handler-retry.ts
648
- var HANDLER_RETRY_DELAYS_MS = [
649
- 6e4,
650
- // 1m
651
- 3e5,
652
- // 5m
653
- 18e5,
654
- // 30m
655
- 36e5,
656
- // 1h
657
- 216e5,
658
- // 6h
659
- 864e5,
660
- // 24h
661
- 1728e5
662
- // 48h
663
- ];
664
- var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
665
-
666
- // ../core/src/attribution/index.ts
667
- import { z as z3 } from "zod";
668
-
669
- // ../core/src/app-url.ts
670
- var PRODUCTION_APP_URL = "https://app.robotrock.io";
671
- var PRODUCTION_API_URL = "https://api.robotrock.io/v1";
672
- var DEV_API_URL = "http://localhost:4001/v1";
673
- var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
674
- function normalizeRobotRockApiBaseUrl(baseUrl) {
675
- const trimmed = baseUrl.trim().replace(/\/+$/, "");
676
- if (trimmed.endsWith("/v1")) {
677
- return trimmed;
678
- }
679
- return `${trimmed}/v1`;
680
- }
681
- function getRobotRockApiBaseUrl() {
682
- const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
683
- if (explicit) {
684
- return normalizeRobotRockApiBaseUrl(explicit);
685
- }
686
- if (process.env.NODE_ENV === "production") {
687
- return PRODUCTION_API_URL;
688
- }
689
- return DEV_API_URL;
690
- }
691
-
692
- // ../core/src/attribution/index.ts
693
- var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
694
- var attributionSchema = z3.object({
695
- utmSource: z3.string().optional(),
696
- utmMedium: z3.string().optional(),
697
- utmCampaign: z3.string().optional(),
698
- utmContent: z3.string().optional(),
699
- utmTerm: z3.string().optional(),
700
- gclid: z3.string().optional(),
701
- landingUrl: z3.string().optional(),
702
- referrer: z3.string().optional(),
703
- capturedAt: z3.number()
704
- });
705
-
706
833
  // src/auth-headers.ts
834
+ var ROBOTROCK_ACTING_USER_ID_HEADER = "x-robotrock-acting-user-id";
707
835
  function buildRobotRockAuthHeaders(auth) {
708
836
  if (auth.kind === "apiKey") {
709
- return {
837
+ const headers2 = {
710
838
  "X-Api-Key": auth.apiKey
711
839
  };
840
+ if (auth.actingUserId?.trim()) {
841
+ headers2[ROBOTROCK_ACTING_USER_ID_HEADER] = auth.actingUserId.trim();
842
+ }
843
+ return headers2;
712
844
  }
713
- return {
845
+ const headers = {
714
846
  Authorization: `Bearer ${auth.token}`,
715
847
  "X-RobotRock-Tenant-Slug": auth.tenantSlug,
716
848
  "X-RobotRock-Connection-Id": auth.connectionId
717
849
  };
850
+ if (auth.actingUserId?.trim()) {
851
+ headers[ROBOTROCK_ACTING_USER_ID_HEADER] = auth.actingUserId.trim();
852
+ }
853
+ return headers;
718
854
  }
719
855
  function resolveRobotRockAuthConfig(overrides) {
720
856
  if (overrides?.agentService) {
@@ -858,6 +994,29 @@ function createChatsApi(config) {
858
994
  );
859
995
  }
860
996
  },
997
+ async logToolExecution(input) {
998
+ const validation = agentChatAuditToolBodySchema.safeParse(input);
999
+ if (!validation.success) {
1000
+ throw new RobotRockError(
1001
+ `Invalid audit tool input: ${validation.error.issues[0]?.message}`,
1002
+ 400,
1003
+ validation.error.issues
1004
+ );
1005
+ }
1006
+ const response = await fetch(`${config.baseUrl}/agent-chats/audit-tool`, {
1007
+ method: "POST",
1008
+ headers: headers(),
1009
+ body: JSON.stringify(validation.data)
1010
+ });
1011
+ if (!response.ok) {
1012
+ const data = await parseResponseBody(response);
1013
+ throw new RobotRockError(
1014
+ getErrorMessage(data, "Failed to log chat tool execution"),
1015
+ response.status,
1016
+ data
1017
+ );
1018
+ }
1019
+ },
861
1020
  async linkTask(input) {
862
1021
  const validation = agentChatLinkTaskBodySchema.safeParse(input);
863
1022
  if (!validation.success) {
@@ -960,7 +1119,9 @@ var RobotRock = class {
960
1119
  create: (task) => this.createTaskRequest(task),
961
1120
  get: (taskId) => this.getTaskById(taskId),
962
1121
  cancel: (taskId) => this.cancelTaskRequest(taskId),
963
- sendUpdate: (input) => this.sendThreadUpdate(input)
1122
+ sendUpdate: (input) => this.sendThreadUpdate(input),
1123
+ list: (input) => this.listTasksRequest(input),
1124
+ search: (input) => this.searchTasksRequest(input)
964
1125
  };
965
1126
  this.chats = createChatsApi({
966
1127
  baseUrl: this.baseUrl,
@@ -1157,6 +1318,47 @@ var RobotRock = class {
1157
1318
  );
1158
1319
  }
1159
1320
  }
1321
+ async listTasksRequest(input) {
1322
+ const params = new URLSearchParams();
1323
+ for (const [key, value] of Object.entries(input ?? {})) {
1324
+ if (value !== void 0 && value !== "") {
1325
+ params.set(key, String(value));
1326
+ }
1327
+ }
1328
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
1329
+ const response = await fetch(`${this.baseUrl}/tasks${suffix}`, {
1330
+ method: "GET",
1331
+ headers: this.authHeaders()
1332
+ });
1333
+ const data = await parseResponseBody(response);
1334
+ if (!response.ok) {
1335
+ throw new RobotRockError(
1336
+ getErrorMessage(data, "Failed to list tasks"),
1337
+ response.status,
1338
+ data
1339
+ );
1340
+ }
1341
+ return data;
1342
+ }
1343
+ async searchTasksRequest(input) {
1344
+ const params = new URLSearchParams({ q: input.q });
1345
+ if (input.limit !== void 0) {
1346
+ params.set("limit", String(input.limit));
1347
+ }
1348
+ const response = await fetch(`${this.baseUrl}/tasks/search?${params.toString()}`, {
1349
+ method: "GET",
1350
+ headers: this.authHeaders()
1351
+ });
1352
+ const data = await parseResponseBody(response);
1353
+ if (!response.ok) {
1354
+ throw new RobotRockError(
1355
+ getErrorMessage(data, "Failed to search tasks"),
1356
+ response.status,
1357
+ data
1358
+ );
1359
+ }
1360
+ return data;
1361
+ }
1160
1362
  };
1161
1363
  function createClient(config) {
1162
1364
  return new RobotRock(config);
@@ -1288,6 +1490,13 @@ function requireTenantCaller(ctx) {
1288
1490
  }
1289
1491
  return caller;
1290
1492
  }
1493
+ function requireAdminCaller(ctx) {
1494
+ const caller = requireTenantCaller(ctx);
1495
+ if (!caller.isAdmin) {
1496
+ throw new Error("Tenant admin access is required.");
1497
+ }
1498
+ return caller;
1499
+ }
1291
1500
 
1292
1501
  // src/eve/agent/client-from-session.ts
1293
1502
  var warnedMissingAuth = false;
@@ -1476,37 +1685,71 @@ async function postRobotRockLinkChatTask(ctx, input) {
1476
1685
  }
1477
1686
  }
1478
1687
 
1688
+ // src/eve/tool-reply-guidance.ts
1689
+ var TOOL_REPLY_GUIDANCE_FIELD = "replyGuidance";
1690
+ var WHOAMI_REPLY_GUIDANCE = "The dashboard shows a profile card with name, email, workspace, role, and groups. Do not restate those in your reply. Only add context not in the card (e.g. permissions, refund approval rules, missing group membership).";
1691
+ var MY_ACCESS_REPLY_GUIDANCE = "Access details may render in chat UI. Do not restate role, groups, or admin capabilities if already visible. Only explain what the user can or cannot do for their question (e.g. finance group required for refunds \u2265 $10,000). When access.tenantAdmin is false and the user needs manageTeam, manageGroups, or query-tasks capabilities, explain briefly then call ask_question to offer sending an admin request to tenant admins \u2014 do not tell them to find an admin manually without offering delegation first.";
1692
+ var CREATE_INBOX_TASK_REPLY_GUIDANCE = "A task card shows title, assignee, and inbox status in chat. Do not restate task ID, assignee, or delegation details from the card. Only mention next steps or answer the user's question.";
1693
+ var SEARCH_PRODUCTS_REPLY_GUIDANCE = "Product results render as a list card in chat. Do not restate product names, prices, or SKUs. Only add context not in the list (e.g. no matches, recommendations).";
1694
+ var MANAGE_TEAM_MEMBERS_LIST_REPLY_GUIDANCE = "Team members render as a list card in chat. Do not restate names, emails, or roles from the list. Only add context not shown (e.g. duplicates, next admin actions).";
1695
+ var MANAGE_TEAM_MEMBERS_DETAIL_REPLY_GUIDANCE = "Team member details render in chat UI. Do not restate name, email, or role from the card. Only add next steps or policy context.";
1696
+ var MANAGE_GROUPS_LIST_REPLY_GUIDANCE = "Groups render as a list card in chat. Do not restate group names, slugs, or descriptions from the list. Use slug (not internal id) for get, update, delete, and membership actions. Only add context not shown.";
1697
+ var MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE = "Group details render in chat UI. Do not restate fields already visible in the card. Only add next steps.";
1698
+ var QUERY_TASKS_LIST_REPLY_GUIDANCE = "Tasks render as a list card in chat. Do not restate task names, ids, or statuses from the list. Only add context not shown (e.g. filters applied, recommended next action).";
1699
+ var QUERY_TASKS_DETAIL_REPLY_GUIDANCE = "Task details render in chat UI. Do not restate fields already visible in the card. Only add analysis or next steps.";
1700
+ var ASSIGN_TASKS_REPLY_GUIDANCE = "Reassignment results render in chat UI. Do not restate task ids or assignee emails from the card. Only mention failures, partial success, or next steps.";
1701
+ var ADMIN_MUTATION_REPLY_GUIDANCE = "The action result renders in chat UI. Do not restate fields already visible in the card. Confirm outcome briefly or add next steps only.";
1702
+ function withReplyGuidance(result, guidance) {
1703
+ return {
1704
+ ...result,
1705
+ [TOOL_REPLY_GUIDANCE_FIELD]: guidance
1706
+ };
1707
+ }
1708
+
1479
1709
  // src/eve/tools/inbox/create-task.ts
1480
1710
  var CREATE_INBOX_TASK_TOOL_NAME = "create_robotrock_task";
1481
- var actionSchema = z4.object({
1482
- id: z4.string().min(1).describe("Stable action id, e.g. approve or reject."),
1483
- title: z4.string().min(1).describe("Button label shown in the inbox."),
1484
- description: z4.string().min(1).optional()
1711
+ var actionSchema = z6.object({
1712
+ id: z6.string().min(1).describe("Stable action id, e.g. approve or reject."),
1713
+ title: z6.string().min(1).describe("Button label shown in the inbox."),
1714
+ description: z6.string().min(1).optional()
1485
1715
  });
1486
- var assignToSchema3 = z4.object({
1487
- users: z4.array(z4.string().email()).optional().describe("Assignee emails \u2014 only these users (plus group members) see the task."),
1488
- groups: z4.array(z4.string().min(1)).optional().describe('Group slugs, e.g. "finance". Only members of these groups see the task.')
1716
+ var assignToSchema3 = z6.object({
1717
+ users: z6.array(z6.string().email()).optional().describe("Assignee emails \u2014 only these users (plus group members) see the task."),
1718
+ groups: z6.array(z6.string().min(1)).optional().describe(
1719
+ 'Group slugs, e.g. "finance" or virtual "admins". Virtual "all" means everyone; omit assignTo for the same effect.'
1720
+ )
1489
1721
  }).optional().refine(
1490
1722
  (value) => value === void 0 || (value.users?.length ?? 0) > 0 || (value.groups?.length ?? 0) > 0,
1491
1723
  { message: "assignTo needs at least one user email or group slug." }
1724
+ ).refine(
1725
+ (value) => {
1726
+ const groups = value?.groups ?? [];
1727
+ if (groups.includes("all") && groups.length > 1) {
1728
+ return false;
1729
+ }
1730
+ return true;
1731
+ },
1732
+ { message: 'Cannot combine "all" with other group slugs' }
1492
1733
  );
1493
- var contextSchema = z4.object({
1494
- data: z4.record(z4.string(), z4.unknown()).optional().describe("Structured fields shown in the inbox task detail."),
1495
- ui: z4.record(z4.string(), z4.unknown()).optional().describe("Optional ui:* hints keyed by context.data field name.")
1734
+ var contextSchema = z6.object({
1735
+ data: z6.record(z6.string(), z6.unknown()).optional().describe("Structured fields shown in the inbox task detail."),
1736
+ ui: z6.record(z6.string(), z6.unknown()).optional().describe(
1737
+ "Optional ui:* hints keyed by context.data field name (ui:widget, ui:title, ui:options). Use currency for amounts, date for ISO timestamps, link/image for URLs. Load the robotrock skill \u2192 context-widgets reference for the full widget catalog."
1738
+ )
1496
1739
  }).optional();
1497
- var createInboxTaskInputSchema = z4.object({
1498
- type: z4.string().min(1).describe("Task category slug, e.g. refund-approval or budget-approval."),
1499
- name: z4.string().min(1).describe("Short title shown in the inbox list."),
1500
- description: z4.string().min(1).optional(),
1501
- actions: z4.array(actionSchema).min(1).describe("At least one reviewer action (approve, reject, etc.)."),
1740
+ var createInboxTaskInputSchema = z6.object({
1741
+ type: z6.string().min(1).describe("Task category slug, e.g. refund-approval or budget-approval."),
1742
+ name: z6.string().min(1).describe("Short title shown in the inbox list."),
1743
+ description: z6.string().min(1).optional(),
1744
+ actions: z6.array(actionSchema).min(1).describe("At least one reviewer action (approve, reject, etc.)."),
1502
1745
  assignTo: assignToSchema3.describe(
1503
1746
  "Limit visibility to specific users and/or groups. Omit to show the task to everyone in the tenant."
1504
1747
  ),
1505
1748
  context: contextSchema,
1506
- validUntilHours: z4.number().positive().optional().describe("Optional deadline in hours from now. Defaults to the tenant task TTL."),
1507
- priority: z4.enum(["low", "normal", "high", "urgent"]).optional(),
1508
- updateMessage: z4.string().min(1).optional().describe("Optional thread status update logged when the task is created."),
1509
- delegationReason: z4.string().min(1).optional().describe(
1749
+ validUntilHours: z6.number().positive().optional().describe("Optional deadline in hours from now. Defaults to the tenant task TTL."),
1750
+ priority: z6.enum(["low", "normal", "high", "urgent"]).optional(),
1751
+ updateMessage: z6.string().min(1).optional().describe("Optional thread status update logged when the task is created."),
1752
+ delegationReason: z6.string().min(1).optional().describe(
1510
1753
  "User-facing explanation of why the requester cannot self-approve and the task was routed elsewhere. Required when assignTo excludes the caller."
1511
1754
  )
1512
1755
  });
@@ -1519,7 +1762,7 @@ function defaultResolveDelegationReason(input) {
1519
1762
  }
1520
1763
  function defineCreateInboxTaskTool(options) {
1521
1764
  return defineTool({
1522
- description: "Create a RobotRock inbox task and assign it to users or groups. Does not wait for a response. Only call this after the user explicitly asked to create/send/delegate an inbox task, or after they confirmed via ask_question. Never create a task silently when the user only asked for a preview, dummy example, or explanation. Always set delegationReason when assignTo excludes the caller. For refund approvals include chargeId, amount, currency, and reason in context.data.",
1765
+ description: "Create a RobotRock inbox task and assign it to users or groups. Does not wait for a response. Only call this after the user explicitly asked to create/send/delegate an inbox task, or after they confirmed via ask_question. Never create a task silently when the user only asked for a preview, dummy example, or explanation. Always set delegationReason when assignTo excludes the caller. For refund approvals include chargeId, amount, currency, and reason in context.data. The dashboard renders a task card \u2014 do not restate task ID, assignee, or delegation details in your reply.",
1523
1766
  inputSchema: createInboxTaskInputSchema,
1524
1767
  async execute(input, ctx) {
1525
1768
  const caller = requireTenantCaller(ctx);
@@ -1536,14 +1779,17 @@ function defineCreateInboxTaskTool(options) {
1536
1779
  publicTaskId: task.taskId,
1537
1780
  toolCallId: ctx.callId
1538
1781
  });
1539
- return {
1540
- ...task,
1541
- name: input.name,
1542
- assignedTo: input.assignTo ?? null,
1543
- requestedBy: caller.email,
1544
- delegationReason: delegationReason ?? null,
1545
- message: delegationReason ? `${delegationReason} This chat updates when the assignee decides.` : "Task created in RobotRock. Assignees can handle it from their inbox; this chat will update when they decide."
1546
- };
1782
+ return withReplyGuidance(
1783
+ {
1784
+ ...task,
1785
+ name: input.name,
1786
+ assignedTo: input.assignTo ?? null,
1787
+ requestedBy: caller.email,
1788
+ delegationReason: delegationReason ?? null,
1789
+ message: delegationReason ? `${delegationReason} This chat updates when the assignee decides.` : "Task created in RobotRock. Assignees can handle it from their inbox; this chat will update when they decide."
1790
+ },
1791
+ CREATE_INBOX_TASK_REPLY_GUIDANCE
1792
+ );
1547
1793
  }
1548
1794
  });
1549
1795
  }
@@ -1551,9 +1797,102 @@ var createInboxTaskTool = defineCreateInboxTaskTool();
1551
1797
 
1552
1798
  // src/eve/tools/identity/my-access.ts
1553
1799
  import { defineTool as defineTool2 } from "eve/tools";
1554
- import { z as z5 } from "zod";
1800
+ import { z as z7 } from "zod";
1801
+
1802
+ // src/eve/tool-result-display.ts
1803
+ function toolDisplayResult(data, options) {
1804
+ const display = options?.widget || options?.title || options?.description ? {
1805
+ ...options.widget ? { widget: options.widget } : {},
1806
+ ...options.title ? { title: options.title } : {},
1807
+ ...options.description ? { description: options.description } : {}
1808
+ } : void 0;
1809
+ return {
1810
+ ...display ? { display } : {},
1811
+ data,
1812
+ ...options?.ui ? { ui: options.ui } : {}
1813
+ };
1814
+ }
1815
+
1816
+ // src/eve/tool-display-format.ts
1817
+ function formatToolObjectResult(data, options) {
1818
+ return withReplyGuidance(
1819
+ toolDisplayResult(data, {
1820
+ title: options.title,
1821
+ description: options.description,
1822
+ ui: options.ui
1823
+ }),
1824
+ options.replyGuidance
1825
+ );
1826
+ }
1827
+ function formatToolListResult(listKey, items, options) {
1828
+ const listFieldUi = options.itemWidget ? {
1829
+ "ui:widget": "list",
1830
+ items: {
1831
+ "ui:widget": options.itemWidget,
1832
+ ...options.itemUi ?? {}
1833
+ }
1834
+ } : {
1835
+ "ui:widget": "table",
1836
+ ...options.itemUi ? { items: options.itemUi } : {}
1837
+ };
1838
+ return formatToolObjectResult(
1839
+ { [listKey]: items },
1840
+ {
1841
+ title: options.title,
1842
+ ui: {
1843
+ [listKey]: listFieldUi
1844
+ },
1845
+ replyGuidance: options.replyGuidance
1846
+ }
1847
+ );
1848
+ }
1849
+
1850
+ // src/eve/tools/identity/format-my-access.ts
1851
+ var ACCESS_FIELD_UI = {
1852
+ workspace: { "ui:title": "Workspace" },
1853
+ role: { "ui:title": "Role" },
1854
+ tenantAdmin: { "ui:title": "Tenant admin", "ui:widget": "boolean" },
1855
+ groups: { "ui:title": "Groups" },
1856
+ manageSettings: { "ui:title": "Manage settings", "ui:widget": "boolean" },
1857
+ manageBilling: { "ui:title": "Manage billing", "ui:widget": "boolean" },
1858
+ manageTeam: { "ui:title": "Manage team", "ui:widget": "boolean" },
1859
+ manageIntegrations: {
1860
+ "ui:title": "Manage integrations",
1861
+ "ui:widget": "boolean"
1862
+ },
1863
+ email: { "ui:title": "Email" }
1864
+ };
1865
+ function formatMyAccessResult(input) {
1866
+ return formatToolObjectResult(
1867
+ {
1868
+ access: {
1869
+ workspace: input.tenantSlug,
1870
+ role: input.tenantRole ?? "member",
1871
+ tenantAdmin: input.isTenantAdmin,
1872
+ groups: input.groupSlugs.join(", ") || "\u2014",
1873
+ manageSettings: input.capabilities.manageSettings,
1874
+ manageBilling: input.capabilities.manageBilling,
1875
+ manageTeam: input.capabilities.manageTeam,
1876
+ manageIntegrations: input.capabilities.manageIntegrations,
1877
+ ...input.email ? { email: input.email } : {}
1878
+ }
1879
+ },
1880
+ {
1881
+ ui: {
1882
+ access: {
1883
+ "ui:widget": "access",
1884
+ "ui:title": "Your access",
1885
+ items: ACCESS_FIELD_UI
1886
+ }
1887
+ },
1888
+ replyGuidance: MY_ACCESS_REPLY_GUIDANCE
1889
+ }
1890
+ );
1891
+ }
1892
+
1893
+ // src/eve/tools/identity/my-access.ts
1555
1894
  var MY_ACCESS_TOOL_NAME = "get_my_access";
1556
- var myAccessInputSchema = z5.object({});
1895
+ var myAccessInputSchema = z7.object({});
1557
1896
  function tenantCapabilities(isAdmin) {
1558
1897
  return {
1559
1898
  manageSettings: isAdmin,
@@ -1564,25 +1903,27 @@ function tenantCapabilities(isAdmin) {
1564
1903
  }
1565
1904
  function defineMyAccessTool() {
1566
1905
  return defineTool2({
1567
- description: "Check the authenticated user's tenant role, group memberships, and admin capabilities in RobotRock.",
1906
+ description: "Check the authenticated user's tenant role, group memberships, and admin capabilities in RobotRock. Results render as an access card in chat \u2014 do not restate role, groups, or capabilities in your reply.",
1568
1907
  inputSchema: myAccessInputSchema,
1569
1908
  async execute(_input, ctx) {
1570
1909
  const caller = tryResolveTenantCaller(ctx);
1571
1910
  if (!caller) {
1572
- return {
1573
- authenticated: false,
1574
- message: "No RobotRock user is attached to this session. Dashboard chat supplies user context via the Eve proxy."
1575
- };
1911
+ return withReplyGuidance(
1912
+ {
1913
+ authenticated: false,
1914
+ message: "No RobotRock user is attached to this session. Dashboard chat supplies user context via the Eve proxy."
1915
+ },
1916
+ "Explain that no user is attached to this session. Do not invent access details."
1917
+ );
1576
1918
  }
1577
- return {
1578
- authenticated: true,
1919
+ return formatMyAccessResult({
1920
+ tenantSlug: caller.tenantSlug,
1579
1921
  tenantRole: caller.role,
1580
1922
  isTenantAdmin: caller.isAdmin,
1581
1923
  groupSlugs: caller.groups,
1582
1924
  capabilities: tenantCapabilities(caller.isAdmin),
1583
- email: caller.email,
1584
- tenantSlug: caller.tenantSlug
1585
- };
1925
+ email: caller.email
1926
+ });
1586
1927
  }
1587
1928
  });
1588
1929
  }
@@ -1590,38 +1931,874 @@ var myAccessTool = defineMyAccessTool();
1590
1931
 
1591
1932
  // src/eve/tools/identity/whoami.ts
1592
1933
  import { defineTool as defineTool3 } from "eve/tools";
1593
- import { z as z6 } from "zod";
1934
+ import { z as z8 } from "zod";
1594
1935
  var WHOAMI_TOOL_NAME = "whoami";
1595
- var whoamiInputSchema = z6.object({});
1936
+ var whoamiInputSchema = z8.object({});
1596
1937
  function defineWhoamiTool() {
1597
1938
  return defineTool3({
1598
- description: "Return the authenticated RobotRock user, tenant, role, and group memberships for the current chat session.",
1939
+ description: "Return the authenticated RobotRock user, tenant, role, and group memberships for the current chat session. The dashboard renders a profile card \u2014 do not repeat name, email, workspace, role, or groups in your reply; only add context not shown in the card.",
1599
1940
  inputSchema: whoamiInputSchema,
1600
1941
  async execute(_input, ctx) {
1601
1942
  const caller = tryResolveTenantCaller(ctx);
1602
1943
  if (!caller) {
1603
- return {
1604
- authenticated: false,
1605
- message: "No RobotRock user is attached to this session. Dashboard chat supplies user context via the Eve proxy."
1606
- };
1944
+ return withReplyGuidance(
1945
+ {
1946
+ authenticated: false,
1947
+ message: "No RobotRock user is attached to this session. Dashboard chat supplies user context via the Eve proxy."
1948
+ },
1949
+ "Explain that no user is attached to this session. Do not invent identity details."
1950
+ );
1607
1951
  }
1608
- return {
1609
- authenticated: true,
1610
- userId: caller.userId,
1611
- name: caller.name,
1612
- email: caller.email,
1613
- tenantSlug: caller.tenantSlug,
1614
- role: caller.role,
1615
- isAdmin: caller.isAdmin,
1616
- groups: caller.groups.map((slug) => ({ slug })),
1617
- ...caller.workosUserId ? { workosUserId: caller.workosUserId } : {},
1618
- sessionId: ctx.session.id
1619
- };
1952
+ return withReplyGuidance(
1953
+ {
1954
+ authenticated: true,
1955
+ userId: caller.userId,
1956
+ name: caller.name,
1957
+ email: caller.email,
1958
+ tenantSlug: caller.tenantSlug,
1959
+ role: caller.role,
1960
+ isAdmin: caller.isAdmin,
1961
+ groups: caller.groups.map((slug) => ({ slug })),
1962
+ ...caller.workosUserId ? { workosUserId: caller.workosUserId } : {},
1963
+ sessionId: ctx.session.id
1964
+ },
1965
+ WHOAMI_REPLY_GUIDANCE
1966
+ );
1620
1967
  }
1621
1968
  });
1622
1969
  }
1623
1970
  var whoamiTool = defineWhoamiTool();
1624
1971
 
1972
+ // src/eve/tools/catalog/search-products.ts
1973
+ import { defineTool as defineTool4 } from "eve/tools";
1974
+ import { z as z9 } from "zod";
1975
+ var SEARCH_PRODUCTS_TOOL_NAME = "search_products";
1976
+ var searchProductsInputSchema = z9.object({
1977
+ query: z9.string().min(1).describe("Product name or SKU to search for.")
1978
+ });
1979
+ var DEMO_PRODUCTS = [
1980
+ {
1981
+ id: "sku-1001",
1982
+ name: "Wireless Keyboard",
1983
+ price: 79.99,
1984
+ currency: "USD",
1985
+ inStock: true
1986
+ },
1987
+ {
1988
+ id: "sku-2042",
1989
+ name: "USB-C Hub",
1990
+ price: 45.99,
1991
+ currency: "USD",
1992
+ inStock: true
1993
+ },
1994
+ {
1995
+ id: "sku-3308",
1996
+ name: "Monitor Stand",
1997
+ price: 129.99,
1998
+ currency: "USD",
1999
+ inStock: false
2000
+ }
2001
+ ];
2002
+ function defineSearchProductsTool() {
2003
+ return defineTool4({
2004
+ description: "Search the product catalog and return matching items with rich list UI. Results render as a product list card \u2014 do not restate product names, prices, or SKUs in your reply.",
2005
+ inputSchema: searchProductsInputSchema,
2006
+ async execute({ query }) {
2007
+ const normalized = query.trim().toLowerCase();
2008
+ const items = DEMO_PRODUCTS.filter(
2009
+ (product) => product.name.toLowerCase().includes(normalized) || product.id.toLowerCase().includes(normalized)
2010
+ );
2011
+ return withReplyGuidance(
2012
+ toolDisplayResult(
2013
+ { items: [...items] },
2014
+ {
2015
+ title: items.length === 1 ? "1 product" : `${items.length} products`,
2016
+ ui: {
2017
+ items: {
2018
+ "ui:widget": "list",
2019
+ "ui:title": "Results",
2020
+ items: {
2021
+ "ui:widget": "productInfo"
2022
+ }
2023
+ }
2024
+ }
2025
+ }
2026
+ ),
2027
+ SEARCH_PRODUCTS_REPLY_GUIDANCE
2028
+ );
2029
+ }
2030
+ });
2031
+ }
2032
+ var searchProductsTool = defineSearchProductsTool();
2033
+
2034
+ // src/agent-admin.ts
2035
+ async function agentAdminFetch(config, path, init) {
2036
+ const baseUrl = (config.baseUrl?.trim() || getRobotRockApiBaseUrl()).replace(
2037
+ /\/+$/,
2038
+ ""
2039
+ );
2040
+ const url = `${baseUrl}/agent-admin${path}`;
2041
+ const response = await fetch(url, {
2042
+ ...init,
2043
+ headers: {
2044
+ "Content-Type": "application/json",
2045
+ ...buildRobotRockAuthHeaders(config.auth),
2046
+ ...init?.headers ?? {}
2047
+ }
2048
+ });
2049
+ const data = await parseResponseBody(response);
2050
+ if (!response.ok) {
2051
+ throw new RobotRockError(
2052
+ getErrorMessage(data, `Agent admin request failed (${response.status})`),
2053
+ response.status,
2054
+ data
2055
+ );
2056
+ }
2057
+ return data;
2058
+ }
2059
+ function createAgentAdminApi(config) {
2060
+ return {
2061
+ members: {
2062
+ list: () => agentAdminFetch(config, "/members"),
2063
+ get: (memberRef) => agentAdminFetch(config, `/members/${encodeURIComponent(memberRef)}`),
2064
+ invite: (body) => agentAdminFetch(config, "/members", {
2065
+ method: "POST",
2066
+ body: JSON.stringify(body)
2067
+ }),
2068
+ updateRole: (memberRef, role) => agentAdminFetch(
2069
+ config,
2070
+ `/members/${encodeURIComponent(memberRef)}/role`,
2071
+ {
2072
+ method: "PATCH",
2073
+ body: JSON.stringify({ role })
2074
+ }
2075
+ ),
2076
+ remove: (memberId) => agentAdminFetch(
2077
+ config,
2078
+ `/members/${encodeURIComponent(memberId)}`,
2079
+ {
2080
+ method: "DELETE"
2081
+ }
2082
+ )
2083
+ },
2084
+ groups: {
2085
+ list: () => agentAdminFetch(config, "/groups"),
2086
+ get: (groupId) => agentAdminFetch(
2087
+ config,
2088
+ `/groups/${encodeURIComponent(groupId)}`
2089
+ ),
2090
+ create: (body) => agentAdminFetch(config, "/groups", {
2091
+ method: "POST",
2092
+ body: JSON.stringify(body)
2093
+ }),
2094
+ update: (groupId, body) => agentAdminFetch(
2095
+ config,
2096
+ `/groups/${encodeURIComponent(groupId)}`,
2097
+ {
2098
+ method: "PATCH",
2099
+ body: JSON.stringify(body)
2100
+ }
2101
+ ),
2102
+ delete: (groupId) => agentAdminFetch(
2103
+ config,
2104
+ `/groups/${encodeURIComponent(groupId)}`,
2105
+ {
2106
+ method: "DELETE"
2107
+ }
2108
+ ),
2109
+ addMember: (groupRef, memberRef) => agentAdminFetch(
2110
+ config,
2111
+ `/groups/${encodeURIComponent(groupRef)}/members`,
2112
+ {
2113
+ method: "POST",
2114
+ body: JSON.stringify({ userId: memberRef })
2115
+ }
2116
+ ),
2117
+ removeMember: (groupRef, memberRef) => agentAdminFetch(
2118
+ config,
2119
+ `/groups/${encodeURIComponent(groupRef)}/members/${encodeURIComponent(memberRef)}`,
2120
+ { method: "DELETE" }
2121
+ )
2122
+ },
2123
+ tasks: {
2124
+ list: (query) => {
2125
+ const params = new URLSearchParams();
2126
+ for (const [key, value] of Object.entries(query ?? {})) {
2127
+ if (value !== void 0 && value !== "") {
2128
+ params.set(key, String(value));
2129
+ }
2130
+ }
2131
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
2132
+ return agentAdminFetch(
2133
+ config,
2134
+ `/tasks${suffix}`
2135
+ );
2136
+ },
2137
+ search: (q, limit) => {
2138
+ const params = new URLSearchParams({ q });
2139
+ if (limit !== void 0) {
2140
+ params.set("limit", String(limit));
2141
+ }
2142
+ return agentAdminFetch(
2143
+ config,
2144
+ `/tasks/search?${params.toString()}`
2145
+ );
2146
+ },
2147
+ get: (taskId) => agentAdminFetch(config, `/tasks/${taskId}`),
2148
+ assign: (body) => agentAdminFetch(config, "/tasks/assign", {
2149
+ method: "POST",
2150
+ body: JSON.stringify(body)
2151
+ })
2152
+ }
2153
+ };
2154
+ }
2155
+ function createBoundAgentAdminClient(ctx) {
2156
+ const caller = requireTenantCaller(ctx);
2157
+ const baseUrl = process.env.ROBOTROCK_BASE_URL?.trim();
2158
+ const serviceToken = process.env.ROBOTROCK_AGENT_SERVICE_TOKEN?.trim();
2159
+ if (caller.connectionId && serviceToken) {
2160
+ return createAgentAdminApi({
2161
+ baseUrl,
2162
+ auth: resolveRobotRockAuthConfig({
2163
+ agentService: {
2164
+ token: serviceToken,
2165
+ tenantSlug: caller.tenantSlug,
2166
+ connectionId: caller.connectionId,
2167
+ actingUserId: caller.userId
2168
+ }
2169
+ })
2170
+ });
2171
+ }
2172
+ const apiKey = process.env.ROBOTROCK_API_KEY?.trim();
2173
+ if (apiKey) {
2174
+ return createAgentAdminApi({
2175
+ baseUrl,
2176
+ auth: {
2177
+ kind: "apiKey",
2178
+ apiKey,
2179
+ actingUserId: caller.userId
2180
+ }
2181
+ });
2182
+ }
2183
+ throw new Error(
2184
+ "Agent admin auth is unset. Set ROBOTROCK_AGENT_SERVICE_TOKEN for hosted multi-tenant agents, or ROBOTROCK_API_KEY for self-hosted and localhost deployments."
2185
+ );
2186
+ }
2187
+ function requireBoundAgentAdminClient(ctx) {
2188
+ requireAdminCaller(ctx);
2189
+ return createBoundAgentAdminClient(ctx);
2190
+ }
2191
+
2192
+ // src/eve/tools/admin/format-team-members-list.ts
2193
+ var MEMBER_DETAIL_UI = {
2194
+ name: { "ui:title": "Name" },
2195
+ email: { "ui:title": "Email" },
2196
+ role: { "ui:title": "Role" },
2197
+ membershipKind: { "ui:title": "Membership" }
2198
+ };
2199
+ function serializeMemberRow(member) {
2200
+ return {
2201
+ name: member.user.name,
2202
+ email: member.user.email,
2203
+ role: member.role,
2204
+ membershipKind: member.membershipKind
2205
+ };
2206
+ }
2207
+ function formatTeamMembersListResult(members) {
2208
+ const countLabel = members.length === 1 ? "1 team member" : `${members.length} team members`;
2209
+ return formatToolListResult(
2210
+ "members",
2211
+ members.map(serializeMemberRow),
2212
+ {
2213
+ title: countLabel,
2214
+ itemWidget: "tenantMember",
2215
+ replyGuidance: MANAGE_TEAM_MEMBERS_LIST_REPLY_GUIDANCE
2216
+ }
2217
+ );
2218
+ }
2219
+ function formatTeamMemberDetailResult(member, options) {
2220
+ return formatToolObjectResult(serializeMemberRow(member), {
2221
+ title: options?.title ?? member.user.name,
2222
+ ui: MEMBER_DETAIL_UI,
2223
+ replyGuidance: MANAGE_TEAM_MEMBERS_DETAIL_REPLY_GUIDANCE
2224
+ });
2225
+ }
2226
+
2227
+ // src/eve/tools/admin/manage-team-members.ts
2228
+ import { defineTool as defineTool5 } from "eve/tools";
2229
+ import { z as z10 } from "zod";
2230
+ var MANAGE_TEAM_MEMBERS_TOOL_NAME = "manage_team_members";
2231
+ var manageTeamMembersInputSchema = z10.object({
2232
+ action: z10.enum(["list", "get", "invite", "update_role", "remove"]),
2233
+ userId: z10.string().min(1).optional().describe(
2234
+ "Convex users table id for get, update_role, and remove. Prefer email when the member list only shows email."
2235
+ ),
2236
+ email: z10.string().email().optional().describe(
2237
+ "Member email for get, update_role, and remove; invitee email for invite."
2238
+ ),
2239
+ role: z10.enum(["admin", "member"]).optional().describe("Role for invite and update_role.")
2240
+ }).superRefine((input, ctx) => {
2241
+ const requireField = (field, message) => {
2242
+ if (!input[field]) {
2243
+ ctx.addIssue({ code: "custom", message, path: [field] });
2244
+ }
2245
+ };
2246
+ const requireUserIdOrEmail = (message) => {
2247
+ if (!input.userId && !input.email) {
2248
+ ctx.addIssue({ code: "custom", message, path: ["email"] });
2249
+ }
2250
+ };
2251
+ switch (input.action) {
2252
+ case "get":
2253
+ requireUserIdOrEmail("userId or email is required for this action.");
2254
+ break;
2255
+ case "remove":
2256
+ requireUserIdOrEmail(
2257
+ "userId or email is required when removing a member."
2258
+ );
2259
+ break;
2260
+ case "invite":
2261
+ requireField("email", "email is required when inviting a member.");
2262
+ break;
2263
+ case "update_role":
2264
+ requireUserIdOrEmail(
2265
+ "userId or email is required when updating a role."
2266
+ );
2267
+ requireField("role", "role is required when updating a role.");
2268
+ break;
2269
+ }
2270
+ });
2271
+ function resolveMemberRef(input) {
2272
+ return input.userId ?? input.email;
2273
+ }
2274
+ function formatMemberMutationResult(payload, title) {
2275
+ return formatToolObjectResult(payload, {
2276
+ title,
2277
+ ui: {
2278
+ success: { "ui:title": "Success", "ui:widget": "boolean" },
2279
+ promoted: { "ui:title": "Promoted existing user", "ui:widget": "boolean" }
2280
+ },
2281
+ replyGuidance: ADMIN_MUTATION_REPLY_GUIDANCE
2282
+ });
2283
+ }
2284
+ function defineManageTeamMembersTool() {
2285
+ return defineTool5({
2286
+ description: "Tenant-admin tool for workspace team members: list, get, invite, change role, or remove. Requires tenant admin access. Use member email from list results for get, update_role, and remove \u2014 internal ids are optional. Results render as chat UI cards \u2014 do not restate member names, emails, or roles in your reply.",
2287
+ inputSchema: manageTeamMembersInputSchema,
2288
+ async execute(input, ctx) {
2289
+ const api = requireBoundAgentAdminClient(ctx);
2290
+ try {
2291
+ switch (input.action) {
2292
+ case "list": {
2293
+ const result = await api.members.list();
2294
+ return formatTeamMembersListResult(
2295
+ result.members
2296
+ );
2297
+ }
2298
+ case "get": {
2299
+ const result = await api.members.get(resolveMemberRef(input));
2300
+ return formatTeamMemberDetailResult(result.member);
2301
+ }
2302
+ case "invite": {
2303
+ const result = await api.members.invite({
2304
+ email: input.email,
2305
+ role: input.role
2306
+ });
2307
+ if (result.member) {
2308
+ return formatTeamMemberDetailResult(
2309
+ result.member,
2310
+ { title: "Member invited" }
2311
+ );
2312
+ }
2313
+ return formatMemberMutationResult(
2314
+ result,
2315
+ "Invitation sent"
2316
+ );
2317
+ }
2318
+ case "update_role": {
2319
+ const result = await api.members.updateRole(
2320
+ resolveMemberRef(input),
2321
+ input.role
2322
+ );
2323
+ return formatMemberMutationResult(
2324
+ result,
2325
+ "Member role updated"
2326
+ );
2327
+ }
2328
+ case "remove": {
2329
+ const memberId = resolveMemberRef(input);
2330
+ const result = await api.members.remove(memberId);
2331
+ return formatMemberMutationResult(
2332
+ result,
2333
+ "Member removed"
2334
+ );
2335
+ }
2336
+ }
2337
+ } catch (error) {
2338
+ if (error instanceof RobotRockError) {
2339
+ return {
2340
+ ok: false,
2341
+ status: error.statusCode,
2342
+ message: error.message,
2343
+ response: error.response
2344
+ };
2345
+ }
2346
+ throw error;
2347
+ }
2348
+ }
2349
+ });
2350
+ }
2351
+ var manageTeamMembersTool = defineManageTeamMembersTool();
2352
+
2353
+ // src/eve/tools/admin/manage-groups.ts
2354
+ import { defineTool as defineTool6 } from "eve/tools";
2355
+ import { z as z11 } from "zod";
2356
+
2357
+ // src/eve/tools/admin/format-groups-list.ts
2358
+ var GROUP_ITEM_UI = {
2359
+ name: { "ui:title": "Name" },
2360
+ slug: { "ui:title": "Slug" },
2361
+ description: { "ui:title": "Description" },
2362
+ memberCount: { "ui:title": "Members", "ui:widget": "number" }
2363
+ };
2364
+ function serializeGroupRow(group) {
2365
+ return {
2366
+ name: group.name,
2367
+ slug: group.slug,
2368
+ description: group.description,
2369
+ memberCount: group.memberCount ?? null
2370
+ };
2371
+ }
2372
+ function formatGroupsListResult(groups) {
2373
+ const countLabel = groups.length === 1 ? "1 group" : `${groups.length} groups`;
2374
+ return formatToolListResult(
2375
+ "groups",
2376
+ groups.map(serializeGroupRow),
2377
+ {
2378
+ title: countLabel,
2379
+ itemWidget: "tenantGroup",
2380
+ replyGuidance: MANAGE_GROUPS_LIST_REPLY_GUIDANCE
2381
+ }
2382
+ );
2383
+ }
2384
+ function formatGroupDetailResult(group) {
2385
+ return formatToolObjectResult(
2386
+ {
2387
+ name: group.name,
2388
+ slug: group.slug,
2389
+ description: group.description,
2390
+ members: group.members.map((member) => ({
2391
+ name: member.user.name,
2392
+ email: member.user.email
2393
+ }))
2394
+ },
2395
+ {
2396
+ title: group.name,
2397
+ ui: {
2398
+ name: { "ui:title": "Name" },
2399
+ slug: { "ui:title": "Slug" },
2400
+ description: { "ui:title": "Description" },
2401
+ members: {
2402
+ "ui:widget": "list",
2403
+ "ui:title": "Members",
2404
+ items: {
2405
+ name: { "ui:title": "Name" },
2406
+ email: { "ui:title": "Email" }
2407
+ }
2408
+ }
2409
+ },
2410
+ replyGuidance: MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE
2411
+ }
2412
+ );
2413
+ }
2414
+ function formatGroupSummaryResult(group) {
2415
+ return formatToolObjectResult(serializeGroupRow(group), {
2416
+ title: group.name,
2417
+ ui: GROUP_ITEM_UI,
2418
+ replyGuidance: MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE
2419
+ });
2420
+ }
2421
+
2422
+ // src/eve/tools/admin/manage-groups.ts
2423
+ var MANAGE_GROUPS_TOOL_NAME = "manage_groups";
2424
+ var manageGroupsInputSchema = z11.object({
2425
+ action: z11.enum([
2426
+ "list",
2427
+ "get",
2428
+ "create",
2429
+ "update",
2430
+ "delete",
2431
+ "add_member",
2432
+ "remove_member"
2433
+ ]),
2434
+ groupId: z11.string().min(1).optional().describe(
2435
+ "Convex group id for get, update, delete, and membership actions. Prefer slug when the group list only shows slug."
2436
+ ),
2437
+ slug: z11.string().min(1).optional().describe(
2438
+ "Group slug (e.g. finance) for get, update, delete, and membership actions."
2439
+ ),
2440
+ userId: z11.string().min(1).optional().describe(
2441
+ "User id for add_member and remove_member. Prefer email when the member list only shows email."
2442
+ ),
2443
+ email: z11.string().email().optional().describe("Member email for add_member and remove_member."),
2444
+ name: z11.string().min(1).optional().describe("Group name for create and update."),
2445
+ description: z11.string().optional().describe("Group description for create and update.")
2446
+ }).superRefine((input, ctx) => {
2447
+ const requireField = (field, message) => {
2448
+ if (!input[field]) {
2449
+ ctx.addIssue({ code: "custom", message, path: [field] });
2450
+ }
2451
+ };
2452
+ const requireGroupIdOrSlug = (message) => {
2453
+ if (!input.groupId && !input.slug) {
2454
+ ctx.addIssue({ code: "custom", message, path: ["slug"] });
2455
+ }
2456
+ };
2457
+ const requireUserIdOrEmail = (message) => {
2458
+ if (!input.userId && !input.email) {
2459
+ ctx.addIssue({ code: "custom", message, path: ["email"] });
2460
+ }
2461
+ };
2462
+ switch (input.action) {
2463
+ case "get":
2464
+ case "delete":
2465
+ requireGroupIdOrSlug(
2466
+ "groupId or slug is required for this action."
2467
+ );
2468
+ break;
2469
+ case "create":
2470
+ requireField("name", "name is required when creating a group.");
2471
+ break;
2472
+ case "update":
2473
+ requireGroupIdOrSlug("groupId or slug is required for update.");
2474
+ break;
2475
+ case "add_member":
2476
+ case "remove_member":
2477
+ requireGroupIdOrSlug(
2478
+ "groupId or slug is required for membership changes."
2479
+ );
2480
+ requireUserIdOrEmail(
2481
+ "userId or email is required for membership changes."
2482
+ );
2483
+ break;
2484
+ }
2485
+ });
2486
+ function formatGroupMutationResult(payload, title) {
2487
+ return formatToolObjectResult(payload, {
2488
+ title,
2489
+ replyGuidance: ADMIN_MUTATION_REPLY_GUIDANCE
2490
+ });
2491
+ }
2492
+ function resolveGroupRef(input) {
2493
+ return input.groupId ?? input.slug;
2494
+ }
2495
+ function resolveMemberRef2(input) {
2496
+ return input.userId ?? input.email;
2497
+ }
2498
+ function defineManageGroupsTool() {
2499
+ return defineTool6({
2500
+ description: "Tenant-admin tool for workspace groups: list, get, create, update, delete, and manage group membership. Requires tenant admin access. Use group slug (e.g. finance) from list results for get and membership actions \u2014 internal ids are optional. Use member email for add_member and remove_member when user ids are unknown. Results render as chat UI cards \u2014 do not restate group or member fields in your reply.",
2501
+ inputSchema: manageGroupsInputSchema,
2502
+ async execute(input, ctx) {
2503
+ const api = requireBoundAgentAdminClient(ctx);
2504
+ try {
2505
+ switch (input.action) {
2506
+ case "list": {
2507
+ const result = await api.groups.list();
2508
+ return formatGroupsListResult(result.groups);
2509
+ }
2510
+ case "get": {
2511
+ const result = await api.groups.get(resolveGroupRef(input));
2512
+ return formatGroupDetailResult(result.group);
2513
+ }
2514
+ case "create": {
2515
+ const result = await api.groups.create({
2516
+ name: input.name,
2517
+ description: input.description
2518
+ });
2519
+ return formatGroupSummaryResult(result.group);
2520
+ }
2521
+ case "update": {
2522
+ const result = await api.groups.update(resolveGroupRef(input), {
2523
+ name: input.name,
2524
+ description: input.description
2525
+ });
2526
+ return formatGroupSummaryResult(result.group);
2527
+ }
2528
+ case "delete": {
2529
+ const result = await api.groups.delete(resolveGroupRef(input));
2530
+ return formatGroupMutationResult(
2531
+ result,
2532
+ "Group deleted"
2533
+ );
2534
+ }
2535
+ case "add_member": {
2536
+ const result = await api.groups.addMember(
2537
+ resolveGroupRef(input),
2538
+ resolveMemberRef2(input)
2539
+ );
2540
+ return formatGroupMutationResult(
2541
+ result,
2542
+ "Group member added"
2543
+ );
2544
+ }
2545
+ case "remove_member": {
2546
+ const result = await api.groups.removeMember(
2547
+ resolveGroupRef(input),
2548
+ resolveMemberRef2(input)
2549
+ );
2550
+ return formatGroupMutationResult(
2551
+ result,
2552
+ "Group member removed"
2553
+ );
2554
+ }
2555
+ }
2556
+ } catch (error) {
2557
+ if (error instanceof RobotRockError) {
2558
+ return {
2559
+ ok: false,
2560
+ status: error.statusCode,
2561
+ message: error.message,
2562
+ response: error.response
2563
+ };
2564
+ }
2565
+ throw error;
2566
+ }
2567
+ }
2568
+ });
2569
+ }
2570
+ var manageGroupsTool = defineManageGroupsTool();
2571
+
2572
+ // src/eve/tools/admin/query-tasks.ts
2573
+ import { defineTool as defineTool7 } from "eve/tools";
2574
+ import { z as z12 } from "zod";
2575
+
2576
+ // src/eve/tools/admin/format-tasks-list.ts
2577
+ function resolveTaskCardLabel(task) {
2578
+ return task.name?.trim() || task.description?.trim() || task.type?.trim() || task.id?.trim() || "Untitled task";
2579
+ }
2580
+ function formatTasksListResult(items, options) {
2581
+ const title = options?.title ?? (items.length === 1 ? "1 task" : `${items.length} tasks`);
2582
+ const result = formatToolListResult(
2583
+ "items",
2584
+ items.map((task) => ({
2585
+ id: task.id,
2586
+ name: resolveTaskCardLabel(task),
2587
+ status: task.status,
2588
+ type: task.type,
2589
+ description: task.description
2590
+ })),
2591
+ {
2592
+ title,
2593
+ itemWidget: "tenantTask",
2594
+ replyGuidance: QUERY_TASKS_LIST_REPLY_GUIDANCE
2595
+ }
2596
+ );
2597
+ if (options?.nextCursor) {
2598
+ return {
2599
+ ...result,
2600
+ data: {
2601
+ ...result.data,
2602
+ nextCursor: options.nextCursor
2603
+ },
2604
+ display: {
2605
+ ...result.display,
2606
+ description: "More tasks available \u2014 pass nextCursor to list again."
2607
+ }
2608
+ };
2609
+ }
2610
+ return result;
2611
+ }
2612
+ function formatTaskSearchResult(items, total) {
2613
+ return formatTasksListResult(items, {
2614
+ title: total === 1 ? "1 matching task" : `${total} matching tasks`
2615
+ });
2616
+ }
2617
+ function formatTaskDetailResult(task) {
2618
+ const title = resolveTaskCardLabel({
2619
+ name: typeof task.name === "string" ? task.name : null,
2620
+ description: typeof task.description === "string" ? task.description : null,
2621
+ type: typeof task.type === "string" ? task.type : null,
2622
+ id: typeof task.id === "string" ? task.id : null
2623
+ });
2624
+ return formatToolObjectResult(
2625
+ {
2626
+ id: task.id ?? null,
2627
+ status: task.status ?? null,
2628
+ type: task.type ?? null,
2629
+ name: task.name ?? null,
2630
+ description: task.description ?? null,
2631
+ validUntil: task.validUntil ?? null,
2632
+ createdAt: task.createdAt ?? null
2633
+ },
2634
+ {
2635
+ title,
2636
+ ui: {
2637
+ id: { "ui:title": "Task ID" },
2638
+ status: { "ui:title": "Status" },
2639
+ type: { "ui:title": "Type" },
2640
+ name: { "ui:title": "Name" },
2641
+ description: { "ui:title": "Description" },
2642
+ validUntil: { "ui:title": "Valid until", "ui:widget": "date" },
2643
+ createdAt: { "ui:title": "Created", "ui:widget": "date" }
2644
+ },
2645
+ replyGuidance: QUERY_TASKS_DETAIL_REPLY_GUIDANCE
2646
+ }
2647
+ );
2648
+ }
2649
+ function formatAssignTasksResult(results, _assignTo) {
2650
+ const succeeded = results.filter((row) => row.success).length;
2651
+ const title = succeeded === results.length ? `${succeeded === 1 ? "1 task" : `${succeeded} tasks`} reassigned` : `${succeeded}/${results.length} tasks reassigned`;
2652
+ return formatToolListResult(
2653
+ "results",
2654
+ results.map((row) => ({
2655
+ id: row.taskId,
2656
+ name: resolveTaskCardLabel({
2657
+ name: row.name,
2658
+ description: row.description,
2659
+ type: row.type,
2660
+ id: row.taskId
2661
+ }),
2662
+ type: row.type ?? null,
2663
+ description: row.description ?? null,
2664
+ status: row.success ? "reassigned" : "failed"
2665
+ })),
2666
+ {
2667
+ title,
2668
+ itemWidget: "tenantTask",
2669
+ replyGuidance: ASSIGN_TASKS_REPLY_GUIDANCE
2670
+ }
2671
+ );
2672
+ }
2673
+
2674
+ // src/eve/tools/admin/query-tasks.ts
2675
+ var QUERY_TASKS_TOOL_NAME = "query_tasks";
2676
+ var queryTasksInputSchema = z12.object({
2677
+ action: z12.enum(["list", "get", "search"]),
2678
+ statusFilter: z12.enum(["all", "open", "handled", "expired"]).optional().describe("Filter by task status for list."),
2679
+ typeFilter: z12.string().optional(),
2680
+ appFilter: z12.string().optional(),
2681
+ sortField: z12.enum(["type", "date", "status", "validUntil"]).optional(),
2682
+ sortDirection: z12.enum(["asc", "desc"]).optional(),
2683
+ limit: z12.number().int().positive().max(100).optional(),
2684
+ cursor: z12.string().optional(),
2685
+ taskId: z12.string().min(1).optional().describe("Public task id or Convex tasks table id for get."),
2686
+ query: z12.string().min(1).optional().describe("Search type, name, description, or id for search.")
2687
+ }).superRefine((input, ctx) => {
2688
+ switch (input.action) {
2689
+ case "get":
2690
+ if (!input.taskId) {
2691
+ ctx.addIssue({
2692
+ code: "custom",
2693
+ message: "taskId is required for get.",
2694
+ path: ["taskId"]
2695
+ });
2696
+ }
2697
+ break;
2698
+ case "search":
2699
+ if (!input.query) {
2700
+ ctx.addIssue({
2701
+ code: "custom",
2702
+ message: "query is required for search.",
2703
+ path: ["query"]
2704
+ });
2705
+ }
2706
+ break;
2707
+ }
2708
+ });
2709
+ function defineQueryTasksTool() {
2710
+ return defineTool7({
2711
+ description: "Tenant-admin tool to list, fetch detail, or search inbox tasks in the workspace. Requires tenant admin access. Results render as chat UI cards \u2014 do not restate task names, ids, or statuses in your reply.",
2712
+ inputSchema: queryTasksInputSchema,
2713
+ async execute(input, ctx) {
2714
+ const api = requireBoundAgentAdminClient(ctx);
2715
+ try {
2716
+ switch (input.action) {
2717
+ case "list": {
2718
+ const result = await api.tasks.list({
2719
+ statusFilter: input.statusFilter,
2720
+ typeFilter: input.typeFilter,
2721
+ appFilter: input.appFilter,
2722
+ sortField: input.sortField,
2723
+ sortDirection: input.sortDirection,
2724
+ limit: input.limit,
2725
+ cursor: input.cursor
2726
+ });
2727
+ return formatTasksListResult(result.items, {
2728
+ nextCursor: result.nextCursor
2729
+ });
2730
+ }
2731
+ case "get": {
2732
+ const result = await api.tasks.get(input.taskId);
2733
+ return formatTaskDetailResult(result.task);
2734
+ }
2735
+ case "search": {
2736
+ const result = await api.tasks.search(input.query, input.limit);
2737
+ return formatTaskSearchResult(
2738
+ result.items,
2739
+ result.total
2740
+ );
2741
+ }
2742
+ }
2743
+ } catch (error) {
2744
+ if (error instanceof RobotRockError) {
2745
+ return {
2746
+ ok: false,
2747
+ status: error.statusCode,
2748
+ message: error.message,
2749
+ response: error.response
2750
+ };
2751
+ }
2752
+ throw error;
2753
+ }
2754
+ }
2755
+ });
2756
+ }
2757
+ var queryTasksTool = defineQueryTasksTool();
2758
+
2759
+ // src/eve/tools/admin/assign-tasks.ts
2760
+ import { defineTool as defineTool8 } from "eve/tools";
2761
+ import { z as z13 } from "zod";
2762
+ var ASSIGN_TASKS_TOOL_NAME = "assign_tasks";
2763
+ var assignTasksInputSchema = z13.object({
2764
+ taskIds: z13.array(z13.string().min(1)).min(1).max(100).describe(
2765
+ "Public task ids or Convex tasks table ids to reassign. Use query_tasks search/get to resolve ids first."
2766
+ ),
2767
+ assignTo: assignToSchema.refine(
2768
+ (value) => (value.users?.length ?? 0) > 0 || (value.groups?.length ?? 0) > 0,
2769
+ { message: "assignTo needs at least one user email or group slug." }
2770
+ ).describe(
2771
+ 'New assignees \u2014 user emails and/or group slugs (e.g. "finance", virtual "admins").'
2772
+ )
2773
+ });
2774
+ function defineAssignTasksTool() {
2775
+ return defineTool8({
2776
+ description: "Reassign existing inbox tasks to users or groups. Requires access to each task (tenant admins can reassign any task; others only tasks they can see). Use query_tasks to find task ids when needed. Results render as chat UI \u2014 do not restate task ids or assignees in your reply.",
2777
+ inputSchema: assignTasksInputSchema,
2778
+ async execute(input, ctx) {
2779
+ const api = createBoundAgentAdminClient(ctx);
2780
+ try {
2781
+ const result = await api.tasks.assign({
2782
+ taskIds: input.taskIds,
2783
+ assignTo: input.assignTo
2784
+ });
2785
+ return formatAssignTasksResult(result.results, input.assignTo);
2786
+ } catch (error) {
2787
+ if (error instanceof RobotRockError) {
2788
+ return {
2789
+ ok: false,
2790
+ status: error.statusCode,
2791
+ message: error.message,
2792
+ response: error.response
2793
+ };
2794
+ }
2795
+ throw error;
2796
+ }
2797
+ }
2798
+ });
2799
+ }
2800
+ var assignTasksTool = defineAssignTasksTool();
2801
+
1625
2802
  // src/eve/tools/index.ts
1626
2803
  function createRobotrockTools(options) {
1627
2804
  const tools = {};
@@ -1637,17 +2814,34 @@ function createRobotrockTools(options) {
1637
2814
  return tools;
1638
2815
  }
1639
2816
  export {
2817
+ ASSIGN_TASKS_TOOL_NAME,
1640
2818
  CREATE_INBOX_TASK_TOOL_NAME,
2819
+ MANAGE_GROUPS_TOOL_NAME,
2820
+ MANAGE_TEAM_MEMBERS_TOOL_NAME,
1641
2821
  MY_ACCESS_TOOL_NAME,
2822
+ QUERY_TASKS_TOOL_NAME,
2823
+ SEARCH_PRODUCTS_TOOL_NAME,
1642
2824
  WHOAMI_TOOL_NAME,
2825
+ assignTasksInputSchema,
2826
+ assignTasksTool,
1643
2827
  createInboxTaskInputSchema,
1644
2828
  createInboxTaskTool,
1645
2829
  createRobotrockTools,
2830
+ defineAssignTasksTool,
1646
2831
  defineCreateInboxTaskTool,
2832
+ defineManageGroupsTool,
2833
+ defineManageTeamMembersTool,
1647
2834
  defineMyAccessTool,
2835
+ defineQueryTasksTool,
2836
+ defineSearchProductsTool,
1648
2837
  defineWhoamiTool,
2838
+ manageGroupsTool,
2839
+ manageTeamMembersTool,
1649
2840
  myAccessInputSchema,
1650
2841
  myAccessTool,
2842
+ queryTasksTool,
2843
+ searchProductsInputSchema,
2844
+ searchProductsTool,
1651
2845
  whoamiInputSchema,
1652
2846
  whoamiTool
1653
2847
  };