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/workflow/index.js
CHANGED
|
@@ -157,6 +157,25 @@ function isBlockedHostname(hostname) {
|
|
|
157
157
|
}
|
|
158
158
|
return isBlockedIpv4(host) || isBlockedIpv6(host);
|
|
159
159
|
}
|
|
160
|
+
function isLoopbackHandlerUrl(urlString) {
|
|
161
|
+
let url;
|
|
162
|
+
try {
|
|
163
|
+
url = new URL(urlString);
|
|
164
|
+
} catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
if (url.username || url.password) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
const host = url.hostname.toLowerCase();
|
|
174
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
175
|
+
}
|
|
176
|
+
function isAllowedHandlerUrl(urlString) {
|
|
177
|
+
return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
|
|
178
|
+
}
|
|
160
179
|
function isPublicHttpUrl(urlString) {
|
|
161
180
|
let url;
|
|
162
181
|
try {
|
|
@@ -173,6 +192,7 @@ function isPublicHttpUrl(urlString) {
|
|
|
173
192
|
return !isBlockedHostname(url.hostname);
|
|
174
193
|
}
|
|
175
194
|
var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
|
|
195
|
+
var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
|
|
176
196
|
|
|
177
197
|
// ../core/src/schemas/task.ts
|
|
178
198
|
import { z } from "zod";
|
|
@@ -234,6 +254,9 @@ function validateContextPublicUrls(context2) {
|
|
|
234
254
|
var safeUrlSchema = z.string().refine((url) => isPublicHttpUrl(url), {
|
|
235
255
|
message: PUBLIC_HTTP_URL_ERROR
|
|
236
256
|
});
|
|
257
|
+
var handlerUrlSchema = z.string().refine((url) => isAllowedHandlerUrl(url), {
|
|
258
|
+
message: HANDLER_URL_ERROR
|
|
259
|
+
});
|
|
237
260
|
var jsonSchema7Schema = z.custom(
|
|
238
261
|
(val) => typeof val === "object" && val !== null,
|
|
239
262
|
{ message: "Must be a valid JSON Schema object" }
|
|
@@ -243,7 +266,7 @@ var uiSchemaSchema = z.custom((val) => typeof val === "object" && val !== null,
|
|
|
243
266
|
});
|
|
244
267
|
var webhookHandlerSchema = z.object({
|
|
245
268
|
type: z.literal("webhook"),
|
|
246
|
-
url:
|
|
269
|
+
url: handlerUrlSchema,
|
|
247
270
|
headers: z.record(z.string(), z.string())
|
|
248
271
|
});
|
|
249
272
|
var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
@@ -251,13 +274,15 @@ var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
|
251
274
|
tokenId: z.string().min(1)
|
|
252
275
|
});
|
|
253
276
|
var handlerSchema = z.discriminatedUnion("type", [webhookHandlerSchema, triggerHandlerSchema]);
|
|
254
|
-
var
|
|
277
|
+
var taskActionInputSchema = z.object({
|
|
255
278
|
id: z.string().min(1),
|
|
256
279
|
title: z.string().min(1),
|
|
257
280
|
description: z.string().optional(),
|
|
258
281
|
schema: jsonSchema7Schema.optional(),
|
|
259
282
|
ui: uiSchemaSchema.optional(),
|
|
260
|
-
data: z.record(z.string(), z.unknown()).optional()
|
|
283
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
284
|
+
});
|
|
285
|
+
var taskActionSchema = taskActionInputSchema.extend({
|
|
261
286
|
// Optional handlers for this action - if present, must have at least 1
|
|
262
287
|
handlers: z.array(handlerSchema).min(1).optional()
|
|
263
288
|
});
|
|
@@ -365,10 +390,100 @@ var createTaskBodySchema = taskContextObjectBaseSchema.extend({
|
|
|
365
390
|
/** Agent release version — not shown in inbox UI. */
|
|
366
391
|
agent: agentTelemetrySchema.optional()
|
|
367
392
|
}).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
|
|
393
|
+
var agentChatSeedActionSchema = z.object({
|
|
394
|
+
/** Stable action id echoed back on submit; auto-derived from title when omitted. */
|
|
395
|
+
id: z.string().min(1).optional(),
|
|
396
|
+
title: z.string().min(1),
|
|
397
|
+
description: z.string().optional(),
|
|
398
|
+
/** JSON Schema object for the form fields. */
|
|
399
|
+
schema: z.record(z.string(), z.unknown()).optional(),
|
|
400
|
+
/** RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). */
|
|
401
|
+
ui: z.record(z.string(), z.unknown()).optional(),
|
|
402
|
+
/** Optional default field values. */
|
|
403
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
404
|
+
});
|
|
405
|
+
var agentChatSeedMessageSchema = z.object({
|
|
406
|
+
role: z.enum(["user", "assistant"]),
|
|
407
|
+
text: z.string().min(1),
|
|
408
|
+
/** Optional display-name override for the message sender. */
|
|
409
|
+
senderName: z.string().min(1).optional(),
|
|
410
|
+
/**
|
|
411
|
+
* Optional structured input request rendered as a styled RobotRock action
|
|
412
|
+
* widget below the message text. Use this instead of asking the user to reply
|
|
413
|
+
* in plain text so the request is always a proper action form.
|
|
414
|
+
*/
|
|
415
|
+
requestActionInput: z.object({
|
|
416
|
+
prompt: z.string().optional(),
|
|
417
|
+
action: agentChatSeedActionSchema
|
|
418
|
+
}).optional()
|
|
419
|
+
});
|
|
420
|
+
var eveAgentChatTransportSchema = z.object({
|
|
421
|
+
kind: z.literal("eve"),
|
|
422
|
+
chatId: z.string().min(1),
|
|
423
|
+
baseUrl: z.string().url(),
|
|
424
|
+
sessionId: z.string().optional(),
|
|
425
|
+
continuationToken: z.string().optional(),
|
|
426
|
+
streamIndex: z.number().int().nonnegative().optional(),
|
|
427
|
+
isStreaming: z.boolean().optional()
|
|
428
|
+
});
|
|
429
|
+
var createAgentChatBodySchema = z.object({
|
|
430
|
+
/** Agent id (eve agent name). Required unless `parentChatId` is set. */
|
|
431
|
+
agentIdentifier: z.string().min(1).optional(),
|
|
432
|
+
/** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
|
|
433
|
+
parentChatId: z.string().min(1).optional(),
|
|
434
|
+
/** Convex tenantEveConnections id; resolved from the tenant when omitted. */
|
|
435
|
+
eveConnectionId: z.string().min(1).optional(),
|
|
436
|
+
/** Source application id; groups the chat under an inbox section. */
|
|
437
|
+
app: z.string().min(1).optional(),
|
|
438
|
+
assignTo: assignToSchema.optional(),
|
|
439
|
+
title: z.string().min(1),
|
|
440
|
+
messages: z.array(agentChatSeedMessageSchema).default([]),
|
|
441
|
+
/** Provenance label stored on the session ("cron" | "agent" | ...). */
|
|
442
|
+
source: z.string().min(1).optional()
|
|
443
|
+
}).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
|
|
444
|
+
message: "Provide either agentIdentifier or parentChatId"
|
|
445
|
+
});
|
|
446
|
+
var agentChatAuditInputBodySchema = z.object({
|
|
447
|
+
eveSessionId: z.string().min(1),
|
|
448
|
+
userId: z.string().min(1),
|
|
449
|
+
actionId: z.string().min(1),
|
|
450
|
+
actionTitle: z.string().optional(),
|
|
451
|
+
prompt: z.string().optional(),
|
|
452
|
+
data: z.record(z.string(), z.unknown()).optional(),
|
|
453
|
+
idempotencyKey: z.string().optional(),
|
|
454
|
+
/** Eve input request id — used to merge staged HITL metadata. */
|
|
455
|
+
requestId: z.string().optional(),
|
|
456
|
+
/** Eve tool call id — fallback lookup for staged HITL metadata. */
|
|
457
|
+
toolCallId: z.string().optional()
|
|
458
|
+
});
|
|
459
|
+
var eveHitlStagedOptionSchema = z.object({
|
|
460
|
+
id: z.string(),
|
|
461
|
+
label: z.string()
|
|
462
|
+
});
|
|
463
|
+
var agentChatStageHitlBodySchema = z.object({
|
|
464
|
+
eveSessionId: z.string().min(1),
|
|
465
|
+
requests: z.array(
|
|
466
|
+
z.object({
|
|
467
|
+
requestId: z.string().min(1),
|
|
468
|
+
toolCallId: z.string().min(1),
|
|
469
|
+
toolName: z.string().min(1),
|
|
470
|
+
prompt: z.string().min(1),
|
|
471
|
+
display: z.enum(["confirmation", "select", "text"]).optional(),
|
|
472
|
+
allowFreeform: z.boolean().optional(),
|
|
473
|
+
options: z.array(eveHitlStagedOptionSchema).optional(),
|
|
474
|
+
toolInput: z.record(z.string(), z.unknown()).optional()
|
|
475
|
+
})
|
|
476
|
+
)
|
|
477
|
+
});
|
|
478
|
+
var agentChatLinkTaskBodySchema = z.object({
|
|
479
|
+
eveSessionId: z.string().min(1),
|
|
480
|
+
publicTaskId: z.string().min(1),
|
|
481
|
+
toolCallId: z.string().min(1)
|
|
482
|
+
});
|
|
368
483
|
|
|
369
484
|
// src/schemas/index.ts
|
|
370
|
-
var
|
|
371
|
-
message:
|
|
485
|
+
var handlerUrlSchema2 = z2.string().refine((url) => isAllowedHandlerUrl(url), {
|
|
486
|
+
message: HANDLER_URL_ERROR
|
|
372
487
|
});
|
|
373
488
|
var jsonSchema7Schema2 = z2.custom(
|
|
374
489
|
(val) => typeof val === "object" && val !== null,
|
|
@@ -379,7 +494,7 @@ var uiSchemaSchema2 = z2.custom((val) => typeof val === "object" && val !== null
|
|
|
379
494
|
});
|
|
380
495
|
var webhookHandlerSchema2 = z2.object({
|
|
381
496
|
type: z2.literal("webhook"),
|
|
382
|
-
url:
|
|
497
|
+
url: handlerUrlSchema2,
|
|
383
498
|
headers: z2.record(z2.string(), z2.string())
|
|
384
499
|
});
|
|
385
500
|
var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
@@ -387,13 +502,15 @@ var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
|
387
502
|
tokenId: z2.string().min(1)
|
|
388
503
|
});
|
|
389
504
|
var handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
|
|
390
|
-
var
|
|
505
|
+
var taskActionInputSchema2 = z2.object({
|
|
391
506
|
id: z2.string().min(1),
|
|
392
507
|
title: z2.string().min(1),
|
|
393
508
|
description: z2.string().optional(),
|
|
394
509
|
schema: jsonSchema7Schema2.optional(),
|
|
395
510
|
ui: uiSchemaSchema2.optional(),
|
|
396
|
-
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
511
|
+
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
512
|
+
});
|
|
513
|
+
var taskActionSchema2 = taskActionInputSchema2.extend({
|
|
397
514
|
handlers: z2.array(handlerSchema2).min(1).optional()
|
|
398
515
|
});
|
|
399
516
|
var uiFieldSchemaSchema2 = z2.object({
|
|
@@ -525,6 +642,293 @@ function toDiscriminatedApprovalResult(actions, task) {
|
|
|
525
642
|
};
|
|
526
643
|
}
|
|
527
644
|
|
|
645
|
+
// src/http.ts
|
|
646
|
+
var RobotRockError = class extends Error {
|
|
647
|
+
constructor(message, statusCode, response) {
|
|
648
|
+
super(message);
|
|
649
|
+
this.statusCode = statusCode;
|
|
650
|
+
this.response = response;
|
|
651
|
+
this.name = "RobotRockError";
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
async function parseResponseBody(response) {
|
|
655
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
656
|
+
const bodyText = await response.text();
|
|
657
|
+
if (!bodyText) {
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
if (contentType.toLowerCase().includes("application/json")) {
|
|
661
|
+
try {
|
|
662
|
+
return JSON.parse(bodyText);
|
|
663
|
+
} catch {
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
return JSON.parse(bodyText);
|
|
668
|
+
} catch {
|
|
669
|
+
return bodyText;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
function getErrorMessage(data, fallback) {
|
|
673
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
674
|
+
const record = data;
|
|
675
|
+
const maybeMessage = record.message;
|
|
676
|
+
const maybeHint = record.hint;
|
|
677
|
+
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
678
|
+
if (typeof maybeHint === "string" && maybeHint.trim()) {
|
|
679
|
+
return `${maybeMessage.trim()} ${maybeHint.trim()}`;
|
|
680
|
+
}
|
|
681
|
+
return maybeMessage;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (typeof data === "string" && data.trim()) {
|
|
685
|
+
const compact = data.replace(/\s+/g, " ").trim();
|
|
686
|
+
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
687
|
+
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
688
|
+
}
|
|
689
|
+
return fallback;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// ../core/src/handler-retry.ts
|
|
693
|
+
var HANDLER_RETRY_DELAYS_MS = [
|
|
694
|
+
6e4,
|
|
695
|
+
// 1m
|
|
696
|
+
3e5,
|
|
697
|
+
// 5m
|
|
698
|
+
18e5,
|
|
699
|
+
// 30m
|
|
700
|
+
36e5,
|
|
701
|
+
// 1h
|
|
702
|
+
216e5,
|
|
703
|
+
// 6h
|
|
704
|
+
864e5,
|
|
705
|
+
// 24h
|
|
706
|
+
1728e5
|
|
707
|
+
// 48h
|
|
708
|
+
];
|
|
709
|
+
var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
|
|
710
|
+
|
|
711
|
+
// ../core/src/attribution/index.ts
|
|
712
|
+
import { z as z3 } from "zod";
|
|
713
|
+
|
|
714
|
+
// ../core/src/app-url.ts
|
|
715
|
+
var PRODUCTION_APP_URL = "https://app.robotrock.io";
|
|
716
|
+
var PRODUCTION_API_URL = "https://api.robotrock.io/v1";
|
|
717
|
+
var DEV_API_URL = "http://localhost:4001/v1";
|
|
718
|
+
var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
|
|
719
|
+
function normalizeRobotRockApiBaseUrl(baseUrl) {
|
|
720
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
721
|
+
if (trimmed.endsWith("/v1")) {
|
|
722
|
+
return trimmed;
|
|
723
|
+
}
|
|
724
|
+
return `${trimmed}/v1`;
|
|
725
|
+
}
|
|
726
|
+
function getRobotRockApiBaseUrl() {
|
|
727
|
+
const explicit = process.env.ROBOTROCK_BASE_URL?.trim() || process.env.ROBOTROCK_API_URL?.trim();
|
|
728
|
+
if (explicit) {
|
|
729
|
+
return normalizeRobotRockApiBaseUrl(explicit);
|
|
730
|
+
}
|
|
731
|
+
if (process.env.NODE_ENV === "production") {
|
|
732
|
+
return PRODUCTION_API_URL;
|
|
733
|
+
}
|
|
734
|
+
return DEV_API_URL;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// ../core/src/attribution/index.ts
|
|
738
|
+
var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
|
|
739
|
+
var attributionSchema = z3.object({
|
|
740
|
+
utmSource: z3.string().optional(),
|
|
741
|
+
utmMedium: z3.string().optional(),
|
|
742
|
+
utmCampaign: z3.string().optional(),
|
|
743
|
+
utmContent: z3.string().optional(),
|
|
744
|
+
utmTerm: z3.string().optional(),
|
|
745
|
+
gclid: z3.string().optional(),
|
|
746
|
+
landingUrl: z3.string().optional(),
|
|
747
|
+
referrer: z3.string().optional(),
|
|
748
|
+
capturedAt: z3.number()
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
// src/auth-headers.ts
|
|
752
|
+
function buildRobotRockAuthHeaders(auth) {
|
|
753
|
+
if (auth.kind === "apiKey") {
|
|
754
|
+
return {
|
|
755
|
+
"X-Api-Key": auth.apiKey
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
Authorization: `Bearer ${auth.token}`,
|
|
760
|
+
"X-RobotRock-Tenant-Slug": auth.tenantSlug,
|
|
761
|
+
"X-RobotRock-Connection-Id": auth.connectionId
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
function resolveRobotRockAuthConfig(overrides) {
|
|
765
|
+
if (overrides?.agentService) {
|
|
766
|
+
return {
|
|
767
|
+
kind: "agentService",
|
|
768
|
+
...overrides.agentService
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
772
|
+
if (!apiKey) {
|
|
773
|
+
throw new Error(
|
|
774
|
+
"RobotRock auth is required. Set ROBOTROCK_API_KEY, ROBOTROCK_AGENT_SERVICE_TOKEN with tenant context, or pass auth when creating the client."
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
return { kind: "apiKey", apiKey };
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// src/chats.ts
|
|
781
|
+
function createChatsApi(config) {
|
|
782
|
+
const headers = () => ({
|
|
783
|
+
"Content-Type": "application/json",
|
|
784
|
+
...buildRobotRockAuthHeaders(config.auth)
|
|
785
|
+
});
|
|
786
|
+
return {
|
|
787
|
+
async create(input) {
|
|
788
|
+
const bodyPayload = {
|
|
789
|
+
...input,
|
|
790
|
+
app: input.app ?? config.app,
|
|
791
|
+
messages: input.messages ?? []
|
|
792
|
+
};
|
|
793
|
+
const validation = createAgentChatBodySchema.safeParse(bodyPayload);
|
|
794
|
+
if (!validation.success) {
|
|
795
|
+
throw new RobotRockError(
|
|
796
|
+
`Invalid chat: ${validation.error.issues[0]?.message}`,
|
|
797
|
+
400,
|
|
798
|
+
validation.error.issues
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
const response = await fetch(`${config.baseUrl}/agent-chats`, {
|
|
802
|
+
method: "POST",
|
|
803
|
+
headers: headers(),
|
|
804
|
+
body: JSON.stringify(validation.data)
|
|
805
|
+
});
|
|
806
|
+
const data = await parseResponseBody(response);
|
|
807
|
+
if (!response.ok) {
|
|
808
|
+
throw new RobotRockError(
|
|
809
|
+
getErrorMessage(data, "Failed to create chat"),
|
|
810
|
+
response.status,
|
|
811
|
+
data
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
const result = data;
|
|
815
|
+
return { tenantSlug: result.tenantSlug, chats: result.chats };
|
|
816
|
+
},
|
|
817
|
+
async close(chatId, options) {
|
|
818
|
+
if (!chatId) {
|
|
819
|
+
throw new RobotRockError("chatId is required to close a chat", 400);
|
|
820
|
+
}
|
|
821
|
+
const response = await fetch(
|
|
822
|
+
`${config.baseUrl}/agent-chats/${encodeURIComponent(chatId)}/close`,
|
|
823
|
+
{
|
|
824
|
+
method: "POST",
|
|
825
|
+
headers: headers(),
|
|
826
|
+
body: JSON.stringify({ reason: options?.reason })
|
|
827
|
+
}
|
|
828
|
+
);
|
|
829
|
+
if (!response.ok) {
|
|
830
|
+
const data = await parseResponseBody(response);
|
|
831
|
+
throw new RobotRockError(
|
|
832
|
+
getErrorMessage(data, "Failed to close chat"),
|
|
833
|
+
response.status,
|
|
834
|
+
data
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
},
|
|
838
|
+
async stageHitlRequests(input) {
|
|
839
|
+
const validation = agentChatStageHitlBodySchema.safeParse(input);
|
|
840
|
+
if (!validation.success) {
|
|
841
|
+
throw new RobotRockError(
|
|
842
|
+
`Invalid stage HITL input: ${validation.error.issues[0]?.message}`,
|
|
843
|
+
400,
|
|
844
|
+
validation.error.issues
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/stage-hitl`, {
|
|
848
|
+
method: "POST",
|
|
849
|
+
headers: headers(),
|
|
850
|
+
body: JSON.stringify(validation.data)
|
|
851
|
+
});
|
|
852
|
+
if (!response.ok) {
|
|
853
|
+
const data = await parseResponseBody(response);
|
|
854
|
+
throw new RobotRockError(
|
|
855
|
+
getErrorMessage(data, "Failed to stage chat HITL requests"),
|
|
856
|
+
response.status,
|
|
857
|
+
data
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
async getStagedHitlRequests(eveSessionId) {
|
|
862
|
+
const trimmed = eveSessionId.trim();
|
|
863
|
+
if (!trimmed) {
|
|
864
|
+
throw new RobotRockError("eveSessionId is required", 400);
|
|
865
|
+
}
|
|
866
|
+
const url = new URL(`${config.baseUrl}/agent-chats/staged-hitl`);
|
|
867
|
+
url.searchParams.set("eveSessionId", trimmed);
|
|
868
|
+
const response = await fetch(url.toString(), {
|
|
869
|
+
method: "GET",
|
|
870
|
+
headers: headers()
|
|
871
|
+
});
|
|
872
|
+
const data = await parseResponseBody(response);
|
|
873
|
+
if (!response.ok) {
|
|
874
|
+
throw new RobotRockError(
|
|
875
|
+
getErrorMessage(data, "Failed to fetch staged chat HITL requests"),
|
|
876
|
+
response.status,
|
|
877
|
+
data
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
const requests = data.requests;
|
|
881
|
+
return Array.isArray(requests) ? requests : [];
|
|
882
|
+
},
|
|
883
|
+
async logInputSubmission(input) {
|
|
884
|
+
const validation = agentChatAuditInputBodySchema.safeParse(input);
|
|
885
|
+
if (!validation.success) {
|
|
886
|
+
throw new RobotRockError(
|
|
887
|
+
`Invalid audit input: ${validation.error.issues[0]?.message}`,
|
|
888
|
+
400,
|
|
889
|
+
validation.error.issues
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/audit-input`, {
|
|
893
|
+
method: "POST",
|
|
894
|
+
headers: headers(),
|
|
895
|
+
body: JSON.stringify(validation.data)
|
|
896
|
+
});
|
|
897
|
+
if (!response.ok) {
|
|
898
|
+
const data = await parseResponseBody(response);
|
|
899
|
+
throw new RobotRockError(
|
|
900
|
+
getErrorMessage(data, "Failed to log chat input submission"),
|
|
901
|
+
response.status,
|
|
902
|
+
data
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
async linkTask(input) {
|
|
907
|
+
const validation = agentChatLinkTaskBodySchema.safeParse(input);
|
|
908
|
+
if (!validation.success) {
|
|
909
|
+
throw new RobotRockError(
|
|
910
|
+
`Invalid link task input: ${validation.error.issues[0]?.message}`,
|
|
911
|
+
400,
|
|
912
|
+
validation.error.issues
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
const response = await fetch(`${config.baseUrl}/agent-chats/link-task`, {
|
|
916
|
+
method: "POST",
|
|
917
|
+
headers: headers(),
|
|
918
|
+
body: JSON.stringify(validation.data)
|
|
919
|
+
});
|
|
920
|
+
if (!response.ok) {
|
|
921
|
+
const data = await parseResponseBody(response);
|
|
922
|
+
throw new RobotRockError(
|
|
923
|
+
getErrorMessage(data, "Failed to link inbox task to chat"),
|
|
924
|
+
response.status,
|
|
925
|
+
data
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
|
|
528
932
|
// src/client.ts
|
|
529
933
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
530
934
|
var DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -562,22 +966,18 @@ function serializeValidUntil(value) {
|
|
|
562
966
|
}
|
|
563
967
|
throw new RobotRockError("Invalid validUntil: expected a Date or parseable date string", 400);
|
|
564
968
|
}
|
|
565
|
-
var RobotRockError = class extends Error {
|
|
566
|
-
constructor(message, statusCode, response) {
|
|
567
|
-
super(message);
|
|
568
|
-
this.statusCode = statusCode;
|
|
569
|
-
this.response = response;
|
|
570
|
-
this.name = "RobotRockError";
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
969
|
var RobotRock = class {
|
|
574
|
-
|
|
970
|
+
auth;
|
|
575
971
|
baseUrl;
|
|
576
972
|
app;
|
|
577
973
|
agentVersion;
|
|
578
974
|
contextVersion;
|
|
579
975
|
webhook;
|
|
580
976
|
polling;
|
|
977
|
+
/** Task CRUD: `create`, `get`, `cancel`, `sendUpdate`. */
|
|
978
|
+
tasks;
|
|
979
|
+
/** Chat CRUD: `create`, `close`. */
|
|
980
|
+
chats;
|
|
581
981
|
constructor(config) {
|
|
582
982
|
if (config.webhook && config.polling) {
|
|
583
983
|
throw new Error(
|
|
@@ -585,24 +985,42 @@ var RobotRock = class {
|
|
|
585
985
|
);
|
|
586
986
|
}
|
|
587
987
|
const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
588
|
-
|
|
988
|
+
const agentService = config.agentService;
|
|
989
|
+
if (apiKey && agentService) {
|
|
589
990
|
throw new Error(
|
|
590
|
-
"RobotRock
|
|
991
|
+
"RobotRock client cannot configure both apiKey and agentService."
|
|
591
992
|
);
|
|
592
993
|
}
|
|
593
|
-
this.
|
|
594
|
-
|
|
595
|
-
|
|
994
|
+
this.auth = resolveRobotRockAuthConfig({
|
|
995
|
+
...apiKey ? { apiKey } : {},
|
|
996
|
+
...agentService ? { agentService } : {}
|
|
997
|
+
});
|
|
998
|
+
this.baseUrl = config.baseUrl ?? getRobotRockApiBaseUrl();
|
|
596
999
|
this.app = config.app;
|
|
597
1000
|
this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
|
|
598
1001
|
this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
|
|
599
1002
|
this.webhook = config.webhook;
|
|
600
1003
|
this.polling = config.polling ?? {};
|
|
1004
|
+
this.tasks = {
|
|
1005
|
+
create: (task) => this.createTaskRequest(task),
|
|
1006
|
+
get: (taskId) => this.getTaskById(taskId),
|
|
1007
|
+
cancel: (taskId) => this.cancelTaskRequest(taskId),
|
|
1008
|
+
sendUpdate: (input) => this.sendThreadUpdate(input)
|
|
1009
|
+
};
|
|
1010
|
+
this.chats = createChatsApi({
|
|
1011
|
+
baseUrl: this.baseUrl,
|
|
1012
|
+
auth: this.auth,
|
|
1013
|
+
app: this.app
|
|
1014
|
+
});
|
|
601
1015
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
1016
|
+
authHeaders(extra) {
|
|
1017
|
+
return {
|
|
1018
|
+
"Content-Type": "application/json",
|
|
1019
|
+
...buildRobotRockAuthHeaders(this.auth),
|
|
1020
|
+
...extra
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
async createTaskRequest(task) {
|
|
606
1024
|
const normalizedTask = normalizeSendToHumanInput(task, {
|
|
607
1025
|
webhook: this.webhook,
|
|
608
1026
|
app: this.app,
|
|
@@ -626,13 +1044,9 @@ var RobotRock = class {
|
|
|
626
1044
|
validation.error.issues
|
|
627
1045
|
);
|
|
628
1046
|
}
|
|
629
|
-
const headers =
|
|
630
|
-
"
|
|
631
|
-
|
|
632
|
-
};
|
|
633
|
-
if (task.idempotencyKey) {
|
|
634
|
-
headers["Idempotency-Key"] = task.idempotencyKey;
|
|
635
|
-
}
|
|
1047
|
+
const headers = this.authHeaders(
|
|
1048
|
+
task.idempotencyKey ? { "Idempotency-Key": task.idempotencyKey } : void 0
|
|
1049
|
+
);
|
|
636
1050
|
const response = await fetch(`${this.baseUrl}/`, {
|
|
637
1051
|
method: "POST",
|
|
638
1052
|
headers,
|
|
@@ -655,7 +1069,7 @@ var RobotRock = class {
|
|
|
655
1069
|
contextVersion: this.contextVersion,
|
|
656
1070
|
agentVersion: this.agentVersion
|
|
657
1071
|
});
|
|
658
|
-
const createdTaskTask = await this.
|
|
1072
|
+
const createdTaskTask = await this.createTaskRequest(task);
|
|
659
1073
|
const hasHandlers = normalizedTask.actions.some(
|
|
660
1074
|
(action) => Array.isArray(action.handlers) && action.handlers.length > 0
|
|
661
1075
|
);
|
|
@@ -672,7 +1086,7 @@ var RobotRock = class {
|
|
|
672
1086
|
const deadline = validUntilMs !== void 0 ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;
|
|
673
1087
|
const taskId = createdTaskTask.taskId;
|
|
674
1088
|
while (Date.now() < deadline) {
|
|
675
|
-
const existing = await this.
|
|
1089
|
+
const existing = await this.getTaskById(taskId);
|
|
676
1090
|
if (existing?.status === "handled" && existing.handled) {
|
|
677
1091
|
return {
|
|
678
1092
|
mode: "handled",
|
|
@@ -694,15 +1108,38 @@ var RobotRock = class {
|
|
|
694
1108
|
}
|
|
695
1109
|
throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);
|
|
696
1110
|
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Create a task via POST /v1 without waiting for a human response.
|
|
1113
|
+
* @deprecated Use `client.tasks.create()` instead.
|
|
1114
|
+
*/
|
|
1115
|
+
async createTask(task) {
|
|
1116
|
+
return this.tasks.create(task);
|
|
1117
|
+
}
|
|
697
1118
|
/**
|
|
698
1119
|
* Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
|
|
1120
|
+
* @deprecated Use `client.tasks.get()` instead.
|
|
699
1121
|
*/
|
|
700
1122
|
async getTask(taskId) {
|
|
1123
|
+
return this.tasks.get(taskId);
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Log a status update against a thread.
|
|
1127
|
+
* @deprecated Use `client.tasks.sendUpdate()` instead.
|
|
1128
|
+
*/
|
|
1129
|
+
async sendUpdate(input) {
|
|
1130
|
+
return this.tasks.sendUpdate(input);
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Cancel a task by public task id.
|
|
1134
|
+
* @deprecated Use `client.tasks.cancel()` instead.
|
|
1135
|
+
*/
|
|
1136
|
+
async cancelTask(taskId) {
|
|
1137
|
+
return this.tasks.cancel(taskId);
|
|
1138
|
+
}
|
|
1139
|
+
async getTaskById(taskId) {
|
|
701
1140
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
|
|
702
1141
|
method: "GET",
|
|
703
|
-
headers:
|
|
704
|
-
"X-Api-Key": this.apiKey
|
|
705
|
-
}
|
|
1142
|
+
headers: this.authHeaders()
|
|
706
1143
|
});
|
|
707
1144
|
if (response.status === 404) {
|
|
708
1145
|
return null;
|
|
@@ -717,11 +1154,11 @@ var RobotRock = class {
|
|
|
717
1154
|
}
|
|
718
1155
|
return data;
|
|
719
1156
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
1157
|
+
async sendThreadUpdate({
|
|
1158
|
+
threadId,
|
|
1159
|
+
message,
|
|
1160
|
+
status
|
|
1161
|
+
}) {
|
|
725
1162
|
if (!threadId) {
|
|
726
1163
|
throw new RobotRockError("threadId is required to send an update", 400);
|
|
727
1164
|
}
|
|
@@ -737,10 +1174,7 @@ var RobotRock = class {
|
|
|
737
1174
|
`${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,
|
|
738
1175
|
{
|
|
739
1176
|
method: "POST",
|
|
740
|
-
headers:
|
|
741
|
-
"Content-Type": "application/json",
|
|
742
|
-
"X-Api-Key": this.apiKey
|
|
743
|
-
},
|
|
1177
|
+
headers: this.authHeaders(),
|
|
744
1178
|
body: JSON.stringify(validation.data)
|
|
745
1179
|
}
|
|
746
1180
|
);
|
|
@@ -754,12 +1188,10 @@ var RobotRock = class {
|
|
|
754
1188
|
}
|
|
755
1189
|
return data.update;
|
|
756
1190
|
}
|
|
757
|
-
async
|
|
1191
|
+
async cancelTaskRequest(taskId) {
|
|
758
1192
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
|
|
759
1193
|
method: "POST",
|
|
760
|
-
headers:
|
|
761
|
-
"X-Api-Key": this.apiKey
|
|
762
|
-
}
|
|
1194
|
+
headers: this.authHeaders()
|
|
763
1195
|
});
|
|
764
1196
|
if (!response.ok) {
|
|
765
1197
|
const data = await parseResponseBody(response);
|
|
@@ -813,50 +1245,26 @@ function normalizeSendToHumanInput(task, clientDefaults) {
|
|
|
813
1245
|
actions: normalizedActions
|
|
814
1246
|
};
|
|
815
1247
|
}
|
|
816
|
-
async function parseResponseBody(response) {
|
|
817
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
818
|
-
const bodyText = await response.text();
|
|
819
|
-
if (!bodyText) {
|
|
820
|
-
return null;
|
|
821
|
-
}
|
|
822
|
-
if (contentType.toLowerCase().includes("application/json")) {
|
|
823
|
-
try {
|
|
824
|
-
return JSON.parse(bodyText);
|
|
825
|
-
} catch {
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
try {
|
|
829
|
-
return JSON.parse(bodyText);
|
|
830
|
-
} catch {
|
|
831
|
-
return bodyText;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
function getErrorMessage(data, fallback) {
|
|
835
|
-
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
836
|
-
const maybeMessage = data.message;
|
|
837
|
-
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
838
|
-
return maybeMessage;
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
if (typeof data === "string" && data.trim()) {
|
|
842
|
-
const compact = data.replace(/\s+/g, " ").trim();
|
|
843
|
-
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
844
|
-
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
845
|
-
}
|
|
846
|
-
return fallback;
|
|
847
|
-
}
|
|
848
1248
|
|
|
849
1249
|
// src/env.ts
|
|
850
|
-
var DEFAULT_BASE_URL = "https://api.robotrock.io/v1";
|
|
851
1250
|
function resolveRobotRockConfig(overrides) {
|
|
1251
|
+
const agentService = overrides?.agentService;
|
|
852
1252
|
const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;
|
|
853
|
-
if (
|
|
1253
|
+
if (agentService && apiKey) {
|
|
854
1254
|
throw new Error(
|
|
855
|
-
"RobotRock
|
|
1255
|
+
"RobotRock client cannot configure both apiKey and agentService."
|
|
856
1256
|
);
|
|
857
1257
|
}
|
|
858
|
-
const baseUrl = overrides?.baseUrl ??
|
|
1258
|
+
const baseUrl = overrides?.baseUrl ?? getRobotRockApiBaseUrl();
|
|
859
1259
|
const app = overrides?.app ?? process.env.ROBOTROCK_APP;
|
|
1260
|
+
if (agentService) {
|
|
1261
|
+
return app ? { agentService, baseUrl, app } : { agentService, baseUrl };
|
|
1262
|
+
}
|
|
1263
|
+
if (!apiKey) {
|
|
1264
|
+
throw new Error(
|
|
1265
|
+
"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass agentService when creating the client."
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
860
1268
|
return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };
|
|
861
1269
|
}
|
|
862
1270
|
|
|
@@ -1228,7 +1636,7 @@ async function sendRobotRockUpdate(payload) {
|
|
|
1228
1636
|
...baseConfig.version ? { version: baseConfig.version } : {},
|
|
1229
1637
|
...baseConfig.advanced ? { advanced: baseConfig.advanced } : {}
|
|
1230
1638
|
});
|
|
1231
|
-
return client.sendUpdate(update);
|
|
1639
|
+
return client.tasks.sendUpdate(update);
|
|
1232
1640
|
}
|
|
1233
1641
|
async function sendUpdateInWorkflow(payload) {
|
|
1234
1642
|
return sendRobotRockUpdate(payload);
|