robotrock 0.8.5 → 0.9.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 +4 -4
- package/dist/ai/index.js +398 -202
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/trigger.d.ts +3 -3
- package/dist/ai/trigger.js +398 -202
- package/dist/ai/trigger.js.map +1 -1
- package/dist/ai/workflow.d.ts +3 -3
- package/dist/ai/workflow.js +399 -203
- package/dist/ai/workflow.js.map +1 -1
- package/dist/{client-D-XEBOWd.d.ts → client-Cy7YLxms.d.ts} +17 -9
- package/dist/index.d.ts +9 -8
- package/dist/index.js +232 -207
- package/dist/index.js.map +1 -1
- package/dist/otel-platform-DzHyHkGk.d.ts +108 -0
- package/dist/schemas/index.d.ts +162 -104
- package/dist/schemas/index.js +39 -114
- package/dist/schemas/index.js.map +1 -1
- package/dist/{tool-approval-bridge-BKDY5NAY.d.ts → tool-approval-bridge-G765kMJR.d.ts} +1 -1
- package/dist/trigger/index.d.ts +6 -4
- package/dist/trigger/index.js +308 -145
- package/dist/trigger/index.js.map +1 -1
- package/dist/{trigger-CsOLTjsH.d.ts → trigger-D0shjqk0.d.ts} +2 -2
- package/dist/workflow/index.d.ts +6 -4
- package/dist/workflow/index.js +302 -142
- package/dist/workflow/index.js.map +1 -1
- package/package.json +1 -5
- 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
|
}
|
|
@@ -273,7 +273,8 @@ var contextDataSchema = z.object({
|
|
|
273
273
|
data: z.record(z.string(), z.unknown()),
|
|
274
274
|
ui: contextUiSchema
|
|
275
275
|
}).optional();
|
|
276
|
-
var
|
|
276
|
+
var TASK_CONTEXT_FORMAT_VERSION = 2;
|
|
277
|
+
var taskContextObjectBaseSchema = z.object({
|
|
277
278
|
/** Source application id; omitted tasks are grouped in the default inbox. */
|
|
278
279
|
app: z.string().min(1).optional(),
|
|
279
280
|
type: z.string().min(1),
|
|
@@ -281,9 +282,22 @@ var taskContextObjectSchema = z.object({
|
|
|
281
282
|
description: z.string().optional(),
|
|
282
283
|
validUntil: z.string().optional(),
|
|
283
284
|
context: contextDataSchema,
|
|
285
|
+
/** Task context wire format version. @default 2 */
|
|
286
|
+
contextVersion: z.literal(2).optional(),
|
|
287
|
+
/** @deprecated Use `contextVersion`. Accepted on ingest only. */
|
|
284
288
|
version: z.literal(2).optional(),
|
|
285
289
|
actions: z.array(taskActionSchema).min(1, "At least one action is required")
|
|
286
290
|
});
|
|
291
|
+
function normalizeTaskContextVersion(data) {
|
|
292
|
+
const { version: legacyVersion, contextVersion, ...rest } = data;
|
|
293
|
+
return {
|
|
294
|
+
...rest,
|
|
295
|
+
contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
var taskContextObjectSchema = taskContextObjectBaseSchema.transform(
|
|
299
|
+
normalizeTaskContextVersion
|
|
300
|
+
);
|
|
287
301
|
function refineContextPublicUrls(data, ctx) {
|
|
288
302
|
const error = validateContextPublicUrls(data.context);
|
|
289
303
|
if (error) {
|
|
@@ -327,61 +341,11 @@ var threadUpdateInputSchema = z.object({
|
|
|
327
341
|
});
|
|
328
342
|
var taskPriorities = ["low", "normal", "high", "urgent"];
|
|
329
343
|
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
344
|
var agentTelemetrySchema = z.object({
|
|
358
345
|
/** 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({
|
|
346
|
+
version: z.string().min(1)
|
|
347
|
+
});
|
|
348
|
+
var createTaskBodySchema = taskContextObjectBaseSchema.extend({
|
|
385
349
|
assignTo: assignToSchema.optional(),
|
|
386
350
|
/**
|
|
387
351
|
* Groups related tasks together. When omitted, the server generates one and
|
|
@@ -398,9 +362,9 @@ var createTaskBodySchema = taskContextObjectSchema.extend({
|
|
|
398
362
|
* the inbox status bar and the thread update log.
|
|
399
363
|
*/
|
|
400
364
|
update: threadUpdateInputSchema.optional(),
|
|
401
|
-
/** Agent
|
|
365
|
+
/** Agent release version — not shown in inbox UI. */
|
|
402
366
|
agent: agentTelemetrySchema.optional()
|
|
403
|
-
}).superRefine(refineContextPublicUrls);
|
|
367
|
+
}).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
|
|
404
368
|
|
|
405
369
|
// src/schemas/index.ts
|
|
406
370
|
var safeUrlSchema2 = z2.string().refine((url) => isPublicHttpUrl(url), {
|
|
@@ -444,16 +408,29 @@ var contextDataSchema2 = z2.object({
|
|
|
444
408
|
data: z2.record(z2.string(), z2.unknown()),
|
|
445
409
|
ui: contextUiSchema2
|
|
446
410
|
}).optional();
|
|
447
|
-
var
|
|
411
|
+
var TASK_CONTEXT_FORMAT_VERSION2 = 2;
|
|
412
|
+
var taskContextObjectBaseSchema2 = z2.object({
|
|
448
413
|
app: z2.string().min(1).optional(),
|
|
449
414
|
type: z2.string().min(1),
|
|
450
415
|
name: z2.string().min(1),
|
|
451
416
|
description: z2.string().optional(),
|
|
452
417
|
validUntil: z2.string().optional(),
|
|
453
418
|
context: contextDataSchema2,
|
|
419
|
+
contextVersion: z2.literal(2).optional(),
|
|
420
|
+
/** @deprecated Use `contextVersion`. Accepted on ingest only. */
|
|
454
421
|
version: z2.literal(2).optional(),
|
|
455
422
|
actions: z2.array(taskActionSchema2).min(1, "At least one action is required")
|
|
456
423
|
});
|
|
424
|
+
function normalizeTaskContextVersion2(data) {
|
|
425
|
+
const { version: legacyVersion, contextVersion, ...rest } = data;
|
|
426
|
+
return {
|
|
427
|
+
...rest,
|
|
428
|
+
contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION2
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
var taskContextObjectSchema2 = taskContextObjectBaseSchema2.transform(
|
|
432
|
+
normalizeTaskContextVersion2
|
|
433
|
+
);
|
|
457
434
|
function refineContextPublicUrls2(data, ctx) {
|
|
458
435
|
const error = validateContextPublicUrls(data.context);
|
|
459
436
|
if (error) {
|
|
@@ -497,56 +474,10 @@ var threadUpdateInputSchema2 = z2.object({
|
|
|
497
474
|
});
|
|
498
475
|
var taskPriorities2 = ["low", "normal", "high", "urgent"];
|
|
499
476
|
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
477
|
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({
|
|
478
|
+
version: z2.string().min(1)
|
|
479
|
+
});
|
|
480
|
+
var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
|
|
550
481
|
assignTo: assignToSchema2.optional(),
|
|
551
482
|
/**
|
|
552
483
|
* Groups related tasks together. When omitted, the server generates one and
|
|
@@ -564,7 +495,7 @@ var createTaskBodySchema2 = taskContextObjectSchema2.extend({
|
|
|
564
495
|
*/
|
|
565
496
|
update: threadUpdateInputSchema2.optional(),
|
|
566
497
|
agent: agentTelemetrySchema2.optional()
|
|
567
|
-
}).superRefine(refineContextPublicUrls2);
|
|
498
|
+
}).transform(normalizeTaskContextVersion2).superRefine(refineContextPublicUrls2);
|
|
568
499
|
var threadUpdateBodySchema = threadUpdateInputSchema2;
|
|
569
500
|
|
|
570
501
|
// src/approval-result.ts
|
|
@@ -600,6 +531,10 @@ var DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
|
600
531
|
function sleep(ms) {
|
|
601
532
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
602
533
|
}
|
|
534
|
+
function resolveAgentVersionFromEnv() {
|
|
535
|
+
const fromEnv = process.env.AGENT_VERSION?.trim() || process.env.ROBOTROCK_AGENT_VERSION?.trim();
|
|
536
|
+
return fromEnv || void 0;
|
|
537
|
+
}
|
|
603
538
|
function parseValidUntilMs(value) {
|
|
604
539
|
if (value === void 0) {
|
|
605
540
|
return void 0;
|
|
@@ -639,7 +574,8 @@ var RobotRock = class {
|
|
|
639
574
|
apiKey;
|
|
640
575
|
baseUrl;
|
|
641
576
|
app;
|
|
642
|
-
|
|
577
|
+
agentVersion;
|
|
578
|
+
contextVersion;
|
|
643
579
|
webhook;
|
|
644
580
|
polling;
|
|
645
581
|
constructor(config) {
|
|
@@ -658,7 +594,8 @@ var RobotRock = class {
|
|
|
658
594
|
const rawBase = config.baseUrl ?? "https://api.robotrock.io/v1";
|
|
659
595
|
this.baseUrl = rawBase.replace(/\/+$/, "");
|
|
660
596
|
this.app = config.app;
|
|
661
|
-
this.
|
|
597
|
+
this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
|
|
598
|
+
this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
|
|
662
599
|
this.webhook = config.webhook;
|
|
663
600
|
this.polling = config.polling ?? {};
|
|
664
601
|
}
|
|
@@ -669,15 +606,17 @@ var RobotRock = class {
|
|
|
669
606
|
const normalizedTask = normalizeSendToHumanInput(task, {
|
|
670
607
|
webhook: this.webhook,
|
|
671
608
|
app: this.app,
|
|
672
|
-
|
|
609
|
+
contextVersion: this.contextVersion,
|
|
610
|
+
agentVersion: this.agentVersion
|
|
673
611
|
});
|
|
612
|
+
const agentVersion = task.version ?? this.agentVersion;
|
|
674
613
|
const bodyPayload = {
|
|
675
614
|
...normalizedTask,
|
|
676
615
|
...task.assignTo !== void 0 ? { assignTo: task.assignTo } : {},
|
|
677
616
|
...task.threadId !== void 0 ? { threadId: task.threadId } : {},
|
|
678
617
|
...task.priority !== void 0 ? { priority: task.priority } : {},
|
|
679
618
|
...task.update !== void 0 ? { update: task.update } : {},
|
|
680
|
-
...
|
|
619
|
+
...agentVersion !== void 0 ? { agent: { version: agentVersion } } : {}
|
|
681
620
|
};
|
|
682
621
|
const validation = createTaskBodySchema2.safeParse(bodyPayload);
|
|
683
622
|
if (!validation.success) {
|
|
@@ -713,7 +652,8 @@ var RobotRock = class {
|
|
|
713
652
|
const normalizedTask = normalizeSendToHumanInput(task, {
|
|
714
653
|
webhook: this.webhook,
|
|
715
654
|
app: this.app,
|
|
716
|
-
|
|
655
|
+
contextVersion: this.contextVersion,
|
|
656
|
+
agentVersion: this.agentVersion
|
|
717
657
|
});
|
|
718
658
|
const createdTaskTask = await this.createTask(task);
|
|
719
659
|
const hasHandlers = normalizedTask.actions.some(
|
|
@@ -857,6 +797,7 @@ function normalizeSendToHumanInput(task, clientDefaults) {
|
|
|
857
797
|
threadId: _threadId,
|
|
858
798
|
priority: _priority,
|
|
859
799
|
update: _update,
|
|
800
|
+
version: _version,
|
|
860
801
|
validUntil,
|
|
861
802
|
app: taskApp,
|
|
862
803
|
...rest
|
|
@@ -866,7 +807,7 @@ function normalizeSendToHumanInput(task, clientDefaults) {
|
|
|
866
807
|
const app = taskApp ?? clientDefaults.app;
|
|
867
808
|
return {
|
|
868
809
|
...rest,
|
|
869
|
-
|
|
810
|
+
contextVersion: clientDefaults.contextVersion,
|
|
870
811
|
...app ? { app } : {},
|
|
871
812
|
...validUntil !== void 0 ? { validUntil: serializeValidUntil(validUntil) } : {},
|
|
872
813
|
actions: normalizedActions
|
|
@@ -980,6 +921,200 @@ function durationMsToTimeout(durationMs) {
|
|
|
980
921
|
return `${seconds}s`;
|
|
981
922
|
}
|
|
982
923
|
|
|
924
|
+
// src/record-handled-to-otel.ts
|
|
925
|
+
import {
|
|
926
|
+
context,
|
|
927
|
+
trace,
|
|
928
|
+
SpanStatusCode
|
|
929
|
+
} from "@opentelemetry/api";
|
|
930
|
+
var TRACER_NAME = "robotrock";
|
|
931
|
+
var WAIT_SPAN_NAME = "robotrock.wait_for_human";
|
|
932
|
+
var HANDLED_EVENT_NAME = "robotrock.task_handled";
|
|
933
|
+
var INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
934
|
+
function isValidTraceId(traceId) {
|
|
935
|
+
return typeof traceId === "string" && traceId.length > 0 && traceId !== INVALID_TRACE_ID;
|
|
936
|
+
}
|
|
937
|
+
function resolveSpanContext(span) {
|
|
938
|
+
const active = span ?? trace.getActiveSpan();
|
|
939
|
+
const ctx = active?.spanContext();
|
|
940
|
+
if (!ctx || !isValidTraceId(ctx.traceId)) {
|
|
941
|
+
return void 0;
|
|
942
|
+
}
|
|
943
|
+
return { traceId: ctx.traceId, spanId: ctx.spanId };
|
|
944
|
+
}
|
|
945
|
+
function parseTaskCreatedAt(submittedAt) {
|
|
946
|
+
if (submittedAt) {
|
|
947
|
+
const parsed = Date.parse(submittedAt);
|
|
948
|
+
if (!Number.isNaN(parsed)) {
|
|
949
|
+
return parsed;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
return Date.now();
|
|
953
|
+
}
|
|
954
|
+
function parseHandledAtMs(handledAt) {
|
|
955
|
+
if (handledAt instanceof Date) {
|
|
956
|
+
return handledAt.getTime();
|
|
957
|
+
}
|
|
958
|
+
if (typeof handledAt === "number") {
|
|
959
|
+
return handledAt;
|
|
960
|
+
}
|
|
961
|
+
const parsed = Date.parse(handledAt);
|
|
962
|
+
return Number.isNaN(parsed) ? Date.now() : parsed;
|
|
963
|
+
}
|
|
964
|
+
function toRobotRockHandledOtelInput(handled) {
|
|
965
|
+
if ("actionId" in handled) {
|
|
966
|
+
return {
|
|
967
|
+
taskId: handled.taskId,
|
|
968
|
+
action: {
|
|
969
|
+
id: handled.actionId,
|
|
970
|
+
data: handled.data
|
|
971
|
+
},
|
|
972
|
+
handledBy: handled.handledBy,
|
|
973
|
+
handledAt: handled.handledAt
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
return {
|
|
977
|
+
taskId: handled.taskId,
|
|
978
|
+
action: {
|
|
979
|
+
id: handled.action.id,
|
|
980
|
+
title: handled.action.title,
|
|
981
|
+
data: handled.action.data
|
|
982
|
+
},
|
|
983
|
+
handledBy: handled.handledBy,
|
|
984
|
+
handledAt: handled.handledAt
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
function captureRobotRockOtelHandle(task, options) {
|
|
988
|
+
const spanCtx = resolveSpanContext(options?.span);
|
|
989
|
+
return {
|
|
990
|
+
traceId: spanCtx?.traceId ?? "",
|
|
991
|
+
spanId: spanCtx?.spanId ?? "",
|
|
992
|
+
taskId: task.taskId,
|
|
993
|
+
threadId: task.threadId,
|
|
994
|
+
taskCreatedAt: parseTaskCreatedAt(task.submittedAt)
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
function startRobotRockHumanWaitSpan(handle, options) {
|
|
998
|
+
const parent = options?.span ?? trace.getActiveSpan();
|
|
999
|
+
if (!parent) {
|
|
1000
|
+
return void 0;
|
|
1001
|
+
}
|
|
1002
|
+
const tracer = trace.getTracer(options?.tracerName ?? TRACER_NAME);
|
|
1003
|
+
const span = tracer.startSpan(
|
|
1004
|
+
WAIT_SPAN_NAME,
|
|
1005
|
+
{},
|
|
1006
|
+
trace.setSpan(context.active(), parent)
|
|
1007
|
+
);
|
|
1008
|
+
span.setAttribute("robotrock.task_id", handle.taskId);
|
|
1009
|
+
if (handle.threadId) {
|
|
1010
|
+
span.setAttribute("robotrock.thread_id", handle.threadId);
|
|
1011
|
+
}
|
|
1012
|
+
return span;
|
|
1013
|
+
}
|
|
1014
|
+
function recordRobotRockHandledToOtel(handled, options = {}) {
|
|
1015
|
+
const span = options.span ?? trace.getActiveSpan();
|
|
1016
|
+
if (!span) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const input = toRobotRockHandledOtelInput(handled);
|
|
1020
|
+
const handledAtMs = parseHandledAtMs(input.handledAt);
|
|
1021
|
+
const handle = options.handle;
|
|
1022
|
+
const humanWaitMs = handle != null ? Math.max(0, handledAtMs - handle.taskCreatedAt) : void 0;
|
|
1023
|
+
span.setAttribute("robotrock.task_id", input.taskId);
|
|
1024
|
+
span.setAttribute("robotrock.action.id", input.action.id);
|
|
1025
|
+
if (input.action.title) {
|
|
1026
|
+
span.setAttribute("robotrock.action.title", input.action.title);
|
|
1027
|
+
}
|
|
1028
|
+
if (input.handledBy) {
|
|
1029
|
+
span.setAttribute("robotrock.handled_by", input.handledBy);
|
|
1030
|
+
}
|
|
1031
|
+
span.setAttribute("robotrock.handled_at", new Date(handledAtMs).toISOString());
|
|
1032
|
+
if (humanWaitMs != null) {
|
|
1033
|
+
span.setAttribute("robotrock.human_wait_ms", humanWaitMs);
|
|
1034
|
+
}
|
|
1035
|
+
if (input.threadId) {
|
|
1036
|
+
span.setAttribute("robotrock.thread_id", input.threadId);
|
|
1037
|
+
}
|
|
1038
|
+
const eventAttributes = {
|
|
1039
|
+
"robotrock.task_id": input.taskId,
|
|
1040
|
+
"robotrock.action.id": input.action.id
|
|
1041
|
+
};
|
|
1042
|
+
if (input.handledBy) {
|
|
1043
|
+
eventAttributes["robotrock.handled_by"] = input.handledBy;
|
|
1044
|
+
}
|
|
1045
|
+
if (humanWaitMs != null) {
|
|
1046
|
+
eventAttributes["robotrock.human_wait_ms"] = humanWaitMs;
|
|
1047
|
+
}
|
|
1048
|
+
if (options.includeActionData && input.action.data != null) {
|
|
1049
|
+
const serialized = JSON.stringify(input.action.data);
|
|
1050
|
+
const truncated = serialized.length > 512 ? `${serialized.slice(0, 512)}\u2026` : serialized;
|
|
1051
|
+
span.setAttribute("robotrock.action.data", truncated);
|
|
1052
|
+
eventAttributes["robotrock.action.data"] = truncated;
|
|
1053
|
+
}
|
|
1054
|
+
span.addEvent(HANDLED_EVENT_NAME, eventAttributes);
|
|
1055
|
+
}
|
|
1056
|
+
function endRobotRockHumanWaitSpan(span, handled, options = {}) {
|
|
1057
|
+
if (!span) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const outcome = options.outcome ?? (handled ? "handled" : "timeout");
|
|
1061
|
+
if (handled && outcome === "handled") {
|
|
1062
|
+
recordRobotRockHandledToOtel(handled, {
|
|
1063
|
+
span,
|
|
1064
|
+
handle: options.handle,
|
|
1065
|
+
includeActionData: options.includeActionData
|
|
1066
|
+
});
|
|
1067
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
1068
|
+
} else {
|
|
1069
|
+
span.setAttribute("robotrock.outcome", outcome);
|
|
1070
|
+
span.setStatus({
|
|
1071
|
+
code: SpanStatusCode.ERROR,
|
|
1072
|
+
message: outcome === "timeout" ? "Human response timed out before validUntil" : "Human wait failed"
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
span.end();
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// src/otel-platform.ts
|
|
1079
|
+
function shouldRecordRobotRockOtel(recordOtel) {
|
|
1080
|
+
if (recordOtel === true) {
|
|
1081
|
+
return true;
|
|
1082
|
+
}
|
|
1083
|
+
if (recordOtel === false) {
|
|
1084
|
+
return false;
|
|
1085
|
+
}
|
|
1086
|
+
const env = process.env.ROBOTROCK_OTEL_RECORD_HANDLED;
|
|
1087
|
+
return env === "true" || env === "1";
|
|
1088
|
+
}
|
|
1089
|
+
function stripPlatformOtelFields(payload) {
|
|
1090
|
+
const { recordOtel: _recordOtel, otelIncludeActionData: _otelIncludeActionData, ...rest } = payload;
|
|
1091
|
+
return rest;
|
|
1092
|
+
}
|
|
1093
|
+
function beginRobotRockHumanWaitOtel(task, options = {}) {
|
|
1094
|
+
const recordOtel = shouldRecordRobotRockOtel(options.recordOtel);
|
|
1095
|
+
if (!recordOtel) {
|
|
1096
|
+
return { recordOtel: false };
|
|
1097
|
+
}
|
|
1098
|
+
const handle = captureRobotRockOtelHandle(task);
|
|
1099
|
+
const waitSpan = startRobotRockHumanWaitSpan(handle);
|
|
1100
|
+
return {
|
|
1101
|
+
recordOtel: true,
|
|
1102
|
+
handle,
|
|
1103
|
+
waitSpan,
|
|
1104
|
+
includeActionData: options.otelIncludeActionData
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
function finishRobotRockHumanWaitOtel(session, handled, outcome) {
|
|
1108
|
+
if (!session.recordOtel) {
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
endRobotRockHumanWaitSpan(session.waitSpan, handled, {
|
|
1112
|
+
handle: session.handle,
|
|
1113
|
+
outcome,
|
|
1114
|
+
includeActionData: session.includeActionData
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
|
|
983
1118
|
// src/workflow/index.ts
|
|
984
1119
|
var APPROVE_BY_HUMAN_ACTIONS = [
|
|
985
1120
|
{ id: "approve", title: "Approve" },
|
|
@@ -993,6 +1128,7 @@ async function createRobotRockTaskForWebhook(input) {
|
|
|
993
1128
|
baseUrl: baseConfig.baseUrl,
|
|
994
1129
|
...input.app ?? baseConfig.app ? { app: input.app ?? baseConfig.app } : {},
|
|
995
1130
|
...baseConfig.version ? { version: baseConfig.version } : {},
|
|
1131
|
+
...baseConfig.advanced ? { advanced: baseConfig.advanced } : {},
|
|
996
1132
|
webhook: { url: input.webhookUrl }
|
|
997
1133
|
});
|
|
998
1134
|
return client.sendToHuman({
|
|
@@ -1013,7 +1149,7 @@ async function parseRobotRockWebhookRequest(request) {
|
|
|
1013
1149
|
async function sendToHumanInWorkflow(payload) {
|
|
1014
1150
|
var _stack = [];
|
|
1015
1151
|
try {
|
|
1016
|
-
const { validUntil: validUntilInput, app, ...
|
|
1152
|
+
const { validUntil: validUntilInput, app, recordOtel, otelIncludeActionData, ...taskFields } = payload;
|
|
1017
1153
|
const { validUntil, timeout } = resolveWaitTiming(validUntilInput);
|
|
1018
1154
|
const timeoutMs = parseValidUntilMs2(validUntil) - Date.now();
|
|
1019
1155
|
const webhook = __using(_stack, createWebhook());
|
|
@@ -1021,31 +1157,54 @@ async function sendToHumanInWorkflow(payload) {
|
|
|
1021
1157
|
webhookUrl: webhook.url,
|
|
1022
1158
|
app,
|
|
1023
1159
|
validUntil,
|
|
1024
|
-
taskInput
|
|
1160
|
+
taskInput: stripPlatformOtelFields(taskFields)
|
|
1025
1161
|
});
|
|
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
|
-
}
|
|
1162
|
+
const otelSession = beginRobotRockHumanWaitOtel(sendResult.task, {
|
|
1163
|
+
recordOtel,
|
|
1164
|
+
otelIncludeActionData
|
|
1048
1165
|
});
|
|
1166
|
+
let handledPayload = null;
|
|
1167
|
+
let waitOutcome = "pending";
|
|
1168
|
+
try {
|
|
1169
|
+
const outcome = await Promise.race([
|
|
1170
|
+
webhook.then((request) => parseRobotRockWebhookRequest(request)),
|
|
1171
|
+
sleep2(timeoutMs).then(() => ({ timedOut: true }))
|
|
1172
|
+
]);
|
|
1173
|
+
if ("timedOut" in outcome) {
|
|
1174
|
+
waitOutcome = "timeout";
|
|
1175
|
+
throw new Error(`Human response timed out before validUntil (${timeout})`);
|
|
1176
|
+
}
|
|
1177
|
+
handledPayload = outcome;
|
|
1178
|
+
waitOutcome = "handled";
|
|
1179
|
+
return toDiscriminatedApprovalResult(payload.actions, {
|
|
1180
|
+
id: outcome.taskId,
|
|
1181
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1182
|
+
status: "handled",
|
|
1183
|
+
context: sendResult.task.context,
|
|
1184
|
+
validUntil: Date.now(),
|
|
1185
|
+
handledAt: new Date(outcome.handledAt).getTime(),
|
|
1186
|
+
handled: {
|
|
1187
|
+
action: {
|
|
1188
|
+
id: outcome.action.id,
|
|
1189
|
+
data: outcome.action.data
|
|
1190
|
+
},
|
|
1191
|
+
handledBy: outcome.handledBy
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
if (waitOutcome === "pending") {
|
|
1196
|
+
waitOutcome = "error";
|
|
1197
|
+
}
|
|
1198
|
+
throw error;
|
|
1199
|
+
} finally {
|
|
1200
|
+
if (waitOutcome !== "pending") {
|
|
1201
|
+
finishRobotRockHumanWaitOtel(
|
|
1202
|
+
otelSession,
|
|
1203
|
+
handledPayload,
|
|
1204
|
+
waitOutcome === "handled" ? "handled" : waitOutcome
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1049
1208
|
} catch (_) {
|
|
1050
1209
|
var _error = _, _hasError = true;
|
|
1051
1210
|
} finally {
|
|
@@ -1066,7 +1225,8 @@ async function sendRobotRockUpdate(payload) {
|
|
|
1066
1225
|
apiKey: baseConfig.apiKey,
|
|
1067
1226
|
baseUrl: baseConfig.baseUrl,
|
|
1068
1227
|
...app ?? baseConfig.app ? { app: app ?? baseConfig.app } : {},
|
|
1069
|
-
...baseConfig.version ? { version: baseConfig.version } : {}
|
|
1228
|
+
...baseConfig.version ? { version: baseConfig.version } : {},
|
|
1229
|
+
...baseConfig.advanced ? { advanced: baseConfig.advanced } : {}
|
|
1070
1230
|
});
|
|
1071
1231
|
return client.sendUpdate(update);
|
|
1072
1232
|
}
|