robotrock 0.8.5 → 1.0.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 +976 -281
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/trigger.d.ts +4 -3
- package/dist/ai/trigger.js +934 -281
- package/dist/ai/trigger.js.map +1 -1
- package/dist/ai/workflow.d.ts +15 -4
- package/dist/ai/workflow.js +854 -282
- package/dist/ai/workflow.js.map +1 -1
- package/dist/client-CzVmjXpz.d.ts +219 -0
- package/dist/index.d.ts +17 -9
- package/dist/index.js +495 -273
- package/dist/index.js.map +1 -1
- package/dist/otel-platform-DzHyHkGk.d.ts +108 -0
- package/dist/schemas/index.d.ts +172 -104
- package/dist/schemas/index.js +98 -118
- package/dist/schemas/index.js.map +1 -1
- package/dist/{tool-approval-bridge-BKDY5NAY.d.ts → tool-approval-bridge-DbwUEBHv.d.ts} +93 -2
- package/dist/trigger/index.d.ts +7 -4
- package/dist/trigger/index.js +558 -201
- package/dist/trigger/index.js.map +1 -1
- package/dist/{trigger-CsOLTjsH.d.ts → trigger-BCKBbAV7.d.ts} +64 -3
- package/dist/workflow/index.d.ts +7 -4
- package/dist/workflow/index.js +553 -199
- package/dist/workflow/index.js.map +1 -1
- package/package.json +1 -5
- package/dist/client-D-XEBOWd.d.ts +0 -137
- package/dist/handler-webhook-BqEi6Bk-.d.ts +0 -16
- package/dist/otel/index.d.ts +0 -49
- package/dist/otel/index.js +0 -633
- package/dist/otel/index.js.map +0 -1
package/dist/workflow/index.js
CHANGED
|
@@ -213,12 +213,12 @@ function validateUrlValue(value, widget) {
|
|
|
213
213
|
}
|
|
214
214
|
return null;
|
|
215
215
|
}
|
|
216
|
-
function validateContextPublicUrls(
|
|
217
|
-
if (!
|
|
216
|
+
function validateContextPublicUrls(context2) {
|
|
217
|
+
if (!context2?.data) {
|
|
218
218
|
return null;
|
|
219
219
|
}
|
|
220
|
-
for (const [field, value] of Object.entries(
|
|
221
|
-
const widget = widgetType(
|
|
220
|
+
for (const [field, value] of Object.entries(context2.data)) {
|
|
221
|
+
const widget = widgetType(context2.ui, field);
|
|
222
222
|
if (!widget) {
|
|
223
223
|
continue;
|
|
224
224
|
}
|
|
@@ -251,13 +251,15 @@ var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
|
251
251
|
tokenId: z.string().min(1)
|
|
252
252
|
});
|
|
253
253
|
var handlerSchema = z.discriminatedUnion("type", [webhookHandlerSchema, triggerHandlerSchema]);
|
|
254
|
-
var
|
|
254
|
+
var taskActionInputSchema = z.object({
|
|
255
255
|
id: z.string().min(1),
|
|
256
256
|
title: z.string().min(1),
|
|
257
257
|
description: z.string().optional(),
|
|
258
258
|
schema: jsonSchema7Schema.optional(),
|
|
259
259
|
ui: uiSchemaSchema.optional(),
|
|
260
|
-
data: z.record(z.string(), z.unknown()).optional()
|
|
260
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
261
|
+
});
|
|
262
|
+
var taskActionSchema = taskActionInputSchema.extend({
|
|
261
263
|
// Optional handlers for this action - if present, must have at least 1
|
|
262
264
|
handlers: z.array(handlerSchema).min(1).optional()
|
|
263
265
|
});
|
|
@@ -273,7 +275,8 @@ var contextDataSchema = z.object({
|
|
|
273
275
|
data: z.record(z.string(), z.unknown()),
|
|
274
276
|
ui: contextUiSchema
|
|
275
277
|
}).optional();
|
|
276
|
-
var
|
|
278
|
+
var TASK_CONTEXT_FORMAT_VERSION = 2;
|
|
279
|
+
var taskContextObjectBaseSchema = z.object({
|
|
277
280
|
/** Source application id; omitted tasks are grouped in the default inbox. */
|
|
278
281
|
app: z.string().min(1).optional(),
|
|
279
282
|
type: z.string().min(1),
|
|
@@ -281,9 +284,22 @@ var taskContextObjectSchema = z.object({
|
|
|
281
284
|
description: z.string().optional(),
|
|
282
285
|
validUntil: z.string().optional(),
|
|
283
286
|
context: contextDataSchema,
|
|
287
|
+
/** Task context wire format version. @default 2 */
|
|
288
|
+
contextVersion: z.literal(2).optional(),
|
|
289
|
+
/** @deprecated Use `contextVersion`. Accepted on ingest only. */
|
|
284
290
|
version: z.literal(2).optional(),
|
|
285
291
|
actions: z.array(taskActionSchema).min(1, "At least one action is required")
|
|
286
292
|
});
|
|
293
|
+
function normalizeTaskContextVersion(data) {
|
|
294
|
+
const { version: legacyVersion, contextVersion, ...rest } = data;
|
|
295
|
+
return {
|
|
296
|
+
...rest,
|
|
297
|
+
contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
var taskContextObjectSchema = taskContextObjectBaseSchema.transform(
|
|
301
|
+
normalizeTaskContextVersion
|
|
302
|
+
);
|
|
287
303
|
function refineContextPublicUrls(data, ctx) {
|
|
288
304
|
const error = validateContextPublicUrls(data.context);
|
|
289
305
|
if (error) {
|
|
@@ -327,61 +343,11 @@ var threadUpdateInputSchema = z.object({
|
|
|
327
343
|
});
|
|
328
344
|
var taskPriorities = ["low", "normal", "high", "urgent"];
|
|
329
345
|
var taskPrioritySchema = z.enum(taskPriorities);
|
|
330
|
-
var nonNegativeInt = z.number().int().nonnegative();
|
|
331
|
-
var agentCostTokensSchema = z.object({
|
|
332
|
-
input: nonNegativeInt.optional(),
|
|
333
|
-
output: nonNegativeInt.optional(),
|
|
334
|
-
total: nonNegativeInt.optional()
|
|
335
|
-
});
|
|
336
|
-
var agentCostSchema = z.object({
|
|
337
|
-
tokens: agentCostTokensSchema.optional(),
|
|
338
|
-
eur: z.number().nonnegative().optional(),
|
|
339
|
-
usd: z.number().nonnegative().optional()
|
|
340
|
-
});
|
|
341
|
-
var AGENT_INFO_MAX_KEYS = 32;
|
|
342
|
-
var AGENT_TOOL_CALLS_MAX_KEYS = 64;
|
|
343
|
-
var AGENT_OTEL_SPANS_MAX = 32;
|
|
344
|
-
var agentToolCallsSchema = z.record(z.string().min(1), nonNegativeInt);
|
|
345
|
-
var agentOtelSpanStatusSchema = z.enum(["ok", "error"]);
|
|
346
|
-
var agentOtelSpanSummarySchema = z.object({
|
|
347
|
-
name: z.string().min(1),
|
|
348
|
-
durationMs: z.number().nonnegative(),
|
|
349
|
-
status: agentOtelSpanStatusSchema
|
|
350
|
-
});
|
|
351
|
-
var agentOtelSchema = z.object({
|
|
352
|
-
traceId: z.string().min(1),
|
|
353
|
-
spanId: z.string().min(1).optional(),
|
|
354
|
-
rootDurationMs: z.number().nonnegative().optional(),
|
|
355
|
-
spans: z.array(agentOtelSpanSummarySchema).max(AGENT_OTEL_SPANS_MAX).optional()
|
|
356
|
-
});
|
|
357
346
|
var agentTelemetrySchema = z.object({
|
|
358
347
|
/** Agent or app version (semver, git SHA, deploy tag — caller-defined). */
|
|
359
|
-
version: z.string().min(1)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
/** Per-tool invocation counts keyed by tool name. */
|
|
363
|
-
toolCalls: agentToolCallsSchema.optional(),
|
|
364
|
-
cost: agentCostSchema.optional(),
|
|
365
|
-
/** Free-form metadata for experiments (model, prompt variant, etc.). */
|
|
366
|
-
info: z.record(z.string(), z.unknown()).optional(),
|
|
367
|
-
/** Structured OpenTelemetry span snapshot for feedback analysis. */
|
|
368
|
-
otel: agentOtelSchema.optional()
|
|
369
|
-
}).refine(
|
|
370
|
-
(data) => {
|
|
371
|
-
const keys = data.info ? Object.keys(data.info) : [];
|
|
372
|
-
return keys.length <= AGENT_INFO_MAX_KEYS;
|
|
373
|
-
},
|
|
374
|
-
{ message: `agent.info may contain at most ${AGENT_INFO_MAX_KEYS} keys` }
|
|
375
|
-
).refine(
|
|
376
|
-
(data) => {
|
|
377
|
-
const keys = data.toolCalls ? Object.keys(data.toolCalls) : [];
|
|
378
|
-
return keys.length <= AGENT_TOOL_CALLS_MAX_KEYS;
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
message: `agent.toolCalls may contain at most ${AGENT_TOOL_CALLS_MAX_KEYS} tool names`
|
|
382
|
-
}
|
|
383
|
-
);
|
|
384
|
-
var createTaskBodySchema = taskContextObjectSchema.extend({
|
|
348
|
+
version: z.string().min(1)
|
|
349
|
+
});
|
|
350
|
+
var createTaskBodySchema = taskContextObjectBaseSchema.extend({
|
|
385
351
|
assignTo: assignToSchema.optional(),
|
|
386
352
|
/**
|
|
387
353
|
* Groups related tasks together. When omitted, the server generates one and
|
|
@@ -398,9 +364,59 @@ var createTaskBodySchema = taskContextObjectSchema.extend({
|
|
|
398
364
|
* the inbox status bar and the thread update log.
|
|
399
365
|
*/
|
|
400
366
|
update: threadUpdateInputSchema.optional(),
|
|
401
|
-
/** Agent
|
|
367
|
+
/** Agent release version — not shown in inbox UI. */
|
|
402
368
|
agent: agentTelemetrySchema.optional()
|
|
403
|
-
}).superRefine(refineContextPublicUrls);
|
|
369
|
+
}).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
|
|
370
|
+
var agentChatSeedActionSchema = z.object({
|
|
371
|
+
/** Stable action id echoed back on submit; auto-derived from title when omitted. */
|
|
372
|
+
id: z.string().min(1).optional(),
|
|
373
|
+
title: z.string().min(1),
|
|
374
|
+
description: z.string().optional(),
|
|
375
|
+
/** JSON Schema object for the form fields. */
|
|
376
|
+
schema: z.record(z.string(), z.unknown()).optional(),
|
|
377
|
+
/** RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). */
|
|
378
|
+
ui: z.record(z.string(), z.unknown()).optional(),
|
|
379
|
+
/** Optional default field values. */
|
|
380
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
381
|
+
});
|
|
382
|
+
var agentChatSeedMessageSchema = z.object({
|
|
383
|
+
role: z.enum(["user", "assistant"]),
|
|
384
|
+
text: z.string().min(1),
|
|
385
|
+
/** Optional display-name override for the message sender. */
|
|
386
|
+
senderName: z.string().min(1).optional(),
|
|
387
|
+
/**
|
|
388
|
+
* Optional structured input request rendered as a styled RobotRock action
|
|
389
|
+
* widget below the message text. Use this instead of asking the user to reply
|
|
390
|
+
* in plain text so the request is always a proper action form.
|
|
391
|
+
*/
|
|
392
|
+
requestActionInput: z.object({
|
|
393
|
+
prompt: z.string().optional(),
|
|
394
|
+
action: agentChatSeedActionSchema
|
|
395
|
+
}).optional()
|
|
396
|
+
});
|
|
397
|
+
var createAgentChatBodySchema = z.object({
|
|
398
|
+
/** Trigger chat agent id (task slug). Required unless `parentChatId` is set. */
|
|
399
|
+
agentIdentifier: z.string().min(1).optional(),
|
|
400
|
+
/** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
|
|
401
|
+
parentChatId: z.string().min(1).optional(),
|
|
402
|
+
/** Convex tenantTriggerConnections id; resolved from the tenant when omitted. */
|
|
403
|
+
connectionId: z.string().min(1).optional(),
|
|
404
|
+
/** Source application id; groups the chat under an inbox section. */
|
|
405
|
+
app: z.string().min(1).optional(),
|
|
406
|
+
assignTo: assignToSchema.optional(),
|
|
407
|
+
title: z.string().min(1),
|
|
408
|
+
messages: z.array(agentChatSeedMessageSchema).default([]),
|
|
409
|
+
/** Provenance label stored on the session ("cron" | "agent" | ...). */
|
|
410
|
+
source: z.string().min(1).optional()
|
|
411
|
+
}).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
|
|
412
|
+
message: "Provide either agentIdentifier or parentChatId"
|
|
413
|
+
});
|
|
414
|
+
var agentChatTransportBodySchema = z.object({
|
|
415
|
+
chatId: z.string().min(1),
|
|
416
|
+
publicAccessToken: z.string().min(1),
|
|
417
|
+
lastEventId: z.string().optional(),
|
|
418
|
+
isStreaming: z.boolean().optional()
|
|
419
|
+
});
|
|
404
420
|
|
|
405
421
|
// src/schemas/index.ts
|
|
406
422
|
var safeUrlSchema2 = z2.string().refine((url) => isPublicHttpUrl(url), {
|
|
@@ -423,13 +439,15 @@ var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
|
423
439
|
tokenId: z2.string().min(1)
|
|
424
440
|
});
|
|
425
441
|
var handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
|
|
426
|
-
var
|
|
442
|
+
var taskActionInputSchema2 = z2.object({
|
|
427
443
|
id: z2.string().min(1),
|
|
428
444
|
title: z2.string().min(1),
|
|
429
445
|
description: z2.string().optional(),
|
|
430
446
|
schema: jsonSchema7Schema2.optional(),
|
|
431
447
|
ui: uiSchemaSchema2.optional(),
|
|
432
|
-
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
448
|
+
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
449
|
+
});
|
|
450
|
+
var taskActionSchema2 = taskActionInputSchema2.extend({
|
|
433
451
|
handlers: z2.array(handlerSchema2).min(1).optional()
|
|
434
452
|
});
|
|
435
453
|
var uiFieldSchemaSchema2 = z2.object({
|
|
@@ -444,16 +462,29 @@ var contextDataSchema2 = z2.object({
|
|
|
444
462
|
data: z2.record(z2.string(), z2.unknown()),
|
|
445
463
|
ui: contextUiSchema2
|
|
446
464
|
}).optional();
|
|
447
|
-
var
|
|
465
|
+
var TASK_CONTEXT_FORMAT_VERSION2 = 2;
|
|
466
|
+
var taskContextObjectBaseSchema2 = z2.object({
|
|
448
467
|
app: z2.string().min(1).optional(),
|
|
449
468
|
type: z2.string().min(1),
|
|
450
469
|
name: z2.string().min(1),
|
|
451
470
|
description: z2.string().optional(),
|
|
452
471
|
validUntil: z2.string().optional(),
|
|
453
472
|
context: contextDataSchema2,
|
|
473
|
+
contextVersion: z2.literal(2).optional(),
|
|
474
|
+
/** @deprecated Use `contextVersion`. Accepted on ingest only. */
|
|
454
475
|
version: z2.literal(2).optional(),
|
|
455
476
|
actions: z2.array(taskActionSchema2).min(1, "At least one action is required")
|
|
456
477
|
});
|
|
478
|
+
function normalizeTaskContextVersion2(data) {
|
|
479
|
+
const { version: legacyVersion, contextVersion, ...rest } = data;
|
|
480
|
+
return {
|
|
481
|
+
...rest,
|
|
482
|
+
contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION2
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
var taskContextObjectSchema2 = taskContextObjectBaseSchema2.transform(
|
|
486
|
+
normalizeTaskContextVersion2
|
|
487
|
+
);
|
|
457
488
|
function refineContextPublicUrls2(data, ctx) {
|
|
458
489
|
const error = validateContextPublicUrls(data.context);
|
|
459
490
|
if (error) {
|
|
@@ -497,56 +528,10 @@ var threadUpdateInputSchema2 = z2.object({
|
|
|
497
528
|
});
|
|
498
529
|
var taskPriorities2 = ["low", "normal", "high", "urgent"];
|
|
499
530
|
var taskPrioritySchema2 = z2.enum(taskPriorities2);
|
|
500
|
-
var nonNegativeInt2 = z2.number().int().nonnegative();
|
|
501
|
-
var agentCostTokensSchema2 = z2.object({
|
|
502
|
-
input: nonNegativeInt2.optional(),
|
|
503
|
-
output: nonNegativeInt2.optional(),
|
|
504
|
-
total: nonNegativeInt2.optional()
|
|
505
|
-
});
|
|
506
|
-
var agentCostSchema2 = z2.object({
|
|
507
|
-
tokens: agentCostTokensSchema2.optional(),
|
|
508
|
-
eur: z2.number().nonnegative().optional(),
|
|
509
|
-
usd: z2.number().nonnegative().optional()
|
|
510
|
-
});
|
|
511
|
-
var AGENT_INFO_MAX_KEYS2 = 32;
|
|
512
|
-
var AGENT_TOOL_CALLS_MAX_KEYS2 = 64;
|
|
513
|
-
var AGENT_OTEL_SPANS_MAX2 = 32;
|
|
514
|
-
var agentToolCallsSchema2 = z2.record(z2.string().min(1), nonNegativeInt2);
|
|
515
|
-
var agentOtelSpanStatusSchema2 = z2.enum(["ok", "error"]);
|
|
516
|
-
var agentOtelSpanSummarySchema2 = z2.object({
|
|
517
|
-
name: z2.string().min(1),
|
|
518
|
-
durationMs: z2.number().nonnegative(),
|
|
519
|
-
status: agentOtelSpanStatusSchema2
|
|
520
|
-
});
|
|
521
|
-
var agentOtelSchema2 = z2.object({
|
|
522
|
-
traceId: z2.string().min(1),
|
|
523
|
-
spanId: z2.string().min(1).optional(),
|
|
524
|
-
rootDurationMs: z2.number().nonnegative().optional(),
|
|
525
|
-
spans: z2.array(agentOtelSpanSummarySchema2).max(AGENT_OTEL_SPANS_MAX2).optional()
|
|
526
|
-
});
|
|
527
531
|
var agentTelemetrySchema2 = z2.object({
|
|
528
|
-
version: z2.string().min(1)
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
cost: agentCostSchema2.optional(),
|
|
532
|
-
info: z2.record(z2.string(), z2.unknown()).optional(),
|
|
533
|
-
otel: agentOtelSchema2.optional()
|
|
534
|
-
}).refine(
|
|
535
|
-
(data) => {
|
|
536
|
-
const keys = data.info ? Object.keys(data.info) : [];
|
|
537
|
-
return keys.length <= AGENT_INFO_MAX_KEYS2;
|
|
538
|
-
},
|
|
539
|
-
{ message: `agent.info may contain at most ${AGENT_INFO_MAX_KEYS2} keys` }
|
|
540
|
-
).refine(
|
|
541
|
-
(data) => {
|
|
542
|
-
const keys = data.toolCalls ? Object.keys(data.toolCalls) : [];
|
|
543
|
-
return keys.length <= AGENT_TOOL_CALLS_MAX_KEYS2;
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
message: `agent.toolCalls may contain at most ${AGENT_TOOL_CALLS_MAX_KEYS2} tool names`
|
|
547
|
-
}
|
|
548
|
-
);
|
|
549
|
-
var createTaskBodySchema2 = taskContextObjectSchema2.extend({
|
|
532
|
+
version: z2.string().min(1)
|
|
533
|
+
});
|
|
534
|
+
var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
|
|
550
535
|
assignTo: assignToSchema2.optional(),
|
|
551
536
|
/**
|
|
552
537
|
* Groups related tasks together. When omitted, the server generates one and
|
|
@@ -564,7 +549,7 @@ var createTaskBodySchema2 = taskContextObjectSchema2.extend({
|
|
|
564
549
|
*/
|
|
565
550
|
update: threadUpdateInputSchema2.optional(),
|
|
566
551
|
agent: agentTelemetrySchema2.optional()
|
|
567
|
-
}).superRefine(refineContextPublicUrls2);
|
|
552
|
+
}).transform(normalizeTaskContextVersion2).superRefine(refineContextPublicUrls2);
|
|
568
553
|
var threadUpdateBodySchema = threadUpdateInputSchema2;
|
|
569
554
|
|
|
570
555
|
// src/approval-result.ts
|
|
@@ -594,12 +579,159 @@ function toDiscriminatedApprovalResult(actions, task) {
|
|
|
594
579
|
};
|
|
595
580
|
}
|
|
596
581
|
|
|
582
|
+
// src/http.ts
|
|
583
|
+
var RobotRockError = class extends Error {
|
|
584
|
+
constructor(message, statusCode, response) {
|
|
585
|
+
super(message);
|
|
586
|
+
this.statusCode = statusCode;
|
|
587
|
+
this.response = response;
|
|
588
|
+
this.name = "RobotRockError";
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
async function parseResponseBody(response) {
|
|
592
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
593
|
+
const bodyText = await response.text();
|
|
594
|
+
if (!bodyText) {
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
if (contentType.toLowerCase().includes("application/json")) {
|
|
598
|
+
try {
|
|
599
|
+
return JSON.parse(bodyText);
|
|
600
|
+
} catch {
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
return JSON.parse(bodyText);
|
|
605
|
+
} catch {
|
|
606
|
+
return bodyText;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function getErrorMessage(data, fallback) {
|
|
610
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
611
|
+
const maybeMessage = data.message;
|
|
612
|
+
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
613
|
+
return maybeMessage;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (typeof data === "string" && data.trim()) {
|
|
617
|
+
const compact = data.replace(/\s+/g, " ").trim();
|
|
618
|
+
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
619
|
+
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
620
|
+
}
|
|
621
|
+
return fallback;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// ../core/src/handler-retry.ts
|
|
625
|
+
var HANDLER_RETRY_DELAYS_MS = [
|
|
626
|
+
6e4,
|
|
627
|
+
// 1m
|
|
628
|
+
3e5,
|
|
629
|
+
// 5m
|
|
630
|
+
18e5,
|
|
631
|
+
// 30m
|
|
632
|
+
36e5,
|
|
633
|
+
// 1h
|
|
634
|
+
216e5,
|
|
635
|
+
// 6h
|
|
636
|
+
864e5,
|
|
637
|
+
// 24h
|
|
638
|
+
1728e5
|
|
639
|
+
// 48h
|
|
640
|
+
];
|
|
641
|
+
var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
|
|
642
|
+
|
|
643
|
+
// ../core/src/attribution/index.ts
|
|
644
|
+
import { z as z3 } from "zod";
|
|
645
|
+
|
|
646
|
+
// ../core/src/app-url.ts
|
|
647
|
+
var PRODUCTION_APP_URL = "https://app.robotrock.io";
|
|
648
|
+
var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
|
|
649
|
+
|
|
650
|
+
// ../core/src/attribution/index.ts
|
|
651
|
+
var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
|
|
652
|
+
var attributionSchema = z3.object({
|
|
653
|
+
utmSource: z3.string().optional(),
|
|
654
|
+
utmMedium: z3.string().optional(),
|
|
655
|
+
utmCampaign: z3.string().optional(),
|
|
656
|
+
utmContent: z3.string().optional(),
|
|
657
|
+
utmTerm: z3.string().optional(),
|
|
658
|
+
gclid: z3.string().optional(),
|
|
659
|
+
landingUrl: z3.string().optional(),
|
|
660
|
+
referrer: z3.string().optional(),
|
|
661
|
+
capturedAt: z3.number()
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
// src/chats.ts
|
|
665
|
+
function createChatsApi(config) {
|
|
666
|
+
const headers = () => ({
|
|
667
|
+
"Content-Type": "application/json",
|
|
668
|
+
"X-Api-Key": config.apiKey
|
|
669
|
+
});
|
|
670
|
+
return {
|
|
671
|
+
async create(input) {
|
|
672
|
+
const bodyPayload = {
|
|
673
|
+
...input,
|
|
674
|
+
app: input.app ?? config.app,
|
|
675
|
+
messages: input.messages ?? []
|
|
676
|
+
};
|
|
677
|
+
const validation = createAgentChatBodySchema.safeParse(bodyPayload);
|
|
678
|
+
if (!validation.success) {
|
|
679
|
+
throw new RobotRockError(
|
|
680
|
+
`Invalid chat: ${validation.error.issues[0]?.message}`,
|
|
681
|
+
400,
|
|
682
|
+
validation.error.issues
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
const response = await fetch(`${config.baseUrl}/agent-chats`, {
|
|
686
|
+
method: "POST",
|
|
687
|
+
headers: headers(),
|
|
688
|
+
body: JSON.stringify(validation.data)
|
|
689
|
+
});
|
|
690
|
+
const data = await parseResponseBody(response);
|
|
691
|
+
if (!response.ok) {
|
|
692
|
+
throw new RobotRockError(
|
|
693
|
+
getErrorMessage(data, "Failed to create chat"),
|
|
694
|
+
response.status,
|
|
695
|
+
data
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
const result = data;
|
|
699
|
+
return { tenantSlug: result.tenantSlug, chats: result.chats };
|
|
700
|
+
},
|
|
701
|
+
async close(chatId, options) {
|
|
702
|
+
if (!chatId) {
|
|
703
|
+
throw new RobotRockError("chatId is required to close a chat", 400);
|
|
704
|
+
}
|
|
705
|
+
const response = await fetch(
|
|
706
|
+
`${config.baseUrl}/agent-chats/${encodeURIComponent(chatId)}/close`,
|
|
707
|
+
{
|
|
708
|
+
method: "POST",
|
|
709
|
+
headers: headers(),
|
|
710
|
+
body: JSON.stringify({ reason: options?.reason })
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
if (!response.ok) {
|
|
714
|
+
const data = await parseResponseBody(response);
|
|
715
|
+
throw new RobotRockError(
|
|
716
|
+
getErrorMessage(data, "Failed to close chat"),
|
|
717
|
+
response.status,
|
|
718
|
+
data
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
597
725
|
// src/client.ts
|
|
598
726
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
599
727
|
var DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
600
728
|
function sleep(ms) {
|
|
601
729
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
602
730
|
}
|
|
731
|
+
function resolveAgentVersionFromEnv() {
|
|
732
|
+
const fromEnv = process.env.AGENT_VERSION?.trim() || process.env.ROBOTROCK_AGENT_VERSION?.trim();
|
|
733
|
+
return fromEnv || void 0;
|
|
734
|
+
}
|
|
603
735
|
function parseValidUntilMs(value) {
|
|
604
736
|
if (value === void 0) {
|
|
605
737
|
return void 0;
|
|
@@ -627,21 +759,18 @@ function serializeValidUntil(value) {
|
|
|
627
759
|
}
|
|
628
760
|
throw new RobotRockError("Invalid validUntil: expected a Date or parseable date string", 400);
|
|
629
761
|
}
|
|
630
|
-
var RobotRockError = class extends Error {
|
|
631
|
-
constructor(message, statusCode, response) {
|
|
632
|
-
super(message);
|
|
633
|
-
this.statusCode = statusCode;
|
|
634
|
-
this.response = response;
|
|
635
|
-
this.name = "RobotRockError";
|
|
636
|
-
}
|
|
637
|
-
};
|
|
638
762
|
var RobotRock = class {
|
|
639
763
|
apiKey;
|
|
640
764
|
baseUrl;
|
|
641
765
|
app;
|
|
642
|
-
|
|
766
|
+
agentVersion;
|
|
767
|
+
contextVersion;
|
|
643
768
|
webhook;
|
|
644
769
|
polling;
|
|
770
|
+
/** Task CRUD: `create`, `get`, `cancel`, `sendUpdate`. */
|
|
771
|
+
tasks;
|
|
772
|
+
/** Chat CRUD: `create`, `close`. */
|
|
773
|
+
chats;
|
|
645
774
|
constructor(config) {
|
|
646
775
|
if (config.webhook && config.polling) {
|
|
647
776
|
throw new Error(
|
|
@@ -658,26 +787,37 @@ var RobotRock = class {
|
|
|
658
787
|
const rawBase = config.baseUrl ?? "https://api.robotrock.io/v1";
|
|
659
788
|
this.baseUrl = rawBase.replace(/\/+$/, "");
|
|
660
789
|
this.app = config.app;
|
|
661
|
-
this.
|
|
790
|
+
this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
|
|
791
|
+
this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
|
|
662
792
|
this.webhook = config.webhook;
|
|
663
793
|
this.polling = config.polling ?? {};
|
|
794
|
+
this.tasks = {
|
|
795
|
+
create: (task) => this.createTaskRequest(task),
|
|
796
|
+
get: (taskId) => this.getTaskById(taskId),
|
|
797
|
+
cancel: (taskId) => this.cancelTaskRequest(taskId),
|
|
798
|
+
sendUpdate: (input) => this.sendThreadUpdate(input)
|
|
799
|
+
};
|
|
800
|
+
this.chats = createChatsApi({
|
|
801
|
+
baseUrl: this.baseUrl,
|
|
802
|
+
apiKey: this.apiKey,
|
|
803
|
+
app: this.app
|
|
804
|
+
});
|
|
664
805
|
}
|
|
665
|
-
|
|
666
|
-
* Create a task via POST /v1 without waiting for a human response.
|
|
667
|
-
*/
|
|
668
|
-
async createTask(task) {
|
|
806
|
+
async createTaskRequest(task) {
|
|
669
807
|
const normalizedTask = normalizeSendToHumanInput(task, {
|
|
670
808
|
webhook: this.webhook,
|
|
671
809
|
app: this.app,
|
|
672
|
-
|
|
810
|
+
contextVersion: this.contextVersion,
|
|
811
|
+
agentVersion: this.agentVersion
|
|
673
812
|
});
|
|
813
|
+
const agentVersion = task.version ?? this.agentVersion;
|
|
674
814
|
const bodyPayload = {
|
|
675
815
|
...normalizedTask,
|
|
676
816
|
...task.assignTo !== void 0 ? { assignTo: task.assignTo } : {},
|
|
677
817
|
...task.threadId !== void 0 ? { threadId: task.threadId } : {},
|
|
678
818
|
...task.priority !== void 0 ? { priority: task.priority } : {},
|
|
679
819
|
...task.update !== void 0 ? { update: task.update } : {},
|
|
680
|
-
...
|
|
820
|
+
...agentVersion !== void 0 ? { agent: { version: agentVersion } } : {}
|
|
681
821
|
};
|
|
682
822
|
const validation = createTaskBodySchema2.safeParse(bodyPayload);
|
|
683
823
|
if (!validation.success) {
|
|
@@ -713,9 +853,10 @@ var RobotRock = class {
|
|
|
713
853
|
const normalizedTask = normalizeSendToHumanInput(task, {
|
|
714
854
|
webhook: this.webhook,
|
|
715
855
|
app: this.app,
|
|
716
|
-
|
|
856
|
+
contextVersion: this.contextVersion,
|
|
857
|
+
agentVersion: this.agentVersion
|
|
717
858
|
});
|
|
718
|
-
const createdTaskTask = await this.
|
|
859
|
+
const createdTaskTask = await this.createTaskRequest(task);
|
|
719
860
|
const hasHandlers = normalizedTask.actions.some(
|
|
720
861
|
(action) => Array.isArray(action.handlers) && action.handlers.length > 0
|
|
721
862
|
);
|
|
@@ -732,7 +873,7 @@ var RobotRock = class {
|
|
|
732
873
|
const deadline = validUntilMs !== void 0 ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;
|
|
733
874
|
const taskId = createdTaskTask.taskId;
|
|
734
875
|
while (Date.now() < deadline) {
|
|
735
|
-
const existing = await this.
|
|
876
|
+
const existing = await this.getTaskById(taskId);
|
|
736
877
|
if (existing?.status === "handled" && existing.handled) {
|
|
737
878
|
return {
|
|
738
879
|
mode: "handled",
|
|
@@ -754,10 +895,35 @@ var RobotRock = class {
|
|
|
754
895
|
}
|
|
755
896
|
throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);
|
|
756
897
|
}
|
|
898
|
+
/**
|
|
899
|
+
* Create a task via POST /v1 without waiting for a human response.
|
|
900
|
+
* @deprecated Use `client.tasks.create()` instead.
|
|
901
|
+
*/
|
|
902
|
+
async createTask(task) {
|
|
903
|
+
return this.tasks.create(task);
|
|
904
|
+
}
|
|
757
905
|
/**
|
|
758
906
|
* Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
|
|
907
|
+
* @deprecated Use `client.tasks.get()` instead.
|
|
759
908
|
*/
|
|
760
909
|
async getTask(taskId) {
|
|
910
|
+
return this.tasks.get(taskId);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Log a status update against a thread.
|
|
914
|
+
* @deprecated Use `client.tasks.sendUpdate()` instead.
|
|
915
|
+
*/
|
|
916
|
+
async sendUpdate(input) {
|
|
917
|
+
return this.tasks.sendUpdate(input);
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Cancel a task by public task id.
|
|
921
|
+
* @deprecated Use `client.tasks.cancel()` instead.
|
|
922
|
+
*/
|
|
923
|
+
async cancelTask(taskId) {
|
|
924
|
+
return this.tasks.cancel(taskId);
|
|
925
|
+
}
|
|
926
|
+
async getTaskById(taskId) {
|
|
761
927
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
|
|
762
928
|
method: "GET",
|
|
763
929
|
headers: {
|
|
@@ -777,11 +943,11 @@ var RobotRock = class {
|
|
|
777
943
|
}
|
|
778
944
|
return data;
|
|
779
945
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
946
|
+
async sendThreadUpdate({
|
|
947
|
+
threadId,
|
|
948
|
+
message,
|
|
949
|
+
status
|
|
950
|
+
}) {
|
|
785
951
|
if (!threadId) {
|
|
786
952
|
throw new RobotRockError("threadId is required to send an update", 400);
|
|
787
953
|
}
|
|
@@ -814,7 +980,7 @@ var RobotRock = class {
|
|
|
814
980
|
}
|
|
815
981
|
return data.update;
|
|
816
982
|
}
|
|
817
|
-
async
|
|
983
|
+
async cancelTaskRequest(taskId) {
|
|
818
984
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
|
|
819
985
|
method: "POST",
|
|
820
986
|
headers: {
|
|
@@ -857,6 +1023,7 @@ function normalizeSendToHumanInput(task, clientDefaults) {
|
|
|
857
1023
|
threadId: _threadId,
|
|
858
1024
|
priority: _priority,
|
|
859
1025
|
update: _update,
|
|
1026
|
+
version: _version,
|
|
860
1027
|
validUntil,
|
|
861
1028
|
app: taskApp,
|
|
862
1029
|
...rest
|
|
@@ -866,44 +1033,12 @@ function normalizeSendToHumanInput(task, clientDefaults) {
|
|
|
866
1033
|
const app = taskApp ?? clientDefaults.app;
|
|
867
1034
|
return {
|
|
868
1035
|
...rest,
|
|
869
|
-
|
|
1036
|
+
contextVersion: clientDefaults.contextVersion,
|
|
870
1037
|
...app ? { app } : {},
|
|
871
1038
|
...validUntil !== void 0 ? { validUntil: serializeValidUntil(validUntil) } : {},
|
|
872
1039
|
actions: normalizedActions
|
|
873
1040
|
};
|
|
874
1041
|
}
|
|
875
|
-
async function parseResponseBody(response) {
|
|
876
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
877
|
-
const bodyText = await response.text();
|
|
878
|
-
if (!bodyText) {
|
|
879
|
-
return null;
|
|
880
|
-
}
|
|
881
|
-
if (contentType.toLowerCase().includes("application/json")) {
|
|
882
|
-
try {
|
|
883
|
-
return JSON.parse(bodyText);
|
|
884
|
-
} catch {
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
try {
|
|
888
|
-
return JSON.parse(bodyText);
|
|
889
|
-
} catch {
|
|
890
|
-
return bodyText;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
function getErrorMessage(data, fallback) {
|
|
894
|
-
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
895
|
-
const maybeMessage = data.message;
|
|
896
|
-
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
897
|
-
return maybeMessage;
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
if (typeof data === "string" && data.trim()) {
|
|
901
|
-
const compact = data.replace(/\s+/g, " ").trim();
|
|
902
|
-
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
903
|
-
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
904
|
-
}
|
|
905
|
-
return fallback;
|
|
906
|
-
}
|
|
907
1042
|
|
|
908
1043
|
// src/env.ts
|
|
909
1044
|
var DEFAULT_BASE_URL = "https://api.robotrock.io/v1";
|
|
@@ -980,6 +1115,200 @@ function durationMsToTimeout(durationMs) {
|
|
|
980
1115
|
return `${seconds}s`;
|
|
981
1116
|
}
|
|
982
1117
|
|
|
1118
|
+
// src/record-handled-to-otel.ts
|
|
1119
|
+
import {
|
|
1120
|
+
context,
|
|
1121
|
+
trace,
|
|
1122
|
+
SpanStatusCode
|
|
1123
|
+
} from "@opentelemetry/api";
|
|
1124
|
+
var TRACER_NAME = "robotrock";
|
|
1125
|
+
var WAIT_SPAN_NAME = "robotrock.wait_for_human";
|
|
1126
|
+
var HANDLED_EVENT_NAME = "robotrock.task_handled";
|
|
1127
|
+
var INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
1128
|
+
function isValidTraceId(traceId) {
|
|
1129
|
+
return typeof traceId === "string" && traceId.length > 0 && traceId !== INVALID_TRACE_ID;
|
|
1130
|
+
}
|
|
1131
|
+
function resolveSpanContext(span) {
|
|
1132
|
+
const active = span ?? trace.getActiveSpan();
|
|
1133
|
+
const ctx = active?.spanContext();
|
|
1134
|
+
if (!ctx || !isValidTraceId(ctx.traceId)) {
|
|
1135
|
+
return void 0;
|
|
1136
|
+
}
|
|
1137
|
+
return { traceId: ctx.traceId, spanId: ctx.spanId };
|
|
1138
|
+
}
|
|
1139
|
+
function parseTaskCreatedAt(submittedAt) {
|
|
1140
|
+
if (submittedAt) {
|
|
1141
|
+
const parsed = Date.parse(submittedAt);
|
|
1142
|
+
if (!Number.isNaN(parsed)) {
|
|
1143
|
+
return parsed;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return Date.now();
|
|
1147
|
+
}
|
|
1148
|
+
function parseHandledAtMs(handledAt) {
|
|
1149
|
+
if (handledAt instanceof Date) {
|
|
1150
|
+
return handledAt.getTime();
|
|
1151
|
+
}
|
|
1152
|
+
if (typeof handledAt === "number") {
|
|
1153
|
+
return handledAt;
|
|
1154
|
+
}
|
|
1155
|
+
const parsed = Date.parse(handledAt);
|
|
1156
|
+
return Number.isNaN(parsed) ? Date.now() : parsed;
|
|
1157
|
+
}
|
|
1158
|
+
function toRobotRockHandledOtelInput(handled) {
|
|
1159
|
+
if ("actionId" in handled) {
|
|
1160
|
+
return {
|
|
1161
|
+
taskId: handled.taskId,
|
|
1162
|
+
action: {
|
|
1163
|
+
id: handled.actionId,
|
|
1164
|
+
data: handled.data
|
|
1165
|
+
},
|
|
1166
|
+
handledBy: handled.handledBy,
|
|
1167
|
+
handledAt: handled.handledAt
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
return {
|
|
1171
|
+
taskId: handled.taskId,
|
|
1172
|
+
action: {
|
|
1173
|
+
id: handled.action.id,
|
|
1174
|
+
title: handled.action.title,
|
|
1175
|
+
data: handled.action.data
|
|
1176
|
+
},
|
|
1177
|
+
handledBy: handled.handledBy,
|
|
1178
|
+
handledAt: handled.handledAt
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
function captureRobotRockOtelHandle(task, options) {
|
|
1182
|
+
const spanCtx = resolveSpanContext(options?.span);
|
|
1183
|
+
return {
|
|
1184
|
+
traceId: spanCtx?.traceId ?? "",
|
|
1185
|
+
spanId: spanCtx?.spanId ?? "",
|
|
1186
|
+
taskId: task.taskId,
|
|
1187
|
+
threadId: task.threadId,
|
|
1188
|
+
taskCreatedAt: parseTaskCreatedAt(task.submittedAt)
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
function startRobotRockHumanWaitSpan(handle, options) {
|
|
1192
|
+
const parent = options?.span ?? trace.getActiveSpan();
|
|
1193
|
+
if (!parent) {
|
|
1194
|
+
return void 0;
|
|
1195
|
+
}
|
|
1196
|
+
const tracer = trace.getTracer(options?.tracerName ?? TRACER_NAME);
|
|
1197
|
+
const span = tracer.startSpan(
|
|
1198
|
+
WAIT_SPAN_NAME,
|
|
1199
|
+
{},
|
|
1200
|
+
trace.setSpan(context.active(), parent)
|
|
1201
|
+
);
|
|
1202
|
+
span.setAttribute("robotrock.task_id", handle.taskId);
|
|
1203
|
+
if (handle.threadId) {
|
|
1204
|
+
span.setAttribute("robotrock.thread_id", handle.threadId);
|
|
1205
|
+
}
|
|
1206
|
+
return span;
|
|
1207
|
+
}
|
|
1208
|
+
function recordRobotRockHandledToOtel(handled, options = {}) {
|
|
1209
|
+
const span = options.span ?? trace.getActiveSpan();
|
|
1210
|
+
if (!span) {
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
const input = toRobotRockHandledOtelInput(handled);
|
|
1214
|
+
const handledAtMs = parseHandledAtMs(input.handledAt);
|
|
1215
|
+
const handle = options.handle;
|
|
1216
|
+
const humanWaitMs = handle != null ? Math.max(0, handledAtMs - handle.taskCreatedAt) : void 0;
|
|
1217
|
+
span.setAttribute("robotrock.task_id", input.taskId);
|
|
1218
|
+
span.setAttribute("robotrock.action.id", input.action.id);
|
|
1219
|
+
if (input.action.title) {
|
|
1220
|
+
span.setAttribute("robotrock.action.title", input.action.title);
|
|
1221
|
+
}
|
|
1222
|
+
if (input.handledBy) {
|
|
1223
|
+
span.setAttribute("robotrock.handled_by", input.handledBy);
|
|
1224
|
+
}
|
|
1225
|
+
span.setAttribute("robotrock.handled_at", new Date(handledAtMs).toISOString());
|
|
1226
|
+
if (humanWaitMs != null) {
|
|
1227
|
+
span.setAttribute("robotrock.human_wait_ms", humanWaitMs);
|
|
1228
|
+
}
|
|
1229
|
+
if (input.threadId) {
|
|
1230
|
+
span.setAttribute("robotrock.thread_id", input.threadId);
|
|
1231
|
+
}
|
|
1232
|
+
const eventAttributes = {
|
|
1233
|
+
"robotrock.task_id": input.taskId,
|
|
1234
|
+
"robotrock.action.id": input.action.id
|
|
1235
|
+
};
|
|
1236
|
+
if (input.handledBy) {
|
|
1237
|
+
eventAttributes["robotrock.handled_by"] = input.handledBy;
|
|
1238
|
+
}
|
|
1239
|
+
if (humanWaitMs != null) {
|
|
1240
|
+
eventAttributes["robotrock.human_wait_ms"] = humanWaitMs;
|
|
1241
|
+
}
|
|
1242
|
+
if (options.includeActionData && input.action.data != null) {
|
|
1243
|
+
const serialized = JSON.stringify(input.action.data);
|
|
1244
|
+
const truncated = serialized.length > 512 ? `${serialized.slice(0, 512)}\u2026` : serialized;
|
|
1245
|
+
span.setAttribute("robotrock.action.data", truncated);
|
|
1246
|
+
eventAttributes["robotrock.action.data"] = truncated;
|
|
1247
|
+
}
|
|
1248
|
+
span.addEvent(HANDLED_EVENT_NAME, eventAttributes);
|
|
1249
|
+
}
|
|
1250
|
+
function endRobotRockHumanWaitSpan(span, handled, options = {}) {
|
|
1251
|
+
if (!span) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
const outcome = options.outcome ?? (handled ? "handled" : "timeout");
|
|
1255
|
+
if (handled && outcome === "handled") {
|
|
1256
|
+
recordRobotRockHandledToOtel(handled, {
|
|
1257
|
+
span,
|
|
1258
|
+
handle: options.handle,
|
|
1259
|
+
includeActionData: options.includeActionData
|
|
1260
|
+
});
|
|
1261
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1262
|
+
} else {
|
|
1263
|
+
span.setAttribute("robotrock.outcome", outcome);
|
|
1264
|
+
span.setStatus({
|
|
1265
|
+
code: SpanStatusCode.ERROR,
|
|
1266
|
+
message: outcome === "timeout" ? "Human response timed out before validUntil" : "Human wait failed"
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
span.end();
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/otel-platform.ts
|
|
1273
|
+
function shouldRecordRobotRockOtel(recordOtel) {
|
|
1274
|
+
if (recordOtel === true) {
|
|
1275
|
+
return true;
|
|
1276
|
+
}
|
|
1277
|
+
if (recordOtel === false) {
|
|
1278
|
+
return false;
|
|
1279
|
+
}
|
|
1280
|
+
const env = process.env.ROBOTROCK_OTEL_RECORD_HANDLED;
|
|
1281
|
+
return env === "true" || env === "1";
|
|
1282
|
+
}
|
|
1283
|
+
function stripPlatformOtelFields(payload) {
|
|
1284
|
+
const { recordOtel: _recordOtel, otelIncludeActionData: _otelIncludeActionData, ...rest } = payload;
|
|
1285
|
+
return rest;
|
|
1286
|
+
}
|
|
1287
|
+
function beginRobotRockHumanWaitOtel(task, options = {}) {
|
|
1288
|
+
const recordOtel = shouldRecordRobotRockOtel(options.recordOtel);
|
|
1289
|
+
if (!recordOtel) {
|
|
1290
|
+
return { recordOtel: false };
|
|
1291
|
+
}
|
|
1292
|
+
const handle = captureRobotRockOtelHandle(task);
|
|
1293
|
+
const waitSpan = startRobotRockHumanWaitSpan(handle);
|
|
1294
|
+
return {
|
|
1295
|
+
recordOtel: true,
|
|
1296
|
+
handle,
|
|
1297
|
+
waitSpan,
|
|
1298
|
+
includeActionData: options.otelIncludeActionData
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
function finishRobotRockHumanWaitOtel(session, handled, outcome) {
|
|
1302
|
+
if (!session.recordOtel) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
endRobotRockHumanWaitSpan(session.waitSpan, handled, {
|
|
1306
|
+
handle: session.handle,
|
|
1307
|
+
outcome,
|
|
1308
|
+
includeActionData: session.includeActionData
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
|
|
983
1312
|
// src/workflow/index.ts
|
|
984
1313
|
var APPROVE_BY_HUMAN_ACTIONS = [
|
|
985
1314
|
{ id: "approve", title: "Approve" },
|
|
@@ -993,6 +1322,7 @@ async function createRobotRockTaskForWebhook(input) {
|
|
|
993
1322
|
baseUrl: baseConfig.baseUrl,
|
|
994
1323
|
...input.app ?? baseConfig.app ? { app: input.app ?? baseConfig.app } : {},
|
|
995
1324
|
...baseConfig.version ? { version: baseConfig.version } : {},
|
|
1325
|
+
...baseConfig.advanced ? { advanced: baseConfig.advanced } : {},
|
|
996
1326
|
webhook: { url: input.webhookUrl }
|
|
997
1327
|
});
|
|
998
1328
|
return client.sendToHuman({
|
|
@@ -1013,7 +1343,7 @@ async function parseRobotRockWebhookRequest(request) {
|
|
|
1013
1343
|
async function sendToHumanInWorkflow(payload) {
|
|
1014
1344
|
var _stack = [];
|
|
1015
1345
|
try {
|
|
1016
|
-
const { validUntil: validUntilInput, app, ...
|
|
1346
|
+
const { validUntil: validUntilInput, app, recordOtel, otelIncludeActionData, ...taskFields } = payload;
|
|
1017
1347
|
const { validUntil, timeout } = resolveWaitTiming(validUntilInput);
|
|
1018
1348
|
const timeoutMs = parseValidUntilMs2(validUntil) - Date.now();
|
|
1019
1349
|
const webhook = __using(_stack, createWebhook());
|
|
@@ -1021,31 +1351,54 @@ async function sendToHumanInWorkflow(payload) {
|
|
|
1021
1351
|
webhookUrl: webhook.url,
|
|
1022
1352
|
app,
|
|
1023
1353
|
validUntil,
|
|
1024
|
-
taskInput
|
|
1354
|
+
taskInput: stripPlatformOtelFields(taskFields)
|
|
1025
1355
|
});
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
]);
|
|
1030
|
-
if ("timedOut" in outcome) {
|
|
1031
|
-
throw new Error(`Human response timed out before validUntil (${timeout})`);
|
|
1032
|
-
}
|
|
1033
|
-
const output = outcome;
|
|
1034
|
-
return toDiscriminatedApprovalResult(payload.actions, {
|
|
1035
|
-
id: output.taskId,
|
|
1036
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
1037
|
-
status: "handled",
|
|
1038
|
-
context: sendResult.task.context,
|
|
1039
|
-
validUntil: Date.now(),
|
|
1040
|
-
handledAt: new Date(output.handledAt).getTime(),
|
|
1041
|
-
handled: {
|
|
1042
|
-
action: {
|
|
1043
|
-
id: output.action.id,
|
|
1044
|
-
data: output.action.data
|
|
1045
|
-
},
|
|
1046
|
-
handledBy: output.handledBy
|
|
1047
|
-
}
|
|
1356
|
+
const otelSession = beginRobotRockHumanWaitOtel(sendResult.task, {
|
|
1357
|
+
recordOtel,
|
|
1358
|
+
otelIncludeActionData
|
|
1048
1359
|
});
|
|
1360
|
+
let handledPayload = null;
|
|
1361
|
+
let waitOutcome = "pending";
|
|
1362
|
+
try {
|
|
1363
|
+
const outcome = await Promise.race([
|
|
1364
|
+
webhook.then((request) => parseRobotRockWebhookRequest(request)),
|
|
1365
|
+
sleep2(timeoutMs).then(() => ({ timedOut: true }))
|
|
1366
|
+
]);
|
|
1367
|
+
if ("timedOut" in outcome) {
|
|
1368
|
+
waitOutcome = "timeout";
|
|
1369
|
+
throw new Error(`Human response timed out before validUntil (${timeout})`);
|
|
1370
|
+
}
|
|
1371
|
+
handledPayload = outcome;
|
|
1372
|
+
waitOutcome = "handled";
|
|
1373
|
+
return toDiscriminatedApprovalResult(payload.actions, {
|
|
1374
|
+
id: outcome.taskId,
|
|
1375
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1376
|
+
status: "handled",
|
|
1377
|
+
context: sendResult.task.context,
|
|
1378
|
+
validUntil: Date.now(),
|
|
1379
|
+
handledAt: new Date(outcome.handledAt).getTime(),
|
|
1380
|
+
handled: {
|
|
1381
|
+
action: {
|
|
1382
|
+
id: outcome.action.id,
|
|
1383
|
+
data: outcome.action.data
|
|
1384
|
+
},
|
|
1385
|
+
handledBy: outcome.handledBy
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
} catch (error) {
|
|
1389
|
+
if (waitOutcome === "pending") {
|
|
1390
|
+
waitOutcome = "error";
|
|
1391
|
+
}
|
|
1392
|
+
throw error;
|
|
1393
|
+
} finally {
|
|
1394
|
+
if (waitOutcome !== "pending") {
|
|
1395
|
+
finishRobotRockHumanWaitOtel(
|
|
1396
|
+
otelSession,
|
|
1397
|
+
handledPayload,
|
|
1398
|
+
waitOutcome === "handled" ? "handled" : waitOutcome
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1049
1402
|
} catch (_) {
|
|
1050
1403
|
var _error = _, _hasError = true;
|
|
1051
1404
|
} finally {
|
|
@@ -1066,9 +1419,10 @@ async function sendRobotRockUpdate(payload) {
|
|
|
1066
1419
|
apiKey: baseConfig.apiKey,
|
|
1067
1420
|
baseUrl: baseConfig.baseUrl,
|
|
1068
1421
|
...app ?? baseConfig.app ? { app: app ?? baseConfig.app } : {},
|
|
1069
|
-
...baseConfig.version ? { version: baseConfig.version } : {}
|
|
1422
|
+
...baseConfig.version ? { version: baseConfig.version } : {},
|
|
1423
|
+
...baseConfig.advanced ? { advanced: baseConfig.advanced } : {}
|
|
1070
1424
|
});
|
|
1071
|
-
return client.sendUpdate(update);
|
|
1425
|
+
return client.tasks.sendUpdate(update);
|
|
1072
1426
|
}
|
|
1073
1427
|
async function sendUpdateInWorkflow(payload) {
|
|
1074
1428
|
return sendRobotRockUpdate(payload);
|