robotrock 1.3.3 → 1.4.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 (79) hide show
  1. package/README.md +32 -0
  2. package/dist/agent-admin.d.ts +5 -0
  3. package/dist/agent-admin.js +75 -2
  4. package/dist/agent-admin.js.map +1 -1
  5. package/dist/ai/index.d.ts +5 -5
  6. package/dist/ai/index.js +128 -4
  7. package/dist/ai/index.js.map +1 -1
  8. package/dist/ai/trigger.d.ts +3 -3
  9. package/dist/ai/trigger.js +128 -4
  10. package/dist/ai/trigger.js.map +1 -1
  11. package/dist/ai/workflow.d.ts +3 -3
  12. package/dist/ai/workflow.js +128 -4
  13. package/dist/ai/workflow.js.map +1 -1
  14. package/dist/{client-CZ5eWH5v.d.ts → client-BxbxttFH.d.ts} +19 -1
  15. package/dist/eve/agent/index.d.ts +4 -3
  16. package/dist/eve/agent/index.js +736 -414
  17. package/dist/eve/agent/index.js.map +1 -1
  18. package/dist/eve/index.d.ts +4 -3
  19. package/dist/eve/index.js +437 -45
  20. package/dist/eve/index.js.map +1 -1
  21. package/dist/eve/tools/admin/assign-tasks.d.ts +40 -8
  22. package/dist/eve/tools/admin/assign-tasks.js +328 -66
  23. package/dist/eve/tools/admin/assign-tasks.js.map +1 -1
  24. package/dist/eve/tools/admin/get-workspace-usage.d.ts +71 -0
  25. package/dist/eve/tools/admin/get-workspace-usage.js +1353 -0
  26. package/dist/eve/tools/admin/get-workspace-usage.js.map +1 -0
  27. package/dist/eve/tools/admin/manage-groups.d.ts +122 -8
  28. package/dist/eve/tools/admin/manage-groups.js +348 -94
  29. package/dist/eve/tools/admin/manage-groups.js.map +1 -1
  30. package/dist/eve/tools/admin/manage-team-members.d.ts +86 -8
  31. package/dist/eve/tools/admin/manage-team-members.js +318 -72
  32. package/dist/eve/tools/admin/manage-team-members.js.map +1 -1
  33. package/dist/eve/tools/admin/query-tasks.d.ts +82 -8
  34. package/dist/eve/tools/admin/query-tasks.js +360 -113
  35. package/dist/eve/tools/admin/query-tasks.js.map +1 -1
  36. package/dist/eve/tools/catalog/generate-image.d.ts +64 -0
  37. package/dist/eve/tools/catalog/generate-image.js +2065 -0
  38. package/dist/eve/tools/catalog/generate-image.js.map +1 -0
  39. package/dist/eve/tools/catalog/generate-random-chart.d.ts +71 -0
  40. package/dist/eve/tools/catalog/generate-random-chart.js +372 -0
  41. package/dist/eve/tools/catalog/generate-random-chart.js.map +1 -0
  42. package/dist/eve/tools/catalog/search-products.d.ts +36 -44
  43. package/dist/eve/tools/catalog/search-products.js +237 -33
  44. package/dist/eve/tools/catalog/search-products.js.map +1 -1
  45. package/dist/eve/tools/identity/index.d.ts +2 -2
  46. package/dist/eve/tools/identity/index.js +35 -44
  47. package/dist/eve/tools/identity/index.js.map +1 -1
  48. package/dist/eve/tools/identity/my-access.d.ts +90 -6
  49. package/dist/eve/tools/identity/my-access.js +35 -44
  50. package/dist/eve/tools/identity/my-access.js.map +1 -1
  51. package/dist/eve/tools/identity/whoami.d.ts +1 -1
  52. package/dist/eve/tools/identity/whoami.js.map +1 -1
  53. package/dist/eve/tools/inbox/create-task.d.ts +1 -1
  54. package/dist/eve/tools/inbox/create-task.js +119 -2
  55. package/dist/eve/tools/inbox/create-task.js.map +1 -1
  56. package/dist/eve/tools/inbox/index.d.ts +1 -1
  57. package/dist/eve/tools/inbox/index.js +119 -2
  58. package/dist/eve/tools/inbox/index.js.map +1 -1
  59. package/dist/eve/tools/index.d.ts +5 -2
  60. package/dist/eve/tools/index.js +932 -288
  61. package/dist/eve/tools/index.js.map +1 -1
  62. package/dist/index-Drj0Rzf_.d.ts +905 -0
  63. package/dist/index.d.ts +5 -4
  64. package/dist/index.js +335 -20
  65. package/dist/index.js.map +1 -1
  66. package/dist/schemas/index.js +67 -1
  67. package/dist/schemas/index.js.map +1 -1
  68. package/dist/{tool-approval-bridge-DnGaRES4.d.ts → tool-approval-bridge-Cz7qQUpw.d.ts} +1 -1
  69. package/dist/{tool-reply-guidance-C3qrT1In.d.ts → tool-reply-guidance-CJko9liH.d.ts} +5 -2
  70. package/dist/tool-result-ui-meta-KT0VafEO.d.ts +52 -0
  71. package/dist/trigger/index.d.ts +1 -1
  72. package/dist/trigger/index.js +118 -2
  73. package/dist/trigger/index.js.map +1 -1
  74. package/dist/{trigger--qTIK0s6.d.ts → trigger-C1ooSegc.d.ts} +2 -2
  75. package/dist/workflow/index.d.ts +1 -1
  76. package/dist/workflow/index.js +118 -2
  77. package/dist/workflow/index.js.map +1 -1
  78. package/package.json +21 -4
  79. package/dist/index-DePyAbTI.d.ts +0 -203
@@ -449,6 +449,40 @@ var agentChatLinkTaskBodySchema = z.object({
449
449
  publicTaskId: z.string().min(1),
450
450
  toolCallId: z.string().min(1)
451
451
  });
452
+ var AGENT_FILE_TAGS_MAX = 20;
453
+ var AGENT_FILE_TAG_MAX_LENGTH = 64;
454
+ function normalizeAgentFileTags(tags) {
455
+ if (!tags?.length) return void 0;
456
+ const seen = /* @__PURE__ */ new Set();
457
+ const out = [];
458
+ for (const raw of tags) {
459
+ const tag = raw.trim().toLowerCase().slice(0, AGENT_FILE_TAG_MAX_LENGTH);
460
+ if (!tag || seen.has(tag)) continue;
461
+ seen.add(tag);
462
+ out.push(tag);
463
+ if (out.length >= AGENT_FILE_TAGS_MAX) break;
464
+ }
465
+ return out.length > 0 ? out : void 0;
466
+ }
467
+ var agentChatUploadImageBodySchema = z.object({
468
+ mediaType: z.string().min(1),
469
+ /** Raw base64 (no data: URL prefix). */
470
+ base64: z.string().min(1),
471
+ chatId: z.string().min(1).optional(),
472
+ publicTaskId: z.string().min(1).optional(),
473
+ source: z.string().min(1).optional(),
474
+ /** Display / search name (e.g. `sunset-robot.png`). */
475
+ filename: z.string().min(1).max(255).optional(),
476
+ /** Human-readable description (e.g. generation prompt). */
477
+ description: z.string().min(1).max(2e3).optional(),
478
+ /**
479
+ * Optional labels for later grouping/filtering.
480
+ * Normalized to lowercase trimmed unique strings (max 20, 64 chars each).
481
+ */
482
+ tags: z.array(z.string().min(1).max(AGENT_FILE_TAG_MAX_LENGTH)).max(AGENT_FILE_TAGS_MAX).optional().transform((tags) => normalizeAgentFileTags(tags))
483
+ }).refine((data) => Boolean(data.chatId || data.publicTaskId), {
484
+ message: "Provide chatId and/or publicTaskId"
485
+ });
452
486
 
453
487
  // ../core/src/schemas/tool-result-display.ts
454
488
  import { z as z2 } from "zod";
@@ -477,7 +511,8 @@ var tenantRoleSchema = z3.enum(["admin", "member"]);
477
511
  var agentAdminUserSchema = z3.object({
478
512
  id: z3.string(),
479
513
  email: z3.string().email(),
480
- name: z3.string()
514
+ name: z3.string(),
515
+ profilePictureUrl: z3.string().nullable().optional()
481
516
  });
482
517
  var agentAdminMemberSchema = z3.object({
483
518
  userId: z3.string(),
@@ -562,6 +597,37 @@ var assignTasksBodySchema = z3.object({
562
597
  { message: "assignTo needs at least one user email or group slug." }
563
598
  )
564
599
  });
600
+ var agentAdminPlanLimitsSchema = z3.object({
601
+ tasksPerDay: z3.number(),
602
+ members: z3.number(),
603
+ apiKeys: z3.number(),
604
+ groups: z3.number(),
605
+ auditLogRetention: z3.number(),
606
+ rateLimitPerSecond: z3.number(),
607
+ taskRetentionDays: z3.number()
608
+ });
609
+ var agentAdminUsageSchema = z3.object({
610
+ workspace: z3.string(),
611
+ planName: z3.string(),
612
+ planType: z3.string(),
613
+ trialState: z3.enum(["none", "active", "expired"]),
614
+ daysRemaining: z3.number().nullable(),
615
+ isPaidPro: z3.boolean(),
616
+ subscriptionStatus: z3.string().nullable(),
617
+ tasksToday: z3.number(),
618
+ maxTasksPerDay: z3.number().nullable(),
619
+ tasksResetAt: z3.number(),
620
+ openTasks: z3.number(),
621
+ totalTasks: z3.number(),
622
+ seatsCurrent: z3.number(),
623
+ seatsMax: z3.number().nullable(),
624
+ groupsCurrent: z3.number(),
625
+ groupsMax: z3.number().nullable(),
626
+ apiKeysCurrent: z3.number(),
627
+ apiKeysMax: z3.number().nullable(),
628
+ rateLimitPerSecond: z3.number(),
629
+ limits: agentAdminPlanLimitsSchema
630
+ });
565
631
 
566
632
  // src/schemas/index.ts
567
633
  var handlerUrlSchema2 = z4.string().refine((url) => isAllowedHandlerUrl(url), {
@@ -865,7 +931,11 @@ function resolveRobotRockAuthConfig(overrides) {
865
931
  "RobotRock auth is required. Set ROBOTROCK_API_KEY, ROBOTROCK_AGENT_SERVICE_TOKEN with tenant context, or pass auth when creating the client."
866
932
  );
867
933
  }
868
- return { kind: "apiKey", apiKey };
934
+ return {
935
+ kind: "apiKey",
936
+ apiKey,
937
+ ...overrides?.actingUserId?.trim() ? { actingUserId: overrides.actingUserId.trim() } : {}
938
+ };
869
939
  }
870
940
 
871
941
  // src/chat-correlation.ts
@@ -1070,6 +1140,51 @@ function createChatsApi(config) {
1070
1140
  data
1071
1141
  );
1072
1142
  }
1143
+ },
1144
+ async uploadImage(input) {
1145
+ const validation = agentChatUploadImageBodySchema.safeParse(input);
1146
+ if (!validation.success) {
1147
+ throw new RobotRockError(
1148
+ `Invalid image upload: ${validation.error.issues[0]?.message}`,
1149
+ 400,
1150
+ validation.error.issues
1151
+ );
1152
+ }
1153
+ const response = await fetch(`${config.baseUrl}/agent-chats/images`, {
1154
+ method: "POST",
1155
+ headers: headers(),
1156
+ body: JSON.stringify(validation.data)
1157
+ });
1158
+ const data = await parseResponseBody(response);
1159
+ if (!response.ok) {
1160
+ throw new RobotRockError(
1161
+ getErrorMessage(data, "Failed to upload chat image"),
1162
+ response.status,
1163
+ data
1164
+ );
1165
+ }
1166
+ const uploaded = data;
1167
+ if (typeof uploaded.storageId !== "string" || typeof uploaded.url !== "string" || typeof uploaded.mediaType !== "string") {
1168
+ throw new RobotRockError(
1169
+ "Image upload returned an invalid response",
1170
+ 500,
1171
+ data
1172
+ );
1173
+ }
1174
+ return {
1175
+ storageId: uploaded.storageId,
1176
+ url: uploaded.url,
1177
+ mediaType: uploaded.mediaType,
1178
+ ...typeof uploaded.chatId === "string" ? { chatId: uploaded.chatId } : {},
1179
+ ...typeof uploaded.publicTaskId === "string" ? { publicTaskId: uploaded.publicTaskId } : {},
1180
+ ...typeof uploaded.filename === "string" ? { filename: uploaded.filename } : {},
1181
+ ...typeof uploaded.description === "string" ? { description: uploaded.description } : {},
1182
+ ...Array.isArray(uploaded.tags) ? {
1183
+ tags: uploaded.tags.filter(
1184
+ (tag) => typeof tag === "string"
1185
+ )
1186
+ } : {}
1187
+ };
1073
1188
  }
1074
1189
  };
1075
1190
  }
@@ -1139,6 +1254,7 @@ var RobotRock = class {
1139
1254
  }
1140
1255
  this.auth = resolveRobotRockAuthConfig({
1141
1256
  ...apiKey ? { apiKey } : {},
1257
+ ...config.actingUserId ? { actingUserId: config.actingUserId } : {},
1142
1258
  ...agentService ? { agentService } : {}
1143
1259
  });
1144
1260
  this.chatCorrelation = config.chatCorrelation;
@@ -1543,6 +1659,7 @@ function tryCreateBoundRobotRockClient(ctx) {
1543
1659
  if (apiKey) {
1544
1660
  return createClient({
1545
1661
  apiKey,
1662
+ ...caller?.userId ? { actingUserId: caller.userId } : {},
1546
1663
  baseUrl: process.env.ROBOTROCK_BASE_URL?.trim(),
1547
1664
  chatCorrelation
1548
1665
  });
@@ -1710,12 +1827,38 @@ async function postRobotRockLinkChatTask(ctx, input) {
1710
1827
  }
1711
1828
  }
1712
1829
 
1830
+ // src/eve/tool-ui-hint.ts
1831
+ var TOOL_UI_HINT_FIELD = "uiHint";
1832
+ function withUiHint(result, hint) {
1833
+ return {
1834
+ ...result,
1835
+ [TOOL_UI_HINT_FIELD]: hint
1836
+ };
1837
+ }
1838
+
1839
+ // src/eve/tool-result-ui-meta.ts
1840
+ var TOOL_UI_FIELD = "ui";
1841
+ var TOOL_RESULT_UI_ENTITY_ID_RE = /^[a-z][a-z0-9_]{0,63}$/;
1842
+ function withToolUi(result, ui) {
1843
+ const existing = typeof result[TOOL_UI_FIELD] === "object" && result[TOOL_UI_FIELD] !== null && !Array.isArray(result[TOOL_UI_FIELD]) ? result[TOOL_UI_FIELD] : {};
1844
+ return {
1845
+ ...result,
1846
+ [TOOL_UI_FIELD]: {
1847
+ ...existing,
1848
+ ...ui
1849
+ }
1850
+ };
1851
+ }
1852
+
1713
1853
  // src/eve/tool-reply-guidance.ts
1714
1854
  var TOOL_REPLY_GUIDANCE_FIELD = "replyGuidance";
1715
1855
  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).";
1716
- 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.";
1856
+ 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, query-tasks, or workspace-usage 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.";
1857
+ var GET_WORKSPACE_USAGE_REPLY_GUIDANCE = "Workspace plan and usage render as a card in chat. Do not restate plan name, task counts, seats, groups, API keys, or rate limits from the card. Only add context not shown (e.g. upgrade options, that LLM token/cost meters are not tracked, or next steps). Never invent token or dollar spend numbers.";
1717
1858
  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.";
1718
1859
  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).";
1860
+ var GENERATE_RANDOM_CHART_REPLY_GUIDANCE = "Chart metrics render as a chart card in chat. Do not restate series values, dates, or categories from the chart. Only add brief context (e.g. that this is demo data).";
1861
+ var GENERATE_IMAGE_REPLY_GUIDANCE = "The generated image renders in chat UI. Do not describe the image pixels or restate the prompt. Only add a short acknowledgement or next-step question if useful.";
1719
1862
  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).";
1720
1863
  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.";
1721
1864
  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.";
@@ -1824,69 +1967,38 @@ var createInboxTaskTool = defineCreateInboxTaskTool();
1824
1967
  import { defineTool as defineTool2 } from "eve/tools";
1825
1968
  import { z as z7 } from "zod";
1826
1969
 
1827
- // src/eve/tool-result-display.ts
1828
- function toolDisplayResult(data, options) {
1829
- const display = options?.widget || options?.title || options?.description ? {
1830
- ...options.widget ? { widget: options.widget } : {},
1831
- ...options.title ? { title: options.title } : {},
1832
- ...options.description ? { description: options.description } : {}
1833
- } : void 0;
1834
- return {
1835
- ...display ? { display } : {},
1836
- data,
1837
- ...options?.ui ? { ui: options.ui } : {}
1838
- };
1839
- }
1840
-
1841
1970
  // src/eve/tool-display-format.ts
1842
1971
  function formatToolObjectResult(data, options) {
1843
- return withReplyGuidance(
1844
- toolDisplayResult(data, {
1845
- title: options.title,
1846
- description: options.description,
1847
- ui: options.ui
1848
- }),
1972
+ let result = withReplyGuidance(
1973
+ data,
1849
1974
  options.replyGuidance
1850
1975
  );
1976
+ if (options.ui) {
1977
+ result = withToolUi(result, options.ui);
1978
+ }
1979
+ if (options.uiHint) {
1980
+ result = withUiHint(result, options.uiHint);
1981
+ }
1982
+ return result;
1851
1983
  }
1852
1984
  function formatToolListResult(listKey, items, options) {
1853
- const listFieldUi = options.itemWidget ? {
1854
- "ui:widget": "list",
1855
- items: {
1856
- "ui:widget": options.itemWidget,
1857
- ...options.itemUi ?? {}
1858
- }
1859
- } : {
1860
- "ui:widget": "table",
1861
- ...options.itemUi ? { items: options.itemUi } : {}
1985
+ const ui = {
1986
+ ...options.ui,
1987
+ layout: "list",
1988
+ rowsPath: listKey,
1989
+ ...options.entity ? { entity: options.entity } : {},
1990
+ ...options.present !== void 0 ? { present: options.present } : {}
1862
1991
  };
1863
- return formatToolObjectResult(
1864
- { [listKey]: items },
1865
- {
1866
- title: options.title,
1867
- ui: {
1868
- [listKey]: listFieldUi
1869
- },
1870
- replyGuidance: options.replyGuidance
1871
- }
1992
+ return withUiHint(
1993
+ withToolUi(
1994
+ withReplyGuidance({ [listKey]: items }, options.replyGuidance),
1995
+ ui
1996
+ ),
1997
+ "list"
1872
1998
  );
1873
1999
  }
1874
2000
 
1875
2001
  // src/eve/tools/identity/format-my-access.ts
1876
- var ACCESS_FIELD_UI = {
1877
- workspace: { "ui:title": "Workspace" },
1878
- role: { "ui:title": "Role" },
1879
- tenantAdmin: { "ui:title": "Tenant admin", "ui:widget": "boolean" },
1880
- groups: { "ui:title": "Groups" },
1881
- manageSettings: { "ui:title": "Manage settings", "ui:widget": "boolean" },
1882
- manageBilling: { "ui:title": "Manage billing", "ui:widget": "boolean" },
1883
- manageTeam: { "ui:title": "Manage team", "ui:widget": "boolean" },
1884
- manageIntegrations: {
1885
- "ui:title": "Manage integrations",
1886
- "ui:widget": "boolean"
1887
- },
1888
- email: { "ui:title": "Email" }
1889
- };
1890
2002
  function formatMyAccessResult(input) {
1891
2003
  return formatToolObjectResult(
1892
2004
  {
@@ -1903,14 +2015,8 @@ function formatMyAccessResult(input) {
1903
2015
  }
1904
2016
  },
1905
2017
  {
1906
- ui: {
1907
- access: {
1908
- "ui:widget": "access",
1909
- "ui:title": "Your access",
1910
- items: ACCESS_FIELD_UI
1911
- }
1912
- },
1913
- replyGuidance: MY_ACCESS_REPLY_GUIDANCE
2018
+ replyGuidance: MY_ACCESS_REPLY_GUIDANCE,
2019
+ ui: { entity: "access" }
1914
2020
  }
1915
2021
  );
1916
2022
  }
@@ -1928,7 +2034,7 @@ function tenantCapabilities(isAdmin) {
1928
2034
  }
1929
2035
  function defineMyAccessTool() {
1930
2036
  return defineTool2({
1931
- 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.",
2037
+ description: "Check the authenticated user's tenant role, group memberships, and admin capabilities in RobotRock. Always call this before tenant-admin tools (manage_team_members, manage_groups, query_tasks, get_workspace_usage) in the same turn \u2014 including read-only requests like listing users or usage. Results render as a visible access tool card in chat like other tools; do not restate role, groups, or capabilities in your reply.",
1932
2038
  inputSchema: myAccessInputSchema,
1933
2039
  async execute(_input, ctx) {
1934
2040
  const caller = tryResolveTenantCaller(ctx);
@@ -1996,10 +2102,207 @@ var whoamiTool = defineWhoamiTool();
1996
2102
 
1997
2103
  // src/eve/tools/catalog/search-products.ts
1998
2104
  import { defineTool as defineTool4 } from "eve/tools";
2105
+ import { z as z10 } from "zod";
2106
+
2107
+ // src/eve/entity-schemas.ts
1999
2108
  import { z as z9 } from "zod";
2109
+ function buildTenantTaskUrl(tenantSlug, task) {
2110
+ const q = new URLSearchParams();
2111
+ if (task.app && task.app !== "default") {
2112
+ q.set("app", task.app);
2113
+ }
2114
+ if (task.type?.trim()) {
2115
+ q.set("type", task.type.trim());
2116
+ }
2117
+ q.set("selected", task.id);
2118
+ return `/${tenantSlug}/inbox?${q.toString()}`;
2119
+ }
2120
+ function buildTenantGroupUrl(tenantSlug, slug) {
2121
+ return `/${tenantSlug}/team/groups/${slug}`;
2122
+ }
2123
+ var toolResultUiMetaSchema = z9.object({
2124
+ present: z9.boolean().optional(),
2125
+ entity: z9.string().regex(TOOL_RESULT_UI_ENTITY_ID_RE).optional(),
2126
+ rowsPath: z9.string().min(1).optional(),
2127
+ layout: z9.enum(["list", "chart", "table"]).optional()
2128
+ }).strict();
2129
+ var agentOnlyFields = {
2130
+ replyGuidance: z9.string().optional(),
2131
+ ui: toolResultUiMetaSchema.optional(),
2132
+ uiHint: z9.enum(["list", "chart", "table"]).optional()
2133
+ };
2134
+ function withAgentOnlyFields(shape) {
2135
+ return z9.object({
2136
+ ...shape,
2137
+ ...agentOnlyFields
2138
+ });
2139
+ }
2140
+ var productEntityRowSchema = z9.object({
2141
+ id: z9.string().min(1),
2142
+ name: z9.string().min(1),
2143
+ price: z9.number(),
2144
+ currency: z9.string().min(1),
2145
+ inStock: z9.boolean(),
2146
+ url: z9.string().min(1)
2147
+ });
2148
+ var metricPointEntityRowSchema = z9.object({
2149
+ date: z9.string().optional(),
2150
+ category: z9.string().optional(),
2151
+ label: z9.string().optional()
2152
+ }).catchall(z9.union([z9.string(), z9.number()]));
2153
+ var memberEntityRowSchema = z9.object({
2154
+ name: z9.string(),
2155
+ email: z9.string(),
2156
+ role: z9.string(),
2157
+ membershipKind: z9.string(),
2158
+ profilePictureUrl: z9.string().nullable()
2159
+ });
2160
+ var taskEntityRowSchema = z9.object({
2161
+ id: z9.string().min(1),
2162
+ name: z9.string().min(1),
2163
+ status: z9.string().min(1),
2164
+ type: z9.string().nullable(),
2165
+ description: z9.string().nullable(),
2166
+ validUntil: z9.number(),
2167
+ createdAt: z9.number(),
2168
+ url: z9.string().min(1),
2169
+ threadPriority: z9.string().nullable().optional()
2170
+ });
2171
+ var groupEntityRowSchema = z9.object({
2172
+ name: z9.string().min(1),
2173
+ slug: z9.string().min(1),
2174
+ description: z9.string().nullable(),
2175
+ memberCount: z9.number().nullable(),
2176
+ url: z9.string().min(1)
2177
+ });
2178
+ var groupDetailEntitySchema = z9.object({
2179
+ name: z9.string().min(1),
2180
+ slug: z9.string().min(1),
2181
+ description: z9.string().nullable(),
2182
+ url: z9.string().min(1),
2183
+ members: z9.array(
2184
+ z9.object({
2185
+ name: z9.string(),
2186
+ email: z9.string(),
2187
+ profilePictureUrl: z9.string().nullable()
2188
+ })
2189
+ )
2190
+ });
2191
+ var statusEntityRowSchema = z9.object({
2192
+ id: z9.string().min(1),
2193
+ name: z9.string().min(1),
2194
+ status: z9.string().min(1),
2195
+ url: z9.string().min(1),
2196
+ type: z9.string().nullable().optional(),
2197
+ description: z9.string().nullable().optional()
2198
+ });
2199
+ var agentAdminErrorResultSchema = z9.object({
2200
+ ok: z9.literal(false),
2201
+ status: z9.number().optional(),
2202
+ message: z9.string(),
2203
+ response: z9.unknown().optional()
2204
+ });
2205
+ var agentAdminMutationResultSchema = z9.object({
2206
+ ...agentOnlyFields
2207
+ }).passthrough();
2208
+ var searchProductsOutputSchema = withAgentOnlyFields({
2209
+ items: z9.array(productEntityRowSchema)
2210
+ });
2211
+ var generateRandomChartOutputSchema = withAgentOnlyFields({
2212
+ title: z9.string().min(1),
2213
+ axis: z9.enum(["time", "category"]),
2214
+ series: z9.array(metricPointEntityRowSchema)
2215
+ });
2216
+ var generateImageOutputSchema = withAgentOnlyFields({
2217
+ prompt: z9.string().min(1),
2218
+ mediaType: z9.string().min(1),
2219
+ model: z9.string().min(1),
2220
+ storageId: z9.string().min(1),
2221
+ url: z9.string().min(1),
2222
+ /** @deprecated Legacy sessions only — prefer storageId/url. */
2223
+ base64: z9.string().min(1).optional()
2224
+ });
2225
+ var manageTeamMembersListOutputSchema = withAgentOnlyFields({
2226
+ members: z9.array(memberEntityRowSchema)
2227
+ });
2228
+ var manageTeamMembersDetailOutputSchema = withAgentOnlyFields(
2229
+ memberEntityRowSchema.shape
2230
+ );
2231
+ var manageTeamMembersOutputSchema = z9.union([
2232
+ manageTeamMembersListOutputSchema,
2233
+ manageTeamMembersDetailOutputSchema,
2234
+ agentAdminMutationResultSchema,
2235
+ agentAdminErrorResultSchema
2236
+ ]);
2237
+ var manageGroupsListOutputSchema = withAgentOnlyFields({
2238
+ groups: z9.array(groupEntityRowSchema)
2239
+ });
2240
+ var manageGroupsDetailOutputSchema = withAgentOnlyFields(
2241
+ groupDetailEntitySchema.shape
2242
+ );
2243
+ var manageGroupsSummaryOutputSchema = withAgentOnlyFields(
2244
+ groupEntityRowSchema.shape
2245
+ );
2246
+ var manageGroupsOutputSchema = z9.union([
2247
+ manageGroupsListOutputSchema,
2248
+ manageGroupsDetailOutputSchema,
2249
+ manageGroupsSummaryOutputSchema,
2250
+ agentAdminMutationResultSchema,
2251
+ agentAdminErrorResultSchema
2252
+ ]);
2253
+ var queryTasksListOutputSchema = withAgentOnlyFields({
2254
+ items: z9.array(taskEntityRowSchema),
2255
+ nextCursor: z9.string().nullable().optional()
2256
+ });
2257
+ var queryTasksDetailOutputSchema = withAgentOnlyFields({
2258
+ id: z9.string().nullable(),
2259
+ status: z9.string().nullable(),
2260
+ type: z9.string().nullable(),
2261
+ name: z9.string().nullable(),
2262
+ description: z9.string().nullable(),
2263
+ validUntil: z9.number().nullable(),
2264
+ createdAt: z9.number().nullable(),
2265
+ url: z9.string().min(1).nullable()
2266
+ });
2267
+ var queryTasksOutputSchema = z9.union([
2268
+ queryTasksListOutputSchema,
2269
+ queryTasksDetailOutputSchema,
2270
+ agentAdminErrorResultSchema
2271
+ ]);
2272
+ var assignTasksOutputSchema = z9.union([
2273
+ withAgentOnlyFields({
2274
+ results: z9.array(statusEntityRowSchema)
2275
+ }),
2276
+ agentAdminErrorResultSchema
2277
+ ]);
2278
+ var workspaceUsageEntitySchema = z9.object({
2279
+ workspace: z9.string(),
2280
+ plan: z9.string(),
2281
+ planType: z9.string(),
2282
+ trialState: z9.string(),
2283
+ daysRemaining: z9.number().nullable(),
2284
+ isPaidPro: z9.boolean(),
2285
+ subscriptionStatus: z9.string(),
2286
+ tasksToday: z9.string(),
2287
+ tasksResetAt: z9.string(),
2288
+ openTasks: z9.number(),
2289
+ totalTasks: z9.number(),
2290
+ seats: z9.string(),
2291
+ groups: z9.string(),
2292
+ apiKeys: z9.string(),
2293
+ rateLimitPerSecond: z9.number()
2294
+ });
2295
+ var getWorkspaceUsageOutputSchema = z9.union([
2296
+ withAgentOnlyFields({
2297
+ usage: workspaceUsageEntitySchema
2298
+ }),
2299
+ agentAdminErrorResultSchema
2300
+ ]);
2301
+
2302
+ // src/eve/tools/catalog/search-products.ts
2000
2303
  var SEARCH_PRODUCTS_TOOL_NAME = "search_products";
2001
- var searchProductsInputSchema = z9.object({
2002
- query: z9.string().min(1).describe("Product name or SKU to search for.")
2304
+ var searchProductsInputSchema = z10.object({
2305
+ query: z10.string().min(1).describe("Product name or SKU to search for.")
2003
2306
  });
2004
2307
  var DEMO_PRODUCTS = [
2005
2308
  {
@@ -2007,55 +2310,348 @@ var DEMO_PRODUCTS = [
2007
2310
  name: "Wireless Keyboard",
2008
2311
  price: 79.99,
2009
2312
  currency: "USD",
2010
- inStock: true
2313
+ inStock: true,
2314
+ url: "https://shop.example.com/products/sku-1001"
2011
2315
  },
2012
2316
  {
2013
2317
  id: "sku-2042",
2014
2318
  name: "USB-C Hub",
2015
2319
  price: 45.99,
2016
2320
  currency: "USD",
2017
- inStock: true
2321
+ inStock: true,
2322
+ url: "https://shop.example.com/products/sku-2042"
2018
2323
  },
2019
2324
  {
2020
2325
  id: "sku-3308",
2021
2326
  name: "Monitor Stand",
2022
2327
  price: 129.99,
2023
2328
  currency: "USD",
2024
- inStock: false
2329
+ inStock: false,
2330
+ url: "https://shop.example.com/products/sku-3308"
2025
2331
  }
2026
2332
  ];
2027
2333
  function defineSearchProductsTool() {
2028
2334
  return defineTool4({
2029
- 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.",
2335
+ description: "Search the product catalog and return matching items. Results render in chat UI \u2014 do not restate product names, prices, or SKUs in your reply.",
2030
2336
  inputSchema: searchProductsInputSchema,
2337
+ outputSchema: searchProductsOutputSchema,
2031
2338
  async execute({ query }) {
2032
2339
  const normalized = query.trim().toLowerCase();
2033
2340
  const items = DEMO_PRODUCTS.filter(
2034
2341
  (product) => product.name.toLowerCase().includes(normalized) || product.id.toLowerCase().includes(normalized)
2035
2342
  );
2036
- return withReplyGuidance(
2037
- toolDisplayResult(
2038
- { items: [...items] },
2039
- {
2040
- title: items.length === 1 ? "1 product" : `${items.length} products`,
2041
- ui: {
2042
- items: {
2043
- "ui:widget": "list",
2044
- "ui:title": "Results",
2045
- items: {
2046
- "ui:widget": "productInfo"
2047
- }
2048
- }
2049
- }
2050
- }
2051
- ),
2052
- SEARCH_PRODUCTS_REPLY_GUIDANCE
2343
+ return formatToolListResult(
2344
+ "items",
2345
+ items.map((product) => ({ ...product })),
2346
+ {
2347
+ replyGuidance: SEARCH_PRODUCTS_REPLY_GUIDANCE,
2348
+ entity: "product"
2349
+ }
2053
2350
  );
2054
2351
  }
2055
2352
  });
2056
2353
  }
2057
2354
  var searchProductsTool = defineSearchProductsTool();
2058
2355
 
2356
+ // src/eve/tools/catalog/generate-random-chart.ts
2357
+ import { defineTool as defineTool5 } from "eve/tools";
2358
+ import { z as z11 } from "zod";
2359
+ var GENERATE_RANDOM_CHART_TOOL_NAME = "generate_random_chart";
2360
+ var generateRandomChartInputSchema = z11.object({
2361
+ axis: z11.enum(["time", "category", "random"]).optional().describe(
2362
+ "X-axis style: time (line), category (bar), or random. Defaults to random."
2363
+ ),
2364
+ seriesCount: z11.number().int().min(1).max(3).optional().describe("Number of numeric series (1\u20133). Defaults to a random 1\u20132."),
2365
+ pointCount: z11.number().int().min(4).max(30).optional().describe("Number of data points (4\u201330). Defaults to a random 8\u201314."),
2366
+ seed: z11.number().int().optional().describe("Optional seed for reproducible random data.")
2367
+ });
2368
+ function createRng(seed) {
2369
+ let state = seed === void 0 ? (Math.floor(Math.random() * 2147483647) ^ Date.now()) >>> 0 : seed >>> 0;
2370
+ if (state === 0) {
2371
+ state = 1;
2372
+ }
2373
+ return () => {
2374
+ state ^= state << 13;
2375
+ state ^= state >>> 17;
2376
+ state ^= state << 5;
2377
+ return (state >>> 0) / 4294967296;
2378
+ };
2379
+ }
2380
+ function pick(rng, items) {
2381
+ return items[Math.floor(rng() * items.length)];
2382
+ }
2383
+ function randomInt(rng, min, max) {
2384
+ return min + Math.floor(rng() * (max - min + 1));
2385
+ }
2386
+ function roundMetric(value) {
2387
+ return Math.round(value * 10) / 10;
2388
+ }
2389
+ var TIME_TITLES = [
2390
+ "Task throughput",
2391
+ "Approvals over time",
2392
+ "Inbox volume",
2393
+ "Agent tool calls",
2394
+ "Webhook deliveries"
2395
+ ];
2396
+ var CATEGORY_TITLES = [
2397
+ "Tasks by status",
2398
+ "Approvals by team",
2399
+ "Volume by region",
2400
+ "Spend by category",
2401
+ "Tickets by priority"
2402
+ ];
2403
+ var TIME_SERIES_KEYS = [
2404
+ ["value"],
2405
+ ["created", "handled"],
2406
+ ["open", "handled", "expired"]
2407
+ ];
2408
+ var CATEGORY_SERIES_KEYS = [
2409
+ ["value"],
2410
+ ["revenue", "costs"],
2411
+ ["approved", "rejected", "pending"]
2412
+ ];
2413
+ var CATEGORIES = [
2414
+ ["North", "South", "East", "West", "Central"],
2415
+ ["Finance", "Ops", "Support", "Engineering", "Sales"],
2416
+ ["P0", "P1", "P2", "P3", "P4"],
2417
+ ["Draft", "Open", "Handled", "Expired", "Cancelled"]
2418
+ ];
2419
+ function formatDate(daysAgo) {
2420
+ const date = /* @__PURE__ */ new Date();
2421
+ date.setUTCHours(0, 0, 0, 0);
2422
+ date.setUTCDate(date.getUTCDate() - daysAgo);
2423
+ return date.toISOString().slice(0, 10);
2424
+ }
2425
+ function buildSeriesPoints(args) {
2426
+ const { rng, axis, seriesKeys, pointCount } = args;
2427
+ const baselines = seriesKeys.map(() => 20 + rng() * 80);
2428
+ if (axis === "time") {
2429
+ return Array.from({ length: pointCount }, (_, index) => {
2430
+ const point = {
2431
+ date: formatDate(pointCount - 1 - index)
2432
+ };
2433
+ for (let i = 0; i < seriesKeys.length; i++) {
2434
+ const drift = (rng() - 0.45) * 12;
2435
+ baselines[i] = Math.max(1, baselines[i] + drift);
2436
+ point[seriesKeys[i]] = roundMetric(baselines[i]);
2437
+ }
2438
+ return point;
2439
+ });
2440
+ }
2441
+ const labels = pick(rng, CATEGORIES).slice(0, pointCount);
2442
+ return labels.map((label) => {
2443
+ const point = { category: label };
2444
+ for (let i = 0; i < seriesKeys.length; i++) {
2445
+ point[seriesKeys[i]] = roundMetric(8 + rng() * 120);
2446
+ }
2447
+ return point;
2448
+ });
2449
+ }
2450
+ function buildRandomChartData(input = {}) {
2451
+ const rng = createRng(input.seed);
2452
+ const axis = input.axis === "time" || input.axis === "category" ? input.axis : pick(rng, ["time", "category"]);
2453
+ const seriesCount = input.seriesCount ?? randomInt(rng, 1, 2);
2454
+ const pointCount = input.pointCount ?? (axis === "time" ? randomInt(rng, 8, 14) : randomInt(rng, 4, 6));
2455
+ const keyPool = axis === "time" ? TIME_SERIES_KEYS : CATEGORY_SERIES_KEYS;
2456
+ const seriesKeys = keyPool.find((keys) => keys.length === seriesCount) ?? keyPool[0];
2457
+ const title = pick(rng, axis === "time" ? TIME_TITLES : CATEGORY_TITLES);
2458
+ const series = buildSeriesPoints({
2459
+ rng,
2460
+ axis,
2461
+ seriesKeys,
2462
+ pointCount
2463
+ });
2464
+ return { title, axis, series };
2465
+ }
2466
+ function defineGenerateRandomChartTool() {
2467
+ return defineTool5({
2468
+ description: "Generate random chart-ready demo metrics for testing chat chart UI. Results render as a chart card \u2014 do not restate series values in your reply.",
2469
+ inputSchema: generateRandomChartInputSchema,
2470
+ outputSchema: generateRandomChartOutputSchema,
2471
+ async execute(input) {
2472
+ const data = buildRandomChartData(input);
2473
+ return formatToolObjectResult(data, {
2474
+ replyGuidance: GENERATE_RANDOM_CHART_REPLY_GUIDANCE,
2475
+ uiHint: "chart",
2476
+ ui: {
2477
+ layout: "chart",
2478
+ rowsPath: "series",
2479
+ entity: "metric_point",
2480
+ present: true
2481
+ }
2482
+ });
2483
+ }
2484
+ });
2485
+ }
2486
+ var generateRandomChartTool = defineGenerateRandomChartTool();
2487
+
2488
+ // src/eve/tools/catalog/generate-image.ts
2489
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
2490
+ import { createGateway, generateImage } from "ai";
2491
+ import { defineTool as defineTool6 } from "eve/tools";
2492
+ import { z as z12 } from "zod";
2493
+ var GENERATE_IMAGE_TOOL_NAME = "generate_image";
2494
+ var DEFAULT_IMAGE_MODEL = "black-forest-labs/flux.2-klein-4b";
2495
+ var DEFAULT_IMAGE_SIZE = "512";
2496
+ var DEFAULT_IMAGE_ASPECT_RATIO = "1:1";
2497
+ var generateImageInputSchema = z12.object({
2498
+ prompt: z12.string().min(1).describe("Detailed description of the image to generate")
2499
+ });
2500
+ function normalizeEnvValue(value) {
2501
+ if (!value) {
2502
+ return void 0;
2503
+ }
2504
+ return value.replace(/^["']|["']$/g, "");
2505
+ }
2506
+ function isJwtExpired(token, bufferSeconds = 60) {
2507
+ try {
2508
+ const payload = JSON.parse(
2509
+ Buffer.from(token.split(".")[1] ?? "", "base64url").toString("utf8")
2510
+ );
2511
+ return typeof payload.exp !== "number" || Date.now() / 1e3 >= payload.exp - bufferSeconds;
2512
+ } catch {
2513
+ return true;
2514
+ }
2515
+ }
2516
+ function resolveAiImageModel(modelId = normalizeEnvValue(process.env.AI_IMAGE_MODEL) ?? DEFAULT_IMAGE_MODEL) {
2517
+ const openRouterKey = normalizeEnvValue(process.env.OPENROUTER_API_KEY);
2518
+ if (openRouterKey) {
2519
+ const openrouter = createOpenRouter({ apiKey: openRouterKey });
2520
+ return {
2521
+ provider: "openrouter",
2522
+ model: openrouter.imageModel(modelId),
2523
+ modelId
2524
+ };
2525
+ }
2526
+ const gatewayKey = normalizeEnvValue(process.env.AI_GATEWAY_API_KEY);
2527
+ if (gatewayKey) {
2528
+ const gateway2 = createGateway({ apiKey: gatewayKey });
2529
+ return {
2530
+ provider: "ai-gateway-api-key",
2531
+ model: gateway2.imageModel(modelId),
2532
+ modelId
2533
+ };
2534
+ }
2535
+ const oidcToken = normalizeEnvValue(process.env.VERCEL_OIDC_TOKEN);
2536
+ if (!oidcToken) {
2537
+ throw new Error(
2538
+ `No AI provider credentials for image model "${modelId}". Set OPENROUTER_API_KEY (preferred), or AI_GATEWAY_API_KEY / VERCEL_OIDC_TOKEN.`
2539
+ );
2540
+ }
2541
+ if (isJwtExpired(oidcToken)) {
2542
+ throw new Error(
2543
+ "VERCEL_OIDC_TOKEN is expired. Set OPENROUTER_API_KEY instead, or refresh the OIDC token."
2544
+ );
2545
+ }
2546
+ process.env.VERCEL_OIDC_TOKEN = oidcToken;
2547
+ const gateway = createGateway();
2548
+ return {
2549
+ provider: "ai-gateway-oidc",
2550
+ model: gateway.imageModel(modelId),
2551
+ modelId
2552
+ };
2553
+ }
2554
+ function resolveAiImageSize() {
2555
+ return normalizeEnvValue(process.env.AI_IMAGE_SIZE) ?? DEFAULT_IMAGE_SIZE;
2556
+ }
2557
+ function resolveAiImageAspectRatio() {
2558
+ return normalizeEnvValue(process.env.AI_IMAGE_ASPECT_RATIO) ?? DEFAULT_IMAGE_ASPECT_RATIO;
2559
+ }
2560
+ function extensionForMediaType(mediaType) {
2561
+ const normalized = mediaType.toLowerCase();
2562
+ if (normalized.includes("jpeg") || normalized.includes("jpg")) return "jpg";
2563
+ if (normalized.includes("webp")) return "webp";
2564
+ if (normalized.includes("gif")) return "gif";
2565
+ return "png";
2566
+ }
2567
+ function filenameFromImagePrompt(prompt, mediaType) {
2568
+ const slug = prompt.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
2569
+ return `${slug || "generated-image"}.${extensionForMediaType(mediaType)}`;
2570
+ }
2571
+ async function generateImageBytes(input, options) {
2572
+ const { model, modelId } = resolveAiImageModel();
2573
+ const size = resolveAiImageSize();
2574
+ const aspectRatio = resolveAiImageAspectRatio();
2575
+ try {
2576
+ const { image } = await generateImage({
2577
+ model,
2578
+ prompt: input.prompt,
2579
+ aspectRatio,
2580
+ abortSignal: options?.abortSignal,
2581
+ size
2582
+ });
2583
+ if (!image.base64) {
2584
+ throw new Error(`Image model "${modelId}" returned no image data.`);
2585
+ }
2586
+ return {
2587
+ prompt: input.prompt,
2588
+ mediaType: image.mediaType || "image/png",
2589
+ model: modelId,
2590
+ base64: image.base64
2591
+ };
2592
+ } catch (error) {
2593
+ const message = error instanceof Error ? error.message : "Image generation failed.";
2594
+ throw new Error(`Image generation failed (${modelId}): ${message}`);
2595
+ }
2596
+ }
2597
+ function defineGenerateImageTool() {
2598
+ return defineTool6({
2599
+ description: "Generate an image from a text prompt using a cheap/fast image model. Use when the user asks to draw, create, or generate a picture or illustration. The image renders in chat UI \u2014 do not describe the pixels in your reply.",
2600
+ inputSchema: generateImageInputSchema,
2601
+ outputSchema: generateImageOutputSchema,
2602
+ toModelOutput(output) {
2603
+ return {
2604
+ type: "text",
2605
+ value: `Generated an image for: "${output.prompt}" (model: ${output.model}).`
2606
+ };
2607
+ },
2608
+ async execute(input, ctx) {
2609
+ const caller = tryResolveTenantCaller(ctx);
2610
+ const chatId = caller?.chatId?.trim();
2611
+ if (!chatId) {
2612
+ throw new Error(
2613
+ "generate_image requires a dashboard chat session (missing chatId)."
2614
+ );
2615
+ }
2616
+ const client = tryCreateBoundRobotRockClient(ctx);
2617
+ if (!client) {
2618
+ throw new Error(
2619
+ "RobotRock auth is unset. Configure ROBOTROCK_AGENT_SERVICE_TOKEN for hosted agents or ROBOTROCK_API_KEY for self-hosted deployments."
2620
+ );
2621
+ }
2622
+ const generated = await generateImageBytes(input, {
2623
+ abortSignal: ctx?.abortSignal
2624
+ });
2625
+ const uploaded = await client.chats.uploadImage({
2626
+ mediaType: generated.mediaType,
2627
+ base64: generated.base64,
2628
+ chatId,
2629
+ source: GENERATE_IMAGE_TOOL_NAME,
2630
+ filename: filenameFromImagePrompt(generated.prompt, generated.mediaType),
2631
+ description: generated.prompt,
2632
+ tags: [GENERATE_IMAGE_TOOL_NAME]
2633
+ });
2634
+ return formatToolObjectResult(
2635
+ {
2636
+ prompt: generated.prompt,
2637
+ mediaType: uploaded.mediaType || generated.mediaType,
2638
+ model: generated.model,
2639
+ storageId: uploaded.storageId,
2640
+ url: uploaded.url
2641
+ },
2642
+ {
2643
+ replyGuidance: GENERATE_IMAGE_REPLY_GUIDANCE,
2644
+ ui: {
2645
+ present: true,
2646
+ entity: "generated_image"
2647
+ }
2648
+ }
2649
+ );
2650
+ }
2651
+ });
2652
+ }
2653
+ var generateImageTool = defineGenerateImageTool();
2654
+
2059
2655
  // src/agent-admin.ts
2060
2656
  async function agentAdminFetch(config, path, init) {
2061
2657
  const baseUrl = (config.baseUrl?.trim() || getRobotRockApiBaseUrl()).replace(
@@ -2084,6 +2680,9 @@ async function agentAdminFetch(config, path, init) {
2084
2680
  }
2085
2681
  function createAgentAdminApi(config) {
2086
2682
  return {
2683
+ usage: {
2684
+ get: () => agentAdminFetch(config, "/usage")
2685
+ },
2087
2686
  members: {
2088
2687
  list: () => agentAdminFetch(config, "/members"),
2089
2688
  get: (memberRef) => agentAdminFetch(config, `/members/${encodeURIComponent(memberRef)}`),
@@ -2227,53 +2826,45 @@ function requireBoundAgentAdminClient(ctx) {
2227
2826
  }
2228
2827
 
2229
2828
  // src/eve/tools/admin/format-team-members-list.ts
2230
- var MEMBER_DETAIL_UI = {
2231
- name: { "ui:title": "Name" },
2232
- email: { "ui:title": "Email" },
2233
- role: { "ui:title": "Role" },
2234
- membershipKind: { "ui:title": "Membership" }
2235
- };
2236
2829
  function serializeMemberRow(member) {
2237
2830
  return {
2238
2831
  name: member.user.name,
2239
2832
  email: member.user.email,
2240
2833
  role: member.role,
2241
- membershipKind: member.membershipKind
2834
+ membershipKind: member.membershipKind,
2835
+ profilePictureUrl: member.user.profilePictureUrl ?? null
2242
2836
  };
2243
2837
  }
2244
2838
  function formatTeamMembersListResult(members) {
2245
- const countLabel = members.length === 1 ? "1 team member" : `${members.length} team members`;
2246
2839
  return formatToolListResult(
2247
2840
  "members",
2248
2841
  members.map(serializeMemberRow),
2249
2842
  {
2250
- title: countLabel,
2251
- itemWidget: "tenantMember",
2252
- replyGuidance: MANAGE_TEAM_MEMBERS_LIST_REPLY_GUIDANCE
2843
+ replyGuidance: MANAGE_TEAM_MEMBERS_LIST_REPLY_GUIDANCE,
2844
+ entity: "member"
2253
2845
  }
2254
2846
  );
2255
2847
  }
2256
- function formatTeamMemberDetailResult(member, options) {
2848
+ function formatTeamMemberDetailResult(member) {
2257
2849
  return formatToolObjectResult(serializeMemberRow(member), {
2258
- title: options?.title ?? member.user.name,
2259
- ui: MEMBER_DETAIL_UI,
2260
- replyGuidance: MANAGE_TEAM_MEMBERS_DETAIL_REPLY_GUIDANCE
2850
+ replyGuidance: MANAGE_TEAM_MEMBERS_DETAIL_REPLY_GUIDANCE,
2851
+ ui: { entity: "member" }
2261
2852
  });
2262
2853
  }
2263
2854
 
2264
2855
  // src/eve/tools/admin/manage-team-members.ts
2265
- import { defineTool as defineTool5 } from "eve/tools";
2266
- import { z as z10 } from "zod";
2856
+ import { defineTool as defineTool7 } from "eve/tools";
2857
+ import { z as z13 } from "zod";
2267
2858
  var MANAGE_TEAM_MEMBERS_TOOL_NAME = "manage_team_members";
2268
- var manageTeamMembersInputSchema = z10.object({
2269
- action: z10.enum(["list", "get", "invite", "update_role", "remove"]),
2270
- userId: z10.string().min(1).optional().describe(
2859
+ var manageTeamMembersInputSchema = z13.object({
2860
+ action: z13.enum(["list", "get", "invite", "update_role", "remove"]),
2861
+ userId: z13.string().min(1).optional().describe(
2271
2862
  "Convex users table id for get, update_role, and remove. Prefer email when the member list only shows email."
2272
2863
  ),
2273
- email: z10.string().email().optional().describe(
2864
+ email: z13.string().email().optional().describe(
2274
2865
  "Member email for get, update_role, and remove; invitee email for invite."
2275
2866
  ),
2276
- role: z10.enum(["admin", "member"]).optional().describe("Role for invite and update_role.")
2867
+ role: z13.enum(["admin", "member"]).optional().describe("Role for invite and update_role.")
2277
2868
  }).superRefine((input, ctx) => {
2278
2869
  const requireField = (field, message) => {
2279
2870
  if (!input[field]) {
@@ -2308,20 +2899,16 @@ var manageTeamMembersInputSchema = z10.object({
2308
2899
  function resolveMemberRef(input) {
2309
2900
  return input.userId ?? input.email;
2310
2901
  }
2311
- function formatMemberMutationResult(payload, title) {
2902
+ function formatMemberMutationResult(payload) {
2312
2903
  return formatToolObjectResult(payload, {
2313
- title,
2314
- ui: {
2315
- success: { "ui:title": "Success", "ui:widget": "boolean" },
2316
- promoted: { "ui:title": "Promoted existing user", "ui:widget": "boolean" }
2317
- },
2318
2904
  replyGuidance: ADMIN_MUTATION_REPLY_GUIDANCE
2319
2905
  });
2320
2906
  }
2321
2907
  function defineManageTeamMembersTool() {
2322
- return defineTool5({
2323
- 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.",
2908
+ return defineTool7({
2909
+ description: "Tenant-admin tool for workspace team members: list, get, invite, change role, or remove. Requires tenant admin access. Call get_my_access in the same turn before this tool to verify admin access (the check stays a compact success marker unless it is the only presentable result). 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.",
2324
2910
  inputSchema: manageTeamMembersInputSchema,
2911
+ outputSchema: manageTeamMembersOutputSchema,
2325
2912
  async execute(input, ctx) {
2326
2913
  const api = requireBoundAgentAdminClient(ctx);
2327
2914
  try {
@@ -2343,13 +2930,11 @@ function defineManageTeamMembersTool() {
2343
2930
  });
2344
2931
  if (result.member) {
2345
2932
  return formatTeamMemberDetailResult(
2346
- result.member,
2347
- { title: "Member invited" }
2933
+ result.member
2348
2934
  );
2349
2935
  }
2350
2936
  return formatMemberMutationResult(
2351
- result,
2352
- "Invitation sent"
2937
+ result
2353
2938
  );
2354
2939
  }
2355
2940
  case "update_role": {
@@ -2358,16 +2943,14 @@ function defineManageTeamMembersTool() {
2358
2943
  input.role
2359
2944
  );
2360
2945
  return formatMemberMutationResult(
2361
- result,
2362
- "Member role updated"
2946
+ result
2363
2947
  );
2364
2948
  }
2365
2949
  case "remove": {
2366
2950
  const memberId = resolveMemberRef(input);
2367
2951
  const result = await api.members.remove(memberId);
2368
2952
  return formatMemberMutationResult(
2369
- result,
2370
- "Member removed"
2953
+ result
2371
2954
  );
2372
2955
  }
2373
2956
  }
@@ -2388,78 +2971,59 @@ function defineManageTeamMembersTool() {
2388
2971
  var manageTeamMembersTool = defineManageTeamMembersTool();
2389
2972
 
2390
2973
  // src/eve/tools/admin/manage-groups.ts
2391
- import { defineTool as defineTool6 } from "eve/tools";
2392
- import { z as z11 } from "zod";
2974
+ import { defineTool as defineTool8 } from "eve/tools";
2975
+ import { z as z14 } from "zod";
2393
2976
 
2394
2977
  // src/eve/tools/admin/format-groups-list.ts
2395
- var GROUP_ITEM_UI = {
2396
- name: { "ui:title": "Name" },
2397
- slug: { "ui:title": "Slug" },
2398
- description: { "ui:title": "Description" },
2399
- memberCount: { "ui:title": "Members", "ui:widget": "number" }
2400
- };
2401
- function serializeGroupRow(group) {
2978
+ function serializeGroupRow(group, tenantSlug) {
2402
2979
  return {
2403
2980
  name: group.name,
2404
2981
  slug: group.slug,
2405
2982
  description: group.description,
2406
- memberCount: group.memberCount ?? null
2983
+ memberCount: group.memberCount ?? null,
2984
+ url: buildTenantGroupUrl(tenantSlug, group.slug)
2407
2985
  };
2408
2986
  }
2409
- function formatGroupsListResult(groups) {
2410
- const countLabel = groups.length === 1 ? "1 group" : `${groups.length} groups`;
2987
+ function formatGroupsListResult(groups, options) {
2411
2988
  return formatToolListResult(
2412
2989
  "groups",
2413
- groups.map(serializeGroupRow),
2990
+ groups.map((group) => serializeGroupRow(group, options.tenantSlug)),
2414
2991
  {
2415
- title: countLabel,
2416
- itemWidget: "tenantGroup",
2417
- replyGuidance: MANAGE_GROUPS_LIST_REPLY_GUIDANCE
2992
+ replyGuidance: MANAGE_GROUPS_LIST_REPLY_GUIDANCE,
2993
+ entity: "group"
2418
2994
  }
2419
2995
  );
2420
2996
  }
2421
- function formatGroupDetailResult(group) {
2997
+ function formatGroupDetailResult(group, options) {
2422
2998
  return formatToolObjectResult(
2423
2999
  {
2424
3000
  name: group.name,
2425
3001
  slug: group.slug,
2426
3002
  description: group.description,
3003
+ url: buildTenantGroupUrl(options.tenantSlug, group.slug),
2427
3004
  members: group.members.map((member) => ({
2428
3005
  name: member.user.name,
2429
- email: member.user.email
3006
+ email: member.user.email,
3007
+ profilePictureUrl: member.user.profilePictureUrl ?? null
2430
3008
  }))
2431
3009
  },
2432
3010
  {
2433
- title: group.name,
2434
- ui: {
2435
- name: { "ui:title": "Name" },
2436
- slug: { "ui:title": "Slug" },
2437
- description: { "ui:title": "Description" },
2438
- members: {
2439
- "ui:widget": "list",
2440
- "ui:title": "Members",
2441
- items: {
2442
- name: { "ui:title": "Name" },
2443
- email: { "ui:title": "Email" }
2444
- }
2445
- }
2446
- },
2447
- replyGuidance: MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE
3011
+ replyGuidance: MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE,
3012
+ ui: { entity: "group" }
2448
3013
  }
2449
3014
  );
2450
3015
  }
2451
- function formatGroupSummaryResult(group) {
2452
- return formatToolObjectResult(serializeGroupRow(group), {
2453
- title: group.name,
2454
- ui: GROUP_ITEM_UI,
2455
- replyGuidance: MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE
3016
+ function formatGroupSummaryResult(group, options) {
3017
+ return formatToolObjectResult(serializeGroupRow(group, options.tenantSlug), {
3018
+ replyGuidance: MANAGE_GROUPS_DETAIL_REPLY_GUIDANCE,
3019
+ ui: { entity: "group" }
2456
3020
  });
2457
3021
  }
2458
3022
 
2459
3023
  // src/eve/tools/admin/manage-groups.ts
2460
3024
  var MANAGE_GROUPS_TOOL_NAME = "manage_groups";
2461
- var manageGroupsInputSchema = z11.object({
2462
- action: z11.enum([
3025
+ var manageGroupsInputSchema = z14.object({
3026
+ action: z14.enum([
2463
3027
  "list",
2464
3028
  "get",
2465
3029
  "create",
@@ -2468,18 +3032,18 @@ var manageGroupsInputSchema = z11.object({
2468
3032
  "add_member",
2469
3033
  "remove_member"
2470
3034
  ]),
2471
- groupId: z11.string().min(1).optional().describe(
3035
+ groupId: z14.string().min(1).optional().describe(
2472
3036
  "Convex group id for get, update, delete, and membership actions. Prefer slug when the group list only shows slug."
2473
3037
  ),
2474
- slug: z11.string().min(1).optional().describe(
3038
+ slug: z14.string().min(1).optional().describe(
2475
3039
  "Group slug (e.g. finance) for get, update, delete, and membership actions."
2476
3040
  ),
2477
- userId: z11.string().min(1).optional().describe(
3041
+ userId: z14.string().min(1).optional().describe(
2478
3042
  "User id for add_member and remove_member. Prefer email when the member list only shows email."
2479
3043
  ),
2480
- email: z11.string().email().optional().describe("Member email for add_member and remove_member."),
2481
- name: z11.string().min(1).optional().describe("Group name for create and update."),
2482
- description: z11.string().optional().describe("Group description for create and update.")
3044
+ email: z14.string().email().optional().describe("Member email for add_member and remove_member."),
3045
+ name: z14.string().min(1).optional().describe("Group name for create and update."),
3046
+ description: z14.string().optional().describe("Group description for create and update.")
2483
3047
  }).superRefine((input, ctx) => {
2484
3048
  const requireField = (field, message) => {
2485
3049
  if (!input[field]) {
@@ -2520,9 +3084,8 @@ var manageGroupsInputSchema = z11.object({
2520
3084
  break;
2521
3085
  }
2522
3086
  });
2523
- function formatGroupMutationResult(payload, title) {
3087
+ function formatGroupMutationResult(payload) {
2524
3088
  return formatToolObjectResult(payload, {
2525
- title,
2526
3089
  replyGuidance: ADMIN_MUTATION_REPLY_GUIDANCE
2527
3090
  });
2528
3091
  }
@@ -2533,40 +3096,51 @@ function resolveMemberRef2(input) {
2533
3096
  return input.userId ?? input.email;
2534
3097
  }
2535
3098
  function defineManageGroupsTool() {
2536
- return defineTool6({
2537
- 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.",
3099
+ return defineTool8({
3100
+ description: "Tenant-admin tool for workspace groups: list, get, create, update, delete, and manage group membership. Requires tenant admin access. Call get_my_access in the same turn before this tool to verify admin access (the check stays a compact success marker unless it is the only presentable result). 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.",
2538
3101
  inputSchema: manageGroupsInputSchema,
3102
+ outputSchema: manageGroupsOutputSchema,
2539
3103
  async execute(input, ctx) {
3104
+ const caller = requireAdminCaller(ctx);
2540
3105
  const api = requireBoundAgentAdminClient(ctx);
3106
+ const tenantSlug = caller.tenantSlug;
2541
3107
  try {
2542
3108
  switch (input.action) {
2543
3109
  case "list": {
2544
3110
  const result = await api.groups.list();
2545
- return formatGroupsListResult(result.groups);
3111
+ return formatGroupsListResult(result.groups, {
3112
+ tenantSlug
3113
+ });
2546
3114
  }
2547
3115
  case "get": {
2548
3116
  const result = await api.groups.get(resolveGroupRef(input));
2549
- return formatGroupDetailResult(result.group);
3117
+ return formatGroupDetailResult(
3118
+ result.group,
3119
+ { tenantSlug }
3120
+ );
2550
3121
  }
2551
3122
  case "create": {
2552
3123
  const result = await api.groups.create({
2553
3124
  name: input.name,
2554
3125
  description: input.description
2555
3126
  });
2556
- return formatGroupSummaryResult(result.group);
3127
+ return formatGroupSummaryResult(result.group, {
3128
+ tenantSlug
3129
+ });
2557
3130
  }
2558
3131
  case "update": {
2559
3132
  const result = await api.groups.update(resolveGroupRef(input), {
2560
3133
  name: input.name,
2561
3134
  description: input.description
2562
3135
  });
2563
- return formatGroupSummaryResult(result.group);
3136
+ return formatGroupSummaryResult(result.group, {
3137
+ tenantSlug
3138
+ });
2564
3139
  }
2565
3140
  case "delete": {
2566
3141
  const result = await api.groups.delete(resolveGroupRef(input));
2567
3142
  return formatGroupMutationResult(
2568
- result,
2569
- "Group deleted"
3143
+ result
2570
3144
  );
2571
3145
  }
2572
3146
  case "add_member": {
@@ -2575,8 +3149,7 @@ function defineManageGroupsTool() {
2575
3149
  resolveMemberRef2(input)
2576
3150
  );
2577
3151
  return formatGroupMutationResult(
2578
- result,
2579
- "Group member added"
3152
+ result
2580
3153
  );
2581
3154
  }
2582
3155
  case "remove_member": {
@@ -2585,8 +3158,7 @@ function defineManageGroupsTool() {
2585
3158
  resolveMemberRef2(input)
2586
3159
  );
2587
3160
  return formatGroupMutationResult(
2588
- result,
2589
- "Group member removed"
3161
+ result
2590
3162
  );
2591
3163
  }
2592
3164
  }
@@ -2607,120 +3179,101 @@ function defineManageGroupsTool() {
2607
3179
  var manageGroupsTool = defineManageGroupsTool();
2608
3180
 
2609
3181
  // src/eve/tools/admin/query-tasks.ts
2610
- import { defineTool as defineTool7 } from "eve/tools";
2611
- import { z as z12 } from "zod";
3182
+ import { defineTool as defineTool9 } from "eve/tools";
3183
+ import { z as z15 } from "zod";
2612
3184
 
2613
3185
  // src/eve/tools/admin/format-tasks-list.ts
2614
3186
  function resolveTaskCardLabel(task) {
2615
3187
  return task.name?.trim() || task.description?.trim() || task.type?.trim() || task.id?.trim() || "Untitled task";
2616
3188
  }
2617
- function formatTasksListResult(items, options) {
2618
- const title = options?.title ?? (items.length === 1 ? "1 task" : `${items.length} tasks`);
2619
- const result = formatToolListResult(
2620
- "items",
2621
- items.map((task) => ({
3189
+ function serializeTaskRow(task, tenantSlug) {
3190
+ return {
3191
+ id: task.id,
3192
+ name: resolveTaskCardLabel(task),
3193
+ status: task.status,
3194
+ type: task.type,
3195
+ description: task.description,
3196
+ validUntil: task.validUntil,
3197
+ createdAt: task.createdAt,
3198
+ threadPriority: task.threadPriority,
3199
+ url: buildTenantTaskUrl(tenantSlug, {
2622
3200
  id: task.id,
2623
- name: resolveTaskCardLabel(task),
2624
- status: task.status,
2625
- type: task.type,
2626
- description: task.description
2627
- })),
2628
- {
2629
- title,
2630
- itemWidget: "tenantTask",
2631
- replyGuidance: QUERY_TASKS_LIST_REPLY_GUIDANCE
2632
- }
2633
- );
2634
- if (options?.nextCursor) {
2635
- return {
2636
- ...result,
2637
- data: {
2638
- ...result.data,
2639
- nextCursor: options.nextCursor
2640
- },
2641
- display: {
2642
- ...result.display,
2643
- description: "More tasks available \u2014 pass nextCursor to list again."
2644
- }
2645
- };
2646
- }
2647
- return result;
3201
+ type: task.type
3202
+ })
3203
+ };
2648
3204
  }
2649
- function formatTaskSearchResult(items, total) {
2650
- return formatTasksListResult(items, {
2651
- title: total === 1 ? "1 matching task" : `${total} matching tasks`
3205
+ function formatTasksListResult(items, options) {
3206
+ const payload = {
3207
+ items: items.map((task) => serializeTaskRow(task, options.tenantSlug))
3208
+ };
3209
+ if (options.nextCursor) {
3210
+ payload.nextCursor = options.nextCursor;
3211
+ }
3212
+ return formatToolObjectResult(payload, {
3213
+ replyGuidance: QUERY_TASKS_LIST_REPLY_GUIDANCE,
3214
+ ui: { layout: "list", entity: "task", rowsPath: "items" }
2652
3215
  });
2653
3216
  }
2654
- function formatTaskDetailResult(task) {
2655
- const title = resolveTaskCardLabel({
2656
- name: typeof task.name === "string" ? task.name : null,
2657
- description: typeof task.description === "string" ? task.description : null,
2658
- type: typeof task.type === "string" ? task.type : null,
2659
- id: typeof task.id === "string" ? task.id : null
2660
- });
3217
+ function formatTaskSearchResult(items, options) {
3218
+ return formatTasksListResult(items, options);
3219
+ }
3220
+ function formatTaskDetailResult(task, options) {
3221
+ const id = typeof task.id === "string" ? task.id : null;
3222
+ const type = typeof task.type === "string" ? task.type : null;
3223
+ const url = id !== null ? buildTenantTaskUrl(options.tenantSlug, { id, type }) : null;
2661
3224
  return formatToolObjectResult(
2662
3225
  {
2663
- id: task.id ?? null,
2664
- status: task.status ?? null,
2665
- type: task.type ?? null,
2666
- name: task.name ?? null,
2667
- description: task.description ?? null,
2668
- validUntil: task.validUntil ?? null,
2669
- createdAt: task.createdAt ?? null
3226
+ id,
3227
+ status: typeof task.status === "string" ? task.status : null,
3228
+ type,
3229
+ name: typeof task.name === "string" ? task.name : null,
3230
+ description: typeof task.description === "string" ? task.description : null,
3231
+ validUntil: typeof task.validUntil === "number" ? task.validUntil : null,
3232
+ createdAt: typeof task.createdAt === "number" ? task.createdAt : null,
3233
+ url
2670
3234
  },
2671
3235
  {
2672
- title,
2673
- ui: {
2674
- id: { "ui:title": "Task ID" },
2675
- status: { "ui:title": "Status" },
2676
- type: { "ui:title": "Type" },
2677
- name: { "ui:title": "Name" },
2678
- description: { "ui:title": "Description" },
2679
- validUntil: { "ui:title": "Valid until", "ui:widget": "date" },
2680
- createdAt: { "ui:title": "Created", "ui:widget": "date" }
2681
- },
2682
- replyGuidance: QUERY_TASKS_DETAIL_REPLY_GUIDANCE
3236
+ replyGuidance: QUERY_TASKS_DETAIL_REPLY_GUIDANCE,
3237
+ ui: { entity: "task" }
2683
3238
  }
2684
3239
  );
2685
3240
  }
2686
- function formatAssignTasksResult(results, _assignTo) {
2687
- const succeeded = results.filter((row) => row.success).length;
2688
- const title = succeeded === results.length ? `${succeeded === 1 ? "1 task" : `${succeeded} tasks`} reassigned` : `${succeeded}/${results.length} tasks reassigned`;
2689
- return formatToolListResult(
2690
- "results",
2691
- results.map((row) => ({
3241
+ function formatAssignTasksResult(results, _assignTo, options) {
3242
+ const rows = results.map((row) => ({
3243
+ id: row.taskId,
3244
+ name: resolveTaskCardLabel({
3245
+ name: row.name,
3246
+ description: row.description,
3247
+ type: row.type,
3248
+ id: row.taskId
3249
+ }),
3250
+ type: row.type ?? null,
3251
+ description: row.description ?? null,
3252
+ status: row.success ? "reassigned" : "failed",
3253
+ url: buildTenantTaskUrl(options.tenantSlug, {
2692
3254
  id: row.taskId,
2693
- name: resolveTaskCardLabel({
2694
- name: row.name,
2695
- description: row.description,
2696
- type: row.type,
2697
- id: row.taskId
2698
- }),
2699
- type: row.type ?? null,
2700
- description: row.description ?? null,
2701
- status: row.success ? "reassigned" : "failed"
2702
- })),
2703
- {
2704
- title,
2705
- itemWidget: "tenantTask",
2706
- replyGuidance: ASSIGN_TASKS_REPLY_GUIDANCE
2707
- }
2708
- );
3255
+ type: row.type
3256
+ })
3257
+ }));
3258
+ return formatToolListResult("results", rows, {
3259
+ replyGuidance: ASSIGN_TASKS_REPLY_GUIDANCE,
3260
+ entity: "status"
3261
+ });
2709
3262
  }
2710
3263
 
2711
3264
  // src/eve/tools/admin/query-tasks.ts
2712
3265
  var QUERY_TASKS_TOOL_NAME = "query_tasks";
2713
- var queryTasksInputSchema = z12.object({
2714
- action: z12.enum(["list", "get", "search"]),
2715
- statusFilter: z12.enum(["all", "open", "handled", "expired"]).optional().describe("Filter by task status for list."),
2716
- typeFilter: z12.string().optional(),
2717
- appFilter: z12.string().optional(),
2718
- sortField: z12.enum(["type", "date", "status", "validUntil"]).optional(),
2719
- sortDirection: z12.enum(["asc", "desc"]).optional(),
2720
- limit: z12.number().int().positive().max(100).optional(),
2721
- cursor: z12.string().optional(),
2722
- taskId: z12.string().min(1).optional().describe("Public task id or Convex tasks table id for get."),
2723
- query: z12.string().min(1).optional().describe("Search type, name, description, or id for search.")
3266
+ var queryTasksInputSchema = z15.object({
3267
+ action: z15.enum(["list", "get", "search"]),
3268
+ statusFilter: z15.enum(["all", "open", "handled", "expired"]).optional().describe("Filter by task status for list."),
3269
+ typeFilter: z15.string().optional(),
3270
+ appFilter: z15.string().optional(),
3271
+ sortField: z15.enum(["type", "date", "status", "validUntil"]).optional(),
3272
+ sortDirection: z15.enum(["asc", "desc"]).optional(),
3273
+ limit: z15.number().int().positive().max(100).optional(),
3274
+ cursor: z15.string().optional(),
3275
+ taskId: z15.string().min(1).optional().describe("Public task id or Convex tasks table id for get."),
3276
+ query: z15.string().min(1).optional().describe("Search type, name, description, or id for search.")
2724
3277
  }).superRefine((input, ctx) => {
2725
3278
  switch (input.action) {
2726
3279
  case "get":
@@ -2744,11 +3297,14 @@ var queryTasksInputSchema = z12.object({
2744
3297
  }
2745
3298
  });
2746
3299
  function defineQueryTasksTool() {
2747
- return defineTool7({
2748
- 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.",
3300
+ return defineTool9({
3301
+ description: "Tenant-admin tool to list, fetch detail, or search inbox tasks in the workspace. Requires tenant admin access. Call get_my_access in the same turn before this tool to verify admin access (the check stays a compact success marker unless it is the only presentable result). Results render as chat UI cards \u2014 do not restate task names, ids, or statuses in your reply.",
2749
3302
  inputSchema: queryTasksInputSchema,
3303
+ outputSchema: queryTasksOutputSchema,
2750
3304
  async execute(input, ctx) {
3305
+ const caller = requireAdminCaller(ctx);
2751
3306
  const api = requireBoundAgentAdminClient(ctx);
3307
+ const tenantSlug = caller.tenantSlug;
2752
3308
  try {
2753
3309
  switch (input.action) {
2754
3310
  case "list": {
@@ -2762,18 +3318,22 @@ function defineQueryTasksTool() {
2762
3318
  cursor: input.cursor
2763
3319
  });
2764
3320
  return formatTasksListResult(result.items, {
3321
+ tenantSlug,
2765
3322
  nextCursor: result.nextCursor
2766
3323
  });
2767
3324
  }
2768
3325
  case "get": {
2769
3326
  const result = await api.tasks.get(input.taskId);
2770
- return formatTaskDetailResult(result.task);
3327
+ return formatTaskDetailResult(
3328
+ result.task,
3329
+ { tenantSlug }
3330
+ );
2771
3331
  }
2772
3332
  case "search": {
2773
3333
  const result = await api.tasks.search(input.query, input.limit);
2774
3334
  return formatTaskSearchResult(
2775
3335
  result.items,
2776
- result.total
3336
+ { tenantSlug }
2777
3337
  );
2778
3338
  }
2779
3339
  }
@@ -2794,11 +3354,11 @@ function defineQueryTasksTool() {
2794
3354
  var queryTasksTool = defineQueryTasksTool();
2795
3355
 
2796
3356
  // src/eve/tools/admin/assign-tasks.ts
2797
- import { defineTool as defineTool8 } from "eve/tools";
2798
- import { z as z13 } from "zod";
3357
+ import { defineTool as defineTool10 } from "eve/tools";
3358
+ import { z as z16 } from "zod";
2799
3359
  var ASSIGN_TASKS_TOOL_NAME = "assign_tasks";
2800
- var assignTasksInputSchema = z13.object({
2801
- taskIds: z13.array(z13.string().min(1)).min(1).max(100).describe(
3360
+ var assignTasksInputSchema = z16.object({
3361
+ taskIds: z16.array(z16.string().min(1)).min(1).max(100).describe(
2802
3362
  "Public task ids or Convex tasks table ids to reassign. Use query_tasks search/get to resolve ids first."
2803
3363
  ),
2804
3364
  assignTo: assignToSchema.refine(
@@ -2809,17 +3369,21 @@ var assignTasksInputSchema = z13.object({
2809
3369
  )
2810
3370
  });
2811
3371
  function defineAssignTasksTool() {
2812
- return defineTool8({
3372
+ return defineTool10({
2813
3373
  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.",
2814
3374
  inputSchema: assignTasksInputSchema,
3375
+ outputSchema: assignTasksOutputSchema,
2815
3376
  async execute(input, ctx) {
3377
+ const caller = requireTenantCaller(ctx);
2816
3378
  const api = createBoundAgentAdminClient(ctx);
2817
3379
  try {
2818
3380
  const result = await api.tasks.assign({
2819
3381
  taskIds: input.taskIds,
2820
3382
  assignTo: input.assignTo
2821
3383
  });
2822
- return formatAssignTasksResult(result.results, input.assignTo);
3384
+ return formatAssignTasksResult(result.results, input.assignTo, {
3385
+ tenantSlug: caller.tenantSlug
3386
+ });
2823
3387
  } catch (error) {
2824
3388
  if (error instanceof RobotRockError) {
2825
3389
  return {
@@ -2836,6 +3400,72 @@ function defineAssignTasksTool() {
2836
3400
  }
2837
3401
  var assignTasksTool = defineAssignTasksTool();
2838
3402
 
3403
+ // src/eve/tools/admin/get-workspace-usage.ts
3404
+ import { defineTool as defineTool11 } from "eve/tools";
3405
+ import { z as z17 } from "zod";
3406
+
3407
+ // src/eve/tools/admin/format-workspace-usage.ts
3408
+ function formatLimit(current, max) {
3409
+ return max === null ? `${current} / unlimited` : `${current} / ${max}`;
3410
+ }
3411
+ function formatWorkspaceUsageResult(usage) {
3412
+ const tasksLimit = usage.maxTasksPerDay === null ? `${usage.tasksToday} / unlimited` : `${usage.tasksToday} / ${usage.maxTasksPerDay}`;
3413
+ return formatToolObjectResult(
3414
+ {
3415
+ usage: {
3416
+ workspace: usage.workspace,
3417
+ plan: usage.planName,
3418
+ planType: usage.planType,
3419
+ trialState: usage.trialState,
3420
+ daysRemaining: usage.daysRemaining,
3421
+ isPaidPro: usage.isPaidPro,
3422
+ subscriptionStatus: usage.subscriptionStatus ?? "\u2014",
3423
+ tasksToday: tasksLimit,
3424
+ tasksResetAt: new Date(usage.tasksResetAt).toISOString(),
3425
+ openTasks: usage.openTasks,
3426
+ totalTasks: usage.totalTasks,
3427
+ seats: formatLimit(usage.seatsCurrent, usage.seatsMax),
3428
+ groups: formatLimit(usage.groupsCurrent, usage.groupsMax),
3429
+ apiKeys: formatLimit(usage.apiKeysCurrent, usage.apiKeysMax),
3430
+ rateLimitPerSecond: usage.rateLimitPerSecond
3431
+ }
3432
+ },
3433
+ {
3434
+ replyGuidance: GET_WORKSPACE_USAGE_REPLY_GUIDANCE,
3435
+ ui: { entity: "usage" }
3436
+ }
3437
+ );
3438
+ }
3439
+
3440
+ // src/eve/tools/admin/get-workspace-usage.ts
3441
+ var GET_WORKSPACE_USAGE_TOOL_NAME = "get_workspace_usage";
3442
+ var getWorkspaceUsageInputSchema = z17.object({});
3443
+ function defineGetWorkspaceUsageTool() {
3444
+ return defineTool11({
3445
+ description: "Tenant-admin tool for workspace plan, limits, and usage (tasks today, seats, groups, API keys, rate limits). Does not include LLM token counts or dollar spend \u2014 those are not tracked. Requires tenant admin access. Call get_my_access in the same turn before this tool. Results render as a chat UI card \u2014 do not restate plan or usage numbers in your reply.",
3446
+ inputSchema: getWorkspaceUsageInputSchema,
3447
+ outputSchema: getWorkspaceUsageOutputSchema,
3448
+ async execute(_input, ctx) {
3449
+ const api = requireBoundAgentAdminClient(ctx);
3450
+ try {
3451
+ const result = await api.usage.get();
3452
+ return formatWorkspaceUsageResult(result.usage);
3453
+ } catch (error) {
3454
+ if (error instanceof RobotRockError) {
3455
+ return {
3456
+ ok: false,
3457
+ status: error.statusCode,
3458
+ message: error.message,
3459
+ response: error.response
3460
+ };
3461
+ }
3462
+ throw error;
3463
+ }
3464
+ }
3465
+ });
3466
+ }
3467
+ var getWorkspaceUsageTool = defineGetWorkspaceUsageTool();
3468
+
2839
3469
  // src/eve/tools/index.ts
2840
3470
  function createRobotrockTools(options) {
2841
3471
  const tools = {};
@@ -2853,6 +3483,9 @@ function createRobotrockTools(options) {
2853
3483
  export {
2854
3484
  ASSIGN_TASKS_TOOL_NAME,
2855
3485
  CREATE_INBOX_TASK_TOOL_NAME,
3486
+ GENERATE_IMAGE_TOOL_NAME,
3487
+ GENERATE_RANDOM_CHART_TOOL_NAME,
3488
+ GET_WORKSPACE_USAGE_TOOL_NAME,
2856
3489
  MANAGE_GROUPS_TOOL_NAME,
2857
3490
  MANAGE_TEAM_MEMBERS_TOOL_NAME,
2858
3491
  MY_ACCESS_TOOL_NAME,
@@ -2861,17 +3494,28 @@ export {
2861
3494
  WHOAMI_TOOL_NAME,
2862
3495
  assignTasksInputSchema,
2863
3496
  assignTasksTool,
3497
+ buildRandomChartData,
2864
3498
  createInboxTaskInputSchema,
2865
3499
  createInboxTaskTool,
2866
3500
  createRobotrockTools,
2867
3501
  defineAssignTasksTool,
2868
3502
  defineCreateInboxTaskTool,
3503
+ defineGenerateImageTool,
3504
+ defineGenerateRandomChartTool,
3505
+ defineGetWorkspaceUsageTool,
2869
3506
  defineManageGroupsTool,
2870
3507
  defineManageTeamMembersTool,
2871
3508
  defineMyAccessTool,
2872
3509
  defineQueryTasksTool,
2873
3510
  defineSearchProductsTool,
2874
3511
  defineWhoamiTool,
3512
+ generateImageBytes,
3513
+ generateImageInputSchema,
3514
+ generateImageTool,
3515
+ generateRandomChartInputSchema,
3516
+ generateRandomChartTool,
3517
+ getWorkspaceUsageInputSchema,
3518
+ getWorkspaceUsageTool,
2875
3519
  manageGroupsTool,
2876
3520
  manageTeamMembersTool,
2877
3521
  myAccessInputSchema,