robotrock 1.0.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 +5 -5
- package/dist/ai/index.js +285 -47
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/trigger.d.ts +3 -3
- package/dist/ai/trigger.js +285 -47
- package/dist/ai/trigger.js.map +1 -1
- package/dist/ai/workflow.d.ts +3 -3
- package/dist/ai/workflow.js +285 -47
- package/dist/ai/workflow.js.map +1 -1
- package/dist/{client-CzVmjXpz.d.ts → client-XTnFHGFE.d.ts} +34 -5
- 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 +5 -44
- package/dist/index.js +541 -42
- package/dist/index.js.map +1 -1
- package/dist/schemas/index.js +75 -12
- package/dist/schemas/index.js.map +1 -1
- package/dist/tenant-5YKDrdC-.d.ts +23 -0
- package/dist/{tool-approval-bridge-DbwUEBHv.d.ts → tool-approval-bridge-C4bTm8vu.d.ts} +1 -1
- package/dist/trigger/index.d.ts +1 -1
- package/dist/trigger/index.js +256 -42
- package/dist/trigger/index.js.map +1 -1
- package/dist/{trigger-BCKBbAV7.d.ts → trigger-Dn0DFiyU.d.ts} +2 -2
- package/dist/workflow/index.d.ts +1 -1
- package/dist/workflow/index.js +256 -42
- package/dist/workflow/index.js.map +1 -1
- package/package.json +44 -7
package/dist/index.js
CHANGED
|
@@ -108,6 +108,25 @@ function isBlockedHostname(hostname) {
|
|
|
108
108
|
}
|
|
109
109
|
return isBlockedIpv4(host) || isBlockedIpv6(host);
|
|
110
110
|
}
|
|
111
|
+
function isLoopbackHandlerUrl(urlString) {
|
|
112
|
+
let url;
|
|
113
|
+
try {
|
|
114
|
+
url = new URL(urlString);
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
if (url.username || url.password) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
const host = url.hostname.toLowerCase();
|
|
125
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
126
|
+
}
|
|
127
|
+
function isAllowedHandlerUrl(urlString) {
|
|
128
|
+
return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
|
|
129
|
+
}
|
|
111
130
|
function isPublicHttpUrl(urlString) {
|
|
112
131
|
let url;
|
|
113
132
|
try {
|
|
@@ -124,6 +143,7 @@ function isPublicHttpUrl(urlString) {
|
|
|
124
143
|
return !isBlockedHostname(url.hostname);
|
|
125
144
|
}
|
|
126
145
|
var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
|
|
146
|
+
var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
|
|
127
147
|
|
|
128
148
|
// ../core/src/schemas/task.ts
|
|
129
149
|
import { z } from "zod";
|
|
@@ -185,6 +205,9 @@ function validateContextPublicUrls(context2) {
|
|
|
185
205
|
var safeUrlSchema = z.string().refine((url) => isPublicHttpUrl(url), {
|
|
186
206
|
message: PUBLIC_HTTP_URL_ERROR
|
|
187
207
|
});
|
|
208
|
+
var handlerUrlSchema = z.string().refine((url) => isAllowedHandlerUrl(url), {
|
|
209
|
+
message: HANDLER_URL_ERROR
|
|
210
|
+
});
|
|
188
211
|
var jsonSchema7Schema = z.custom(
|
|
189
212
|
(val) => typeof val === "object" && val !== null,
|
|
190
213
|
{ message: "Must be a valid JSON Schema object" }
|
|
@@ -194,7 +217,7 @@ var uiSchemaSchema = z.custom((val) => typeof val === "object" && val !== null,
|
|
|
194
217
|
});
|
|
195
218
|
var webhookHandlerSchema = z.object({
|
|
196
219
|
type: z.literal("webhook"),
|
|
197
|
-
url:
|
|
220
|
+
url: handlerUrlSchema,
|
|
198
221
|
headers: z.record(z.string(), z.string())
|
|
199
222
|
});
|
|
200
223
|
var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
@@ -345,13 +368,22 @@ var agentChatSeedMessageSchema = z.object({
|
|
|
345
368
|
action: agentChatSeedActionSchema
|
|
346
369
|
}).optional()
|
|
347
370
|
});
|
|
371
|
+
var eveAgentChatTransportSchema = z.object({
|
|
372
|
+
kind: z.literal("eve"),
|
|
373
|
+
chatId: z.string().min(1),
|
|
374
|
+
baseUrl: z.string().url(),
|
|
375
|
+
sessionId: z.string().optional(),
|
|
376
|
+
continuationToken: z.string().optional(),
|
|
377
|
+
streamIndex: z.number().int().nonnegative().optional(),
|
|
378
|
+
isStreaming: z.boolean().optional()
|
|
379
|
+
});
|
|
348
380
|
var createAgentChatBodySchema = z.object({
|
|
349
|
-
/**
|
|
381
|
+
/** Agent id (eve agent name). Required unless `parentChatId` is set. */
|
|
350
382
|
agentIdentifier: z.string().min(1).optional(),
|
|
351
383
|
/** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
|
|
352
384
|
parentChatId: z.string().min(1).optional(),
|
|
353
|
-
/** Convex
|
|
354
|
-
|
|
385
|
+
/** Convex tenantEveConnections id; resolved from the tenant when omitted. */
|
|
386
|
+
eveConnectionId: z.string().min(1).optional(),
|
|
355
387
|
/** Source application id; groups the chat under an inbox section. */
|
|
356
388
|
app: z.string().min(1).optional(),
|
|
357
389
|
assignTo: assignToSchema.optional(),
|
|
@@ -362,16 +394,47 @@ var createAgentChatBodySchema = z.object({
|
|
|
362
394
|
}).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
|
|
363
395
|
message: "Provide either agentIdentifier or parentChatId"
|
|
364
396
|
});
|
|
365
|
-
var
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
397
|
+
var agentChatAuditInputBodySchema = z.object({
|
|
398
|
+
eveSessionId: z.string().min(1),
|
|
399
|
+
userId: z.string().min(1),
|
|
400
|
+
actionId: z.string().min(1),
|
|
401
|
+
actionTitle: z.string().optional(),
|
|
402
|
+
prompt: z.string().optional(),
|
|
403
|
+
data: z.record(z.string(), z.unknown()).optional(),
|
|
404
|
+
idempotencyKey: z.string().optional(),
|
|
405
|
+
/** Eve input request id — used to merge staged HITL metadata. */
|
|
406
|
+
requestId: z.string().optional(),
|
|
407
|
+
/** Eve tool call id — fallback lookup for staged HITL metadata. */
|
|
408
|
+
toolCallId: z.string().optional()
|
|
409
|
+
});
|
|
410
|
+
var eveHitlStagedOptionSchema = z.object({
|
|
411
|
+
id: z.string(),
|
|
412
|
+
label: z.string()
|
|
413
|
+
});
|
|
414
|
+
var agentChatStageHitlBodySchema = z.object({
|
|
415
|
+
eveSessionId: z.string().min(1),
|
|
416
|
+
requests: z.array(
|
|
417
|
+
z.object({
|
|
418
|
+
requestId: z.string().min(1),
|
|
419
|
+
toolCallId: z.string().min(1),
|
|
420
|
+
toolName: z.string().min(1),
|
|
421
|
+
prompt: z.string().min(1),
|
|
422
|
+
display: z.enum(["confirmation", "select", "text"]).optional(),
|
|
423
|
+
allowFreeform: z.boolean().optional(),
|
|
424
|
+
options: z.array(eveHitlStagedOptionSchema).optional(),
|
|
425
|
+
toolInput: z.record(z.string(), z.unknown()).optional()
|
|
426
|
+
})
|
|
427
|
+
)
|
|
428
|
+
});
|
|
429
|
+
var agentChatLinkTaskBodySchema = z.object({
|
|
430
|
+
eveSessionId: z.string().min(1),
|
|
431
|
+
publicTaskId: z.string().min(1),
|
|
432
|
+
toolCallId: z.string().min(1)
|
|
370
433
|
});
|
|
371
434
|
|
|
372
435
|
// src/schemas/index.ts
|
|
373
|
-
var
|
|
374
|
-
message:
|
|
436
|
+
var handlerUrlSchema2 = z2.string().refine((url) => isAllowedHandlerUrl(url), {
|
|
437
|
+
message: HANDLER_URL_ERROR
|
|
375
438
|
});
|
|
376
439
|
var jsonSchema7Schema2 = z2.custom(
|
|
377
440
|
(val) => typeof val === "object" && val !== null,
|
|
@@ -382,7 +445,7 @@ var uiSchemaSchema2 = z2.custom((val) => typeof val === "object" && val !== null
|
|
|
382
445
|
});
|
|
383
446
|
var webhookHandlerSchema2 = z2.object({
|
|
384
447
|
type: z2.literal("webhook"),
|
|
385
|
-
url:
|
|
448
|
+
url: handlerUrlSchema2,
|
|
386
449
|
headers: z2.record(z2.string(), z2.string())
|
|
387
450
|
});
|
|
388
451
|
var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
@@ -568,8 +631,13 @@ async function parseResponseBody(response) {
|
|
|
568
631
|
}
|
|
569
632
|
function getErrorMessage(data, fallback) {
|
|
570
633
|
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
571
|
-
const
|
|
634
|
+
const record = data;
|
|
635
|
+
const maybeMessage = record.message;
|
|
636
|
+
const maybeHint = record.hint;
|
|
572
637
|
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
638
|
+
if (typeof maybeHint === "string" && maybeHint.trim()) {
|
|
639
|
+
return `${maybeMessage.trim()} ${maybeHint.trim()}`;
|
|
640
|
+
}
|
|
573
641
|
return maybeMessage;
|
|
574
642
|
}
|
|
575
643
|
}
|
|
@@ -605,7 +673,26 @@ import { z as z3 } from "zod";
|
|
|
605
673
|
|
|
606
674
|
// ../core/src/app-url.ts
|
|
607
675
|
var PRODUCTION_APP_URL = "https://app.robotrock.io";
|
|
676
|
+
var PRODUCTION_API_URL = "https://api.robotrock.io/v1";
|
|
677
|
+
var DEV_API_URL = "http://localhost:4001/v1";
|
|
608
678
|
var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
|
|
679
|
+
function normalizeRobotRockApiBaseUrl(baseUrl) {
|
|
680
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
681
|
+
if (trimmed.endsWith("/v1")) {
|
|
682
|
+
return trimmed;
|
|
683
|
+
}
|
|
684
|
+
return `${trimmed}/v1`;
|
|
685
|
+
}
|
|
686
|
+
function getRobotRockApiBaseUrl() {
|
|
687
|
+
const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
|
|
688
|
+
if (explicit) {
|
|
689
|
+
return normalizeRobotRockApiBaseUrl(explicit);
|
|
690
|
+
}
|
|
691
|
+
if (process.env.NODE_ENV === "production") {
|
|
692
|
+
return PRODUCTION_API_URL;
|
|
693
|
+
}
|
|
694
|
+
return DEV_API_URL;
|
|
695
|
+
}
|
|
609
696
|
|
|
610
697
|
// ../core/src/attribution/index.ts
|
|
611
698
|
var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
|
|
@@ -621,11 +708,40 @@ var attributionSchema = z3.object({
|
|
|
621
708
|
capturedAt: z3.number()
|
|
622
709
|
});
|
|
623
710
|
|
|
711
|
+
// src/auth-headers.ts
|
|
712
|
+
function buildRobotRockAuthHeaders(auth) {
|
|
713
|
+
if (auth.kind === "apiKey") {
|
|
714
|
+
return {
|
|
715
|
+
"X-Api-Key": auth.apiKey
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
return {
|
|
719
|
+
Authorization: `Bearer ${auth.token}`,
|
|
720
|
+
"X-RobotRock-Tenant-Slug": auth.tenantSlug,
|
|
721
|
+
"X-RobotRock-Connection-Id": auth.connectionId
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function resolveRobotRockAuthConfig(overrides) {
|
|
725
|
+
if (overrides?.agentService) {
|
|
726
|
+
return {
|
|
727
|
+
kind: "agentService",
|
|
728
|
+
...overrides.agentService
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
732
|
+
if (!apiKey) {
|
|
733
|
+
throw new Error(
|
|
734
|
+
"RobotRock auth is required. Set ROBOTROCK_API_KEY, ROBOTROCK_AGENT_SERVICE_TOKEN with tenant context, or pass auth when creating the client."
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
return { kind: "apiKey", apiKey };
|
|
738
|
+
}
|
|
739
|
+
|
|
624
740
|
// src/chats.ts
|
|
625
741
|
function createChatsApi(config) {
|
|
626
742
|
const headers = () => ({
|
|
627
743
|
"Content-Type": "application/json",
|
|
628
|
-
|
|
744
|
+
...buildRobotRockAuthHeaders(config.auth)
|
|
629
745
|
});
|
|
630
746
|
return {
|
|
631
747
|
async create(input) {
|
|
@@ -678,6 +794,97 @@ function createChatsApi(config) {
|
|
|
678
794
|
data
|
|
679
795
|
);
|
|
680
796
|
}
|
|
797
|
+
},
|
|
798
|
+
async stageHitlRequests(input) {
|
|
799
|
+
const validation = agentChatStageHitlBodySchema.safeParse(input);
|
|
800
|
+
if (!validation.success) {
|
|
801
|
+
throw new RobotRockError(
|
|
802
|
+
`Invalid stage HITL input: ${validation.error.issues[0]?.message}`,
|
|
803
|
+
400,
|
|
804
|
+
validation.error.issues
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/stage-hitl`, {
|
|
808
|
+
method: "POST",
|
|
809
|
+
headers: headers(),
|
|
810
|
+
body: JSON.stringify(validation.data)
|
|
811
|
+
});
|
|
812
|
+
if (!response.ok) {
|
|
813
|
+
const data = await parseResponseBody(response);
|
|
814
|
+
throw new RobotRockError(
|
|
815
|
+
getErrorMessage(data, "Failed to stage chat HITL requests"),
|
|
816
|
+
response.status,
|
|
817
|
+
data
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
async getStagedHitlRequests(eveSessionId) {
|
|
822
|
+
const trimmed = eveSessionId.trim();
|
|
823
|
+
if (!trimmed) {
|
|
824
|
+
throw new RobotRockError("eveSessionId is required", 400);
|
|
825
|
+
}
|
|
826
|
+
const url = new URL(`${config.baseUrl}/agent-chats/staged-hitl`);
|
|
827
|
+
url.searchParams.set("eveSessionId", trimmed);
|
|
828
|
+
const response = await fetch(url.toString(), {
|
|
829
|
+
method: "GET",
|
|
830
|
+
headers: headers()
|
|
831
|
+
});
|
|
832
|
+
const data = await parseResponseBody(response);
|
|
833
|
+
if (!response.ok) {
|
|
834
|
+
throw new RobotRockError(
|
|
835
|
+
getErrorMessage(data, "Failed to fetch staged chat HITL requests"),
|
|
836
|
+
response.status,
|
|
837
|
+
data
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
const requests = data.requests;
|
|
841
|
+
return Array.isArray(requests) ? requests : [];
|
|
842
|
+
},
|
|
843
|
+
async logInputSubmission(input) {
|
|
844
|
+
const validation = agentChatAuditInputBodySchema.safeParse(input);
|
|
845
|
+
if (!validation.success) {
|
|
846
|
+
throw new RobotRockError(
|
|
847
|
+
`Invalid audit input: ${validation.error.issues[0]?.message}`,
|
|
848
|
+
400,
|
|
849
|
+
validation.error.issues
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/audit-input`, {
|
|
853
|
+
method: "POST",
|
|
854
|
+
headers: headers(),
|
|
855
|
+
body: JSON.stringify(validation.data)
|
|
856
|
+
});
|
|
857
|
+
if (!response.ok) {
|
|
858
|
+
const data = await parseResponseBody(response);
|
|
859
|
+
throw new RobotRockError(
|
|
860
|
+
getErrorMessage(data, "Failed to log chat input submission"),
|
|
861
|
+
response.status,
|
|
862
|
+
data
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
async linkTask(input) {
|
|
867
|
+
const validation = agentChatLinkTaskBodySchema.safeParse(input);
|
|
868
|
+
if (!validation.success) {
|
|
869
|
+
throw new RobotRockError(
|
|
870
|
+
`Invalid link task input: ${validation.error.issues[0]?.message}`,
|
|
871
|
+
400,
|
|
872
|
+
validation.error.issues
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/link-task`, {
|
|
876
|
+
method: "POST",
|
|
877
|
+
headers: headers(),
|
|
878
|
+
body: JSON.stringify(validation.data)
|
|
879
|
+
});
|
|
880
|
+
if (!response.ok) {
|
|
881
|
+
const data = await parseResponseBody(response);
|
|
882
|
+
throw new RobotRockError(
|
|
883
|
+
getErrorMessage(data, "Failed to link inbox task to chat"),
|
|
884
|
+
response.status,
|
|
885
|
+
data
|
|
886
|
+
);
|
|
887
|
+
}
|
|
681
888
|
}
|
|
682
889
|
};
|
|
683
890
|
}
|
|
@@ -720,7 +927,7 @@ function serializeValidUntil(value) {
|
|
|
720
927
|
throw new RobotRockError("Invalid validUntil: expected a Date or parseable date string", 400);
|
|
721
928
|
}
|
|
722
929
|
var RobotRock = class {
|
|
723
|
-
|
|
930
|
+
auth;
|
|
724
931
|
baseUrl;
|
|
725
932
|
app;
|
|
726
933
|
agentVersion;
|
|
@@ -738,14 +945,17 @@ var RobotRock = class {
|
|
|
738
945
|
);
|
|
739
946
|
}
|
|
740
947
|
const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
741
|
-
|
|
948
|
+
const agentService = config.agentService;
|
|
949
|
+
if (apiKey && agentService) {
|
|
742
950
|
throw new Error(
|
|
743
|
-
"RobotRock
|
|
951
|
+
"RobotRock client cannot configure both apiKey and agentService."
|
|
744
952
|
);
|
|
745
953
|
}
|
|
746
|
-
this.
|
|
747
|
-
|
|
748
|
-
|
|
954
|
+
this.auth = resolveRobotRockAuthConfig({
|
|
955
|
+
...apiKey ? { apiKey } : {},
|
|
956
|
+
...agentService ? { agentService } : {}
|
|
957
|
+
});
|
|
958
|
+
this.baseUrl = config.baseUrl ?? getRobotRockApiBaseUrl();
|
|
749
959
|
this.app = config.app;
|
|
750
960
|
this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
|
|
751
961
|
this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
|
|
@@ -759,10 +969,17 @@ var RobotRock = class {
|
|
|
759
969
|
};
|
|
760
970
|
this.chats = createChatsApi({
|
|
761
971
|
baseUrl: this.baseUrl,
|
|
762
|
-
|
|
972
|
+
auth: this.auth,
|
|
763
973
|
app: this.app
|
|
764
974
|
});
|
|
765
975
|
}
|
|
976
|
+
authHeaders(extra) {
|
|
977
|
+
return {
|
|
978
|
+
"Content-Type": "application/json",
|
|
979
|
+
...buildRobotRockAuthHeaders(this.auth),
|
|
980
|
+
...extra
|
|
981
|
+
};
|
|
982
|
+
}
|
|
766
983
|
async createTaskRequest(task) {
|
|
767
984
|
const normalizedTask = normalizeSendToHumanInput(task, {
|
|
768
985
|
webhook: this.webhook,
|
|
@@ -787,13 +1004,9 @@ var RobotRock = class {
|
|
|
787
1004
|
validation.error.issues
|
|
788
1005
|
);
|
|
789
1006
|
}
|
|
790
|
-
const headers =
|
|
791
|
-
"
|
|
792
|
-
|
|
793
|
-
};
|
|
794
|
-
if (task.idempotencyKey) {
|
|
795
|
-
headers["Idempotency-Key"] = task.idempotencyKey;
|
|
796
|
-
}
|
|
1007
|
+
const headers = this.authHeaders(
|
|
1008
|
+
task.idempotencyKey ? { "Idempotency-Key": task.idempotencyKey } : void 0
|
|
1009
|
+
);
|
|
797
1010
|
const response = await fetch(`${this.baseUrl}/`, {
|
|
798
1011
|
method: "POST",
|
|
799
1012
|
headers,
|
|
@@ -886,9 +1099,7 @@ var RobotRock = class {
|
|
|
886
1099
|
async getTaskById(taskId) {
|
|
887
1100
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
|
|
888
1101
|
method: "GET",
|
|
889
|
-
headers:
|
|
890
|
-
"X-Api-Key": this.apiKey
|
|
891
|
-
}
|
|
1102
|
+
headers: this.authHeaders()
|
|
892
1103
|
});
|
|
893
1104
|
if (response.status === 404) {
|
|
894
1105
|
return null;
|
|
@@ -923,10 +1134,7 @@ var RobotRock = class {
|
|
|
923
1134
|
`${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,
|
|
924
1135
|
{
|
|
925
1136
|
method: "POST",
|
|
926
|
-
headers:
|
|
927
|
-
"Content-Type": "application/json",
|
|
928
|
-
"X-Api-Key": this.apiKey
|
|
929
|
-
},
|
|
1137
|
+
headers: this.authHeaders(),
|
|
930
1138
|
body: JSON.stringify(validation.data)
|
|
931
1139
|
}
|
|
932
1140
|
);
|
|
@@ -943,9 +1151,7 @@ var RobotRock = class {
|
|
|
943
1151
|
async cancelTaskRequest(taskId) {
|
|
944
1152
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
|
|
945
1153
|
method: "POST",
|
|
946
|
-
headers:
|
|
947
|
-
"X-Api-Key": this.apiKey
|
|
948
|
-
}
|
|
1154
|
+
headers: this.authHeaders()
|
|
949
1155
|
});
|
|
950
1156
|
if (!response.ok) {
|
|
951
1157
|
const data = await parseResponseBody(response);
|
|
@@ -1001,16 +1207,24 @@ function normalizeSendToHumanInput(task, clientDefaults) {
|
|
|
1001
1207
|
}
|
|
1002
1208
|
|
|
1003
1209
|
// src/env.ts
|
|
1004
|
-
var DEFAULT_BASE_URL = "https://api.robotrock.io/v1";
|
|
1005
1210
|
function resolveRobotRockConfig(overrides) {
|
|
1211
|
+
const agentService = overrides?.agentService;
|
|
1006
1212
|
const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
1007
|
-
if (
|
|
1213
|
+
if (agentService && apiKey) {
|
|
1008
1214
|
throw new Error(
|
|
1009
|
-
"RobotRock
|
|
1215
|
+
"RobotRock client cannot configure both apiKey and agentService."
|
|
1010
1216
|
);
|
|
1011
1217
|
}
|
|
1012
|
-
const baseUrl = overrides?.baseUrl ??
|
|
1218
|
+
const baseUrl = overrides?.baseUrl ?? getRobotRockApiBaseUrl();
|
|
1013
1219
|
const app = overrides?.app ?? process.env.ROBOTROCK_APP;
|
|
1220
|
+
if (agentService) {
|
|
1221
|
+
return app ? { agentService, baseUrl, app } : { agentService, baseUrl };
|
|
1222
|
+
}
|
|
1223
|
+
if (!apiKey) {
|
|
1224
|
+
throw new Error(
|
|
1225
|
+
"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass agentService when creating the client."
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1014
1228
|
return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };
|
|
1015
1229
|
}
|
|
1016
1230
|
function resolveRobotRockClient(client, configOverrides) {
|
|
@@ -1111,6 +1325,277 @@ function shouldStopAgentForHandledAction(actionId) {
|
|
|
1111
1325
|
return isPlatformTerminalAction(actionId);
|
|
1112
1326
|
}
|
|
1113
1327
|
|
|
1328
|
+
// src/eve/input-request.ts
|
|
1329
|
+
var EVE_INPUT_SUBMIT_ACTION_ID = "submit";
|
|
1330
|
+
var EVE_INPUT_OTHER_CHOICE_ID = "__other__";
|
|
1331
|
+
var EVE_INPUT_OTHER_CHOICE_LABEL = "Type your own answer";
|
|
1332
|
+
var CONFIRMATION_DEFAULT_OPTIONS = [
|
|
1333
|
+
{ id: "approve", label: "Approve", style: "primary" },
|
|
1334
|
+
{ id: "deny", label: "Deny", style: "danger" }
|
|
1335
|
+
];
|
|
1336
|
+
var SELECT_PER_OPTION_THRESHOLD = 6;
|
|
1337
|
+
function asRecord(value) {
|
|
1338
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
return value;
|
|
1342
|
+
}
|
|
1343
|
+
function readStringField(data, key) {
|
|
1344
|
+
const value = data[key];
|
|
1345
|
+
if (typeof value !== "string") {
|
|
1346
|
+
return void 0;
|
|
1347
|
+
}
|
|
1348
|
+
const trimmed = value.trim();
|
|
1349
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1350
|
+
}
|
|
1351
|
+
function resolveEveInputDisplay(request, toolName) {
|
|
1352
|
+
if (request.display) {
|
|
1353
|
+
return request.display;
|
|
1354
|
+
}
|
|
1355
|
+
if (toolName === "ask_question") {
|
|
1356
|
+
return request.options && request.options.length > 0 ? "select" : "text";
|
|
1357
|
+
}
|
|
1358
|
+
if (request.options && request.options.length > 0) {
|
|
1359
|
+
return "select";
|
|
1360
|
+
}
|
|
1361
|
+
return "confirmation";
|
|
1362
|
+
}
|
|
1363
|
+
function confirmationActions(request) {
|
|
1364
|
+
const options = request.options && request.options.length > 0 ? request.options : CONFIRMATION_DEFAULT_OPTIONS;
|
|
1365
|
+
return options.map((option) => ({
|
|
1366
|
+
id: option.id,
|
|
1367
|
+
title: option.label,
|
|
1368
|
+
...option.description ? { description: option.description } : {}
|
|
1369
|
+
}));
|
|
1370
|
+
}
|
|
1371
|
+
function textSubmitAction(prompt) {
|
|
1372
|
+
return {
|
|
1373
|
+
id: EVE_INPUT_SUBMIT_ACTION_ID,
|
|
1374
|
+
title: "Submit",
|
|
1375
|
+
schema: {
|
|
1376
|
+
type: "object",
|
|
1377
|
+
required: ["answer"],
|
|
1378
|
+
properties: {
|
|
1379
|
+
answer: {
|
|
1380
|
+
type: "string",
|
|
1381
|
+
title: "Your answer"
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
},
|
|
1385
|
+
ui: {
|
|
1386
|
+
answer: {
|
|
1387
|
+
"ui:title": prompt.trim() || "Your answer",
|
|
1388
|
+
"ui:widget": "textarea"
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
function selectPerOptionActions(options) {
|
|
1394
|
+
return options.map((option) => ({
|
|
1395
|
+
id: option.id,
|
|
1396
|
+
title: option.label,
|
|
1397
|
+
...option.description ? { description: option.description } : {}
|
|
1398
|
+
}));
|
|
1399
|
+
}
|
|
1400
|
+
function selectFormAction(request) {
|
|
1401
|
+
const options = request.options ?? [];
|
|
1402
|
+
const allowFreeform = request.allowFreeform === true;
|
|
1403
|
+
const enumValues = options.map((option) => option.id);
|
|
1404
|
+
const enumNames = options.map((option) => option.label);
|
|
1405
|
+
if (allowFreeform) {
|
|
1406
|
+
enumValues.push(EVE_INPUT_OTHER_CHOICE_ID);
|
|
1407
|
+
enumNames.push(EVE_INPUT_OTHER_CHOICE_LABEL);
|
|
1408
|
+
}
|
|
1409
|
+
const properties = {
|
|
1410
|
+
choice: {
|
|
1411
|
+
type: "string",
|
|
1412
|
+
title: "Choose one",
|
|
1413
|
+
enum: enumValues
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
if (allowFreeform) {
|
|
1417
|
+
properties.other = {
|
|
1418
|
+
type: "string",
|
|
1419
|
+
title: "Your answer"
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
const schema = {
|
|
1423
|
+
type: "object",
|
|
1424
|
+
required: ["choice"],
|
|
1425
|
+
properties
|
|
1426
|
+
};
|
|
1427
|
+
if (allowFreeform) {
|
|
1428
|
+
schema.allOf = [
|
|
1429
|
+
{
|
|
1430
|
+
if: {
|
|
1431
|
+
properties: {
|
|
1432
|
+
choice: { const: EVE_INPUT_OTHER_CHOICE_ID }
|
|
1433
|
+
},
|
|
1434
|
+
required: ["choice"]
|
|
1435
|
+
},
|
|
1436
|
+
then: {
|
|
1437
|
+
required: ["other"],
|
|
1438
|
+
properties: {
|
|
1439
|
+
other: {
|
|
1440
|
+
type: "string",
|
|
1441
|
+
minLength: 1
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
];
|
|
1447
|
+
}
|
|
1448
|
+
const ui = {
|
|
1449
|
+
choice: {
|
|
1450
|
+
"ui:widget": "radio",
|
|
1451
|
+
"ui:enumNames": enumNames
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
if (allowFreeform) {
|
|
1455
|
+
ui.other = {
|
|
1456
|
+
"ui:placeholder": "Enter your answer"
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
return {
|
|
1460
|
+
id: EVE_INPUT_SUBMIT_ACTION_ID,
|
|
1461
|
+
title: "Submit",
|
|
1462
|
+
schema,
|
|
1463
|
+
ui
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
function normalizeEveSelectFormData(data) {
|
|
1467
|
+
const choice = typeof data.choice === "string" ? data.choice.trim() : void 0;
|
|
1468
|
+
if (!choice) {
|
|
1469
|
+
return data;
|
|
1470
|
+
}
|
|
1471
|
+
if (choice === EVE_INPUT_OTHER_CHOICE_ID) {
|
|
1472
|
+
return {
|
|
1473
|
+
choice,
|
|
1474
|
+
...data.other !== void 0 ? { other: data.other } : {}
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
return { choice };
|
|
1478
|
+
}
|
|
1479
|
+
function eveInputRequestToActions(request, options) {
|
|
1480
|
+
const display = resolveEveInputDisplay(request, options?.toolName);
|
|
1481
|
+
switch (display) {
|
|
1482
|
+
case "confirmation":
|
|
1483
|
+
return confirmationActions(request);
|
|
1484
|
+
case "text":
|
|
1485
|
+
return [textSubmitAction(request.prompt)];
|
|
1486
|
+
case "select": {
|
|
1487
|
+
const selectOptions = request.options ?? [];
|
|
1488
|
+
if (selectOptions.length === 0) {
|
|
1489
|
+
return [textSubmitAction(request.prompt)];
|
|
1490
|
+
}
|
|
1491
|
+
if (selectOptions.length <= SELECT_PER_OPTION_THRESHOLD && request.allowFreeform !== true) {
|
|
1492
|
+
return selectPerOptionActions(selectOptions);
|
|
1493
|
+
}
|
|
1494
|
+
return [selectFormAction(request)];
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
function eveInputRequestTaskType(request, options) {
|
|
1499
|
+
const display = resolveEveInputDisplay(request, options?.toolName);
|
|
1500
|
+
if (display === "confirmation" && options?.toolName) {
|
|
1501
|
+
return `eve-approval:${options.toolName}`;
|
|
1502
|
+
}
|
|
1503
|
+
return `eve-input:${display}`;
|
|
1504
|
+
}
|
|
1505
|
+
function taskHandledToEveInputResponse(request, actionId, actionData, options) {
|
|
1506
|
+
const base = { requestId: request.requestId };
|
|
1507
|
+
if (isPlatformTerminalAction(actionId)) {
|
|
1508
|
+
const feedback = parsePlatformRejectRequestData(actionData)?.feedback;
|
|
1509
|
+
return {
|
|
1510
|
+
...base,
|
|
1511
|
+
optionId: "deny",
|
|
1512
|
+
...feedback ? { text: feedback } : {}
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
const display = resolveEveInputDisplay(request, options?.toolName);
|
|
1516
|
+
const selectOptions = request.options ?? [];
|
|
1517
|
+
const data = asRecord(actionData);
|
|
1518
|
+
if (display === "confirmation") {
|
|
1519
|
+
return { ...base, optionId: actionId };
|
|
1520
|
+
}
|
|
1521
|
+
const matchingOption = selectOptions.find((option) => option.id === actionId);
|
|
1522
|
+
if (matchingOption) {
|
|
1523
|
+
return { ...base, optionId: actionId };
|
|
1524
|
+
}
|
|
1525
|
+
if (actionId === EVE_INPUT_SUBMIT_ACTION_ID && data) {
|
|
1526
|
+
const submissionData = display === "select" && request.allowFreeform === true ? normalizeEveSelectFormData(data) : data;
|
|
1527
|
+
const answer = readStringField(submissionData, "answer");
|
|
1528
|
+
if (answer) {
|
|
1529
|
+
return { ...base, text: answer };
|
|
1530
|
+
}
|
|
1531
|
+
const choice = readStringField(submissionData, "choice");
|
|
1532
|
+
if (choice === EVE_INPUT_OTHER_CHOICE_ID) {
|
|
1533
|
+
const other = readStringField(submissionData, "other");
|
|
1534
|
+
if (other) {
|
|
1535
|
+
return { ...base, text: other };
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
if (choice) {
|
|
1539
|
+
if (selectOptions.some((option) => option.id === choice)) {
|
|
1540
|
+
return { ...base, optionId: choice };
|
|
1541
|
+
}
|
|
1542
|
+
return { ...base, text: choice };
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
if (data) {
|
|
1546
|
+
const answer = readStringField(data, "answer");
|
|
1547
|
+
if (answer) {
|
|
1548
|
+
return { ...base, text: answer };
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
return { ...base, optionId: actionId };
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// src/eve/tool-display.ts
|
|
1555
|
+
var DEFAULT_TOOL_DISPLAY_LABELS = {
|
|
1556
|
+
refund_charge: "Refund a customer charge",
|
|
1557
|
+
deploy_release: "Deploy a release",
|
|
1558
|
+
get_weather: "Get weather",
|
|
1559
|
+
get_my_access: "Check my access",
|
|
1560
|
+
whoami: "Who am I",
|
|
1561
|
+
create_robotrock_task: "Create a RobotRock task"
|
|
1562
|
+
};
|
|
1563
|
+
var toolDisplayLabelOverrides = {};
|
|
1564
|
+
function setToolDisplayLabelOverrides(overrides) {
|
|
1565
|
+
toolDisplayLabelOverrides = overrides;
|
|
1566
|
+
}
|
|
1567
|
+
function formatToolName(toolName) {
|
|
1568
|
+
const spaced = toolName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").trim();
|
|
1569
|
+
if (!spaced) {
|
|
1570
|
+
return "Tool";
|
|
1571
|
+
}
|
|
1572
|
+
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
1573
|
+
}
|
|
1574
|
+
function getToolDisplayLabel(toolName) {
|
|
1575
|
+
const trimmed = toolName.trim();
|
|
1576
|
+
if (!trimmed) {
|
|
1577
|
+
return "Tool";
|
|
1578
|
+
}
|
|
1579
|
+
return toolDisplayLabelOverrides[trimmed] ?? DEFAULT_TOOL_DISPLAY_LABELS[trimmed] ?? formatToolName(trimmed);
|
|
1580
|
+
}
|
|
1581
|
+
function formatEveApprovalTitle(request, toolName) {
|
|
1582
|
+
const display = resolveEveInputDisplay(request, toolName);
|
|
1583
|
+
if (display !== "confirmation" || !toolName) {
|
|
1584
|
+
return request.prompt;
|
|
1585
|
+
}
|
|
1586
|
+
return `Approve: ${getToolDisplayLabel(toolName)}`;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// src/eve/resume-message.ts
|
|
1590
|
+
function buildTaskHandledResumeMessage(payload) {
|
|
1591
|
+
const handledBy = payload.handledBy?.trim() || "someone";
|
|
1592
|
+
const actionTitle = payload.action.title.trim();
|
|
1593
|
+
return `RobotRock task ${payload.taskId} was handled: ${actionTitle} by ${handledBy}. Briefly tell the user what was decided and what happens next.`;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// src/eve/index.ts
|
|
1597
|
+
var ROBOTROCK_READY_HOOK_SLUG = "robotrock-ready";
|
|
1598
|
+
|
|
1114
1599
|
// src/webhook.ts
|
|
1115
1600
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
1116
1601
|
import { z as z4 } from "zod";
|
|
@@ -1410,6 +1895,10 @@ function finishRobotRockHumanWaitOtel(session, handled, outcome) {
|
|
|
1410
1895
|
export {
|
|
1411
1896
|
DEFAULT_TASK_PRIORITY,
|
|
1412
1897
|
DEFAULT_THREAD_UPDATE_STATUS,
|
|
1898
|
+
DEFAULT_TOOL_DISPLAY_LABELS,
|
|
1899
|
+
EVE_INPUT_OTHER_CHOICE_ID,
|
|
1900
|
+
EVE_INPUT_OTHER_CHOICE_LABEL,
|
|
1901
|
+
EVE_INPUT_SUBMIT_ACTION_ID,
|
|
1413
1902
|
LOWEST_TASK_PRIORITY,
|
|
1414
1903
|
PLATFORM_MARK_DONE_ACTION_ID,
|
|
1415
1904
|
PLATFORM_MARK_DONE_ACTION_TITLE,
|
|
@@ -1417,6 +1906,7 @@ export {
|
|
|
1417
1906
|
PLATFORM_REJECT_REQUEST_ACTION_TITLE,
|
|
1418
1907
|
PLATFORM_TERMINAL_ACTION_IDS,
|
|
1419
1908
|
PlatformRejectRequestError,
|
|
1909
|
+
ROBOTROCK_READY_HOOK_SLUG,
|
|
1420
1910
|
RobotRock,
|
|
1421
1911
|
RobotRockError,
|
|
1422
1912
|
RobotRockWebhookError,
|
|
@@ -1430,26 +1920,35 @@ export {
|
|
|
1430
1920
|
assignToSchema2 as assignToSchema,
|
|
1431
1921
|
attachWebhookToActions,
|
|
1432
1922
|
beginRobotRockHumanWaitOtel,
|
|
1923
|
+
buildTaskHandledResumeMessage,
|
|
1433
1924
|
captureRobotRockOtelHandle,
|
|
1434
1925
|
createAgentChatBodySchema,
|
|
1435
1926
|
createChatsApi,
|
|
1436
1927
|
createClient,
|
|
1437
1928
|
createTaskBodySchema2 as createTaskBodySchema,
|
|
1438
1929
|
endRobotRockHumanWaitSpan,
|
|
1930
|
+
eveInputRequestTaskType,
|
|
1931
|
+
eveInputRequestToActions,
|
|
1439
1932
|
finishRobotRockHumanWaitOtel,
|
|
1933
|
+
formatEveApprovalTitle,
|
|
1934
|
+
getToolDisplayLabel,
|
|
1440
1935
|
isPlatformMarkDoneAction,
|
|
1441
1936
|
isPlatformRejectRequestAction,
|
|
1442
1937
|
isPlatformTerminalAction,
|
|
1938
|
+
normalizeEveSelectFormData,
|
|
1443
1939
|
parseHandledOutcome,
|
|
1444
1940
|
parsePlatformRejectRequestData,
|
|
1445
1941
|
recordRobotRockHandledToOtel,
|
|
1942
|
+
resolveEveInputDisplay,
|
|
1446
1943
|
resolveRobotRockClient,
|
|
1447
1944
|
resolveRobotRockConfig,
|
|
1945
|
+
setToolDisplayLabelOverrides,
|
|
1448
1946
|
shouldRecordRobotRockOtel,
|
|
1449
1947
|
shouldStopAgentForHandledAction,
|
|
1450
1948
|
startRobotRockHumanWaitSpan,
|
|
1451
1949
|
stripPlatformOtelFields,
|
|
1452
1950
|
taskContextSchema2 as taskContextSchema,
|
|
1951
|
+
taskHandledToEveInputResponse,
|
|
1453
1952
|
taskPriorities2 as taskPriorities,
|
|
1454
1953
|
taskPrioritySchema2 as taskPrioritySchema,
|
|
1455
1954
|
threadUpdateBodySchema,
|