robotrock 0.9.0 → 1.1.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 (52) hide show
  1. package/dist/ai/index.d.ts +18 -7
  2. package/dist/ai/index.js +852 -115
  3. package/dist/ai/index.js.map +1 -1
  4. package/dist/ai/trigger.d.ts +4 -3
  5. package/dist/ai/trigger.js +810 -115
  6. package/dist/ai/trigger.js.map +1 -1
  7. package/dist/ai/workflow.d.ts +15 -4
  8. package/dist/ai/workflow.js +729 -115
  9. package/dist/ai/workflow.js.map +1 -1
  10. package/dist/client-XTnFHGFE.d.ts +248 -0
  11. package/dist/eve/agent/index.d.ts +188 -0
  12. package/dist/eve/agent/index.js +2322 -0
  13. package/dist/eve/agent/index.js.map +1 -0
  14. package/dist/eve/index.d.ts +5 -0
  15. package/dist/eve/index.js +446 -0
  16. package/dist/eve/index.js.map +1 -0
  17. package/dist/eve/tools/identity/index.d.ts +6 -0
  18. package/dist/eve/tools/identity/index.js +144 -0
  19. package/dist/eve/tools/identity/index.js.map +1 -0
  20. package/dist/eve/tools/identity/my-access.d.ts +58 -0
  21. package/dist/eve/tools/identity/my-access.js +106 -0
  22. package/dist/eve/tools/identity/my-access.js.map +1 -0
  23. package/dist/eve/tools/identity/whoami.d.ts +45 -0
  24. package/dist/eve/tools/identity/whoami.js +101 -0
  25. package/dist/eve/tools/identity/whoami.js.map +1 -0
  26. package/dist/eve/tools/inbox/create-task.d.ts +113 -0
  27. package/dist/eve/tools/inbox/create-task.js +1557 -0
  28. package/dist/eve/tools/inbox/create-task.js.map +1 -0
  29. package/dist/eve/tools/inbox/index.d.ts +5 -0
  30. package/dist/eve/tools/inbox/index.js +1557 -0
  31. package/dist/eve/tools/inbox/index.js.map +1 -0
  32. package/dist/eve/tools/index.d.ts +17 -0
  33. package/dist/eve/tools/index.js +1654 -0
  34. package/dist/eve/tools/index.js.map +1 -0
  35. package/dist/index-BL9qKHA8.d.ts +141 -0
  36. package/dist/index.d.ts +12 -44
  37. package/dist/index.js +793 -97
  38. package/dist/index.js.map +1 -1
  39. package/dist/schemas/index.d.ts +11 -1
  40. package/dist/schemas/index.js +126 -8
  41. package/dist/schemas/index.js.map +1 -1
  42. package/dist/tenant-5YKDrdC-.d.ts +23 -0
  43. package/dist/{tool-approval-bridge-G765kMJR.d.ts → tool-approval-bridge-C4bTm8vu.d.ts} +93 -2
  44. package/dist/trigger/index.d.ts +2 -1
  45. package/dist/trigger/index.js +495 -87
  46. package/dist/trigger/index.js.map +1 -1
  47. package/dist/{trigger-D0shjqk0.d.ts → trigger-Dn0DFiyU.d.ts} +64 -3
  48. package/dist/workflow/index.d.ts +2 -1
  49. package/dist/workflow/index.js +496 -88
  50. package/dist/workflow/index.js.map +1 -1
  51. package/package.json +44 -7
  52. package/dist/client-Cy7YLxms.d.ts +0 -145
package/dist/ai/index.js CHANGED
@@ -75,6 +75,13 @@ var init_convex_sanitize = __esm({
75
75
  }
76
76
  });
77
77
 
78
+ // ../core/src/utils/deployment-secret-encryption.ts
79
+ var init_deployment_secret_encryption = __esm({
80
+ "../core/src/utils/deployment-secret-encryption.ts"() {
81
+ "use strict";
82
+ }
83
+ });
84
+
78
85
  // ../core/src/utils/safe-url.ts
79
86
  function normalizeHostname(hostname) {
80
87
  return hostname.toLowerCase().replace(/^\[|\]$/g, "");
@@ -177,6 +184,25 @@ function isBlockedHostname(hostname) {
177
184
  }
178
185
  return isBlockedIpv4(host) || isBlockedIpv6(host);
179
186
  }
187
+ function isLoopbackHandlerUrl(urlString) {
188
+ let url;
189
+ try {
190
+ url = new URL(urlString);
191
+ } catch {
192
+ return false;
193
+ }
194
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
195
+ return false;
196
+ }
197
+ if (url.username || url.password) {
198
+ return false;
199
+ }
200
+ const host = url.hostname.toLowerCase();
201
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
202
+ }
203
+ function isAllowedHandlerUrl(urlString) {
204
+ return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
205
+ }
180
206
  function isPublicHttpUrl(urlString) {
181
207
  let url;
182
208
  try {
@@ -192,7 +218,7 @@ function isPublicHttpUrl(urlString) {
192
218
  }
193
219
  return !isBlockedHostname(url.hostname);
194
220
  }
195
- var BLOCKED_HOSTNAMES, PUBLIC_HTTP_URL_ERROR;
221
+ var BLOCKED_HOSTNAMES, PUBLIC_HTTP_URL_ERROR, HANDLER_URL_ERROR;
196
222
  var init_safe_url = __esm({
197
223
  "../core/src/utils/safe-url.ts"() {
198
224
  "use strict";
@@ -202,6 +228,7 @@ var init_safe_url = __esm({
202
228
  "metadata.goog"
203
229
  ]);
204
230
  PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
231
+ HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
205
232
  }
206
233
  });
207
234
 
@@ -218,6 +245,7 @@ var init_utils = __esm({
218
245
  "use strict";
219
246
  init_cn();
220
247
  init_convex_sanitize();
248
+ init_deployment_secret_encryption();
221
249
  init_safe_url();
222
250
  init_task_app();
223
251
  }
@@ -301,7 +329,7 @@ function refineContextPublicUrls(data, ctx) {
301
329
  });
302
330
  }
303
331
  }
304
- var safeUrlSchema, jsonSchema7Schema, uiSchemaSchema, webhookHandlerSchema, triggerHandlerSchema, handlerSchema, taskActionSchema, uiFieldSchemaSchema, contextUiSchema, contextDataSchema, TASK_CONTEXT_FORMAT_VERSION, taskContextObjectBaseSchema, taskContextObjectSchema, taskContextSchema, assignToSchema, threadUpdateMessageSchema, threadUpdateStatuses, threadUpdateStatusSchema, threadUpdateInputSchema, taskPriorities, taskPrioritySchema, agentTelemetrySchema, createTaskBodySchema;
332
+ var safeUrlSchema, handlerUrlSchema, jsonSchema7Schema, uiSchemaSchema, webhookHandlerSchema, triggerHandlerSchema, handlerSchema, taskActionInputSchema, taskActionSchema, uiFieldSchemaSchema, contextUiSchema, contextDataSchema, TASK_CONTEXT_FORMAT_VERSION, taskContextObjectBaseSchema, taskContextObjectSchema, taskContextSchema, assignToSchema, threadUpdateMessageSchema, threadUpdateStatuses, threadUpdateStatusSchema, threadUpdateInputSchema, taskPriorities, taskPrioritySchema, agentTelemetrySchema, createTaskBodySchema, agentChatSeedActionSchema, agentChatSeedMessageSchema, eveAgentChatTransportSchema, createAgentChatBodySchema, agentChatAuditInputBodySchema, eveHitlStagedOptionSchema, agentChatStageHitlBodySchema, agentChatLinkTaskBodySchema;
305
333
  var init_task = __esm({
306
334
  "../core/src/schemas/task.ts"() {
307
335
  "use strict";
@@ -310,6 +338,9 @@ var init_task = __esm({
310
338
  safeUrlSchema = z.string().refine((url) => isPublicHttpUrl(url), {
311
339
  message: PUBLIC_HTTP_URL_ERROR
312
340
  });
341
+ handlerUrlSchema = z.string().refine((url) => isAllowedHandlerUrl(url), {
342
+ message: HANDLER_URL_ERROR
343
+ });
313
344
  jsonSchema7Schema = z.custom(
314
345
  (val) => typeof val === "object" && val !== null,
315
346
  { message: "Must be a valid JSON Schema object" }
@@ -319,7 +350,7 @@ var init_task = __esm({
319
350
  });
320
351
  webhookHandlerSchema = z.object({
321
352
  type: z.literal("webhook"),
322
- url: safeUrlSchema,
353
+ url: handlerUrlSchema,
323
354
  headers: z.record(z.string(), z.string())
324
355
  });
325
356
  triggerHandlerSchema = webhookHandlerSchema.extend({
@@ -327,13 +358,15 @@ var init_task = __esm({
327
358
  tokenId: z.string().min(1)
328
359
  });
329
360
  handlerSchema = z.discriminatedUnion("type", [webhookHandlerSchema, triggerHandlerSchema]);
330
- taskActionSchema = z.object({
361
+ taskActionInputSchema = z.object({
331
362
  id: z.string().min(1),
332
363
  title: z.string().min(1),
333
364
  description: z.string().optional(),
334
365
  schema: jsonSchema7Schema.optional(),
335
366
  ui: uiSchemaSchema.optional(),
336
- data: z.record(z.string(), z.unknown()).optional(),
367
+ data: z.record(z.string(), z.unknown()).optional()
368
+ });
369
+ taskActionSchema = taskActionInputSchema.extend({
337
370
  // Optional handlers for this action - if present, must have at least 1
338
371
  handlers: z.array(handlerSchema).min(1).optional()
339
372
  });
@@ -424,6 +457,96 @@ var init_task = __esm({
424
457
  /** Agent release version — not shown in inbox UI. */
425
458
  agent: agentTelemetrySchema.optional()
426
459
  }).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
460
+ agentChatSeedActionSchema = z.object({
461
+ /** Stable action id echoed back on submit; auto-derived from title when omitted. */
462
+ id: z.string().min(1).optional(),
463
+ title: z.string().min(1),
464
+ description: z.string().optional(),
465
+ /** JSON Schema object for the form fields. */
466
+ schema: z.record(z.string(), z.unknown()).optional(),
467
+ /** RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). */
468
+ ui: z.record(z.string(), z.unknown()).optional(),
469
+ /** Optional default field values. */
470
+ data: z.record(z.string(), z.unknown()).optional()
471
+ });
472
+ agentChatSeedMessageSchema = z.object({
473
+ role: z.enum(["user", "assistant"]),
474
+ text: z.string().min(1),
475
+ /** Optional display-name override for the message sender. */
476
+ senderName: z.string().min(1).optional(),
477
+ /**
478
+ * Optional structured input request rendered as a styled RobotRock action
479
+ * widget below the message text. Use this instead of asking the user to reply
480
+ * in plain text so the request is always a proper action form.
481
+ */
482
+ requestActionInput: z.object({
483
+ prompt: z.string().optional(),
484
+ action: agentChatSeedActionSchema
485
+ }).optional()
486
+ });
487
+ eveAgentChatTransportSchema = z.object({
488
+ kind: z.literal("eve"),
489
+ chatId: z.string().min(1),
490
+ baseUrl: z.string().url(),
491
+ sessionId: z.string().optional(),
492
+ continuationToken: z.string().optional(),
493
+ streamIndex: z.number().int().nonnegative().optional(),
494
+ isStreaming: z.boolean().optional()
495
+ });
496
+ createAgentChatBodySchema = z.object({
497
+ /** Agent id (eve agent name). Required unless `parentChatId` is set. */
498
+ agentIdentifier: z.string().min(1).optional(),
499
+ /** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
500
+ parentChatId: z.string().min(1).optional(),
501
+ /** Convex tenantEveConnections id; resolved from the tenant when omitted. */
502
+ eveConnectionId: z.string().min(1).optional(),
503
+ /** Source application id; groups the chat under an inbox section. */
504
+ app: z.string().min(1).optional(),
505
+ assignTo: assignToSchema.optional(),
506
+ title: z.string().min(1),
507
+ messages: z.array(agentChatSeedMessageSchema).default([]),
508
+ /** Provenance label stored on the session ("cron" | "agent" | ...). */
509
+ source: z.string().min(1).optional()
510
+ }).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
511
+ message: "Provide either agentIdentifier or parentChatId"
512
+ });
513
+ agentChatAuditInputBodySchema = z.object({
514
+ eveSessionId: z.string().min(1),
515
+ userId: z.string().min(1),
516
+ actionId: z.string().min(1),
517
+ actionTitle: z.string().optional(),
518
+ prompt: z.string().optional(),
519
+ data: z.record(z.string(), z.unknown()).optional(),
520
+ idempotencyKey: z.string().optional(),
521
+ /** Eve input request id — used to merge staged HITL metadata. */
522
+ requestId: z.string().optional(),
523
+ /** Eve tool call id — fallback lookup for staged HITL metadata. */
524
+ toolCallId: z.string().optional()
525
+ });
526
+ eveHitlStagedOptionSchema = z.object({
527
+ id: z.string(),
528
+ label: z.string()
529
+ });
530
+ agentChatStageHitlBodySchema = z.object({
531
+ eveSessionId: z.string().min(1),
532
+ requests: z.array(
533
+ z.object({
534
+ requestId: z.string().min(1),
535
+ toolCallId: z.string().min(1),
536
+ toolName: z.string().min(1),
537
+ prompt: z.string().min(1),
538
+ display: z.enum(["confirmation", "select", "text"]).optional(),
539
+ allowFreeform: z.boolean().optional(),
540
+ options: z.array(eveHitlStagedOptionSchema).optional(),
541
+ toolInput: z.record(z.string(), z.unknown()).optional()
542
+ })
543
+ )
544
+ });
545
+ agentChatLinkTaskBodySchema = z.object({
546
+ eveSessionId: z.string().min(1),
547
+ publicTaskId: z.string().min(1),
548
+ toolCallId: z.string().min(1)
549
+ });
427
550
  }
428
551
  });
429
552
 
@@ -463,14 +586,14 @@ function refineContextPublicUrls2(data, ctx) {
463
586
  });
464
587
  }
465
588
  }
466
- var safeUrlSchema2, jsonSchema7Schema2, uiSchemaSchema2, webhookHandlerSchema2, triggerHandlerSchema2, handlerSchema2, taskActionSchema2, uiFieldSchemaSchema2, contextUiSchema2, contextDataSchema2, TASK_CONTEXT_FORMAT_VERSION2, taskContextObjectBaseSchema2, taskContextObjectSchema2, taskContextSchema2, assignToSchema2, threadUpdateMessageSchema2, threadUpdateStatuses2, threadUpdateStatusSchema2, threadUpdateInputSchema2, taskPriorities2, taskPrioritySchema2, agentTelemetrySchema2, createTaskBodySchema2, threadUpdateBodySchema;
589
+ var handlerUrlSchema2, jsonSchema7Schema2, uiSchemaSchema2, webhookHandlerSchema2, triggerHandlerSchema2, handlerSchema2, taskActionInputSchema2, taskActionSchema2, uiFieldSchemaSchema2, contextUiSchema2, contextDataSchema2, TASK_CONTEXT_FORMAT_VERSION2, taskContextObjectBaseSchema2, taskContextObjectSchema2, taskContextSchema2, assignToSchema2, threadUpdateMessageSchema2, threadUpdateStatuses2, threadUpdateStatusSchema2, threadUpdateInputSchema2, taskPriorities2, taskPrioritySchema2, agentTelemetrySchema2, createTaskBodySchema2, threadUpdateBodySchema;
467
590
  var init_schemas2 = __esm({
468
591
  "src/schemas/index.ts"() {
469
592
  "use strict";
470
593
  init_utils();
471
594
  init_schemas();
472
- safeUrlSchema2 = z2.string().refine((url) => isPublicHttpUrl(url), {
473
- message: PUBLIC_HTTP_URL_ERROR
595
+ handlerUrlSchema2 = z2.string().refine((url) => isAllowedHandlerUrl(url), {
596
+ message: HANDLER_URL_ERROR
474
597
  });
475
598
  jsonSchema7Schema2 = z2.custom(
476
599
  (val) => typeof val === "object" && val !== null,
@@ -481,7 +604,7 @@ var init_schemas2 = __esm({
481
604
  });
482
605
  webhookHandlerSchema2 = z2.object({
483
606
  type: z2.literal("webhook"),
484
- url: safeUrlSchema2,
607
+ url: handlerUrlSchema2,
485
608
  headers: z2.record(z2.string(), z2.string())
486
609
  });
487
610
  triggerHandlerSchema2 = webhookHandlerSchema2.extend({
@@ -489,13 +612,15 @@ var init_schemas2 = __esm({
489
612
  tokenId: z2.string().min(1)
490
613
  });
491
614
  handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
492
- taskActionSchema2 = z2.object({
615
+ taskActionInputSchema2 = z2.object({
493
616
  id: z2.string().min(1),
494
617
  title: z2.string().min(1),
495
618
  description: z2.string().optional(),
496
619
  schema: jsonSchema7Schema2.optional(),
497
620
  ui: uiSchemaSchema2.optional(),
498
- data: z2.record(z2.string(), z2.unknown()).optional(),
621
+ data: z2.record(z2.string(), z2.unknown()).optional()
622
+ });
623
+ taskActionSchema2 = taskActionInputSchema2.extend({
499
624
  handlers: z2.array(handlerSchema2).min(1).optional()
500
625
  });
501
626
  uiFieldSchemaSchema2 = z2.object({
@@ -618,6 +743,398 @@ var init_approval_result = __esm({
618
743
  }
619
744
  });
620
745
 
746
+ // src/http.ts
747
+ async function parseResponseBody(response) {
748
+ const contentType = response.headers.get("content-type") ?? "";
749
+ const bodyText = await response.text();
750
+ if (!bodyText) {
751
+ return null;
752
+ }
753
+ if (contentType.toLowerCase().includes("application/json")) {
754
+ try {
755
+ return JSON.parse(bodyText);
756
+ } catch {
757
+ }
758
+ }
759
+ try {
760
+ return JSON.parse(bodyText);
761
+ } catch {
762
+ return bodyText;
763
+ }
764
+ }
765
+ function getErrorMessage(data, fallback) {
766
+ if (data && typeof data === "object" && !Array.isArray(data)) {
767
+ const record = data;
768
+ const maybeMessage = record.message;
769
+ const maybeHint = record.hint;
770
+ if (typeof maybeMessage === "string" && maybeMessage.trim()) {
771
+ if (typeof maybeHint === "string" && maybeHint.trim()) {
772
+ return `${maybeMessage.trim()} ${maybeHint.trim()}`;
773
+ }
774
+ return maybeMessage;
775
+ }
776
+ }
777
+ if (typeof data === "string" && data.trim()) {
778
+ const compact = data.replace(/\s+/g, " ").trim();
779
+ const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
780
+ return `${fallback}. Server returned non-JSON response: ${snippet}`;
781
+ }
782
+ return fallback;
783
+ }
784
+ var RobotRockError;
785
+ var init_http = __esm({
786
+ "src/http.ts"() {
787
+ "use strict";
788
+ RobotRockError = class extends Error {
789
+ constructor(message, statusCode, response) {
790
+ super(message);
791
+ this.statusCode = statusCode;
792
+ this.response = response;
793
+ this.name = "RobotRockError";
794
+ }
795
+ };
796
+ }
797
+ });
798
+
799
+ // ../core/src/types/task.ts
800
+ var init_task2 = __esm({
801
+ "../core/src/types/task.ts"() {
802
+ "use strict";
803
+ }
804
+ });
805
+
806
+ // ../core/src/types/json-schema-infer.ts
807
+ var init_json_schema_infer = __esm({
808
+ "../core/src/types/json-schema-infer.ts"() {
809
+ "use strict";
810
+ }
811
+ });
812
+
813
+ // ../core/src/types/index.ts
814
+ var init_types = __esm({
815
+ "../core/src/types/index.ts"() {
816
+ "use strict";
817
+ init_task2();
818
+ init_json_schema_infer();
819
+ }
820
+ });
821
+
822
+ // ../core/src/plans/index.ts
823
+ var init_plans = __esm({
824
+ "../core/src/plans/index.ts"() {
825
+ "use strict";
826
+ }
827
+ });
828
+
829
+ // ../core/src/handler-retry.ts
830
+ var HANDLER_RETRY_DELAYS_MS, HANDLER_MAX_ATTEMPTS;
831
+ var init_handler_retry = __esm({
832
+ "../core/src/handler-retry.ts"() {
833
+ "use strict";
834
+ HANDLER_RETRY_DELAYS_MS = [
835
+ 6e4,
836
+ // 1m
837
+ 3e5,
838
+ // 5m
839
+ 18e5,
840
+ // 30m
841
+ 36e5,
842
+ // 1h
843
+ 216e5,
844
+ // 6h
845
+ 864e5,
846
+ // 24h
847
+ 1728e5
848
+ // 48h
849
+ ];
850
+ HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
851
+ }
852
+ });
853
+
854
+ // ../core/src/legal.ts
855
+ var init_legal = __esm({
856
+ "../core/src/legal.ts"() {
857
+ "use strict";
858
+ }
859
+ });
860
+
861
+ // ../core/src/welcome-task.ts
862
+ var init_welcome_task = __esm({
863
+ "../core/src/welcome-task.ts"() {
864
+ "use strict";
865
+ }
866
+ });
867
+
868
+ // ../core/src/app-url.ts
869
+ function normalizeRobotRockApiBaseUrl(baseUrl) {
870
+ const trimmed = baseUrl.trim().replace(/\/+$/, "");
871
+ if (trimmed.endsWith("/v1")) {
872
+ return trimmed;
873
+ }
874
+ return `${trimmed}/v1`;
875
+ }
876
+ function getRobotRockApiBaseUrl() {
877
+ const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
878
+ if (explicit) {
879
+ return normalizeRobotRockApiBaseUrl(explicit);
880
+ }
881
+ if (process.env.NODE_ENV === "production") {
882
+ return PRODUCTION_API_URL;
883
+ }
884
+ return DEV_API_URL;
885
+ }
886
+ var PRODUCTION_APP_URL, PRODUCTION_API_URL, DEV_API_URL, APP_SIGNUP_URL;
887
+ var init_app_url = __esm({
888
+ "../core/src/app-url.ts"() {
889
+ "use strict";
890
+ PRODUCTION_APP_URL = "https://app.robotrock.io";
891
+ PRODUCTION_API_URL = "https://api.robotrock.io/v1";
892
+ DEV_API_URL = "http://localhost:4001/v1";
893
+ APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
894
+ }
895
+ });
896
+
897
+ // ../core/src/attribution/index.ts
898
+ import { z as z3 } from "zod";
899
+ var ATTRIBUTION_COOKIE_MAX_AGE, attributionSchema;
900
+ var init_attribution = __esm({
901
+ "../core/src/attribution/index.ts"() {
902
+ "use strict";
903
+ init_app_url();
904
+ init_app_url();
905
+ ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
906
+ attributionSchema = z3.object({
907
+ utmSource: z3.string().optional(),
908
+ utmMedium: z3.string().optional(),
909
+ utmCampaign: z3.string().optional(),
910
+ utmContent: z3.string().optional(),
911
+ utmTerm: z3.string().optional(),
912
+ gclid: z3.string().optional(),
913
+ landingUrl: z3.string().optional(),
914
+ referrer: z3.string().optional(),
915
+ capturedAt: z3.number()
916
+ });
917
+ }
918
+ });
919
+
920
+ // ../core/src/agent-service-auth.ts
921
+ var init_agent_service_auth = __esm({
922
+ "../core/src/agent-service-auth.ts"() {
923
+ "use strict";
924
+ }
925
+ });
926
+
927
+ // ../core/src/index.ts
928
+ var init_src = __esm({
929
+ "../core/src/index.ts"() {
930
+ "use strict";
931
+ init_schemas();
932
+ init_types();
933
+ init_utils();
934
+ init_plans();
935
+ init_handler_retry();
936
+ init_legal();
937
+ init_welcome_task();
938
+ init_attribution();
939
+ init_app_url();
940
+ init_agent_service_auth();
941
+ }
942
+ });
943
+
944
+ // src/auth-headers.ts
945
+ function buildRobotRockAuthHeaders(auth) {
946
+ if (auth.kind === "apiKey") {
947
+ return {
948
+ "X-Api-Key": auth.apiKey
949
+ };
950
+ }
951
+ return {
952
+ Authorization: `Bearer ${auth.token}`,
953
+ "X-RobotRock-Tenant-Slug": auth.tenantSlug,
954
+ "X-RobotRock-Connection-Id": auth.connectionId
955
+ };
956
+ }
957
+ function resolveRobotRockAuthConfig(overrides) {
958
+ if (overrides?.agentService) {
959
+ return {
960
+ kind: "agentService",
961
+ ...overrides.agentService
962
+ };
963
+ }
964
+ const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
965
+ if (!apiKey) {
966
+ throw new Error(
967
+ "RobotRock auth is required. Set ROBOTROCK_API_KEY, ROBOTROCK_AGENT_SERVICE_TOKEN with tenant context, or pass auth when creating the client."
968
+ );
969
+ }
970
+ return { kind: "apiKey", apiKey };
971
+ }
972
+ var init_auth_headers = __esm({
973
+ "src/auth-headers.ts"() {
974
+ "use strict";
975
+ }
976
+ });
977
+
978
+ // src/chats.ts
979
+ function createChatsApi(config) {
980
+ const headers = () => ({
981
+ "Content-Type": "application/json",
982
+ ...buildRobotRockAuthHeaders(config.auth)
983
+ });
984
+ return {
985
+ async create(input) {
986
+ const bodyPayload = {
987
+ ...input,
988
+ app: input.app ?? config.app,
989
+ messages: input.messages ?? []
990
+ };
991
+ const validation = createAgentChatBodySchema.safeParse(bodyPayload);
992
+ if (!validation.success) {
993
+ throw new RobotRockError(
994
+ `Invalid chat: ${validation.error.issues[0]?.message}`,
995
+ 400,
996
+ validation.error.issues
997
+ );
998
+ }
999
+ const response = await fetch(`${config.baseUrl}/agent-chats`, {
1000
+ method: "POST",
1001
+ headers: headers(),
1002
+ body: JSON.stringify(validation.data)
1003
+ });
1004
+ const data = await parseResponseBody(response);
1005
+ if (!response.ok) {
1006
+ throw new RobotRockError(
1007
+ getErrorMessage(data, "Failed to create chat"),
1008
+ response.status,
1009
+ data
1010
+ );
1011
+ }
1012
+ const result = data;
1013
+ return { tenantSlug: result.tenantSlug, chats: result.chats };
1014
+ },
1015
+ async close(chatId, options) {
1016
+ if (!chatId) {
1017
+ throw new RobotRockError("chatId is required to close a chat", 400);
1018
+ }
1019
+ const response = await fetch(
1020
+ `${config.baseUrl}/agent-chats/${encodeURIComponent(chatId)}/close`,
1021
+ {
1022
+ method: "POST",
1023
+ headers: headers(),
1024
+ body: JSON.stringify({ reason: options?.reason })
1025
+ }
1026
+ );
1027
+ if (!response.ok) {
1028
+ const data = await parseResponseBody(response);
1029
+ throw new RobotRockError(
1030
+ getErrorMessage(data, "Failed to close chat"),
1031
+ response.status,
1032
+ data
1033
+ );
1034
+ }
1035
+ },
1036
+ async stageHitlRequests(input) {
1037
+ const validation = agentChatStageHitlBodySchema.safeParse(input);
1038
+ if (!validation.success) {
1039
+ throw new RobotRockError(
1040
+ `Invalid stage HITL input: ${validation.error.issues[0]?.message}`,
1041
+ 400,
1042
+ validation.error.issues
1043
+ );
1044
+ }
1045
+ const response = await fetch(`${config.baseUrl}/agent-chats/stage-hitl`, {
1046
+ method: "POST",
1047
+ headers: headers(),
1048
+ body: JSON.stringify(validation.data)
1049
+ });
1050
+ if (!response.ok) {
1051
+ const data = await parseResponseBody(response);
1052
+ throw new RobotRockError(
1053
+ getErrorMessage(data, "Failed to stage chat HITL requests"),
1054
+ response.status,
1055
+ data
1056
+ );
1057
+ }
1058
+ },
1059
+ async getStagedHitlRequests(eveSessionId) {
1060
+ const trimmed = eveSessionId.trim();
1061
+ if (!trimmed) {
1062
+ throw new RobotRockError("eveSessionId is required", 400);
1063
+ }
1064
+ const url = new URL(`${config.baseUrl}/agent-chats/staged-hitl`);
1065
+ url.searchParams.set("eveSessionId", trimmed);
1066
+ const response = await fetch(url.toString(), {
1067
+ method: "GET",
1068
+ headers: headers()
1069
+ });
1070
+ const data = await parseResponseBody(response);
1071
+ if (!response.ok) {
1072
+ throw new RobotRockError(
1073
+ getErrorMessage(data, "Failed to fetch staged chat HITL requests"),
1074
+ response.status,
1075
+ data
1076
+ );
1077
+ }
1078
+ const requests = data.requests;
1079
+ return Array.isArray(requests) ? requests : [];
1080
+ },
1081
+ async logInputSubmission(input) {
1082
+ const validation = agentChatAuditInputBodySchema.safeParse(input);
1083
+ if (!validation.success) {
1084
+ throw new RobotRockError(
1085
+ `Invalid audit input: ${validation.error.issues[0]?.message}`,
1086
+ 400,
1087
+ validation.error.issues
1088
+ );
1089
+ }
1090
+ const response = await fetch(`${config.baseUrl}/agent-chats/audit-input`, {
1091
+ method: "POST",
1092
+ headers: headers(),
1093
+ body: JSON.stringify(validation.data)
1094
+ });
1095
+ if (!response.ok) {
1096
+ const data = await parseResponseBody(response);
1097
+ throw new RobotRockError(
1098
+ getErrorMessage(data, "Failed to log chat input submission"),
1099
+ response.status,
1100
+ data
1101
+ );
1102
+ }
1103
+ },
1104
+ async linkTask(input) {
1105
+ const validation = agentChatLinkTaskBodySchema.safeParse(input);
1106
+ if (!validation.success) {
1107
+ throw new RobotRockError(
1108
+ `Invalid link task input: ${validation.error.issues[0]?.message}`,
1109
+ 400,
1110
+ validation.error.issues
1111
+ );
1112
+ }
1113
+ const response = await fetch(`${config.baseUrl}/agent-chats/link-task`, {
1114
+ method: "POST",
1115
+ headers: headers(),
1116
+ body: JSON.stringify(validation.data)
1117
+ });
1118
+ if (!response.ok) {
1119
+ const data = await parseResponseBody(response);
1120
+ throw new RobotRockError(
1121
+ getErrorMessage(data, "Failed to link inbox task to chat"),
1122
+ response.status,
1123
+ data
1124
+ );
1125
+ }
1126
+ }
1127
+ };
1128
+ }
1129
+ var init_chats = __esm({
1130
+ "src/chats.ts"() {
1131
+ "use strict";
1132
+ init_src();
1133
+ init_http();
1134
+ init_auth_headers();
1135
+ }
1136
+ });
1137
+
621
1138
  // src/client.ts
622
1139
  function sleep(ms) {
623
1140
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -695,62 +1212,31 @@ function normalizeSendToHumanInput(task2, clientDefaults) {
695
1212
  actions: normalizedActions
696
1213
  };
697
1214
  }
698
- async function parseResponseBody(response) {
699
- const contentType = response.headers.get("content-type") ?? "";
700
- const bodyText = await response.text();
701
- if (!bodyText) {
702
- return null;
703
- }
704
- if (contentType.toLowerCase().includes("application/json")) {
705
- try {
706
- return JSON.parse(bodyText);
707
- } catch {
708
- }
709
- }
710
- try {
711
- return JSON.parse(bodyText);
712
- } catch {
713
- return bodyText;
714
- }
715
- }
716
- function getErrorMessage(data, fallback) {
717
- if (data && typeof data === "object" && !Array.isArray(data)) {
718
- const maybeMessage = data.message;
719
- if (typeof maybeMessage === "string" && maybeMessage.trim()) {
720
- return maybeMessage;
721
- }
722
- }
723
- if (typeof data === "string" && data.trim()) {
724
- const compact = data.replace(/\s+/g, " ").trim();
725
- const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
726
- return `${fallback}. Server returned non-JSON response: ${snippet}`;
727
- }
728
- return fallback;
729
- }
730
- var DEFAULT_POLL_INTERVAL_MS, DEFAULT_TIMEOUT_MS, RobotRockError, RobotRock;
1215
+ var DEFAULT_POLL_INTERVAL_MS, DEFAULT_TIMEOUT_MS, RobotRock;
731
1216
  var init_client = __esm({
732
1217
  "src/client.ts"() {
733
1218
  "use strict";
734
1219
  init_schemas2();
735
1220
  init_approval_result();
1221
+ init_http();
1222
+ init_src();
1223
+ init_chats();
1224
+ init_auth_headers();
1225
+ init_http();
736
1226
  DEFAULT_POLL_INTERVAL_MS = 2e3;
737
1227
  DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
738
- RobotRockError = class extends Error {
739
- constructor(message, statusCode, response) {
740
- super(message);
741
- this.statusCode = statusCode;
742
- this.response = response;
743
- this.name = "RobotRockError";
744
- }
745
- };
746
1228
  RobotRock = class {
747
- apiKey;
1229
+ auth;
748
1230
  baseUrl;
749
1231
  app;
750
1232
  agentVersion;
751
1233
  contextVersion;
752
1234
  webhook;
753
1235
  polling;
1236
+ /** Task CRUD: `create`, `get`, `cancel`, `sendUpdate`. */
1237
+ tasks;
1238
+ /** Chat CRUD: `create`, `close`. */
1239
+ chats;
754
1240
  constructor(config) {
755
1241
  if (config.webhook && config.polling) {
756
1242
  throw new Error(
@@ -758,24 +1244,42 @@ var init_client = __esm({
758
1244
  );
759
1245
  }
760
1246
  const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;
761
- if (!apiKey) {
1247
+ const agentService = config.agentService;
1248
+ if (apiKey && agentService) {
762
1249
  throw new Error(
763
- "RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client."
1250
+ "RobotRock client cannot configure both apiKey and agentService."
764
1251
  );
765
1252
  }
766
- this.apiKey = apiKey;
767
- const rawBase = config.baseUrl ?? "https://api.robotrock.io/v1";
768
- this.baseUrl = rawBase.replace(/\/+$/, "");
1253
+ this.auth = resolveRobotRockAuthConfig({
1254
+ ...apiKey ? { apiKey } : {},
1255
+ ...agentService ? { agentService } : {}
1256
+ });
1257
+ this.baseUrl = config.baseUrl ?? getRobotRockApiBaseUrl();
769
1258
  this.app = config.app;
770
1259
  this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
771
1260
  this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
772
1261
  this.webhook = config.webhook;
773
1262
  this.polling = config.polling ?? {};
1263
+ this.tasks = {
1264
+ create: (task2) => this.createTaskRequest(task2),
1265
+ get: (taskId) => this.getTaskById(taskId),
1266
+ cancel: (taskId) => this.cancelTaskRequest(taskId),
1267
+ sendUpdate: (input) => this.sendThreadUpdate(input)
1268
+ };
1269
+ this.chats = createChatsApi({
1270
+ baseUrl: this.baseUrl,
1271
+ auth: this.auth,
1272
+ app: this.app
1273
+ });
774
1274
  }
775
- /**
776
- * Create a task via POST /v1 without waiting for a human response.
777
- */
778
- async createTask(task2) {
1275
+ authHeaders(extra) {
1276
+ return {
1277
+ "Content-Type": "application/json",
1278
+ ...buildRobotRockAuthHeaders(this.auth),
1279
+ ...extra
1280
+ };
1281
+ }
1282
+ async createTaskRequest(task2) {
779
1283
  const normalizedTask = normalizeSendToHumanInput(task2, {
780
1284
  webhook: this.webhook,
781
1285
  app: this.app,
@@ -799,13 +1303,9 @@ var init_client = __esm({
799
1303
  validation.error.issues
800
1304
  );
801
1305
  }
802
- const headers = {
803
- "Content-Type": "application/json",
804
- "X-Api-Key": this.apiKey
805
- };
806
- if (task2.idempotencyKey) {
807
- headers["Idempotency-Key"] = task2.idempotencyKey;
808
- }
1306
+ const headers = this.authHeaders(
1307
+ task2.idempotencyKey ? { "Idempotency-Key": task2.idempotencyKey } : void 0
1308
+ );
809
1309
  const response = await fetch(`${this.baseUrl}/`, {
810
1310
  method: "POST",
811
1311
  headers,
@@ -828,7 +1328,7 @@ var init_client = __esm({
828
1328
  contextVersion: this.contextVersion,
829
1329
  agentVersion: this.agentVersion
830
1330
  });
831
- const createdTaskTask = await this.createTask(task2);
1331
+ const createdTaskTask = await this.createTaskRequest(task2);
832
1332
  const hasHandlers = normalizedTask.actions.some(
833
1333
  (action) => Array.isArray(action.handlers) && action.handlers.length > 0
834
1334
  );
@@ -845,7 +1345,7 @@ var init_client = __esm({
845
1345
  const deadline = validUntilMs !== void 0 ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;
846
1346
  const taskId = createdTaskTask.taskId;
847
1347
  while (Date.now() < deadline) {
848
- const existing = await this.getTask(taskId);
1348
+ const existing = await this.getTaskById(taskId);
849
1349
  if (existing?.status === "handled" && existing.handled) {
850
1350
  return {
851
1351
  mode: "handled",
@@ -867,15 +1367,38 @@ var init_client = __esm({
867
1367
  }
868
1368
  throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);
869
1369
  }
1370
+ /**
1371
+ * Create a task via POST /v1 without waiting for a human response.
1372
+ * @deprecated Use `client.tasks.create()` instead.
1373
+ */
1374
+ async createTask(task2) {
1375
+ return this.tasks.create(task2);
1376
+ }
870
1377
  /**
871
1378
  * Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
1379
+ * @deprecated Use `client.tasks.get()` instead.
872
1380
  */
873
1381
  async getTask(taskId) {
1382
+ return this.tasks.get(taskId);
1383
+ }
1384
+ /**
1385
+ * Log a status update against a thread.
1386
+ * @deprecated Use `client.tasks.sendUpdate()` instead.
1387
+ */
1388
+ async sendUpdate(input) {
1389
+ return this.tasks.sendUpdate(input);
1390
+ }
1391
+ /**
1392
+ * Cancel a task by public task id.
1393
+ * @deprecated Use `client.tasks.cancel()` instead.
1394
+ */
1395
+ async cancelTask(taskId) {
1396
+ return this.tasks.cancel(taskId);
1397
+ }
1398
+ async getTaskById(taskId) {
874
1399
  const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
875
1400
  method: "GET",
876
- headers: {
877
- "X-Api-Key": this.apiKey
878
- }
1401
+ headers: this.authHeaders()
879
1402
  });
880
1403
  if (response.status === 404) {
881
1404
  return null;
@@ -890,11 +1413,11 @@ var init_client = __esm({
890
1413
  }
891
1414
  return data;
892
1415
  }
893
- /**
894
- * Log a status update against a thread. The update shows in the inbox status
895
- * bar and thread update log for every task in the thread.
896
- */
897
- async sendUpdate({ threadId, message, status }) {
1416
+ async sendThreadUpdate({
1417
+ threadId,
1418
+ message,
1419
+ status
1420
+ }) {
898
1421
  if (!threadId) {
899
1422
  throw new RobotRockError("threadId is required to send an update", 400);
900
1423
  }
@@ -910,10 +1433,7 @@ var init_client = __esm({
910
1433
  `${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,
911
1434
  {
912
1435
  method: "POST",
913
- headers: {
914
- "Content-Type": "application/json",
915
- "X-Api-Key": this.apiKey
916
- },
1436
+ headers: this.authHeaders(),
917
1437
  body: JSON.stringify(validation.data)
918
1438
  }
919
1439
  );
@@ -927,12 +1447,10 @@ var init_client = __esm({
927
1447
  }
928
1448
  return data.update;
929
1449
  }
930
- async cancelTask(taskId) {
1450
+ async cancelTaskRequest(taskId) {
931
1451
  const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
932
1452
  method: "POST",
933
- headers: {
934
- "X-Api-Key": this.apiKey
935
- }
1453
+ headers: this.authHeaders()
936
1454
  });
937
1455
  if (!response.ok) {
938
1456
  const data = await parseResponseBody(response);
@@ -949,22 +1467,30 @@ var init_client = __esm({
949
1467
 
950
1468
  // src/env.ts
951
1469
  function resolveRobotRockConfig(overrides) {
1470
+ const agentService = overrides?.agentService;
952
1471
  const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
953
- if (!apiKey) {
1472
+ if (agentService && apiKey) {
954
1473
  throw new Error(
955
- "RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client."
1474
+ "RobotRock client cannot configure both apiKey and agentService."
956
1475
  );
957
1476
  }
958
- const baseUrl = overrides?.baseUrl ?? process.env.ROBOTROCK_BASE_URL ?? process.env.ROBOTROCK_API_URL ?? DEFAULT_BASE_URL;
1477
+ const baseUrl = overrides?.baseUrl ?? getRobotRockApiBaseUrl();
959
1478
  const app = overrides?.app ?? process.env.ROBOTROCK_APP;
1479
+ if (agentService) {
1480
+ return app ? { agentService, baseUrl, app } : { agentService, baseUrl };
1481
+ }
1482
+ if (!apiKey) {
1483
+ throw new Error(
1484
+ "RobotRock API key is required. Set ROBOTROCK_API_KEY or pass agentService when creating the client."
1485
+ );
1486
+ }
960
1487
  return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };
961
1488
  }
962
- var DEFAULT_BASE_URL;
963
1489
  var init_env = __esm({
964
1490
  "src/env.ts"() {
965
1491
  "use strict";
966
1492
  init_client();
967
- DEFAULT_BASE_URL = "https://api.robotrock.io/v1";
1493
+ init_src();
968
1494
  }
969
1495
  });
970
1496
 
@@ -1470,7 +1996,7 @@ async function sendRobotRockUpdate(payload) {
1470
1996
  ...baseConfig.version ? { version: baseConfig.version } : {},
1471
1997
  ...baseConfig.advanced ? { advanced: baseConfig.advanced } : {}
1472
1998
  });
1473
- return client.sendUpdate(update);
1999
+ return client.tasks.sendUpdate(update);
1474
2000
  }
1475
2001
  async function sendUpdateInWorkflow(payload) {
1476
2002
  return sendRobotRockUpdate(payload);
@@ -1496,7 +2022,7 @@ var init_workflow = __esm({
1496
2022
  import { tool } from "ai";
1497
2023
 
1498
2024
  // src/ai/approve-by-human-tool-core.ts
1499
- import { z as z3 } from "zod";
2025
+ import { z as z4 } from "zod";
1500
2026
 
1501
2027
  // src/ai/context.ts
1502
2028
  init_client();
@@ -1575,9 +2101,19 @@ async function sendUpdateForAi(context2, payload) {
1575
2101
  const client = createClient(
1576
2102
  resolveRobotRockConfig(context2.app ? { app: context2.app } : void 0)
1577
2103
  );
1578
- return client.sendUpdate(payload);
2104
+ return client.tasks.sendUpdate(payload);
1579
2105
  }
1580
- return context2.client.sendUpdate(payload);
2106
+ return context2.client.tasks.sendUpdate(payload);
2107
+ }
2108
+ async function closeChatForAi(context2, payload) {
2109
+ if (context2.mode === "trigger" || context2.mode === "workflow") {
2110
+ const client = createClient(
2111
+ resolveRobotRockConfig(context2.app ? { app: context2.app } : void 0)
2112
+ );
2113
+ await client.chats.close(payload.chatId, { reason: payload.reason });
2114
+ return;
2115
+ }
2116
+ await context2.client.chats.close(payload.chatId, { reason: payload.reason });
1581
2117
  }
1582
2118
  async function approveByHumanForAi(context2, payload) {
1583
2119
  if (context2.mode === "trigger") {
@@ -1640,11 +2176,11 @@ var APPROVE_BY_HUMAN_ACTIONS4 = [
1640
2176
  { id: "approve", title: "Approve" },
1641
2177
  { id: "decline", title: "Decline" }
1642
2178
  ];
1643
- var approveByHumanInputSchema = z3.object({
1644
- type: z3.string().optional().describe("Task type slug; defaults to ai-approval"),
1645
- name: z3.string().describe("Short title for the approval request"),
1646
- description: z3.string().describe("What needs approval and the consequences of approving or declining"),
1647
- contextSummary: z3.string().optional().describe("Optional markdown summary shown to the reviewer")
2179
+ var approveByHumanInputSchema = z4.object({
2180
+ type: z4.string().optional().describe("Task type slug; defaults to ai-approval"),
2181
+ name: z4.string().describe("Short title for the approval request"),
2182
+ description: z4.string().describe("What needs approval and the consequences of approving or declining"),
2183
+ contextSummary: z4.string().optional().describe("Optional markdown summary shown to the reviewer")
1648
2184
  });
1649
2185
  function resolveApproveByHumanToolConfig(clientOrContext, maybeOptions = {}) {
1650
2186
  const isDurable = typeof clientOrContext === "object" && clientOrContext !== null && "mode" in clientOrContext && (clientOrContext.mode === "trigger" || clientOrContext.mode === "workflow");
@@ -1694,16 +2230,16 @@ import { tool as tool2 } from "ai";
1694
2230
 
1695
2231
  // src/ai/create-send-to-human-tool-core.ts
1696
2232
  init_schemas2();
1697
- import { z as z4 } from "zod";
1698
- var sendToHumanToolInputSchema = z4.object({
1699
- type: z4.string().describe("Task type slug shown in the RobotRock inbox"),
1700
- name: z4.string().describe("Short title for the human reviewer"),
1701
- description: z4.string().optional().describe("What you need from the human and why you cannot proceed alone"),
1702
- context: z4.object({
1703
- data: z4.record(z4.string(), z4.unknown()).optional(),
1704
- ui: z4.record(z4.string(), z4.unknown()).optional()
2233
+ import { z as z5 } from "zod";
2234
+ var sendToHumanToolInputSchema = z5.object({
2235
+ type: z5.string().describe("Task type slug shown in the RobotRock inbox"),
2236
+ name: z5.string().describe("Short title for the human reviewer"),
2237
+ description: z5.string().optional().describe("What you need from the human and why you cannot proceed alone"),
2238
+ context: z5.object({
2239
+ data: z5.record(z5.string(), z5.unknown()).optional(),
2240
+ ui: z5.record(z5.string(), z5.unknown()).optional()
1705
2241
  }).optional().describe("Optional structured context for the inbox UI"),
1706
- validUntil: z4.string().datetime().optional().describe("Optional ISO deadline for the task"),
2242
+ validUntil: z5.string().datetime().optional().describe("Optional ISO deadline for the task"),
1707
2243
  assignTo: assignToSchema2.optional().describe(
1708
2244
  "Assign to tenant member emails and/or group slugs; narrows who sees the task in the inbox"
1709
2245
  )
@@ -1757,12 +2293,12 @@ import { tool as tool3 } from "ai";
1757
2293
  // src/ai/create-send-update-tool-core.ts
1758
2294
  init_schemas2();
1759
2295
  init_client();
1760
- import { z as z5 } from "zod";
1761
- var sendUpdateToolInputSchema = z5.object({
1762
- threadId: z5.string().optional().describe(
2296
+ import { z as z6 } from "zod";
2297
+ var sendUpdateToolInputSchema = z6.object({
2298
+ threadId: z6.string().optional().describe(
1763
2299
  "Thread to post the update to. Use the `threadId` returned by a prior send-to-human task. Omit only when a session threadId is configured on the tool."
1764
2300
  ),
1765
- message: z5.string().describe("Short progress update (1-2 sentences) shown in the inbox status bar"),
2301
+ message: z6.string().describe("Short progress update (1-2 sentences) shown in the inbox status bar"),
1766
2302
  status: threadUpdateStatusSchema2.optional().describe(
1767
2303
  "Lifecycle status driving the status-bar icon/color: info, queued, running, waiting, succeeded, failed, cancelled"
1768
2304
  )
@@ -1818,6 +2354,174 @@ function createSendUpdateTool(clientOrOptions, maybeOptions = {}) {
1818
2354
  return tool3(buildSendUpdateToolDefinition(clientOrOptions, maybeOptions));
1819
2355
  }
1820
2356
 
2357
+ // src/ai/request-action-input-tool.ts
2358
+ import { tool as tool4 } from "ai";
2359
+
2360
+ // src/ai/request-action-input-tool-core.ts
2361
+ import { z as z7 } from "zod";
2362
+ var REQUEST_ACTION_INPUT_TOOL_NAME = "requestActionInput";
2363
+ function defaultRequestActionInputActionId(title) {
2364
+ const slug = title.trim().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
2365
+ return slug.length > 0 ? slug : "submit";
2366
+ }
2367
+ var requestActionInputActionSchema = z7.object({
2368
+ id: z7.string().min(1).optional().describe(
2369
+ "Stable action identifier echoed in tool output (e.g. pick-blog-topic). Strongly recommended \u2014 auto-derived from title when omitted."
2370
+ ),
2371
+ title: z7.string().min(1),
2372
+ description: z7.string().optional(),
2373
+ schema: z7.record(z7.string(), z7.unknown()).optional().describe("JSON Schema object for the human feedback form"),
2374
+ ui: z7.record(z7.string(), z7.unknown()).optional().describe(
2375
+ 'RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). Use ui:widget "radio" for 2\u20136 discrete choices rendered as tappable cards.'
2376
+ ),
2377
+ data: z7.record(z7.string(), z7.unknown()).optional().describe("Optional default form field values")
2378
+ });
2379
+ function normalizeRequestActionInputToolInput(input) {
2380
+ const parsed = requestActionInputToolInputSchema.parse(input);
2381
+ return {
2382
+ ...parsed,
2383
+ action: {
2384
+ ...parsed.action,
2385
+ id: parsed.action.id?.trim() || defaultRequestActionInputActionId(parsed.action.title)
2386
+ }
2387
+ };
2388
+ }
2389
+ var requestActionInputToolOutputSchema = z7.object({
2390
+ actionId: z7.string().min(1),
2391
+ data: z7.record(z7.string(), z7.unknown())
2392
+ });
2393
+ var requestActionInputToolInputSchema = z7.object({
2394
+ prompt: z7.string().optional().describe("Optional heading shown above the action widget in chat"),
2395
+ action: requestActionInputActionSchema.describe(
2396
+ "Action widget config: JSON Schema form fields and optional RJSF ui overrides (same shape as RobotRock inbox actions)"
2397
+ )
2398
+ });
2399
+ function buildRequestActionInputToolDefinition(options = {}) {
2400
+ const description = options.description ?? `Ask the user for structured input via a RobotRock action widget in chat. Always set action.id (e.g. "pick-blog-topic") and action.title. Provide action.schema and optional action.ui using the same JSON Schema and RJSF ui shape as inbox action widgets. Put every field you need in a single call \u2014 never invoke this tool more than once per turn. For 2\u20136 discrete options, use a string enum with ui:widget "radio" and ui:enumNames \u2014 never markdown bullet lists. After the tool returns, act on the user's data immediately; do not ask them to confirm choices they already submitted.`;
2401
+ return {
2402
+ description,
2403
+ inputSchema: requestActionInputToolInputSchema,
2404
+ outputSchema: requestActionInputToolOutputSchema
2405
+ };
2406
+ }
2407
+ function isRequestActionInputToolPart(part, toolName = REQUEST_ACTION_INPUT_TOOL_NAME) {
2408
+ return part.type === `tool-${toolName}`;
2409
+ }
2410
+
2411
+ // src/ai/request-action-input-tool.ts
2412
+ function requestActionInputTool(options = {}) {
2413
+ const definition = buildRequestActionInputToolDefinition(options);
2414
+ return tool4(definition);
2415
+ }
2416
+
2417
+ // src/ai/report-status-tool.ts
2418
+ import { tool as tool5 } from "ai";
2419
+
2420
+ // src/ai/report-status-tool-core.ts
2421
+ import { z as z8 } from "zod";
2422
+ var REPORT_STATUS_TOOL_NAME = "reportStatus";
2423
+ var reportStatusPhaseSchema = z8.enum([
2424
+ "info",
2425
+ "running",
2426
+ "waiting",
2427
+ "succeeded",
2428
+ "failed"
2429
+ ]);
2430
+ var reportStatusToolInputSchema = z8.object({
2431
+ message: z8.string().min(1).describe(
2432
+ "Short progress update shown in chat (1-2 sentences). Use while researching, drafting, or waiting on external work."
2433
+ ),
2434
+ phase: reportStatusPhaseSchema.optional().describe(
2435
+ "Lifecycle phase for the status marker. Defaults to running. Use succeeded or failed when a step finishes."
2436
+ )
2437
+ });
2438
+ var reportStatusToolOutputSchema = z8.object({
2439
+ message: z8.string().min(1),
2440
+ phase: reportStatusPhaseSchema
2441
+ });
2442
+ function normalizeReportStatusToolInput(input) {
2443
+ const parsed = reportStatusToolInputSchema.parse(input);
2444
+ return {
2445
+ message: parsed.message.trim(),
2446
+ phase: parsed.phase
2447
+ };
2448
+ }
2449
+ async function executeReportStatusTool(input) {
2450
+ const normalized = normalizeReportStatusToolInput(input);
2451
+ return {
2452
+ message: normalized.message,
2453
+ phase: normalized.phase ?? "running"
2454
+ };
2455
+ }
2456
+ function buildReportStatusToolDefinition(options = {}) {
2457
+ const description = options.description ?? 'Post a short progress update to the chat UI while you work. Call this before and during long steps (research, drafting, tool runs) so the user sees what is happening. Use phase "running" while in progress, "succeeded" or "failed" when a step completes, and "waiting" when blocked on external input.';
2458
+ return {
2459
+ description,
2460
+ inputSchema: reportStatusToolInputSchema,
2461
+ outputSchema: reportStatusToolOutputSchema,
2462
+ execute: executeReportStatusTool
2463
+ };
2464
+ }
2465
+ function isReportStatusToolPart(part, toolName = REPORT_STATUS_TOOL_NAME) {
2466
+ return part.type === `tool-${toolName}`;
2467
+ }
2468
+
2469
+ // src/ai/report-status-tool.ts
2470
+ function reportStatusTool(options = {}) {
2471
+ return tool5(buildReportStatusToolDefinition(options));
2472
+ }
2473
+
2474
+ // src/ai/close-chat-tool.ts
2475
+ import { tool as tool6 } from "ai";
2476
+
2477
+ // src/ai/close-chat-tool-core.ts
2478
+ import { z as z9 } from "zod";
2479
+ var CLOSE_CHAT_TOOL_NAME = "closeChat";
2480
+ var closeChatToolInputSchema = z9.object({
2481
+ reason: z9.string().optional().describe(
2482
+ "Short reason the conversation is being closed (recorded on the audit trail)."
2483
+ )
2484
+ });
2485
+ function resolveCloseChatToolConfig(clientOrOptions, maybeOptions) {
2486
+ const isDurable = typeof clientOrOptions === "object" && clientOrOptions !== null && "mode" in clientOrOptions && (clientOrOptions.mode === "trigger" || clientOrOptions.mode === "workflow");
2487
+ const aiContext = normalizeRobotRockAiContext(
2488
+ isDurable ? {
2489
+ mode: clientOrOptions.mode,
2490
+ app: clientOrOptions.app
2491
+ } : clientOrOptions
2492
+ );
2493
+ const options = isDurable ? clientOrOptions : maybeOptions;
2494
+ if (!options?.chatId) {
2495
+ throw new Error(
2496
+ "closeChatTool: `chatId` is required. Pass the chatId of the chat the agent is running in."
2497
+ );
2498
+ }
2499
+ return { aiContext, options };
2500
+ }
2501
+ function buildCloseChatToolDefinition(clientOrOptions, maybeOptions) {
2502
+ const { aiContext, options } = resolveCloseChatToolConfig(
2503
+ clientOrOptions,
2504
+ maybeOptions
2505
+ );
2506
+ const description = options.description ?? "Close the current chat when the conversation is complete and no further human input is needed. Records the close on the audit trail.";
2507
+ return {
2508
+ description,
2509
+ inputSchema: closeChatToolInputSchema,
2510
+ execute: async (input) => {
2511
+ await closeChatForAi(aiContext, {
2512
+ chatId: options.chatId,
2513
+ reason: input.reason
2514
+ });
2515
+ return { closed: true, chatId: options.chatId };
2516
+ }
2517
+ };
2518
+ }
2519
+
2520
+ // src/ai/close-chat-tool.ts
2521
+ function closeChatTool(clientOrOptions, maybeOptions) {
2522
+ return tool6(buildCloseChatToolDefinition(clientOrOptions, maybeOptions));
2523
+ }
2524
+
1821
2525
  // src/ai/create-ai-tools.ts
1822
2526
  function createRobotRockAiTools(options) {
1823
2527
  const mode = options.mode ?? (options.client ? "polling" : "trigger");
@@ -1845,7 +2549,19 @@ function createRobotRockAiTools(options) {
1845
2549
  }) : createSendUpdateTool(pollingClient, {
1846
2550
  ...options.threadId ? { threadId: options.threadId } : {},
1847
2551
  ...toolOptions
1848
- })
2552
+ }),
2553
+ requestActionInput: (toolOptions = {}) => requestActionInputTool(toolOptions),
2554
+ reportStatus: (toolOptions = {}) => reportStatusTool(toolOptions),
2555
+ closeChat: (toolOptions) => {
2556
+ const chatId = toolOptions?.chatId ?? options.chatId;
2557
+ if (!chatId) {
2558
+ throw new Error(
2559
+ "createRobotRockAiTools: closeChat requires `chatId`. Pass it on `createRobotRockAiTools({ chatId })` or `closeChat({ chatId })`."
2560
+ );
2561
+ }
2562
+ const resolvedOptions = { ...toolOptions, chatId };
2563
+ return durableContext ? closeChatTool({ ...durableContext, ...resolvedOptions }) : closeChatTool(pollingClient, resolvedOptions);
2564
+ }
1849
2565
  };
1850
2566
  }
1851
2567
 
@@ -2106,11 +2822,19 @@ async function runWithRobotRockApprovals(options) {
2106
2822
  }
2107
2823
  export {
2108
2824
  APPROVE_BY_HUMAN_ACTIONS4 as APPROVE_BY_HUMAN_ACTIONS,
2825
+ CLOSE_CHAT_TOOL_NAME,
2109
2826
  DEFAULT_APPROVE_ACTIONS,
2827
+ REPORT_STATUS_TOOL_NAME,
2828
+ REQUEST_ACTION_INPUT_TOOL_NAME,
2110
2829
  applyRobotRockToolApprovalToTools,
2111
2830
  approveByHumanForAi,
2112
2831
  approveByHumanInputSchema,
2113
2832
  approveByHumanTool,
2833
+ buildReportStatusToolDefinition,
2834
+ buildRequestActionInputToolDefinition,
2835
+ closeChatForAi,
2836
+ closeChatTool,
2837
+ closeChatToolInputSchema,
2114
2838
  collectApprovalRequests,
2115
2839
  createRobotRockAiTools,
2116
2840
  createRobotRockAiTriggerContext,
@@ -2120,7 +2844,20 @@ export {
2120
2844
  createSendToHumanTool,
2121
2845
  createSendUpdateTool,
2122
2846
  defaultFormatToolApprovalTask,
2847
+ defaultRequestActionInputActionId,
2848
+ executeReportStatusTool,
2849
+ isReportStatusToolPart,
2850
+ isRequestActionInputToolPart,
2851
+ normalizeReportStatusToolInput,
2852
+ normalizeRequestActionInputToolInput,
2123
2853
  normalizeRobotRockAiContext,
2854
+ reportStatusPhaseSchema,
2855
+ reportStatusTool,
2856
+ reportStatusToolInputSchema,
2857
+ reportStatusToolOutputSchema,
2858
+ requestActionInputTool,
2859
+ requestActionInputToolInputSchema,
2860
+ requestActionInputToolOutputSchema,
2124
2861
  resolveToolApprovalsViaRobotRock,
2125
2862
  runWithRobotRockApprovals,
2126
2863
  sendToHumanForAi,