robotrock 1.3.4 → 1.5.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 (80) hide show
  1. package/README.md +11 -1
  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 +120 -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 +120 -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 +120 -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 -4
  16. package/dist/eve/agent/index.js +577 -261
  17. package/dist/eve/agent/index.js.map +1 -1
  18. package/dist/eve/index.d.ts +4 -4
  19. package/dist/eve/index.js +507 -7
  20. package/dist/eve/index.js.map +1 -1
  21. package/dist/eve/tools/admin/assign-tasks.d.ts +40 -19
  22. package/dist/eve/tools/admin/assign-tasks.js +334 -25
  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 +1365 -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 -7
  28. package/dist/eve/tools/admin/manage-groups.js +350 -31
  29. package/dist/eve/tools/admin/manage-groups.js.map +1 -1
  30. package/dist/eve/tools/admin/manage-team-members.d.ts +86 -7
  31. package/dist/eve/tools/admin/manage-team-members.js +318 -16
  32. package/dist/eve/tools/admin/manage-team-members.js.map +1 -1
  33. package/dist/eve/tools/admin/query-tasks.d.ts +82 -7
  34. package/dist/eve/tools/admin/query-tasks.js +363 -40
  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 +2077 -0
  38. package/dist/eve/tools/catalog/generate-image.js.map +1 -0
  39. package/dist/eve/tools/catalog/generate-random-chart.d.ts +77 -0
  40. package/dist/eve/tools/catalog/generate-random-chart.js +411 -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 -43
  43. package/dist/eve/tools/catalog/search-products.js +253 -6
  44. package/dist/eve/tools/catalog/search-products.js.map +1 -1
  45. package/dist/eve/tools/identity/index.d.ts +2 -1
  46. package/dist/eve/tools/identity/index.js +26 -6
  47. package/dist/eve/tools/identity/index.js.map +1 -1
  48. package/dist/eve/tools/identity/my-access.d.ts +88 -3
  49. package/dist/eve/tools/identity/my-access.js +26 -6
  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 +964 -115
  61. package/dist/eve/tools/index.js.map +1 -1
  62. package/dist/index-amkHKVGs.d.ts +1054 -0
  63. package/dist/index.d.ts +5 -5
  64. package/dist/index.js +328 -13
  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-Blq0XoAr.d.ts +0 -204
  80. package/dist/tool-ui-hint-CMpug5sC.d.ts +0 -13
@@ -0,0 +1,2077 @@
1
+ // src/eve/tools/catalog/generate-image.ts
2
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
3
+ import { createGateway, generateImage } from "ai";
4
+ import { defineTool } from "eve/tools";
5
+ import { z as z7 } from "zod";
6
+
7
+ // src/schemas/index.ts
8
+ import { z as z4 } from "zod";
9
+
10
+ // ../core/src/utils/safe-url.ts
11
+ var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
12
+ "localhost",
13
+ "metadata.google.internal",
14
+ "metadata.goog"
15
+ ]);
16
+ function normalizeHostname(hostname) {
17
+ return hostname.toLowerCase().replace(/^\[|\]$/g, "");
18
+ }
19
+ function isBlockedIpv4(host) {
20
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
21
+ if (!match) {
22
+ return false;
23
+ }
24
+ const octets = match.slice(1, 5).map((part) => Number(part));
25
+ if (octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255)) {
26
+ return true;
27
+ }
28
+ const [a, b, _c, _d] = octets;
29
+ if (a === void 0 || b === void 0) {
30
+ return true;
31
+ }
32
+ if (a === 127 || a === 0) return true;
33
+ if (a === 10) return true;
34
+ if (a === 169 && b === 254) return true;
35
+ if (a === 192 && b === 168) return true;
36
+ if (a === 172 && b >= 16 && b <= 31) return true;
37
+ if (a === 100 && b >= 64 && b <= 127) return true;
38
+ return false;
39
+ }
40
+ function ipv4FromNumericHost(host) {
41
+ if (/^\d+$/.test(host)) {
42
+ const num = Number(host);
43
+ if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
44
+ return null;
45
+ }
46
+ const a = num >>> 24 & 255;
47
+ const b = num >>> 16 & 255;
48
+ const c = num >>> 8 & 255;
49
+ const d = num & 255;
50
+ return `${a}.${b}.${c}.${d}`;
51
+ }
52
+ const hexMatch = /^0x([0-9a-f]{1,8})$/i.exec(host);
53
+ if (hexMatch) {
54
+ const num = Number.parseInt(hexMatch[1], 16);
55
+ if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
56
+ return null;
57
+ }
58
+ const a = num >>> 24 & 255;
59
+ const b = num >>> 16 & 255;
60
+ const c = num >>> 8 & 255;
61
+ const d = num & 255;
62
+ return `${a}.${b}.${c}.${d}`;
63
+ }
64
+ return null;
65
+ }
66
+ function isBlockedIpv4Mapped(host) {
67
+ const mappedDotted = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(host);
68
+ if (mappedDotted) {
69
+ return isBlockedIpv4(mappedDotted[1]);
70
+ }
71
+ const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(host);
72
+ if (mappedHex) {
73
+ const high = Number.parseInt(mappedHex[1], 16);
74
+ const low = Number.parseInt(mappedHex[2], 16);
75
+ if (Number.isFinite(high) && Number.isFinite(low)) {
76
+ const a = high >> 8 & 255;
77
+ const b = high & 255;
78
+ const c = low >> 8 & 255;
79
+ const d = low & 255;
80
+ return isBlockedIpv4(`${a}.${b}.${c}.${d}`);
81
+ }
82
+ }
83
+ return false;
84
+ }
85
+ function isBlockedIpv6(host) {
86
+ if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
87
+ return true;
88
+ }
89
+ if (host.startsWith("fc") || host.startsWith("fd")) {
90
+ return true;
91
+ }
92
+ if (host.startsWith("fe80:")) {
93
+ return true;
94
+ }
95
+ if (isBlockedIpv4Mapped(host)) {
96
+ return true;
97
+ }
98
+ return false;
99
+ }
100
+ function isBlockedHostname(hostname) {
101
+ const host = normalizeHostname(hostname);
102
+ if (!host) {
103
+ return true;
104
+ }
105
+ if (BLOCKED_HOSTNAMES.has(host)) {
106
+ return true;
107
+ }
108
+ if (host.endsWith(".localhost") || host.endsWith(".local")) {
109
+ return true;
110
+ }
111
+ const numericIpv4 = ipv4FromNumericHost(host);
112
+ if (numericIpv4 && isBlockedIpv4(numericIpv4)) {
113
+ return true;
114
+ }
115
+ return isBlockedIpv4(host) || isBlockedIpv6(host);
116
+ }
117
+ function isLoopbackHandlerUrl(urlString) {
118
+ let url;
119
+ try {
120
+ url = new URL(urlString);
121
+ } catch {
122
+ return false;
123
+ }
124
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
125
+ return false;
126
+ }
127
+ if (url.username || url.password) {
128
+ return false;
129
+ }
130
+ const host = url.hostname.toLowerCase();
131
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
132
+ }
133
+ function isAllowedHandlerUrl(urlString) {
134
+ return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
135
+ }
136
+ function isPublicHttpUrl(urlString) {
137
+ let url;
138
+ try {
139
+ url = new URL(urlString);
140
+ } catch {
141
+ return false;
142
+ }
143
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
144
+ return false;
145
+ }
146
+ if (url.username || url.password) {
147
+ return false;
148
+ }
149
+ return !isBlockedHostname(url.hostname);
150
+ }
151
+ var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
152
+ var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
153
+
154
+ // ../core/src/schemas/task.ts
155
+ import { z } from "zod";
156
+
157
+ // ../core/src/schemas/context-urls.ts
158
+ function resolveLinkUrl(value) {
159
+ return value.startsWith("http://") || value.startsWith("https://") ? value : `https://${value}`;
160
+ }
161
+ function widgetType(ui, field) {
162
+ const fieldUi = ui?.[field];
163
+ if (typeof fieldUi !== "object" || fieldUi === null) {
164
+ return void 0;
165
+ }
166
+ const widget = fieldUi["ui:widget"];
167
+ return typeof widget === "string" ? widget : void 0;
168
+ }
169
+ function validateUrlValue(value, widget) {
170
+ if (widget === "image" || widget === "link") {
171
+ if (typeof value !== "string") {
172
+ return PUBLIC_HTTP_URL_ERROR;
173
+ }
174
+ const url = widget === "link" ? resolveLinkUrl(value) : value;
175
+ if (!isPublicHttpUrl(url)) {
176
+ return PUBLIC_HTTP_URL_ERROR;
177
+ }
178
+ return null;
179
+ }
180
+ if (widget === "attachments" && Array.isArray(value)) {
181
+ for (const item of value) {
182
+ if (typeof item !== "object" || item === null) {
183
+ continue;
184
+ }
185
+ const url = item.url;
186
+ if (typeof url === "string" && !isPublicHttpUrl(resolveLinkUrl(url))) {
187
+ return PUBLIC_HTTP_URL_ERROR;
188
+ }
189
+ }
190
+ }
191
+ return null;
192
+ }
193
+ function validateContextPublicUrls(context) {
194
+ if (!context?.data) {
195
+ return null;
196
+ }
197
+ for (const [field, value] of Object.entries(context.data)) {
198
+ const widget = widgetType(context.ui, field);
199
+ if (!widget) {
200
+ continue;
201
+ }
202
+ const error = validateUrlValue(value, widget);
203
+ if (error) {
204
+ return `context.data.${field}: ${error}`;
205
+ }
206
+ }
207
+ return null;
208
+ }
209
+
210
+ // ../core/src/schemas/task.ts
211
+ var safeUrlSchema = z.string().refine((url) => isPublicHttpUrl(url), {
212
+ message: PUBLIC_HTTP_URL_ERROR
213
+ });
214
+ var handlerUrlSchema = z.string().refine((url) => isAllowedHandlerUrl(url), {
215
+ message: HANDLER_URL_ERROR
216
+ });
217
+ var jsonSchema7Schema = z.custom(
218
+ (val) => typeof val === "object" && val !== null,
219
+ { message: "Must be a valid JSON Schema object" }
220
+ );
221
+ var uiSchemaSchema = z.custom((val) => typeof val === "object" && val !== null, {
222
+ message: "Must be a valid UiSchema object"
223
+ });
224
+ var webhookHandlerSchema = z.object({
225
+ type: z.literal("webhook"),
226
+ url: handlerUrlSchema,
227
+ headers: z.record(z.string(), z.string())
228
+ });
229
+ var triggerHandlerSchema = webhookHandlerSchema.extend({
230
+ type: z.literal("trigger"),
231
+ tokenId: z.string().min(1)
232
+ });
233
+ var handlerSchema = z.discriminatedUnion("type", [webhookHandlerSchema, triggerHandlerSchema]);
234
+ var taskActionInputSchema = z.object({
235
+ id: z.string().min(1),
236
+ title: z.string().min(1),
237
+ description: z.string().optional(),
238
+ schema: jsonSchema7Schema.optional(),
239
+ ui: uiSchemaSchema.optional(),
240
+ data: z.record(z.string(), z.unknown()).optional()
241
+ });
242
+ var taskActionSchema = taskActionInputSchema.extend({
243
+ // Optional handlers for this action - if present, must have at least 1
244
+ handlers: z.array(handlerSchema).min(1).optional()
245
+ });
246
+ var uiFieldSchemaSchema = z.object({
247
+ "ui:widget": z.string().optional(),
248
+ "ui:title": z.string().optional(),
249
+ "ui:description": z.string().optional(),
250
+ "ui:options": z.record(z.string(), z.unknown()).optional(),
251
+ items: z.lazy(() => z.record(z.string(), uiFieldSchemaSchema)).optional()
252
+ }).passthrough();
253
+ var contextUiSchema = z.record(z.string(), uiFieldSchemaSchema).optional();
254
+ var contextDataSchema = z.object({
255
+ data: z.record(z.string(), z.unknown()),
256
+ ui: contextUiSchema
257
+ }).optional();
258
+ var TASK_CONTEXT_FORMAT_VERSION = 2;
259
+ var taskContextObjectBaseSchema = z.object({
260
+ /** Source application id; omitted tasks are grouped in the default inbox. */
261
+ app: z.string().min(1).optional(),
262
+ type: z.string().min(1),
263
+ name: z.string().min(1),
264
+ description: z.string().optional(),
265
+ validUntil: z.string().optional(),
266
+ context: contextDataSchema,
267
+ /** Task context wire format version. @default 2 */
268
+ contextVersion: z.literal(2).optional(),
269
+ /** @deprecated Use `contextVersion`. Accepted on ingest only. */
270
+ version: z.literal(2).optional(),
271
+ actions: z.array(taskActionSchema).min(1, "At least one action is required")
272
+ });
273
+ function normalizeTaskContextVersion(data) {
274
+ const { version: legacyVersion, contextVersion, ...rest } = data;
275
+ return {
276
+ ...rest,
277
+ contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION
278
+ };
279
+ }
280
+ var taskContextObjectSchema = taskContextObjectBaseSchema.transform(
281
+ normalizeTaskContextVersion
282
+ );
283
+ function refineContextPublicUrls(data, ctx) {
284
+ const error = validateContextPublicUrls(data.context);
285
+ if (error) {
286
+ ctx.addIssue({
287
+ code: z.ZodIssueCode.custom,
288
+ message: error,
289
+ path: ["context"]
290
+ });
291
+ }
292
+ }
293
+ var taskContextSchema = taskContextObjectSchema.superRefine(
294
+ refineContextPublicUrls
295
+ );
296
+ var assignToSchema = z.object({
297
+ users: z.array(z.string().email()).optional(),
298
+ groups: z.array(z.string().min(1)).optional()
299
+ }).refine(
300
+ (data) => {
301
+ const groups = data.groups ?? [];
302
+ if (groups.includes("all") && groups.length > 1) {
303
+ return false;
304
+ }
305
+ return true;
306
+ },
307
+ { message: 'Cannot combine "all" with other group slugs' }
308
+ );
309
+ var threadUpdateMessageSchema = z.string().min(1).max(500);
310
+ var threadUpdateStatuses = [
311
+ "info",
312
+ "queued",
313
+ "running",
314
+ "waiting",
315
+ "succeeded",
316
+ "failed",
317
+ "cancelled"
318
+ ];
319
+ var threadUpdateStatusSchema = z.enum(threadUpdateStatuses);
320
+ var threadUpdateInputSchema = z.object({
321
+ message: threadUpdateMessageSchema,
322
+ status: threadUpdateStatusSchema.optional()
323
+ });
324
+ var taskPriorities = ["low", "normal", "high", "urgent"];
325
+ var taskPrioritySchema = z.enum(taskPriorities);
326
+ var agentTelemetrySchema = z.object({
327
+ /** Agent or app version (semver, git SHA, deploy tag — caller-defined). */
328
+ version: z.string().min(1)
329
+ });
330
+ var createTaskBodySchema = taskContextObjectBaseSchema.extend({
331
+ assignTo: assignToSchema.optional(),
332
+ /**
333
+ * Groups related tasks together. When omitted, the server generates one and
334
+ * returns it so the caller can reuse it on later tasks in the same thread.
335
+ */
336
+ threadId: z.string().min(1).optional(),
337
+ /**
338
+ * Optional thread priority. When set, applies to the whole thread and
339
+ * overwrites any previous priority. Omit on later tasks to leave unchanged.
340
+ */
341
+ priority: taskPrioritySchema.optional(),
342
+ /**
343
+ * Optional initial status update logged against the task's thread. Shows in
344
+ * the inbox status bar and the thread update log.
345
+ */
346
+ update: threadUpdateInputSchema.optional(),
347
+ /** Agent release version — not shown in inbox UI. */
348
+ agent: agentTelemetrySchema.optional()
349
+ }).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
350
+ var agentChatSeedActionSchema = z.object({
351
+ /** Stable action id echoed back on submit; auto-derived from title when omitted. */
352
+ id: z.string().min(1).optional(),
353
+ title: z.string().min(1),
354
+ description: z.string().optional(),
355
+ /** JSON Schema object for the form fields. */
356
+ schema: z.record(z.string(), z.unknown()).optional(),
357
+ /** RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). */
358
+ ui: z.record(z.string(), z.unknown()).optional(),
359
+ /** Optional default field values. */
360
+ data: z.record(z.string(), z.unknown()).optional()
361
+ });
362
+ var agentChatSeedMessageSchema = z.object({
363
+ role: z.enum(["user", "assistant"]),
364
+ text: z.string().min(1),
365
+ /** Optional display-name override for the message sender. */
366
+ senderName: z.string().min(1).optional(),
367
+ /**
368
+ * Optional structured input request rendered as a styled RobotRock action
369
+ * widget below the message text. Use this instead of asking the user to reply
370
+ * in plain text so the request is always a proper action form.
371
+ */
372
+ requestActionInput: z.object({
373
+ prompt: z.string().optional(),
374
+ action: agentChatSeedActionSchema
375
+ }).optional()
376
+ });
377
+ var eveAgentChatTransportSchema = z.object({
378
+ kind: z.literal("eve"),
379
+ chatId: z.string().min(1),
380
+ baseUrl: z.string().url(),
381
+ sessionId: z.string().optional(),
382
+ continuationToken: z.string().optional(),
383
+ streamIndex: z.number().int().nonnegative().optional(),
384
+ isStreaming: z.boolean().optional()
385
+ });
386
+ var createAgentChatBodySchema = z.object({
387
+ /** Agent id (eve agent name). Required unless `parentChatId` is set. */
388
+ agentIdentifier: z.string().min(1).optional(),
389
+ /** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
390
+ parentChatId: z.string().min(1).optional(),
391
+ /** Convex tenantEveConnections id; resolved from the tenant when omitted. */
392
+ eveConnectionId: z.string().min(1).optional(),
393
+ /** Source application id; groups the chat under an inbox section. */
394
+ app: z.string().min(1).optional(),
395
+ /** Email of the user who owns the chat. Required unless `parentChatId` is set. */
396
+ ownerEmail: z.string().email().optional(),
397
+ title: z.string().min(1),
398
+ messages: z.array(agentChatSeedMessageSchema).default([]),
399
+ /** Provenance label stored on the session ("cron" | "agent" | ...). */
400
+ source: z.string().min(1).optional()
401
+ }).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
402
+ message: "Provide either agentIdentifier or parentChatId"
403
+ }).refine((data) => Boolean(data.ownerEmail || data.parentChatId), {
404
+ message: "Provide ownerEmail unless parentChatId is set"
405
+ });
406
+ var agentChatAuditToolBodySchema = z.object({
407
+ eveSessionId: z.string().min(1),
408
+ userId: z.string().min(1),
409
+ toolCallId: z.string().min(1),
410
+ toolName: z.string().min(1),
411
+ input: z.record(z.string(), z.unknown()).default({}),
412
+ success: z.boolean(),
413
+ status: z.enum(["completed", "failed", "rejected"]),
414
+ error: z.string().optional(),
415
+ idempotencyKey: z.string().optional()
416
+ });
417
+ var agentChatAuditInputBodySchema = z.object({
418
+ eveSessionId: z.string().min(1),
419
+ userId: z.string().min(1),
420
+ actionId: z.string().min(1),
421
+ actionTitle: z.string().optional(),
422
+ prompt: z.string().optional(),
423
+ data: z.record(z.string(), z.unknown()).optional(),
424
+ idempotencyKey: z.string().optional(),
425
+ /** Eve input request id — used to merge staged HITL metadata. */
426
+ requestId: z.string().optional(),
427
+ /** Eve tool call id — fallback lookup for staged HITL metadata. */
428
+ toolCallId: z.string().optional()
429
+ });
430
+ var eveHitlStagedOptionSchema = z.object({
431
+ id: z.string(),
432
+ label: z.string()
433
+ });
434
+ var agentChatStageHitlBodySchema = z.object({
435
+ eveSessionId: z.string().min(1),
436
+ requests: z.array(
437
+ z.object({
438
+ requestId: z.string().min(1),
439
+ toolCallId: z.string().min(1),
440
+ toolName: z.string().min(1),
441
+ prompt: z.string().min(1),
442
+ display: z.enum(["confirmation", "select", "text"]).optional(),
443
+ allowFreeform: z.boolean().optional(),
444
+ options: z.array(eveHitlStagedOptionSchema).optional(),
445
+ toolInput: z.record(z.string(), z.unknown()).optional()
446
+ })
447
+ )
448
+ });
449
+ var agentChatLinkTaskBodySchema = z.object({
450
+ eveSessionId: z.string().min(1),
451
+ publicTaskId: z.string().min(1),
452
+ toolCallId: z.string().min(1)
453
+ });
454
+ var AGENT_FILE_TAGS_MAX = 20;
455
+ var AGENT_FILE_TAG_MAX_LENGTH = 64;
456
+ function normalizeAgentFileTags(tags) {
457
+ if (!tags?.length) return void 0;
458
+ const seen = /* @__PURE__ */ new Set();
459
+ const out = [];
460
+ for (const raw of tags) {
461
+ const tag = raw.trim().toLowerCase().slice(0, AGENT_FILE_TAG_MAX_LENGTH);
462
+ if (!tag || seen.has(tag)) continue;
463
+ seen.add(tag);
464
+ out.push(tag);
465
+ if (out.length >= AGENT_FILE_TAGS_MAX) break;
466
+ }
467
+ return out.length > 0 ? out : void 0;
468
+ }
469
+ var agentChatUploadImageBodySchema = z.object({
470
+ mediaType: z.string().min(1),
471
+ /** Raw base64 (no data: URL prefix). */
472
+ base64: z.string().min(1),
473
+ chatId: z.string().min(1).optional(),
474
+ publicTaskId: z.string().min(1).optional(),
475
+ source: z.string().min(1).optional(),
476
+ /** Display / search name (e.g. `sunset-robot.png`). */
477
+ filename: z.string().min(1).max(255).optional(),
478
+ /** Human-readable description (e.g. generation prompt). */
479
+ description: z.string().min(1).max(2e3).optional(),
480
+ /**
481
+ * Optional labels for later grouping/filtering.
482
+ * Normalized to lowercase trimmed unique strings (max 20, 64 chars each).
483
+ */
484
+ tags: z.array(z.string().min(1).max(AGENT_FILE_TAG_MAX_LENGTH)).max(AGENT_FILE_TAGS_MAX).optional().transform((tags) => normalizeAgentFileTags(tags))
485
+ }).refine((data) => Boolean(data.chatId || data.publicTaskId), {
486
+ message: "Provide chatId and/or publicTaskId"
487
+ });
488
+
489
+ // ../core/src/schemas/tool-result-display.ts
490
+ import { z as z2 } from "zod";
491
+ var toolDisplayMetadataSchema = z2.object({
492
+ widget: z2.string().optional(),
493
+ title: z2.string().optional(),
494
+ description: z2.string().optional()
495
+ });
496
+ var toolDisplayEnvelopeSchema = z2.object({
497
+ display: toolDisplayMetadataSchema.optional(),
498
+ data: z2.record(z2.string(), z2.unknown()),
499
+ ui: z2.record(
500
+ z2.string(),
501
+ z2.object({
502
+ "ui:widget": z2.string().optional(),
503
+ "ui:title": z2.string().optional(),
504
+ "ui:description": z2.string().optional(),
505
+ "ui:options": z2.record(z2.string(), z2.unknown()).optional()
506
+ }).passthrough()
507
+ ).optional()
508
+ });
509
+
510
+ // ../core/src/schemas/agent-admin.ts
511
+ import { z as z3 } from "zod";
512
+ var tenantRoleSchema = z3.enum(["admin", "member"]);
513
+ var agentAdminUserSchema = z3.object({
514
+ id: z3.string(),
515
+ email: z3.string().email(),
516
+ name: z3.string(),
517
+ profilePictureUrl: z3.string().nullable().optional()
518
+ });
519
+ var agentAdminMemberSchema = z3.object({
520
+ userId: z3.string(),
521
+ role: z3.string(),
522
+ membershipKind: z3.enum(["team", "assignee"]),
523
+ hasLoggedIn: z3.boolean(),
524
+ user: agentAdminUserSchema
525
+ });
526
+ var agentAdminGroupSchema = z3.object({
527
+ id: z3.string(),
528
+ name: z3.string(),
529
+ slug: z3.string(),
530
+ description: z3.string().nullable(),
531
+ memberCount: z3.number().optional()
532
+ });
533
+ var agentAdminGroupDetailSchema = agentAdminGroupSchema.extend({
534
+ members: z3.array(
535
+ z3.object({
536
+ userId: z3.string(),
537
+ user: agentAdminUserSchema
538
+ })
539
+ )
540
+ });
541
+ var agentAdminTaskSummarySchema = z3.object({
542
+ id: z3.string(),
543
+ convexId: z3.string(),
544
+ status: z3.string(),
545
+ type: z3.string().nullable(),
546
+ name: z3.string().nullable(),
547
+ description: z3.string().nullable(),
548
+ validUntil: z3.number(),
549
+ createdAt: z3.number(),
550
+ threadPriority: z3.string().nullable(),
551
+ handledByUserId: z3.string().nullable()
552
+ });
553
+ var inviteMemberBodySchema = z3.object({
554
+ email: z3.string().email(),
555
+ role: tenantRoleSchema.optional()
556
+ });
557
+ var updateMemberRoleBodySchema = z3.object({
558
+ role: tenantRoleSchema
559
+ });
560
+ var createGroupBodySchema = z3.object({
561
+ name: z3.string().min(1),
562
+ description: z3.string().optional()
563
+ });
564
+ var updateGroupBodySchema = z3.object({
565
+ name: z3.string().min(1).optional(),
566
+ description: z3.string().optional()
567
+ });
568
+ var addGroupMemberBodySchema = z3.object({
569
+ userId: z3.string().min(1).describe("Convex user id or member email.")
570
+ });
571
+ var listTasksQuerySchema = z3.object({
572
+ statusFilter: z3.enum(["all", "open", "handled", "expired"]).optional(),
573
+ typeFilter: z3.string().optional(),
574
+ appFilter: z3.string().optional(),
575
+ sortField: z3.enum(["type", "date", "status", "validUntil"]).optional(),
576
+ sortDirection: z3.enum(["asc", "desc"]).optional(),
577
+ limit: z3.coerce.number().int().positive().max(100).optional(),
578
+ cursor: z3.string().optional()
579
+ });
580
+ var searchTasksQuerySchema = z3.object({
581
+ q: z3.string().min(1),
582
+ limit: z3.coerce.number().int().positive().max(100).optional()
583
+ });
584
+ var assignTasksResultSchema = z3.object({
585
+ taskId: z3.string(),
586
+ success: z3.boolean(),
587
+ message: z3.string().optional(),
588
+ name: z3.string().nullable().optional(),
589
+ description: z3.string().nullable().optional(),
590
+ type: z3.string().nullable().optional()
591
+ });
592
+ var assignTasksResponseSchema = z3.object({
593
+ results: z3.array(assignTasksResultSchema)
594
+ });
595
+ var assignTasksBodySchema = z3.object({
596
+ taskIds: z3.array(z3.string().min(1)).min(1).max(100),
597
+ assignTo: assignToSchema.refine(
598
+ (value) => (value.users?.length ?? 0) > 0 || (value.groups?.length ?? 0) > 0,
599
+ { message: "assignTo needs at least one user email or group slug." }
600
+ )
601
+ });
602
+ var agentAdminPlanLimitsSchema = z3.object({
603
+ tasksPerDay: z3.number(),
604
+ members: z3.number(),
605
+ apiKeys: z3.number(),
606
+ groups: z3.number(),
607
+ auditLogRetention: z3.number(),
608
+ rateLimitPerSecond: z3.number(),
609
+ taskRetentionDays: z3.number()
610
+ });
611
+ var agentAdminUsageSchema = z3.object({
612
+ workspace: z3.string(),
613
+ planName: z3.string(),
614
+ planType: z3.string(),
615
+ trialState: z3.enum(["none", "active", "expired"]),
616
+ daysRemaining: z3.number().nullable(),
617
+ isPaidPro: z3.boolean(),
618
+ subscriptionStatus: z3.string().nullable(),
619
+ tasksToday: z3.number(),
620
+ maxTasksPerDay: z3.number().nullable(),
621
+ tasksResetAt: z3.number(),
622
+ openTasks: z3.number(),
623
+ totalTasks: z3.number(),
624
+ seatsCurrent: z3.number(),
625
+ seatsMax: z3.number().nullable(),
626
+ groupsCurrent: z3.number(),
627
+ groupsMax: z3.number().nullable(),
628
+ apiKeysCurrent: z3.number(),
629
+ apiKeysMax: z3.number().nullable(),
630
+ rateLimitPerSecond: z3.number(),
631
+ limits: agentAdminPlanLimitsSchema
632
+ });
633
+
634
+ // src/schemas/index.ts
635
+ var handlerUrlSchema2 = z4.string().refine((url) => isAllowedHandlerUrl(url), {
636
+ message: HANDLER_URL_ERROR
637
+ });
638
+ var jsonSchema7Schema2 = z4.custom(
639
+ (val) => typeof val === "object" && val !== null,
640
+ { message: "Must be a valid JSON Schema object" }
641
+ );
642
+ var uiSchemaSchema2 = z4.custom((val) => typeof val === "object" && val !== null, {
643
+ message: "Must be a valid UiSchema object"
644
+ });
645
+ var webhookHandlerSchema2 = z4.object({
646
+ type: z4.literal("webhook"),
647
+ url: handlerUrlSchema2,
648
+ headers: z4.record(z4.string(), z4.string())
649
+ });
650
+ var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
651
+ type: z4.literal("trigger"),
652
+ tokenId: z4.string().min(1)
653
+ });
654
+ var handlerSchema2 = z4.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
655
+ var taskActionInputSchema2 = z4.object({
656
+ id: z4.string().min(1),
657
+ title: z4.string().min(1),
658
+ description: z4.string().optional(),
659
+ schema: jsonSchema7Schema2.optional(),
660
+ ui: uiSchemaSchema2.optional(),
661
+ data: z4.record(z4.string(), z4.unknown()).optional()
662
+ });
663
+ var taskActionSchema2 = taskActionInputSchema2.extend({
664
+ handlers: z4.array(handlerSchema2).min(1).optional()
665
+ });
666
+ var uiFieldSchemaSchema2 = z4.object({
667
+ "ui:widget": z4.string().optional(),
668
+ "ui:title": z4.string().optional(),
669
+ "ui:description": z4.string().optional(),
670
+ "ui:options": z4.record(z4.string(), z4.unknown()).optional(),
671
+ items: z4.lazy(() => z4.record(z4.string(), uiFieldSchemaSchema2)).optional()
672
+ }).passthrough();
673
+ var contextUiSchema2 = z4.record(z4.string(), uiFieldSchemaSchema2).optional();
674
+ var contextDataSchema2 = z4.object({
675
+ data: z4.record(z4.string(), z4.unknown()),
676
+ ui: contextUiSchema2
677
+ }).optional();
678
+ var TASK_CONTEXT_FORMAT_VERSION2 = 2;
679
+ var taskContextObjectBaseSchema2 = z4.object({
680
+ app: z4.string().min(1).optional(),
681
+ type: z4.string().min(1),
682
+ name: z4.string().min(1),
683
+ description: z4.string().optional(),
684
+ validUntil: z4.string().optional(),
685
+ context: contextDataSchema2,
686
+ contextVersion: z4.literal(2).optional(),
687
+ /** @deprecated Use `contextVersion`. Accepted on ingest only. */
688
+ version: z4.literal(2).optional(),
689
+ actions: z4.array(taskActionSchema2).min(1, "At least one action is required")
690
+ });
691
+ function normalizeTaskContextVersion2(data) {
692
+ const { version: legacyVersion, contextVersion, ...rest } = data;
693
+ return {
694
+ ...rest,
695
+ contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION2
696
+ };
697
+ }
698
+ var taskContextObjectSchema2 = taskContextObjectBaseSchema2.transform(
699
+ normalizeTaskContextVersion2
700
+ );
701
+ function refineContextPublicUrls2(data, ctx) {
702
+ const error = validateContextPublicUrls(data.context);
703
+ if (error) {
704
+ ctx.addIssue({
705
+ code: z4.ZodIssueCode.custom,
706
+ message: error,
707
+ path: ["context"]
708
+ });
709
+ }
710
+ }
711
+ var taskContextSchema2 = taskContextObjectSchema2.superRefine(
712
+ refineContextPublicUrls2
713
+ );
714
+ var assignToSchema2 = z4.object({
715
+ users: z4.array(z4.string().email()).optional(),
716
+ groups: z4.array(z4.string().min(1)).optional()
717
+ }).refine(
718
+ (data) => {
719
+ const groups = data.groups ?? [];
720
+ if (groups.includes("all") && groups.length > 1) {
721
+ return false;
722
+ }
723
+ return true;
724
+ },
725
+ { message: 'Cannot combine "all" with other group slugs' }
726
+ );
727
+ var threadUpdateMessageSchema2 = z4.string().min(1).max(500);
728
+ var threadUpdateStatuses2 = [
729
+ "info",
730
+ "queued",
731
+ "running",
732
+ "waiting",
733
+ "succeeded",
734
+ "failed",
735
+ "cancelled"
736
+ ];
737
+ var threadUpdateStatusSchema2 = z4.enum(threadUpdateStatuses2);
738
+ var threadUpdateInputSchema2 = z4.object({
739
+ message: threadUpdateMessageSchema2,
740
+ status: threadUpdateStatusSchema2.optional()
741
+ });
742
+ var taskPriorities2 = ["low", "normal", "high", "urgent"];
743
+ var taskPrioritySchema2 = z4.enum(taskPriorities2);
744
+ var agentTelemetrySchema2 = z4.object({
745
+ version: z4.string().min(1)
746
+ });
747
+ var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
748
+ assignTo: assignToSchema2.optional(),
749
+ /**
750
+ * Groups related tasks together. When omitted, the server generates one and
751
+ * returns it so the caller can reuse it on later tasks in the same thread.
752
+ */
753
+ threadId: z4.string().min(1).optional(),
754
+ /**
755
+ * Optional thread priority. When set, applies to the whole thread and
756
+ * overwrites any previous priority. Omit on later tasks to leave unchanged.
757
+ */
758
+ priority: taskPrioritySchema2.optional(),
759
+ /**
760
+ * Optional initial status update logged against the task's thread. Shows in
761
+ * the inbox status bar and the thread update log.
762
+ */
763
+ update: threadUpdateInputSchema2.optional(),
764
+ agent: agentTelemetrySchema2.optional()
765
+ }).transform(normalizeTaskContextVersion2).superRefine(refineContextPublicUrls2);
766
+ var threadUpdateBodySchema = threadUpdateInputSchema2;
767
+
768
+ // ../core/src/handler-retry.ts
769
+ var HANDLER_RETRY_DELAYS_MS = [
770
+ 6e4,
771
+ // 1m
772
+ 3e5,
773
+ // 5m
774
+ 18e5,
775
+ // 30m
776
+ 36e5,
777
+ // 1h
778
+ 216e5,
779
+ // 6h
780
+ 864e5,
781
+ // 24h
782
+ 1728e5
783
+ // 48h
784
+ ];
785
+ var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
786
+
787
+ // ../core/src/attribution/index.ts
788
+ import { z as z5 } from "zod";
789
+
790
+ // ../core/src/app-url.ts
791
+ var PRODUCTION_APP_URL = "https://app.robotrock.io";
792
+ var PRODUCTION_API_URL = "https://api.robotrock.io/v1";
793
+ var DEV_API_URL = "http://localhost:4001/v1";
794
+ var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
795
+ function normalizeRobotRockApiBaseUrl(baseUrl) {
796
+ const trimmed = baseUrl.trim().replace(/\/+$/, "");
797
+ if (trimmed.endsWith("/v1")) {
798
+ return trimmed;
799
+ }
800
+ return `${trimmed}/v1`;
801
+ }
802
+ function getRobotRockApiBaseUrl() {
803
+ const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
804
+ if (explicit) {
805
+ return normalizeRobotRockApiBaseUrl(explicit);
806
+ }
807
+ if (process.env.NODE_ENV === "production") {
808
+ return PRODUCTION_API_URL;
809
+ }
810
+ return DEV_API_URL;
811
+ }
812
+
813
+ // ../core/src/attribution/index.ts
814
+ var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
815
+ var attributionSchema = z5.object({
816
+ utmSource: z5.string().optional(),
817
+ utmMedium: z5.string().optional(),
818
+ utmCampaign: z5.string().optional(),
819
+ utmContent: z5.string().optional(),
820
+ utmTerm: z5.string().optional(),
821
+ gclid: z5.string().optional(),
822
+ landingUrl: z5.string().optional(),
823
+ referrer: z5.string().optional(),
824
+ capturedAt: z5.number()
825
+ });
826
+
827
+ // src/approval-result.ts
828
+ var TaskTimeoutError = class extends Error {
829
+ constructor(message) {
830
+ super(message);
831
+ this.name = "TaskTimeoutError";
832
+ }
833
+ };
834
+ var TaskExpiredError = class extends Error {
835
+ constructor(message) {
836
+ super(message);
837
+ this.name = "TaskExpiredError";
838
+ }
839
+ };
840
+ function toDiscriminatedApprovalResult(actions, task) {
841
+ void actions;
842
+ if (!task.handled) {
843
+ throw new Error("Task has no handled result");
844
+ }
845
+ return {
846
+ actionId: task.handled.action.id,
847
+ data: task.handled.action.data,
848
+ handledBy: task.handled.handledBy,
849
+ handledAt: new Date(task.handledAt ?? Date.now()),
850
+ taskId: task.id
851
+ };
852
+ }
853
+
854
+ // src/http.ts
855
+ var RobotRockError = class extends Error {
856
+ constructor(message, statusCode, response) {
857
+ super(message);
858
+ this.statusCode = statusCode;
859
+ this.response = response;
860
+ this.name = "RobotRockError";
861
+ }
862
+ };
863
+ async function parseResponseBody(response) {
864
+ const contentType = response.headers.get("content-type") ?? "";
865
+ const bodyText = await response.text();
866
+ if (!bodyText) {
867
+ return null;
868
+ }
869
+ if (contentType.toLowerCase().includes("application/json")) {
870
+ try {
871
+ return JSON.parse(bodyText);
872
+ } catch {
873
+ }
874
+ }
875
+ try {
876
+ return JSON.parse(bodyText);
877
+ } catch {
878
+ return bodyText;
879
+ }
880
+ }
881
+ function getErrorMessage(data, fallback) {
882
+ if (data && typeof data === "object" && !Array.isArray(data)) {
883
+ const record = data;
884
+ const maybeMessage = record.message;
885
+ const maybeHint = record.hint;
886
+ if (typeof maybeMessage === "string" && maybeMessage.trim()) {
887
+ if (typeof maybeHint === "string" && maybeHint.trim()) {
888
+ return `${maybeMessage.trim()} ${maybeHint.trim()}`;
889
+ }
890
+ return maybeMessage;
891
+ }
892
+ }
893
+ if (typeof data === "string" && data.trim()) {
894
+ const compact = data.replace(/\s+/g, " ").trim();
895
+ const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
896
+ return `${fallback}. Server returned non-JSON response: ${snippet}`;
897
+ }
898
+ return fallback;
899
+ }
900
+
901
+ // src/auth-headers.ts
902
+ var ROBOTROCK_ACTING_USER_ID_HEADER = "x-robotrock-acting-user-id";
903
+ function buildRobotRockAuthHeaders(auth) {
904
+ if (auth.kind === "apiKey") {
905
+ const headers2 = {
906
+ "X-Api-Key": auth.apiKey
907
+ };
908
+ if (auth.actingUserId?.trim()) {
909
+ headers2[ROBOTROCK_ACTING_USER_ID_HEADER] = auth.actingUserId.trim();
910
+ }
911
+ return headers2;
912
+ }
913
+ const headers = {
914
+ Authorization: `Bearer ${auth.token}`,
915
+ "X-RobotRock-Tenant-Slug": auth.tenantSlug,
916
+ "X-RobotRock-Connection-Id": auth.connectionId
917
+ };
918
+ if (auth.actingUserId?.trim()) {
919
+ headers[ROBOTROCK_ACTING_USER_ID_HEADER] = auth.actingUserId.trim();
920
+ }
921
+ return headers;
922
+ }
923
+ function resolveRobotRockAuthConfig(overrides) {
924
+ if (overrides?.agentService) {
925
+ return {
926
+ kind: "agentService",
927
+ ...overrides.agentService
928
+ };
929
+ }
930
+ const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
931
+ if (!apiKey) {
932
+ throw new Error(
933
+ "RobotRock auth is required. Set ROBOTROCK_API_KEY, ROBOTROCK_AGENT_SERVICE_TOKEN with tenant context, or pass auth when creating the client."
934
+ );
935
+ }
936
+ return {
937
+ kind: "apiKey",
938
+ apiKey,
939
+ ...overrides?.actingUserId?.trim() ? { actingUserId: overrides.actingUserId.trim() } : {}
940
+ };
941
+ }
942
+
943
+ // src/chat-correlation.ts
944
+ var ROBOTROCK_CHAT_ID_HEADER = "x-robotrock-chat-id";
945
+ var ROBOTROCK_EVE_SESSION_ID_HEADER = "x-robotrock-eve-session-id";
946
+ function resolveChatCorrelationFromEnv() {
947
+ const chatId = process.env.ROBOTROCK_CHAT_ID?.trim();
948
+ const eveSessionId = process.env.ROBOTROCK_EVE_SESSION_ID?.trim();
949
+ if (!chatId && !eveSessionId) {
950
+ return void 0;
951
+ }
952
+ return {
953
+ ...chatId ? { chatId } : {},
954
+ ...eveSessionId ? { eveSessionId } : {}
955
+ };
956
+ }
957
+ function buildChatCorrelationHeaders(correlation) {
958
+ if (!correlation) {
959
+ return {};
960
+ }
961
+ const headers = {};
962
+ const chatId = correlation.chatId?.trim();
963
+ const eveSessionId = correlation.eveSessionId?.trim();
964
+ if (chatId) {
965
+ headers[ROBOTROCK_CHAT_ID_HEADER] = chatId;
966
+ }
967
+ if (eveSessionId) {
968
+ headers[ROBOTROCK_EVE_SESSION_ID_HEADER] = eveSessionId;
969
+ }
970
+ return headers;
971
+ }
972
+
973
+ // src/chats.ts
974
+ function createChatsApi(config) {
975
+ const headers = () => ({
976
+ "Content-Type": "application/json",
977
+ ...buildRobotRockAuthHeaders(config.auth),
978
+ ...buildChatCorrelationHeaders(config.chatCorrelation)
979
+ });
980
+ return {
981
+ async create(input) {
982
+ const bodyPayload = {
983
+ ...input,
984
+ app: input.app ?? config.app,
985
+ messages: input.messages ?? []
986
+ };
987
+ const validation = createAgentChatBodySchema.safeParse(bodyPayload);
988
+ if (!validation.success) {
989
+ throw new RobotRockError(
990
+ `Invalid chat: ${validation.error.issues[0]?.message}`,
991
+ 400,
992
+ validation.error.issues
993
+ );
994
+ }
995
+ const response = await fetch(`${config.baseUrl}/agent-chats`, {
996
+ method: "POST",
997
+ headers: headers(),
998
+ body: JSON.stringify(validation.data)
999
+ });
1000
+ const data = await parseResponseBody(response);
1001
+ if (!response.ok) {
1002
+ throw new RobotRockError(
1003
+ getErrorMessage(data, "Failed to create chat"),
1004
+ response.status,
1005
+ data
1006
+ );
1007
+ }
1008
+ const result = data;
1009
+ return { tenantSlug: result.tenantSlug, chats: result.chats };
1010
+ },
1011
+ async close(chatId, options) {
1012
+ if (!chatId) {
1013
+ throw new RobotRockError("chatId is required to close a chat", 400);
1014
+ }
1015
+ const response = await fetch(
1016
+ `${config.baseUrl}/agent-chats/${encodeURIComponent(chatId)}/close`,
1017
+ {
1018
+ method: "POST",
1019
+ headers: headers(),
1020
+ body: JSON.stringify({ reason: options?.reason })
1021
+ }
1022
+ );
1023
+ if (!response.ok) {
1024
+ const data = await parseResponseBody(response);
1025
+ throw new RobotRockError(
1026
+ getErrorMessage(data, "Failed to close chat"),
1027
+ response.status,
1028
+ data
1029
+ );
1030
+ }
1031
+ },
1032
+ async stageHitlRequests(input) {
1033
+ const validation = agentChatStageHitlBodySchema.safeParse(input);
1034
+ if (!validation.success) {
1035
+ throw new RobotRockError(
1036
+ `Invalid stage HITL input: ${validation.error.issues[0]?.message}`,
1037
+ 400,
1038
+ validation.error.issues
1039
+ );
1040
+ }
1041
+ const response = await fetch(`${config.baseUrl}/agent-chats/stage-hitl`, {
1042
+ method: "POST",
1043
+ headers: headers(),
1044
+ body: JSON.stringify(validation.data)
1045
+ });
1046
+ if (!response.ok) {
1047
+ const data = await parseResponseBody(response);
1048
+ throw new RobotRockError(
1049
+ getErrorMessage(data, "Failed to stage chat HITL requests"),
1050
+ response.status,
1051
+ data
1052
+ );
1053
+ }
1054
+ },
1055
+ async getStagedHitlRequests(eveSessionId) {
1056
+ const trimmed = eveSessionId.trim();
1057
+ if (!trimmed) {
1058
+ throw new RobotRockError("eveSessionId is required", 400);
1059
+ }
1060
+ const url = new URL(`${config.baseUrl}/agent-chats/staged-hitl`);
1061
+ url.searchParams.set("eveSessionId", trimmed);
1062
+ const response = await fetch(url.toString(), {
1063
+ method: "GET",
1064
+ headers: headers()
1065
+ });
1066
+ const data = await parseResponseBody(response);
1067
+ if (!response.ok) {
1068
+ throw new RobotRockError(
1069
+ getErrorMessage(data, "Failed to fetch staged chat HITL requests"),
1070
+ response.status,
1071
+ data
1072
+ );
1073
+ }
1074
+ const requests = data.requests;
1075
+ return Array.isArray(requests) ? requests : [];
1076
+ },
1077
+ async logInputSubmission(input) {
1078
+ const validation = agentChatAuditInputBodySchema.safeParse(input);
1079
+ if (!validation.success) {
1080
+ throw new RobotRockError(
1081
+ `Invalid audit input: ${validation.error.issues[0]?.message}`,
1082
+ 400,
1083
+ validation.error.issues
1084
+ );
1085
+ }
1086
+ const response = await fetch(`${config.baseUrl}/agent-chats/audit-input`, {
1087
+ method: "POST",
1088
+ headers: headers(),
1089
+ body: JSON.stringify(validation.data)
1090
+ });
1091
+ if (!response.ok) {
1092
+ const data = await parseResponseBody(response);
1093
+ throw new RobotRockError(
1094
+ getErrorMessage(data, "Failed to log chat input submission"),
1095
+ response.status,
1096
+ data
1097
+ );
1098
+ }
1099
+ },
1100
+ async logToolExecution(input) {
1101
+ const validation = agentChatAuditToolBodySchema.safeParse(input);
1102
+ if (!validation.success) {
1103
+ throw new RobotRockError(
1104
+ `Invalid audit tool input: ${validation.error.issues[0]?.message}`,
1105
+ 400,
1106
+ validation.error.issues
1107
+ );
1108
+ }
1109
+ const response = await fetch(`${config.baseUrl}/agent-chats/audit-tool`, {
1110
+ method: "POST",
1111
+ headers: headers(),
1112
+ body: JSON.stringify(validation.data)
1113
+ });
1114
+ if (!response.ok) {
1115
+ const data = await parseResponseBody(response);
1116
+ throw new RobotRockError(
1117
+ getErrorMessage(data, "Failed to log chat tool execution"),
1118
+ response.status,
1119
+ data
1120
+ );
1121
+ }
1122
+ },
1123
+ async linkTask(input) {
1124
+ const validation = agentChatLinkTaskBodySchema.safeParse(input);
1125
+ if (!validation.success) {
1126
+ throw new RobotRockError(
1127
+ `Invalid link task input: ${validation.error.issues[0]?.message}`,
1128
+ 400,
1129
+ validation.error.issues
1130
+ );
1131
+ }
1132
+ const response = await fetch(`${config.baseUrl}/agent-chats/link-task`, {
1133
+ method: "POST",
1134
+ headers: headers(),
1135
+ body: JSON.stringify(validation.data)
1136
+ });
1137
+ if (!response.ok) {
1138
+ const data = await parseResponseBody(response);
1139
+ throw new RobotRockError(
1140
+ getErrorMessage(data, "Failed to link inbox task to chat"),
1141
+ response.status,
1142
+ data
1143
+ );
1144
+ }
1145
+ },
1146
+ async uploadImage(input) {
1147
+ const validation = agentChatUploadImageBodySchema.safeParse(input);
1148
+ if (!validation.success) {
1149
+ throw new RobotRockError(
1150
+ `Invalid image upload: ${validation.error.issues[0]?.message}`,
1151
+ 400,
1152
+ validation.error.issues
1153
+ );
1154
+ }
1155
+ const response = await fetch(`${config.baseUrl}/agent-chats/images`, {
1156
+ method: "POST",
1157
+ headers: headers(),
1158
+ body: JSON.stringify(validation.data)
1159
+ });
1160
+ const data = await parseResponseBody(response);
1161
+ if (!response.ok) {
1162
+ throw new RobotRockError(
1163
+ getErrorMessage(data, "Failed to upload chat image"),
1164
+ response.status,
1165
+ data
1166
+ );
1167
+ }
1168
+ const uploaded = data;
1169
+ if (typeof uploaded.storageId !== "string" || typeof uploaded.url !== "string" || typeof uploaded.mediaType !== "string") {
1170
+ throw new RobotRockError(
1171
+ "Image upload returned an invalid response",
1172
+ 500,
1173
+ data
1174
+ );
1175
+ }
1176
+ return {
1177
+ storageId: uploaded.storageId,
1178
+ url: uploaded.url,
1179
+ mediaType: uploaded.mediaType,
1180
+ ...typeof uploaded.chatId === "string" ? { chatId: uploaded.chatId } : {},
1181
+ ...typeof uploaded.publicTaskId === "string" ? { publicTaskId: uploaded.publicTaskId } : {},
1182
+ ...typeof uploaded.filename === "string" ? { filename: uploaded.filename } : {},
1183
+ ...typeof uploaded.description === "string" ? { description: uploaded.description } : {},
1184
+ ...Array.isArray(uploaded.tags) ? {
1185
+ tags: uploaded.tags.filter(
1186
+ (tag) => typeof tag === "string"
1187
+ )
1188
+ } : {}
1189
+ };
1190
+ }
1191
+ };
1192
+ }
1193
+
1194
+ // src/client.ts
1195
+ var DEFAULT_POLL_INTERVAL_MS = 2e3;
1196
+ var DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
1197
+ function sleep(ms) {
1198
+ return new Promise((resolve) => setTimeout(resolve, ms));
1199
+ }
1200
+ function resolveAgentVersionFromEnv() {
1201
+ const fromEnv = process.env.AGENT_VERSION?.trim() || process.env.ROBOTROCK_AGENT_VERSION?.trim();
1202
+ return fromEnv || void 0;
1203
+ }
1204
+ function parseValidUntilMs(value) {
1205
+ if (value === void 0) {
1206
+ return void 0;
1207
+ }
1208
+ if (value instanceof Date) {
1209
+ const ms = value.getTime();
1210
+ return Number.isNaN(ms) ? void 0 : ms;
1211
+ }
1212
+ if (typeof value === "number") {
1213
+ return Number.isFinite(value) ? value : void 0;
1214
+ }
1215
+ const parsed = Date.parse(value);
1216
+ return Number.isNaN(parsed) ? void 0 : parsed;
1217
+ }
1218
+ function serializeValidUntil(value) {
1219
+ if (value instanceof Date) {
1220
+ const ms = value.getTime();
1221
+ if (Number.isNaN(ms)) {
1222
+ throw new RobotRockError("Invalid validUntil: Date is invalid", 400);
1223
+ }
1224
+ return value.toISOString();
1225
+ }
1226
+ if (typeof value === "string" && !Number.isNaN(Date.parse(value))) {
1227
+ return new Date(value).toISOString();
1228
+ }
1229
+ throw new RobotRockError("Invalid validUntil: expected a Date or parseable date string", 400);
1230
+ }
1231
+ var RobotRock = class {
1232
+ auth;
1233
+ chatCorrelation;
1234
+ baseUrl;
1235
+ app;
1236
+ agentVersion;
1237
+ contextVersion;
1238
+ webhook;
1239
+ polling;
1240
+ /** Task CRUD: `create`, `get`, `cancel`, `sendUpdate`. */
1241
+ tasks;
1242
+ /** Chat CRUD: `create`, `close`. */
1243
+ chats;
1244
+ constructor(config) {
1245
+ if (config.webhook && config.polling) {
1246
+ throw new Error(
1247
+ "RobotRock client cannot configure both webhook and polling. Use webhook for callbacks or polling to block until handled."
1248
+ );
1249
+ }
1250
+ const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;
1251
+ const agentService = config.agentService;
1252
+ if (apiKey && agentService) {
1253
+ throw new Error(
1254
+ "RobotRock client cannot configure both apiKey and agentService."
1255
+ );
1256
+ }
1257
+ this.auth = resolveRobotRockAuthConfig({
1258
+ ...apiKey ? { apiKey } : {},
1259
+ ...config.actingUserId ? { actingUserId: config.actingUserId } : {},
1260
+ ...agentService ? { agentService } : {}
1261
+ });
1262
+ this.chatCorrelation = config.chatCorrelation;
1263
+ this.baseUrl = config.baseUrl ?? getRobotRockApiBaseUrl();
1264
+ this.app = config.app;
1265
+ this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
1266
+ this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
1267
+ this.webhook = config.webhook;
1268
+ this.polling = config.polling ?? {};
1269
+ this.tasks = {
1270
+ create: (task) => this.createTaskRequest(task),
1271
+ get: (taskId) => this.getTaskById(taskId),
1272
+ cancel: (taskId) => this.cancelTaskRequest(taskId),
1273
+ sendUpdate: (input) => this.sendThreadUpdate(input),
1274
+ list: (input) => this.listTasksRequest(input),
1275
+ search: (input) => this.searchTasksRequest(input)
1276
+ };
1277
+ this.chats = createChatsApi({
1278
+ baseUrl: this.baseUrl,
1279
+ auth: this.auth,
1280
+ app: this.app,
1281
+ chatCorrelation: this.chatCorrelation
1282
+ });
1283
+ }
1284
+ authHeaders(extra) {
1285
+ return {
1286
+ "Content-Type": "application/json",
1287
+ ...buildRobotRockAuthHeaders(this.auth),
1288
+ ...buildChatCorrelationHeaders(this.chatCorrelation),
1289
+ ...extra
1290
+ };
1291
+ }
1292
+ async createTaskRequest(task) {
1293
+ const normalizedTask = normalizeSendToHumanInput(task, {
1294
+ webhook: this.webhook,
1295
+ app: this.app,
1296
+ contextVersion: this.contextVersion,
1297
+ agentVersion: this.agentVersion
1298
+ });
1299
+ const agentVersion = task.version ?? this.agentVersion;
1300
+ const bodyPayload = {
1301
+ ...normalizedTask,
1302
+ ...task.assignTo !== void 0 ? { assignTo: task.assignTo } : {},
1303
+ ...task.threadId !== void 0 ? { threadId: task.threadId } : {},
1304
+ ...task.priority !== void 0 ? { priority: task.priority } : {},
1305
+ ...task.update !== void 0 ? { update: task.update } : {},
1306
+ ...agentVersion !== void 0 ? { agent: { version: agentVersion } } : {}
1307
+ };
1308
+ const validation = createTaskBodySchema2.safeParse(bodyPayload);
1309
+ if (!validation.success) {
1310
+ throw new RobotRockError(
1311
+ `Invalid task: ${validation.error.issues[0]?.message}`,
1312
+ 400,
1313
+ validation.error.issues
1314
+ );
1315
+ }
1316
+ const headers = this.authHeaders(
1317
+ task.idempotencyKey ? { "Idempotency-Key": task.idempotencyKey } : void 0
1318
+ );
1319
+ const response = await fetch(`${this.baseUrl}/`, {
1320
+ method: "POST",
1321
+ headers,
1322
+ body: JSON.stringify(validation.data)
1323
+ });
1324
+ const data = await parseResponseBody(response);
1325
+ if (!response.ok) {
1326
+ throw new RobotRockError(
1327
+ getErrorMessage(data, "Failed to create task"),
1328
+ response.status,
1329
+ data
1330
+ );
1331
+ }
1332
+ return data.task;
1333
+ }
1334
+ async sendToHuman(task) {
1335
+ const normalizedTask = normalizeSendToHumanInput(task, {
1336
+ webhook: this.webhook,
1337
+ app: this.app,
1338
+ contextVersion: this.contextVersion,
1339
+ agentVersion: this.agentVersion
1340
+ });
1341
+ const createdTaskTask = await this.createTaskRequest(task);
1342
+ const hasHandlers = normalizedTask.actions.some(
1343
+ (action) => Array.isArray(action.handlers) && action.handlers.length > 0
1344
+ );
1345
+ if (hasHandlers) {
1346
+ return {
1347
+ mode: "created",
1348
+ task: createdTaskTask
1349
+ };
1350
+ }
1351
+ const timeoutMs = this.polling.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1352
+ const pollIntervalMs = this.polling.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
1353
+ const pollingDeadline = Date.now() + timeoutMs;
1354
+ const validUntilMs = parseValidUntilMs(createdTaskTask.validUntil);
1355
+ const deadline = validUntilMs !== void 0 ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;
1356
+ const taskId = createdTaskTask.taskId;
1357
+ while (Date.now() < deadline) {
1358
+ const existing = await this.getTaskById(taskId);
1359
+ if (existing?.status === "handled" && existing.handled) {
1360
+ return {
1361
+ mode: "handled",
1362
+ task: createdTaskTask,
1363
+ ...toDiscriminatedApprovalResult(
1364
+ normalizedTask.actions,
1365
+ existing
1366
+ )
1367
+ };
1368
+ }
1369
+ if (existing?.status === "expired" || existing && Date.now() >= existing.validUntil) {
1370
+ throw new TaskExpiredError("Task reached validUntil before a human completed it");
1371
+ }
1372
+ const remainingMs = deadline - Date.now();
1373
+ await sleep(Math.min(pollIntervalMs, Math.max(0, remainingMs)));
1374
+ }
1375
+ if (validUntilMs !== void 0 && Date.now() >= validUntilMs) {
1376
+ throw new TaskExpiredError("Task reached validUntil before a human completed it");
1377
+ }
1378
+ throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);
1379
+ }
1380
+ /**
1381
+ * Create a task via POST /v1 without waiting for a human response.
1382
+ * @deprecated Use `client.tasks.create()` instead.
1383
+ */
1384
+ async createTask(task) {
1385
+ return this.tasks.create(task);
1386
+ }
1387
+ /**
1388
+ * Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
1389
+ * @deprecated Use `client.tasks.get()` instead.
1390
+ */
1391
+ async getTask(taskId) {
1392
+ return this.tasks.get(taskId);
1393
+ }
1394
+ /**
1395
+ * Log a status update against a thread.
1396
+ * @deprecated Use `client.tasks.sendUpdate()` instead.
1397
+ */
1398
+ async sendUpdate(input) {
1399
+ return this.tasks.sendUpdate(input);
1400
+ }
1401
+ /**
1402
+ * Cancel a task by public task id.
1403
+ * @deprecated Use `client.tasks.cancel()` instead.
1404
+ */
1405
+ async cancelTask(taskId) {
1406
+ return this.tasks.cancel(taskId);
1407
+ }
1408
+ async getTaskById(taskId) {
1409
+ const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
1410
+ method: "GET",
1411
+ headers: this.authHeaders()
1412
+ });
1413
+ if (response.status === 404) {
1414
+ return null;
1415
+ }
1416
+ const data = await parseResponseBody(response);
1417
+ if (!response.ok) {
1418
+ throw new RobotRockError(
1419
+ getErrorMessage(data, "Failed to get task"),
1420
+ response.status,
1421
+ data
1422
+ );
1423
+ }
1424
+ return data;
1425
+ }
1426
+ async sendThreadUpdate({
1427
+ threadId,
1428
+ message,
1429
+ status
1430
+ }) {
1431
+ if (!threadId) {
1432
+ throw new RobotRockError("threadId is required to send an update", 400);
1433
+ }
1434
+ const validation = threadUpdateBodySchema.safeParse({ message, status });
1435
+ if (!validation.success) {
1436
+ throw new RobotRockError(
1437
+ `Invalid update: ${validation.error.issues[0]?.message}`,
1438
+ 400,
1439
+ validation.error.issues
1440
+ );
1441
+ }
1442
+ const response = await fetch(
1443
+ `${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,
1444
+ {
1445
+ method: "POST",
1446
+ headers: this.authHeaders(),
1447
+ body: JSON.stringify(validation.data)
1448
+ }
1449
+ );
1450
+ const data = await parseResponseBody(response);
1451
+ if (!response.ok) {
1452
+ throw new RobotRockError(
1453
+ getErrorMessage(data, "Failed to send update"),
1454
+ response.status,
1455
+ data
1456
+ );
1457
+ }
1458
+ return data.update;
1459
+ }
1460
+ async cancelTaskRequest(taskId) {
1461
+ const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
1462
+ method: "POST",
1463
+ headers: this.authHeaders()
1464
+ });
1465
+ if (!response.ok) {
1466
+ const data = await parseResponseBody(response);
1467
+ throw new RobotRockError(
1468
+ getErrorMessage(data, "Failed to cancel task"),
1469
+ response.status,
1470
+ data
1471
+ );
1472
+ }
1473
+ }
1474
+ async listTasksRequest(input) {
1475
+ const params = new URLSearchParams();
1476
+ for (const [key, value] of Object.entries(input ?? {})) {
1477
+ if (value !== void 0 && value !== "") {
1478
+ params.set(key, String(value));
1479
+ }
1480
+ }
1481
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
1482
+ const response = await fetch(`${this.baseUrl}/tasks${suffix}`, {
1483
+ method: "GET",
1484
+ headers: this.authHeaders()
1485
+ });
1486
+ const data = await parseResponseBody(response);
1487
+ if (!response.ok) {
1488
+ throw new RobotRockError(
1489
+ getErrorMessage(data, "Failed to list tasks"),
1490
+ response.status,
1491
+ data
1492
+ );
1493
+ }
1494
+ return data;
1495
+ }
1496
+ async searchTasksRequest(input) {
1497
+ const params = new URLSearchParams({ q: input.q });
1498
+ if (input.limit !== void 0) {
1499
+ params.set("limit", String(input.limit));
1500
+ }
1501
+ const response = await fetch(`${this.baseUrl}/tasks/search?${params.toString()}`, {
1502
+ method: "GET",
1503
+ headers: this.authHeaders()
1504
+ });
1505
+ const data = await parseResponseBody(response);
1506
+ if (!response.ok) {
1507
+ throw new RobotRockError(
1508
+ getErrorMessage(data, "Failed to search tasks"),
1509
+ response.status,
1510
+ data
1511
+ );
1512
+ }
1513
+ return data;
1514
+ }
1515
+ };
1516
+ function createClient(config) {
1517
+ return new RobotRock(config);
1518
+ }
1519
+ function attachWebhookToActions(actions, webhook) {
1520
+ return actions.map((action) => ({
1521
+ ...action,
1522
+ handlers: webhookToHandlers(webhook)
1523
+ }));
1524
+ }
1525
+ function webhookToHandlers(webhook) {
1526
+ return [
1527
+ {
1528
+ type: "webhook",
1529
+ url: webhook.url,
1530
+ headers: webhook.headers ?? {}
1531
+ }
1532
+ ];
1533
+ }
1534
+ function normalizeSendToHumanInput(task, clientDefaults) {
1535
+ const {
1536
+ actions,
1537
+ idempotencyKey: _idempotencyKey,
1538
+ assignTo: _assignTo,
1539
+ threadId: _threadId,
1540
+ priority: _priority,
1541
+ update: _update,
1542
+ version: _version,
1543
+ validUntil,
1544
+ app: taskApp,
1545
+ ...rest
1546
+ } = task;
1547
+ const webhook = clientDefaults.webhook;
1548
+ const normalizedActions = webhook ? attachWebhookToActions(actions, webhook) : actions;
1549
+ const app = taskApp ?? clientDefaults.app;
1550
+ return {
1551
+ ...rest,
1552
+ contextVersion: clientDefaults.contextVersion,
1553
+ ...app ? { app } : {},
1554
+ ...validUntil !== void 0 ? { validUntil: serializeValidUntil(validUntil) } : {},
1555
+ actions: normalizedActions
1556
+ };
1557
+ }
1558
+
1559
+ // src/eve/agent/attributes.ts
1560
+ function readStringAttribute(attributes, key) {
1561
+ const value = attributes?.[key];
1562
+ if (typeof value === "string" && value.length > 0) {
1563
+ return value;
1564
+ }
1565
+ if (Array.isArray(value) && typeof value[0] === "string" && value[0].length > 0) {
1566
+ return value[0];
1567
+ }
1568
+ return void 0;
1569
+ }
1570
+ function readStringArrayAttribute(attributes, key) {
1571
+ const value = attributes?.[key];
1572
+ if (typeof value === "string" && value.length > 0) {
1573
+ return [value];
1574
+ }
1575
+ if (Array.isArray(value)) {
1576
+ return value.filter(
1577
+ (entry) => typeof entry === "string" && entry.length > 0
1578
+ );
1579
+ }
1580
+ return [];
1581
+ }
1582
+ function parseTenantRole(value) {
1583
+ if (value === "admin" || value === "member") {
1584
+ return value;
1585
+ }
1586
+ return null;
1587
+ }
1588
+
1589
+ // src/eve/agent/tenant.ts
1590
+ function tryResolveTenantCaller(ctx) {
1591
+ const caller = ctx.session.auth.initiator ?? ctx.session.auth.current;
1592
+ if (caller?.principalType !== "user") {
1593
+ return null;
1594
+ }
1595
+ const email = readStringAttribute(caller.attributes, "email");
1596
+ const name = readStringAttribute(caller.attributes, "name");
1597
+ const tenantSlug = readStringAttribute(caller.attributes, "tenantSlug") ?? readStringAttribute(caller.attributes, "tenantId");
1598
+ const role = parseTenantRole(readStringAttribute(caller.attributes, "role"));
1599
+ if (!email || !tenantSlug || !caller.principalId || !role) {
1600
+ return null;
1601
+ }
1602
+ const workosUserId = readStringAttribute(caller.attributes, "workosUserId");
1603
+ const connectionId = readStringAttribute(caller.attributes, "connectionId");
1604
+ const chatId = readStringAttribute(caller.attributes, "chatId");
1605
+ const groups = readStringArrayAttribute(caller.attributes, "groups");
1606
+ return {
1607
+ userId: caller.principalId,
1608
+ email,
1609
+ name: name ?? email.split("@")[0] ?? email,
1610
+ tenantSlug,
1611
+ ...connectionId ? { connectionId } : {},
1612
+ ...chatId ? { chatId } : {},
1613
+ role,
1614
+ isAdmin: role === "admin",
1615
+ groups,
1616
+ ...workosUserId ? { workosUserId } : {}
1617
+ };
1618
+ }
1619
+
1620
+ // src/eve/agent/client-from-session.ts
1621
+ var warnedMissingAuth = false;
1622
+ function resolveBoundChatCorrelation(ctx) {
1623
+ const caller = tryResolveTenantCaller(ctx);
1624
+ return {
1625
+ eveSessionId: ctx.session.id,
1626
+ ...caller?.chatId ? { chatId: caller.chatId } : {},
1627
+ ...resolveChatCorrelationFromEnv()
1628
+ };
1629
+ }
1630
+ function tryCreateBoundRobotRockClient(ctx) {
1631
+ const caller = tryResolveTenantCaller(ctx);
1632
+ const serviceToken = process.env.ROBOTROCK_AGENT_SERVICE_TOKEN?.trim();
1633
+ const chatCorrelation = resolveBoundChatCorrelation(ctx);
1634
+ if (caller?.connectionId && serviceToken) {
1635
+ return createClient({
1636
+ baseUrl: process.env.ROBOTROCK_BASE_URL?.trim(),
1637
+ chatCorrelation,
1638
+ agentService: {
1639
+ token: serviceToken,
1640
+ tenantSlug: caller.tenantSlug,
1641
+ connectionId: caller.connectionId,
1642
+ actingUserId: caller.userId
1643
+ }
1644
+ });
1645
+ }
1646
+ const apiKey = process.env.ROBOTROCK_API_KEY?.trim();
1647
+ if (apiKey) {
1648
+ return createClient({
1649
+ apiKey,
1650
+ ...caller?.userId ? { actingUserId: caller.userId } : {},
1651
+ baseUrl: process.env.ROBOTROCK_BASE_URL?.trim(),
1652
+ chatCorrelation
1653
+ });
1654
+ }
1655
+ if (!warnedMissingAuth) {
1656
+ warnedMissingAuth = true;
1657
+ console.warn(
1658
+ "robotrock: set ROBOTROCK_AGENT_SERVICE_TOKEN for hosted multi-tenant auth, or ROBOTROCK_API_KEY for single-tenant deployments."
1659
+ );
1660
+ }
1661
+ return null;
1662
+ }
1663
+
1664
+ // src/eve/entity-schemas.ts
1665
+ import { z as z6 } from "zod";
1666
+
1667
+ // src/eve/tool-ui-hint.ts
1668
+ var TOOL_UI_HINT_FIELD = "uiHint";
1669
+ function withUiHint(result, hint) {
1670
+ return {
1671
+ ...result,
1672
+ [TOOL_UI_HINT_FIELD]: hint
1673
+ };
1674
+ }
1675
+
1676
+ // src/eve/tool-result-ui-meta.ts
1677
+ var TOOL_UI_FIELD = "ui";
1678
+ var TOOL_RESULT_UI_ENTITY_ID_RE = /^[a-z][a-z0-9_]{0,63}$/;
1679
+ function withToolUi(result, ui) {
1680
+ const existing = typeof result[TOOL_UI_FIELD] === "object" && result[TOOL_UI_FIELD] !== null && !Array.isArray(result[TOOL_UI_FIELD]) ? result[TOOL_UI_FIELD] : {};
1681
+ return {
1682
+ ...result,
1683
+ [TOOL_UI_FIELD]: {
1684
+ ...existing,
1685
+ ...ui
1686
+ }
1687
+ };
1688
+ }
1689
+
1690
+ // src/eve/entity-schemas.ts
1691
+ var toolResultUiMetaSchema = z6.object({
1692
+ present: z6.boolean().optional(),
1693
+ entity: z6.string().regex(TOOL_RESULT_UI_ENTITY_ID_RE).optional(),
1694
+ rowsPath: z6.string().min(1).optional(),
1695
+ layout: z6.enum(["list", "chart", "table"]).optional()
1696
+ }).strict();
1697
+ var agentOnlyFields = {
1698
+ replyGuidance: z6.string().optional(),
1699
+ ui: toolResultUiMetaSchema.optional(),
1700
+ uiHint: z6.enum(["list", "chart", "table"]).optional()
1701
+ };
1702
+ function withAgentOnlyFields(shape) {
1703
+ return z6.object({
1704
+ ...shape,
1705
+ ...agentOnlyFields
1706
+ });
1707
+ }
1708
+ var productEntityRowSchema = z6.object({
1709
+ id: z6.string().min(1),
1710
+ name: z6.string().min(1),
1711
+ price: z6.number(),
1712
+ currency: z6.string().min(1),
1713
+ inStock: z6.boolean(),
1714
+ url: z6.string().min(1)
1715
+ });
1716
+ var metricPointEntityRowSchema = z6.object({
1717
+ date: z6.string().optional().describe("X-axis value when xKey is date/time"),
1718
+ category: z6.string().optional().describe("X-axis value when xKey is category"),
1719
+ label: z6.string().optional().describe("X-axis value when xKey is label")
1720
+ }).catchall(z6.union([z6.string(), z6.number()])).describe(
1721
+ "Wide chart point: x-axis field + numeric columns named by yKeys (one series per column)"
1722
+ );
1723
+ var toolChartResultSchema = withAgentOnlyFields({
1724
+ title: z6.string().min(1).optional().describe("Chart title shown above the plot"),
1725
+ description: z6.string().min(1).optional().describe("Optional short subtitle"),
1726
+ type: z6.enum(["line", "bar", "area"]).describe("TRL/shadcn chart variant (time series \u2192 line, categories \u2192 bar)"),
1727
+ xKey: z6.string().min(1).describe('Field on each series row for the x-axis, e.g. "date" or "category"'),
1728
+ yKeys: z6.array(z6.string().min(1)).min(1).describe(
1729
+ 'Numeric series column names on each row, e.g. ["NL","BE"] or ["created","handled"]'
1730
+ ),
1731
+ series: z6.array(metricPointEntityRowSchema).describe(
1732
+ "Wide-format points only \u2014 one object per x value with yKeys as numeric fields"
1733
+ )
1734
+ });
1735
+ var memberEntityRowSchema = z6.object({
1736
+ name: z6.string(),
1737
+ email: z6.string(),
1738
+ role: z6.string(),
1739
+ membershipKind: z6.string(),
1740
+ profilePictureUrl: z6.string().nullable()
1741
+ });
1742
+ var taskEntityRowSchema = z6.object({
1743
+ id: z6.string().min(1),
1744
+ name: z6.string().min(1),
1745
+ status: z6.string().min(1),
1746
+ type: z6.string().nullable(),
1747
+ description: z6.string().nullable(),
1748
+ validUntil: z6.number(),
1749
+ createdAt: z6.number(),
1750
+ url: z6.string().min(1),
1751
+ threadPriority: z6.string().nullable().optional()
1752
+ });
1753
+ var groupEntityRowSchema = z6.object({
1754
+ name: z6.string().min(1),
1755
+ slug: z6.string().min(1),
1756
+ description: z6.string().nullable(),
1757
+ memberCount: z6.number().nullable(),
1758
+ url: z6.string().min(1)
1759
+ });
1760
+ var groupDetailEntitySchema = z6.object({
1761
+ name: z6.string().min(1),
1762
+ slug: z6.string().min(1),
1763
+ description: z6.string().nullable(),
1764
+ url: z6.string().min(1),
1765
+ members: z6.array(
1766
+ z6.object({
1767
+ name: z6.string(),
1768
+ email: z6.string(),
1769
+ profilePictureUrl: z6.string().nullable()
1770
+ })
1771
+ )
1772
+ });
1773
+ var statusEntityRowSchema = z6.object({
1774
+ id: z6.string().min(1),
1775
+ name: z6.string().min(1),
1776
+ status: z6.string().min(1),
1777
+ url: z6.string().min(1),
1778
+ type: z6.string().nullable().optional(),
1779
+ description: z6.string().nullable().optional()
1780
+ });
1781
+ var agentAdminErrorResultSchema = z6.object({
1782
+ ok: z6.literal(false),
1783
+ status: z6.number().optional(),
1784
+ message: z6.string(),
1785
+ response: z6.unknown().optional()
1786
+ });
1787
+ var agentAdminMutationResultSchema = z6.object({
1788
+ ...agentOnlyFields
1789
+ }).passthrough();
1790
+ var searchProductsOutputSchema = withAgentOnlyFields({
1791
+ items: z6.array(productEntityRowSchema)
1792
+ });
1793
+ var generateRandomChartOutputSchema = toolChartResultSchema.extend({
1794
+ title: z6.string().min(1)
1795
+ });
1796
+ var generateImageOutputSchema = withAgentOnlyFields({
1797
+ prompt: z6.string().min(1),
1798
+ mediaType: z6.string().min(1),
1799
+ model: z6.string().min(1),
1800
+ storageId: z6.string().min(1),
1801
+ url: z6.string().min(1),
1802
+ /** @deprecated Legacy sessions only — prefer storageId/url. */
1803
+ base64: z6.string().min(1).optional()
1804
+ });
1805
+ var manageTeamMembersListOutputSchema = withAgentOnlyFields({
1806
+ members: z6.array(memberEntityRowSchema)
1807
+ });
1808
+ var manageTeamMembersDetailOutputSchema = withAgentOnlyFields(
1809
+ memberEntityRowSchema.shape
1810
+ );
1811
+ var manageTeamMembersOutputSchema = z6.union([
1812
+ manageTeamMembersListOutputSchema,
1813
+ manageTeamMembersDetailOutputSchema,
1814
+ agentAdminMutationResultSchema,
1815
+ agentAdminErrorResultSchema
1816
+ ]);
1817
+ var manageGroupsListOutputSchema = withAgentOnlyFields({
1818
+ groups: z6.array(groupEntityRowSchema)
1819
+ });
1820
+ var manageGroupsDetailOutputSchema = withAgentOnlyFields(
1821
+ groupDetailEntitySchema.shape
1822
+ );
1823
+ var manageGroupsSummaryOutputSchema = withAgentOnlyFields(
1824
+ groupEntityRowSchema.shape
1825
+ );
1826
+ var manageGroupsOutputSchema = z6.union([
1827
+ manageGroupsListOutputSchema,
1828
+ manageGroupsDetailOutputSchema,
1829
+ manageGroupsSummaryOutputSchema,
1830
+ agentAdminMutationResultSchema,
1831
+ agentAdminErrorResultSchema
1832
+ ]);
1833
+ var queryTasksListOutputSchema = withAgentOnlyFields({
1834
+ items: z6.array(taskEntityRowSchema),
1835
+ nextCursor: z6.string().nullable().optional()
1836
+ });
1837
+ var queryTasksDetailOutputSchema = withAgentOnlyFields({
1838
+ id: z6.string().nullable(),
1839
+ status: z6.string().nullable(),
1840
+ type: z6.string().nullable(),
1841
+ name: z6.string().nullable(),
1842
+ description: z6.string().nullable(),
1843
+ validUntil: z6.number().nullable(),
1844
+ createdAt: z6.number().nullable(),
1845
+ url: z6.string().min(1).nullable()
1846
+ });
1847
+ var queryTasksOutputSchema = z6.union([
1848
+ queryTasksListOutputSchema,
1849
+ queryTasksDetailOutputSchema,
1850
+ agentAdminErrorResultSchema
1851
+ ]);
1852
+ var assignTasksOutputSchema = z6.union([
1853
+ withAgentOnlyFields({
1854
+ results: z6.array(statusEntityRowSchema)
1855
+ }),
1856
+ agentAdminErrorResultSchema
1857
+ ]);
1858
+ var workspaceUsageEntitySchema = z6.object({
1859
+ workspace: z6.string(),
1860
+ plan: z6.string(),
1861
+ planType: z6.string(),
1862
+ trialState: z6.string(),
1863
+ daysRemaining: z6.number().nullable(),
1864
+ isPaidPro: z6.boolean(),
1865
+ subscriptionStatus: z6.string(),
1866
+ tasksToday: z6.string(),
1867
+ tasksResetAt: z6.string(),
1868
+ openTasks: z6.number(),
1869
+ totalTasks: z6.number(),
1870
+ seats: z6.string(),
1871
+ groups: z6.string(),
1872
+ apiKeys: z6.string(),
1873
+ rateLimitPerSecond: z6.number()
1874
+ });
1875
+ var getWorkspaceUsageOutputSchema = z6.union([
1876
+ withAgentOnlyFields({
1877
+ usage: workspaceUsageEntitySchema
1878
+ }),
1879
+ agentAdminErrorResultSchema
1880
+ ]);
1881
+
1882
+ // src/eve/tool-reply-guidance.ts
1883
+ var TOOL_REPLY_GUIDANCE_FIELD = "replyGuidance";
1884
+ 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.";
1885
+ function withReplyGuidance(result, guidance) {
1886
+ return {
1887
+ ...result,
1888
+ [TOOL_REPLY_GUIDANCE_FIELD]: guidance
1889
+ };
1890
+ }
1891
+
1892
+ // src/eve/tool-display-format.ts
1893
+ function formatToolObjectResult(data, options) {
1894
+ let result = withReplyGuidance(
1895
+ data,
1896
+ options.replyGuidance
1897
+ );
1898
+ if (options.ui) {
1899
+ result = withToolUi(result, options.ui);
1900
+ }
1901
+ if (options.uiHint) {
1902
+ result = withUiHint(result, options.uiHint);
1903
+ }
1904
+ return result;
1905
+ }
1906
+
1907
+ // src/eve/tools/catalog/generate-image.ts
1908
+ var GENERATE_IMAGE_TOOL_NAME = "generate_image";
1909
+ var DEFAULT_IMAGE_MODEL = "black-forest-labs/flux.2-klein-4b";
1910
+ var DEFAULT_IMAGE_SIZE = "512";
1911
+ var DEFAULT_IMAGE_ASPECT_RATIO = "1:1";
1912
+ var generateImageInputSchema = z7.object({
1913
+ prompt: z7.string().min(1).describe("Detailed description of the image to generate")
1914
+ });
1915
+ function normalizeEnvValue(value) {
1916
+ if (!value) {
1917
+ return void 0;
1918
+ }
1919
+ return value.replace(/^["']|["']$/g, "");
1920
+ }
1921
+ function isJwtExpired(token, bufferSeconds = 60) {
1922
+ try {
1923
+ const payload = JSON.parse(
1924
+ Buffer.from(token.split(".")[1] ?? "", "base64url").toString("utf8")
1925
+ );
1926
+ return typeof payload.exp !== "number" || Date.now() / 1e3 >= payload.exp - bufferSeconds;
1927
+ } catch {
1928
+ return true;
1929
+ }
1930
+ }
1931
+ function resolveAiImageModel(modelId = normalizeEnvValue(process.env.AI_IMAGE_MODEL) ?? DEFAULT_IMAGE_MODEL) {
1932
+ const openRouterKey = normalizeEnvValue(process.env.OPENROUTER_API_KEY);
1933
+ if (openRouterKey) {
1934
+ const openrouter = createOpenRouter({ apiKey: openRouterKey });
1935
+ return {
1936
+ provider: "openrouter",
1937
+ model: openrouter.imageModel(modelId),
1938
+ modelId
1939
+ };
1940
+ }
1941
+ const gatewayKey = normalizeEnvValue(process.env.AI_GATEWAY_API_KEY);
1942
+ if (gatewayKey) {
1943
+ const gateway2 = createGateway({ apiKey: gatewayKey });
1944
+ return {
1945
+ provider: "ai-gateway-api-key",
1946
+ model: gateway2.imageModel(modelId),
1947
+ modelId
1948
+ };
1949
+ }
1950
+ const oidcToken = normalizeEnvValue(process.env.VERCEL_OIDC_TOKEN);
1951
+ if (!oidcToken) {
1952
+ throw new Error(
1953
+ `No AI provider credentials for image model "${modelId}". Set OPENROUTER_API_KEY (preferred), or AI_GATEWAY_API_KEY / VERCEL_OIDC_TOKEN.`
1954
+ );
1955
+ }
1956
+ if (isJwtExpired(oidcToken)) {
1957
+ throw new Error(
1958
+ "VERCEL_OIDC_TOKEN is expired. Set OPENROUTER_API_KEY instead, or refresh the OIDC token."
1959
+ );
1960
+ }
1961
+ process.env.VERCEL_OIDC_TOKEN = oidcToken;
1962
+ const gateway = createGateway();
1963
+ return {
1964
+ provider: "ai-gateway-oidc",
1965
+ model: gateway.imageModel(modelId),
1966
+ modelId
1967
+ };
1968
+ }
1969
+ function resolveAiImageSize() {
1970
+ return normalizeEnvValue(process.env.AI_IMAGE_SIZE) ?? DEFAULT_IMAGE_SIZE;
1971
+ }
1972
+ function resolveAiImageAspectRatio() {
1973
+ return normalizeEnvValue(process.env.AI_IMAGE_ASPECT_RATIO) ?? DEFAULT_IMAGE_ASPECT_RATIO;
1974
+ }
1975
+ function extensionForMediaType(mediaType) {
1976
+ const normalized = mediaType.toLowerCase();
1977
+ if (normalized.includes("jpeg") || normalized.includes("jpg")) return "jpg";
1978
+ if (normalized.includes("webp")) return "webp";
1979
+ if (normalized.includes("gif")) return "gif";
1980
+ return "png";
1981
+ }
1982
+ function filenameFromImagePrompt(prompt, mediaType) {
1983
+ const slug = prompt.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
1984
+ return `${slug || "generated-image"}.${extensionForMediaType(mediaType)}`;
1985
+ }
1986
+ async function generateImageBytes(input, options) {
1987
+ const { model, modelId } = resolveAiImageModel();
1988
+ const size = resolveAiImageSize();
1989
+ const aspectRatio = resolveAiImageAspectRatio();
1990
+ try {
1991
+ const { image } = await generateImage({
1992
+ model,
1993
+ prompt: input.prompt,
1994
+ aspectRatio,
1995
+ abortSignal: options?.abortSignal,
1996
+ size
1997
+ });
1998
+ if (!image.base64) {
1999
+ throw new Error(`Image model "${modelId}" returned no image data.`);
2000
+ }
2001
+ return {
2002
+ prompt: input.prompt,
2003
+ mediaType: image.mediaType || "image/png",
2004
+ model: modelId,
2005
+ base64: image.base64
2006
+ };
2007
+ } catch (error) {
2008
+ const message = error instanceof Error ? error.message : "Image generation failed.";
2009
+ throw new Error(`Image generation failed (${modelId}): ${message}`);
2010
+ }
2011
+ }
2012
+ function defineGenerateImageTool() {
2013
+ return defineTool({
2014
+ 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.",
2015
+ inputSchema: generateImageInputSchema,
2016
+ outputSchema: generateImageOutputSchema,
2017
+ toModelOutput(output) {
2018
+ return {
2019
+ type: "text",
2020
+ value: `Generated an image for: "${output.prompt}" (model: ${output.model}).`
2021
+ };
2022
+ },
2023
+ async execute(input, ctx) {
2024
+ const caller = tryResolveTenantCaller(ctx);
2025
+ const chatId = caller?.chatId?.trim();
2026
+ if (!chatId) {
2027
+ throw new Error(
2028
+ "generate_image requires a dashboard chat session (missing chatId)."
2029
+ );
2030
+ }
2031
+ const client = tryCreateBoundRobotRockClient(ctx);
2032
+ if (!client) {
2033
+ throw new Error(
2034
+ "RobotRock auth is unset. Configure ROBOTROCK_AGENT_SERVICE_TOKEN for hosted agents or ROBOTROCK_API_KEY for self-hosted deployments."
2035
+ );
2036
+ }
2037
+ const generated = await generateImageBytes(input, {
2038
+ abortSignal: ctx?.abortSignal
2039
+ });
2040
+ const uploaded = await client.chats.uploadImage({
2041
+ mediaType: generated.mediaType,
2042
+ base64: generated.base64,
2043
+ chatId,
2044
+ source: GENERATE_IMAGE_TOOL_NAME,
2045
+ filename: filenameFromImagePrompt(generated.prompt, generated.mediaType),
2046
+ description: generated.prompt,
2047
+ tags: [GENERATE_IMAGE_TOOL_NAME]
2048
+ });
2049
+ return formatToolObjectResult(
2050
+ {
2051
+ prompt: generated.prompt,
2052
+ mediaType: uploaded.mediaType || generated.mediaType,
2053
+ model: generated.model,
2054
+ storageId: uploaded.storageId,
2055
+ url: uploaded.url
2056
+ },
2057
+ {
2058
+ replyGuidance: GENERATE_IMAGE_REPLY_GUIDANCE,
2059
+ ui: {
2060
+ present: true,
2061
+ entity: "generated_image"
2062
+ }
2063
+ }
2064
+ );
2065
+ }
2066
+ });
2067
+ }
2068
+ var generateImageTool = defineGenerateImageTool();
2069
+ export {
2070
+ GENERATE_IMAGE_TOOL_NAME,
2071
+ defineGenerateImageTool,
2072
+ filenameFromImagePrompt,
2073
+ generateImageBytes,
2074
+ generateImageInputSchema,
2075
+ generateImageTool
2076
+ };
2077
+ //# sourceMappingURL=generate-image.js.map