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.
- package/dist/ai/index.d.ts +18 -7
- package/dist/ai/index.js +852 -115
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/trigger.d.ts +4 -3
- package/dist/ai/trigger.js +810 -115
- package/dist/ai/trigger.js.map +1 -1
- package/dist/ai/workflow.d.ts +15 -4
- package/dist/ai/workflow.js +729 -115
- package/dist/ai/workflow.js.map +1 -1
- package/dist/client-XTnFHGFE.d.ts +248 -0
- package/dist/eve/agent/index.d.ts +188 -0
- package/dist/eve/agent/index.js +2322 -0
- package/dist/eve/agent/index.js.map +1 -0
- package/dist/eve/index.d.ts +5 -0
- package/dist/eve/index.js +446 -0
- package/dist/eve/index.js.map +1 -0
- package/dist/eve/tools/identity/index.d.ts +6 -0
- package/dist/eve/tools/identity/index.js +144 -0
- package/dist/eve/tools/identity/index.js.map +1 -0
- package/dist/eve/tools/identity/my-access.d.ts +58 -0
- package/dist/eve/tools/identity/my-access.js +106 -0
- package/dist/eve/tools/identity/my-access.js.map +1 -0
- package/dist/eve/tools/identity/whoami.d.ts +45 -0
- package/dist/eve/tools/identity/whoami.js +101 -0
- package/dist/eve/tools/identity/whoami.js.map +1 -0
- package/dist/eve/tools/inbox/create-task.d.ts +113 -0
- package/dist/eve/tools/inbox/create-task.js +1557 -0
- package/dist/eve/tools/inbox/create-task.js.map +1 -0
- package/dist/eve/tools/inbox/index.d.ts +5 -0
- package/dist/eve/tools/inbox/index.js +1557 -0
- package/dist/eve/tools/inbox/index.js.map +1 -0
- package/dist/eve/tools/index.d.ts +17 -0
- package/dist/eve/tools/index.js +1654 -0
- package/dist/eve/tools/index.js.map +1 -0
- package/dist/index-BL9qKHA8.d.ts +141 -0
- package/dist/index.d.ts +12 -44
- package/dist/index.js +793 -97
- package/dist/index.js.map +1 -1
- package/dist/schemas/index.d.ts +11 -1
- package/dist/schemas/index.js +126 -8
- package/dist/schemas/index.js.map +1 -1
- package/dist/tenant-5YKDrdC-.d.ts +23 -0
- package/dist/{tool-approval-bridge-G765kMJR.d.ts → tool-approval-bridge-C4bTm8vu.d.ts} +93 -2
- package/dist/trigger/index.d.ts +2 -1
- package/dist/trigger/index.js +495 -87
- package/dist/trigger/index.js.map +1 -1
- package/dist/{trigger-D0shjqk0.d.ts → trigger-Dn0DFiyU.d.ts} +64 -3
- package/dist/workflow/index.d.ts +2 -1
- package/dist/workflow/index.js +496 -88
- package/dist/workflow/index.js.map +1 -1
- package/package.json +44 -7
- package/dist/client-Cy7YLxms.d.ts +0 -145
package/dist/trigger/index.js
CHANGED
|
@@ -305,6 +305,25 @@ function isBlockedHostname(hostname) {
|
|
|
305
305
|
}
|
|
306
306
|
return isBlockedIpv4(host) || isBlockedIpv6(host);
|
|
307
307
|
}
|
|
308
|
+
function isLoopbackHandlerUrl(urlString) {
|
|
309
|
+
let url;
|
|
310
|
+
try {
|
|
311
|
+
url = new URL(urlString);
|
|
312
|
+
} catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
if (url.username || url.password) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
const host = url.hostname.toLowerCase();
|
|
322
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
323
|
+
}
|
|
324
|
+
function isAllowedHandlerUrl(urlString) {
|
|
325
|
+
return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
|
|
326
|
+
}
|
|
308
327
|
function isPublicHttpUrl(urlString) {
|
|
309
328
|
let url;
|
|
310
329
|
try {
|
|
@@ -321,6 +340,7 @@ function isPublicHttpUrl(urlString) {
|
|
|
321
340
|
return !isBlockedHostname(url.hostname);
|
|
322
341
|
}
|
|
323
342
|
var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
|
|
343
|
+
var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
|
|
324
344
|
|
|
325
345
|
// ../core/src/schemas/task.ts
|
|
326
346
|
import { z } from "zod";
|
|
@@ -382,6 +402,9 @@ function validateContextPublicUrls(context2) {
|
|
|
382
402
|
var safeUrlSchema = z.string().refine((url) => isPublicHttpUrl(url), {
|
|
383
403
|
message: PUBLIC_HTTP_URL_ERROR
|
|
384
404
|
});
|
|
405
|
+
var handlerUrlSchema = z.string().refine((url) => isAllowedHandlerUrl(url), {
|
|
406
|
+
message: HANDLER_URL_ERROR
|
|
407
|
+
});
|
|
385
408
|
var jsonSchema7Schema = z.custom(
|
|
386
409
|
(val) => typeof val === "object" && val !== null,
|
|
387
410
|
{ message: "Must be a valid JSON Schema object" }
|
|
@@ -391,7 +414,7 @@ var uiSchemaSchema = z.custom((val) => typeof val === "object" && val !== null,
|
|
|
391
414
|
});
|
|
392
415
|
var webhookHandlerSchema = z.object({
|
|
393
416
|
type: z.literal("webhook"),
|
|
394
|
-
url:
|
|
417
|
+
url: handlerUrlSchema,
|
|
395
418
|
headers: z.record(z.string(), z.string())
|
|
396
419
|
});
|
|
397
420
|
var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
@@ -399,13 +422,15 @@ var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
|
399
422
|
tokenId: z.string().min(1)
|
|
400
423
|
});
|
|
401
424
|
var handlerSchema = z.discriminatedUnion("type", [webhookHandlerSchema, triggerHandlerSchema]);
|
|
402
|
-
var
|
|
425
|
+
var taskActionInputSchema = z.object({
|
|
403
426
|
id: z.string().min(1),
|
|
404
427
|
title: z.string().min(1),
|
|
405
428
|
description: z.string().optional(),
|
|
406
429
|
schema: jsonSchema7Schema.optional(),
|
|
407
430
|
ui: uiSchemaSchema.optional(),
|
|
408
|
-
data: z.record(z.string(), z.unknown()).optional()
|
|
431
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
432
|
+
});
|
|
433
|
+
var taskActionSchema = taskActionInputSchema.extend({
|
|
409
434
|
// Optional handlers for this action - if present, must have at least 1
|
|
410
435
|
handlers: z.array(handlerSchema).min(1).optional()
|
|
411
436
|
});
|
|
@@ -513,10 +538,100 @@ var createTaskBodySchema = taskContextObjectBaseSchema.extend({
|
|
|
513
538
|
/** Agent release version — not shown in inbox UI. */
|
|
514
539
|
agent: agentTelemetrySchema.optional()
|
|
515
540
|
}).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
|
|
541
|
+
var agentChatSeedActionSchema = z.object({
|
|
542
|
+
/** Stable action id echoed back on submit; auto-derived from title when omitted. */
|
|
543
|
+
id: z.string().min(1).optional(),
|
|
544
|
+
title: z.string().min(1),
|
|
545
|
+
description: z.string().optional(),
|
|
546
|
+
/** JSON Schema object for the form fields. */
|
|
547
|
+
schema: z.record(z.string(), z.unknown()).optional(),
|
|
548
|
+
/** RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). */
|
|
549
|
+
ui: z.record(z.string(), z.unknown()).optional(),
|
|
550
|
+
/** Optional default field values. */
|
|
551
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
552
|
+
});
|
|
553
|
+
var agentChatSeedMessageSchema = z.object({
|
|
554
|
+
role: z.enum(["user", "assistant"]),
|
|
555
|
+
text: z.string().min(1),
|
|
556
|
+
/** Optional display-name override for the message sender. */
|
|
557
|
+
senderName: z.string().min(1).optional(),
|
|
558
|
+
/**
|
|
559
|
+
* Optional structured input request rendered as a styled RobotRock action
|
|
560
|
+
* widget below the message text. Use this instead of asking the user to reply
|
|
561
|
+
* in plain text so the request is always a proper action form.
|
|
562
|
+
*/
|
|
563
|
+
requestActionInput: z.object({
|
|
564
|
+
prompt: z.string().optional(),
|
|
565
|
+
action: agentChatSeedActionSchema
|
|
566
|
+
}).optional()
|
|
567
|
+
});
|
|
568
|
+
var eveAgentChatTransportSchema = z.object({
|
|
569
|
+
kind: z.literal("eve"),
|
|
570
|
+
chatId: z.string().min(1),
|
|
571
|
+
baseUrl: z.string().url(),
|
|
572
|
+
sessionId: z.string().optional(),
|
|
573
|
+
continuationToken: z.string().optional(),
|
|
574
|
+
streamIndex: z.number().int().nonnegative().optional(),
|
|
575
|
+
isStreaming: z.boolean().optional()
|
|
576
|
+
});
|
|
577
|
+
var createAgentChatBodySchema = z.object({
|
|
578
|
+
/** Agent id (eve agent name). Required unless `parentChatId` is set. */
|
|
579
|
+
agentIdentifier: z.string().min(1).optional(),
|
|
580
|
+
/** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
|
|
581
|
+
parentChatId: z.string().min(1).optional(),
|
|
582
|
+
/** Convex tenantEveConnections id; resolved from the tenant when omitted. */
|
|
583
|
+
eveConnectionId: z.string().min(1).optional(),
|
|
584
|
+
/** Source application id; groups the chat under an inbox section. */
|
|
585
|
+
app: z.string().min(1).optional(),
|
|
586
|
+
assignTo: assignToSchema.optional(),
|
|
587
|
+
title: z.string().min(1),
|
|
588
|
+
messages: z.array(agentChatSeedMessageSchema).default([]),
|
|
589
|
+
/** Provenance label stored on the session ("cron" | "agent" | ...). */
|
|
590
|
+
source: z.string().min(1).optional()
|
|
591
|
+
}).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
|
|
592
|
+
message: "Provide either agentIdentifier or parentChatId"
|
|
593
|
+
});
|
|
594
|
+
var agentChatAuditInputBodySchema = z.object({
|
|
595
|
+
eveSessionId: z.string().min(1),
|
|
596
|
+
userId: z.string().min(1),
|
|
597
|
+
actionId: z.string().min(1),
|
|
598
|
+
actionTitle: z.string().optional(),
|
|
599
|
+
prompt: z.string().optional(),
|
|
600
|
+
data: z.record(z.string(), z.unknown()).optional(),
|
|
601
|
+
idempotencyKey: z.string().optional(),
|
|
602
|
+
/** Eve input request id — used to merge staged HITL metadata. */
|
|
603
|
+
requestId: z.string().optional(),
|
|
604
|
+
/** Eve tool call id — fallback lookup for staged HITL metadata. */
|
|
605
|
+
toolCallId: z.string().optional()
|
|
606
|
+
});
|
|
607
|
+
var eveHitlStagedOptionSchema = z.object({
|
|
608
|
+
id: z.string(),
|
|
609
|
+
label: z.string()
|
|
610
|
+
});
|
|
611
|
+
var agentChatStageHitlBodySchema = z.object({
|
|
612
|
+
eveSessionId: z.string().min(1),
|
|
613
|
+
requests: z.array(
|
|
614
|
+
z.object({
|
|
615
|
+
requestId: z.string().min(1),
|
|
616
|
+
toolCallId: z.string().min(1),
|
|
617
|
+
toolName: z.string().min(1),
|
|
618
|
+
prompt: z.string().min(1),
|
|
619
|
+
display: z.enum(["confirmation", "select", "text"]).optional(),
|
|
620
|
+
allowFreeform: z.boolean().optional(),
|
|
621
|
+
options: z.array(eveHitlStagedOptionSchema).optional(),
|
|
622
|
+
toolInput: z.record(z.string(), z.unknown()).optional()
|
|
623
|
+
})
|
|
624
|
+
)
|
|
625
|
+
});
|
|
626
|
+
var agentChatLinkTaskBodySchema = z.object({
|
|
627
|
+
eveSessionId: z.string().min(1),
|
|
628
|
+
publicTaskId: z.string().min(1),
|
|
629
|
+
toolCallId: z.string().min(1)
|
|
630
|
+
});
|
|
516
631
|
|
|
517
632
|
// src/schemas/index.ts
|
|
518
|
-
var
|
|
519
|
-
message:
|
|
633
|
+
var handlerUrlSchema2 = z2.string().refine((url) => isAllowedHandlerUrl(url), {
|
|
634
|
+
message: HANDLER_URL_ERROR
|
|
520
635
|
});
|
|
521
636
|
var jsonSchema7Schema2 = z2.custom(
|
|
522
637
|
(val) => typeof val === "object" && val !== null,
|
|
@@ -527,7 +642,7 @@ var uiSchemaSchema2 = z2.custom((val) => typeof val === "object" && val !== null
|
|
|
527
642
|
});
|
|
528
643
|
var webhookHandlerSchema2 = z2.object({
|
|
529
644
|
type: z2.literal("webhook"),
|
|
530
|
-
url:
|
|
645
|
+
url: handlerUrlSchema2,
|
|
531
646
|
headers: z2.record(z2.string(), z2.string())
|
|
532
647
|
});
|
|
533
648
|
var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
@@ -535,13 +650,15 @@ var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
|
535
650
|
tokenId: z2.string().min(1)
|
|
536
651
|
});
|
|
537
652
|
var handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
|
|
538
|
-
var
|
|
653
|
+
var taskActionInputSchema2 = z2.object({
|
|
539
654
|
id: z2.string().min(1),
|
|
540
655
|
title: z2.string().min(1),
|
|
541
656
|
description: z2.string().optional(),
|
|
542
657
|
schema: jsonSchema7Schema2.optional(),
|
|
543
658
|
ui: uiSchemaSchema2.optional(),
|
|
544
|
-
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
659
|
+
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
660
|
+
});
|
|
661
|
+
var taskActionSchema2 = taskActionInputSchema2.extend({
|
|
545
662
|
handlers: z2.array(handlerSchema2).min(1).optional()
|
|
546
663
|
});
|
|
547
664
|
var uiFieldSchemaSchema2 = z2.object({
|
|
@@ -673,6 +790,293 @@ function toDiscriminatedApprovalResult(actions, task2) {
|
|
|
673
790
|
};
|
|
674
791
|
}
|
|
675
792
|
|
|
793
|
+
// src/http.ts
|
|
794
|
+
var RobotRockError = class extends Error {
|
|
795
|
+
constructor(message, statusCode, response) {
|
|
796
|
+
super(message);
|
|
797
|
+
this.statusCode = statusCode;
|
|
798
|
+
this.response = response;
|
|
799
|
+
this.name = "RobotRockError";
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
async function parseResponseBody(response) {
|
|
803
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
804
|
+
const bodyText = await response.text();
|
|
805
|
+
if (!bodyText) {
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
if (contentType.toLowerCase().includes("application/json")) {
|
|
809
|
+
try {
|
|
810
|
+
return JSON.parse(bodyText);
|
|
811
|
+
} catch {
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
return JSON.parse(bodyText);
|
|
816
|
+
} catch {
|
|
817
|
+
return bodyText;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
function getErrorMessage(data, fallback) {
|
|
821
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
822
|
+
const record = data;
|
|
823
|
+
const maybeMessage = record.message;
|
|
824
|
+
const maybeHint = record.hint;
|
|
825
|
+
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
826
|
+
if (typeof maybeHint === "string" && maybeHint.trim()) {
|
|
827
|
+
return `${maybeMessage.trim()} ${maybeHint.trim()}`;
|
|
828
|
+
}
|
|
829
|
+
return maybeMessage;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
if (typeof data === "string" && data.trim()) {
|
|
833
|
+
const compact = data.replace(/\s+/g, " ").trim();
|
|
834
|
+
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
835
|
+
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
836
|
+
}
|
|
837
|
+
return fallback;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// ../core/src/handler-retry.ts
|
|
841
|
+
var HANDLER_RETRY_DELAYS_MS = [
|
|
842
|
+
6e4,
|
|
843
|
+
// 1m
|
|
844
|
+
3e5,
|
|
845
|
+
// 5m
|
|
846
|
+
18e5,
|
|
847
|
+
// 30m
|
|
848
|
+
36e5,
|
|
849
|
+
// 1h
|
|
850
|
+
216e5,
|
|
851
|
+
// 6h
|
|
852
|
+
864e5,
|
|
853
|
+
// 24h
|
|
854
|
+
1728e5
|
|
855
|
+
// 48h
|
|
856
|
+
];
|
|
857
|
+
var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
|
|
858
|
+
|
|
859
|
+
// ../core/src/attribution/index.ts
|
|
860
|
+
import { z as z3 } from "zod";
|
|
861
|
+
|
|
862
|
+
// ../core/src/app-url.ts
|
|
863
|
+
var PRODUCTION_APP_URL = "https://app.robotrock.io";
|
|
864
|
+
var PRODUCTION_API_URL = "https://api.robotrock.io/v1";
|
|
865
|
+
var DEV_API_URL = "http://localhost:4001/v1";
|
|
866
|
+
var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
|
|
867
|
+
function normalizeRobotRockApiBaseUrl(baseUrl) {
|
|
868
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
869
|
+
if (trimmed.endsWith("/v1")) {
|
|
870
|
+
return trimmed;
|
|
871
|
+
}
|
|
872
|
+
return `${trimmed}/v1`;
|
|
873
|
+
}
|
|
874
|
+
function getRobotRockApiBaseUrl() {
|
|
875
|
+
const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
|
|
876
|
+
if (explicit) {
|
|
877
|
+
return normalizeRobotRockApiBaseUrl(explicit);
|
|
878
|
+
}
|
|
879
|
+
if (process.env.NODE_ENV === "production") {
|
|
880
|
+
return PRODUCTION_API_URL;
|
|
881
|
+
}
|
|
882
|
+
return DEV_API_URL;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// ../core/src/attribution/index.ts
|
|
886
|
+
var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
|
|
887
|
+
var attributionSchema = z3.object({
|
|
888
|
+
utmSource: z3.string().optional(),
|
|
889
|
+
utmMedium: z3.string().optional(),
|
|
890
|
+
utmCampaign: z3.string().optional(),
|
|
891
|
+
utmContent: z3.string().optional(),
|
|
892
|
+
utmTerm: z3.string().optional(),
|
|
893
|
+
gclid: z3.string().optional(),
|
|
894
|
+
landingUrl: z3.string().optional(),
|
|
895
|
+
referrer: z3.string().optional(),
|
|
896
|
+
capturedAt: z3.number()
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// src/auth-headers.ts
|
|
900
|
+
function buildRobotRockAuthHeaders(auth) {
|
|
901
|
+
if (auth.kind === "apiKey") {
|
|
902
|
+
return {
|
|
903
|
+
"X-Api-Key": auth.apiKey
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
return {
|
|
907
|
+
Authorization: `Bearer ${auth.token}`,
|
|
908
|
+
"X-RobotRock-Tenant-Slug": auth.tenantSlug,
|
|
909
|
+
"X-RobotRock-Connection-Id": auth.connectionId
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
function resolveRobotRockAuthConfig(overrides) {
|
|
913
|
+
if (overrides?.agentService) {
|
|
914
|
+
return {
|
|
915
|
+
kind: "agentService",
|
|
916
|
+
...overrides.agentService
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
920
|
+
if (!apiKey) {
|
|
921
|
+
throw new Error(
|
|
922
|
+
"RobotRock auth is required. Set ROBOTROCK_API_KEY, ROBOTROCK_AGENT_SERVICE_TOKEN with tenant context, or pass auth when creating the client."
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
return { kind: "apiKey", apiKey };
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// src/chats.ts
|
|
929
|
+
function createChatsApi(config) {
|
|
930
|
+
const headers = () => ({
|
|
931
|
+
"Content-Type": "application/json",
|
|
932
|
+
...buildRobotRockAuthHeaders(config.auth)
|
|
933
|
+
});
|
|
934
|
+
return {
|
|
935
|
+
async create(input) {
|
|
936
|
+
const bodyPayload = {
|
|
937
|
+
...input,
|
|
938
|
+
app: input.app ?? config.app,
|
|
939
|
+
messages: input.messages ?? []
|
|
940
|
+
};
|
|
941
|
+
const validation = createAgentChatBodySchema.safeParse(bodyPayload);
|
|
942
|
+
if (!validation.success) {
|
|
943
|
+
throw new RobotRockError(
|
|
944
|
+
`Invalid chat: ${validation.error.issues[0]?.message}`,
|
|
945
|
+
400,
|
|
946
|
+
validation.error.issues
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
const response = await fetch(`${config.baseUrl}/agent-chats`, {
|
|
950
|
+
method: "POST",
|
|
951
|
+
headers: headers(),
|
|
952
|
+
body: JSON.stringify(validation.data)
|
|
953
|
+
});
|
|
954
|
+
const data = await parseResponseBody(response);
|
|
955
|
+
if (!response.ok) {
|
|
956
|
+
throw new RobotRockError(
|
|
957
|
+
getErrorMessage(data, "Failed to create chat"),
|
|
958
|
+
response.status,
|
|
959
|
+
data
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
const result = data;
|
|
963
|
+
return { tenantSlug: result.tenantSlug, chats: result.chats };
|
|
964
|
+
},
|
|
965
|
+
async close(chatId, options) {
|
|
966
|
+
if (!chatId) {
|
|
967
|
+
throw new RobotRockError("chatId is required to close a chat", 400);
|
|
968
|
+
}
|
|
969
|
+
const response = await fetch(
|
|
970
|
+
`${config.baseUrl}/agent-chats/${encodeURIComponent(chatId)}/close`,
|
|
971
|
+
{
|
|
972
|
+
method: "POST",
|
|
973
|
+
headers: headers(),
|
|
974
|
+
body: JSON.stringify({ reason: options?.reason })
|
|
975
|
+
}
|
|
976
|
+
);
|
|
977
|
+
if (!response.ok) {
|
|
978
|
+
const data = await parseResponseBody(response);
|
|
979
|
+
throw new RobotRockError(
|
|
980
|
+
getErrorMessage(data, "Failed to close chat"),
|
|
981
|
+
response.status,
|
|
982
|
+
data
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
},
|
|
986
|
+
async stageHitlRequests(input) {
|
|
987
|
+
const validation = agentChatStageHitlBodySchema.safeParse(input);
|
|
988
|
+
if (!validation.success) {
|
|
989
|
+
throw new RobotRockError(
|
|
990
|
+
`Invalid stage HITL input: ${validation.error.issues[0]?.message}`,
|
|
991
|
+
400,
|
|
992
|
+
validation.error.issues
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/stage-hitl`, {
|
|
996
|
+
method: "POST",
|
|
997
|
+
headers: headers(),
|
|
998
|
+
body: JSON.stringify(validation.data)
|
|
999
|
+
});
|
|
1000
|
+
if (!response.ok) {
|
|
1001
|
+
const data = await parseResponseBody(response);
|
|
1002
|
+
throw new RobotRockError(
|
|
1003
|
+
getErrorMessage(data, "Failed to stage chat HITL requests"),
|
|
1004
|
+
response.status,
|
|
1005
|
+
data
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
async getStagedHitlRequests(eveSessionId) {
|
|
1010
|
+
const trimmed = eveSessionId.trim();
|
|
1011
|
+
if (!trimmed) {
|
|
1012
|
+
throw new RobotRockError("eveSessionId is required", 400);
|
|
1013
|
+
}
|
|
1014
|
+
const url = new URL(`${config.baseUrl}/agent-chats/staged-hitl`);
|
|
1015
|
+
url.searchParams.set("eveSessionId", trimmed);
|
|
1016
|
+
const response = await fetch(url.toString(), {
|
|
1017
|
+
method: "GET",
|
|
1018
|
+
headers: headers()
|
|
1019
|
+
});
|
|
1020
|
+
const data = await parseResponseBody(response);
|
|
1021
|
+
if (!response.ok) {
|
|
1022
|
+
throw new RobotRockError(
|
|
1023
|
+
getErrorMessage(data, "Failed to fetch staged chat HITL requests"),
|
|
1024
|
+
response.status,
|
|
1025
|
+
data
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
const requests = data.requests;
|
|
1029
|
+
return Array.isArray(requests) ? requests : [];
|
|
1030
|
+
},
|
|
1031
|
+
async logInputSubmission(input) {
|
|
1032
|
+
const validation = agentChatAuditInputBodySchema.safeParse(input);
|
|
1033
|
+
if (!validation.success) {
|
|
1034
|
+
throw new RobotRockError(
|
|
1035
|
+
`Invalid audit input: ${validation.error.issues[0]?.message}`,
|
|
1036
|
+
400,
|
|
1037
|
+
validation.error.issues
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/audit-input`, {
|
|
1041
|
+
method: "POST",
|
|
1042
|
+
headers: headers(),
|
|
1043
|
+
body: JSON.stringify(validation.data)
|
|
1044
|
+
});
|
|
1045
|
+
if (!response.ok) {
|
|
1046
|
+
const data = await parseResponseBody(response);
|
|
1047
|
+
throw new RobotRockError(
|
|
1048
|
+
getErrorMessage(data, "Failed to log chat input submission"),
|
|
1049
|
+
response.status,
|
|
1050
|
+
data
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
async linkTask(input) {
|
|
1055
|
+
const validation = agentChatLinkTaskBodySchema.safeParse(input);
|
|
1056
|
+
if (!validation.success) {
|
|
1057
|
+
throw new RobotRockError(
|
|
1058
|
+
`Invalid link task input: ${validation.error.issues[0]?.message}`,
|
|
1059
|
+
400,
|
|
1060
|
+
validation.error.issues
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/link-task`, {
|
|
1064
|
+
method: "POST",
|
|
1065
|
+
headers: headers(),
|
|
1066
|
+
body: JSON.stringify(validation.data)
|
|
1067
|
+
});
|
|
1068
|
+
if (!response.ok) {
|
|
1069
|
+
const data = await parseResponseBody(response);
|
|
1070
|
+
throw new RobotRockError(
|
|
1071
|
+
getErrorMessage(data, "Failed to link inbox task to chat"),
|
|
1072
|
+
response.status,
|
|
1073
|
+
data
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
|
|
676
1080
|
// src/client.ts
|
|
677
1081
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
678
1082
|
var DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -710,22 +1114,18 @@ function serializeValidUntil(value) {
|
|
|
710
1114
|
}
|
|
711
1115
|
throw new RobotRockError("Invalid validUntil: expected a Date or parseable date string", 400);
|
|
712
1116
|
}
|
|
713
|
-
var RobotRockError = class extends Error {
|
|
714
|
-
constructor(message, statusCode, response) {
|
|
715
|
-
super(message);
|
|
716
|
-
this.statusCode = statusCode;
|
|
717
|
-
this.response = response;
|
|
718
|
-
this.name = "RobotRockError";
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
1117
|
var RobotRock = class {
|
|
722
|
-
|
|
1118
|
+
auth;
|
|
723
1119
|
baseUrl;
|
|
724
1120
|
app;
|
|
725
1121
|
agentVersion;
|
|
726
1122
|
contextVersion;
|
|
727
1123
|
webhook;
|
|
728
1124
|
polling;
|
|
1125
|
+
/** Task CRUD: `create`, `get`, `cancel`, `sendUpdate`. */
|
|
1126
|
+
tasks;
|
|
1127
|
+
/** Chat CRUD: `create`, `close`. */
|
|
1128
|
+
chats;
|
|
729
1129
|
constructor(config) {
|
|
730
1130
|
if (config.webhook && config.polling) {
|
|
731
1131
|
throw new Error(
|
|
@@ -733,24 +1133,42 @@ var RobotRock = class {
|
|
|
733
1133
|
);
|
|
734
1134
|
}
|
|
735
1135
|
const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
736
|
-
|
|
1136
|
+
const agentService = config.agentService;
|
|
1137
|
+
if (apiKey && agentService) {
|
|
737
1138
|
throw new Error(
|
|
738
|
-
"RobotRock
|
|
1139
|
+
"RobotRock client cannot configure both apiKey and agentService."
|
|
739
1140
|
);
|
|
740
1141
|
}
|
|
741
|
-
this.
|
|
742
|
-
|
|
743
|
-
|
|
1142
|
+
this.auth = resolveRobotRockAuthConfig({
|
|
1143
|
+
...apiKey ? { apiKey } : {},
|
|
1144
|
+
...agentService ? { agentService } : {}
|
|
1145
|
+
});
|
|
1146
|
+
this.baseUrl = config.baseUrl ?? getRobotRockApiBaseUrl();
|
|
744
1147
|
this.app = config.app;
|
|
745
1148
|
this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
|
|
746
1149
|
this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
|
|
747
1150
|
this.webhook = config.webhook;
|
|
748
1151
|
this.polling = config.polling ?? {};
|
|
1152
|
+
this.tasks = {
|
|
1153
|
+
create: (task2) => this.createTaskRequest(task2),
|
|
1154
|
+
get: (taskId) => this.getTaskById(taskId),
|
|
1155
|
+
cancel: (taskId) => this.cancelTaskRequest(taskId),
|
|
1156
|
+
sendUpdate: (input) => this.sendThreadUpdate(input)
|
|
1157
|
+
};
|
|
1158
|
+
this.chats = createChatsApi({
|
|
1159
|
+
baseUrl: this.baseUrl,
|
|
1160
|
+
auth: this.auth,
|
|
1161
|
+
app: this.app
|
|
1162
|
+
});
|
|
749
1163
|
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1164
|
+
authHeaders(extra) {
|
|
1165
|
+
return {
|
|
1166
|
+
"Content-Type": "application/json",
|
|
1167
|
+
...buildRobotRockAuthHeaders(this.auth),
|
|
1168
|
+
...extra
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
async createTaskRequest(task2) {
|
|
754
1172
|
const normalizedTask = normalizeSendToHumanInput(task2, {
|
|
755
1173
|
webhook: this.webhook,
|
|
756
1174
|
app: this.app,
|
|
@@ -774,13 +1192,9 @@ var RobotRock = class {
|
|
|
774
1192
|
validation.error.issues
|
|
775
1193
|
);
|
|
776
1194
|
}
|
|
777
|
-
const headers =
|
|
778
|
-
"
|
|
779
|
-
|
|
780
|
-
};
|
|
781
|
-
if (task2.idempotencyKey) {
|
|
782
|
-
headers["Idempotency-Key"] = task2.idempotencyKey;
|
|
783
|
-
}
|
|
1195
|
+
const headers = this.authHeaders(
|
|
1196
|
+
task2.idempotencyKey ? { "Idempotency-Key": task2.idempotencyKey } : void 0
|
|
1197
|
+
);
|
|
784
1198
|
const response = await fetch(`${this.baseUrl}/`, {
|
|
785
1199
|
method: "POST",
|
|
786
1200
|
headers,
|
|
@@ -803,7 +1217,7 @@ var RobotRock = class {
|
|
|
803
1217
|
contextVersion: this.contextVersion,
|
|
804
1218
|
agentVersion: this.agentVersion
|
|
805
1219
|
});
|
|
806
|
-
const createdTaskTask = await this.
|
|
1220
|
+
const createdTaskTask = await this.createTaskRequest(task2);
|
|
807
1221
|
const hasHandlers = normalizedTask.actions.some(
|
|
808
1222
|
(action) => Array.isArray(action.handlers) && action.handlers.length > 0
|
|
809
1223
|
);
|
|
@@ -820,7 +1234,7 @@ var RobotRock = class {
|
|
|
820
1234
|
const deadline = validUntilMs !== void 0 ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;
|
|
821
1235
|
const taskId = createdTaskTask.taskId;
|
|
822
1236
|
while (Date.now() < deadline) {
|
|
823
|
-
const existing = await this.
|
|
1237
|
+
const existing = await this.getTaskById(taskId);
|
|
824
1238
|
if (existing?.status === "handled" && existing.handled) {
|
|
825
1239
|
return {
|
|
826
1240
|
mode: "handled",
|
|
@@ -842,15 +1256,38 @@ var RobotRock = class {
|
|
|
842
1256
|
}
|
|
843
1257
|
throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);
|
|
844
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Create a task via POST /v1 without waiting for a human response.
|
|
1261
|
+
* @deprecated Use `client.tasks.create()` instead.
|
|
1262
|
+
*/
|
|
1263
|
+
async createTask(task2) {
|
|
1264
|
+
return this.tasks.create(task2);
|
|
1265
|
+
}
|
|
845
1266
|
/**
|
|
846
1267
|
* Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
|
|
1268
|
+
* @deprecated Use `client.tasks.get()` instead.
|
|
847
1269
|
*/
|
|
848
1270
|
async getTask(taskId) {
|
|
1271
|
+
return this.tasks.get(taskId);
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Log a status update against a thread.
|
|
1275
|
+
* @deprecated Use `client.tasks.sendUpdate()` instead.
|
|
1276
|
+
*/
|
|
1277
|
+
async sendUpdate(input) {
|
|
1278
|
+
return this.tasks.sendUpdate(input);
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Cancel a task by public task id.
|
|
1282
|
+
* @deprecated Use `client.tasks.cancel()` instead.
|
|
1283
|
+
*/
|
|
1284
|
+
async cancelTask(taskId) {
|
|
1285
|
+
return this.tasks.cancel(taskId);
|
|
1286
|
+
}
|
|
1287
|
+
async getTaskById(taskId) {
|
|
849
1288
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
|
|
850
1289
|
method: "GET",
|
|
851
|
-
headers:
|
|
852
|
-
"X-Api-Key": this.apiKey
|
|
853
|
-
}
|
|
1290
|
+
headers: this.authHeaders()
|
|
854
1291
|
});
|
|
855
1292
|
if (response.status === 404) {
|
|
856
1293
|
return null;
|
|
@@ -865,11 +1302,11 @@ var RobotRock = class {
|
|
|
865
1302
|
}
|
|
866
1303
|
return data;
|
|
867
1304
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1305
|
+
async sendThreadUpdate({
|
|
1306
|
+
threadId,
|
|
1307
|
+
message,
|
|
1308
|
+
status
|
|
1309
|
+
}) {
|
|
873
1310
|
if (!threadId) {
|
|
874
1311
|
throw new RobotRockError("threadId is required to send an update", 400);
|
|
875
1312
|
}
|
|
@@ -885,10 +1322,7 @@ var RobotRock = class {
|
|
|
885
1322
|
`${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,
|
|
886
1323
|
{
|
|
887
1324
|
method: "POST",
|
|
888
|
-
headers:
|
|
889
|
-
"Content-Type": "application/json",
|
|
890
|
-
"X-Api-Key": this.apiKey
|
|
891
|
-
},
|
|
1325
|
+
headers: this.authHeaders(),
|
|
892
1326
|
body: JSON.stringify(validation.data)
|
|
893
1327
|
}
|
|
894
1328
|
);
|
|
@@ -902,12 +1336,10 @@ var RobotRock = class {
|
|
|
902
1336
|
}
|
|
903
1337
|
return data.update;
|
|
904
1338
|
}
|
|
905
|
-
async
|
|
1339
|
+
async cancelTaskRequest(taskId) {
|
|
906
1340
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
|
|
907
1341
|
method: "POST",
|
|
908
|
-
headers:
|
|
909
|
-
"X-Api-Key": this.apiKey
|
|
910
|
-
}
|
|
1342
|
+
headers: this.authHeaders()
|
|
911
1343
|
});
|
|
912
1344
|
if (!response.ok) {
|
|
913
1345
|
const data = await parseResponseBody(response);
|
|
@@ -961,50 +1393,26 @@ function normalizeSendToHumanInput(task2, clientDefaults) {
|
|
|
961
1393
|
actions: normalizedActions
|
|
962
1394
|
};
|
|
963
1395
|
}
|
|
964
|
-
async function parseResponseBody(response) {
|
|
965
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
966
|
-
const bodyText = await response.text();
|
|
967
|
-
if (!bodyText) {
|
|
968
|
-
return null;
|
|
969
|
-
}
|
|
970
|
-
if (contentType.toLowerCase().includes("application/json")) {
|
|
971
|
-
try {
|
|
972
|
-
return JSON.parse(bodyText);
|
|
973
|
-
} catch {
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
try {
|
|
977
|
-
return JSON.parse(bodyText);
|
|
978
|
-
} catch {
|
|
979
|
-
return bodyText;
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
function getErrorMessage(data, fallback) {
|
|
983
|
-
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
984
|
-
const maybeMessage = data.message;
|
|
985
|
-
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
986
|
-
return maybeMessage;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
if (typeof data === "string" && data.trim()) {
|
|
990
|
-
const compact = data.replace(/\s+/g, " ").trim();
|
|
991
|
-
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
992
|
-
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
993
|
-
}
|
|
994
|
-
return fallback;
|
|
995
|
-
}
|
|
996
1396
|
|
|
997
1397
|
// src/env.ts
|
|
998
|
-
var DEFAULT_BASE_URL = "https://api.robotrock.io/v1";
|
|
999
1398
|
function resolveRobotRockConfig(overrides) {
|
|
1399
|
+
const agentService = overrides?.agentService;
|
|
1000
1400
|
const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
1001
|
-
if (
|
|
1401
|
+
if (agentService && apiKey) {
|
|
1002
1402
|
throw new Error(
|
|
1003
|
-
"RobotRock
|
|
1403
|
+
"RobotRock client cannot configure both apiKey and agentService."
|
|
1004
1404
|
);
|
|
1005
1405
|
}
|
|
1006
|
-
const baseUrl = overrides?.baseUrl ??
|
|
1406
|
+
const baseUrl = overrides?.baseUrl ?? getRobotRockApiBaseUrl();
|
|
1007
1407
|
const app = overrides?.app ?? process.env.ROBOTROCK_APP;
|
|
1408
|
+
if (agentService) {
|
|
1409
|
+
return app ? { agentService, baseUrl, app } : { agentService, baseUrl };
|
|
1410
|
+
}
|
|
1411
|
+
if (!apiKey) {
|
|
1412
|
+
throw new Error(
|
|
1413
|
+
"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass agentService when creating the client."
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1008
1416
|
return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };
|
|
1009
1417
|
}
|
|
1010
1418
|
|