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/trigger/index.js
CHANGED
|
@@ -1,6 +1,200 @@
|
|
|
1
1
|
// src/trigger/index.ts
|
|
2
2
|
import { task, wait } from "@trigger.dev/sdk";
|
|
3
3
|
|
|
4
|
+
// src/record-handled-to-otel.ts
|
|
5
|
+
import {
|
|
6
|
+
context,
|
|
7
|
+
trace,
|
|
8
|
+
SpanStatusCode
|
|
9
|
+
} from "@opentelemetry/api";
|
|
10
|
+
var TRACER_NAME = "robotrock";
|
|
11
|
+
var WAIT_SPAN_NAME = "robotrock.wait_for_human";
|
|
12
|
+
var HANDLED_EVENT_NAME = "robotrock.task_handled";
|
|
13
|
+
var INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
14
|
+
function isValidTraceId(traceId) {
|
|
15
|
+
return typeof traceId === "string" && traceId.length > 0 && traceId !== INVALID_TRACE_ID;
|
|
16
|
+
}
|
|
17
|
+
function resolveSpanContext(span) {
|
|
18
|
+
const active = span ?? trace.getActiveSpan();
|
|
19
|
+
const ctx = active?.spanContext();
|
|
20
|
+
if (!ctx || !isValidTraceId(ctx.traceId)) {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
return { traceId: ctx.traceId, spanId: ctx.spanId };
|
|
24
|
+
}
|
|
25
|
+
function parseTaskCreatedAt(submittedAt) {
|
|
26
|
+
if (submittedAt) {
|
|
27
|
+
const parsed = Date.parse(submittedAt);
|
|
28
|
+
if (!Number.isNaN(parsed)) {
|
|
29
|
+
return parsed;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return Date.now();
|
|
33
|
+
}
|
|
34
|
+
function parseHandledAtMs(handledAt) {
|
|
35
|
+
if (handledAt instanceof Date) {
|
|
36
|
+
return handledAt.getTime();
|
|
37
|
+
}
|
|
38
|
+
if (typeof handledAt === "number") {
|
|
39
|
+
return handledAt;
|
|
40
|
+
}
|
|
41
|
+
const parsed = Date.parse(handledAt);
|
|
42
|
+
return Number.isNaN(parsed) ? Date.now() : parsed;
|
|
43
|
+
}
|
|
44
|
+
function toRobotRockHandledOtelInput(handled) {
|
|
45
|
+
if ("actionId" in handled) {
|
|
46
|
+
return {
|
|
47
|
+
taskId: handled.taskId,
|
|
48
|
+
action: {
|
|
49
|
+
id: handled.actionId,
|
|
50
|
+
data: handled.data
|
|
51
|
+
},
|
|
52
|
+
handledBy: handled.handledBy,
|
|
53
|
+
handledAt: handled.handledAt
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
taskId: handled.taskId,
|
|
58
|
+
action: {
|
|
59
|
+
id: handled.action.id,
|
|
60
|
+
title: handled.action.title,
|
|
61
|
+
data: handled.action.data
|
|
62
|
+
},
|
|
63
|
+
handledBy: handled.handledBy,
|
|
64
|
+
handledAt: handled.handledAt
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function captureRobotRockOtelHandle(task2, options) {
|
|
68
|
+
const spanCtx = resolveSpanContext(options?.span);
|
|
69
|
+
return {
|
|
70
|
+
traceId: spanCtx?.traceId ?? "",
|
|
71
|
+
spanId: spanCtx?.spanId ?? "",
|
|
72
|
+
taskId: task2.taskId,
|
|
73
|
+
threadId: task2.threadId,
|
|
74
|
+
taskCreatedAt: parseTaskCreatedAt(task2.submittedAt)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function startRobotRockHumanWaitSpan(handle, options) {
|
|
78
|
+
const parent = options?.span ?? trace.getActiveSpan();
|
|
79
|
+
if (!parent) {
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
const tracer = trace.getTracer(options?.tracerName ?? TRACER_NAME);
|
|
83
|
+
const span = tracer.startSpan(
|
|
84
|
+
WAIT_SPAN_NAME,
|
|
85
|
+
{},
|
|
86
|
+
trace.setSpan(context.active(), parent)
|
|
87
|
+
);
|
|
88
|
+
span.setAttribute("robotrock.task_id", handle.taskId);
|
|
89
|
+
if (handle.threadId) {
|
|
90
|
+
span.setAttribute("robotrock.thread_id", handle.threadId);
|
|
91
|
+
}
|
|
92
|
+
return span;
|
|
93
|
+
}
|
|
94
|
+
function recordRobotRockHandledToOtel(handled, options = {}) {
|
|
95
|
+
const span = options.span ?? trace.getActiveSpan();
|
|
96
|
+
if (!span) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const input = toRobotRockHandledOtelInput(handled);
|
|
100
|
+
const handledAtMs = parseHandledAtMs(input.handledAt);
|
|
101
|
+
const handle = options.handle;
|
|
102
|
+
const humanWaitMs = handle != null ? Math.max(0, handledAtMs - handle.taskCreatedAt) : void 0;
|
|
103
|
+
span.setAttribute("robotrock.task_id", input.taskId);
|
|
104
|
+
span.setAttribute("robotrock.action.id", input.action.id);
|
|
105
|
+
if (input.action.title) {
|
|
106
|
+
span.setAttribute("robotrock.action.title", input.action.title);
|
|
107
|
+
}
|
|
108
|
+
if (input.handledBy) {
|
|
109
|
+
span.setAttribute("robotrock.handled_by", input.handledBy);
|
|
110
|
+
}
|
|
111
|
+
span.setAttribute("robotrock.handled_at", new Date(handledAtMs).toISOString());
|
|
112
|
+
if (humanWaitMs != null) {
|
|
113
|
+
span.setAttribute("robotrock.human_wait_ms", humanWaitMs);
|
|
114
|
+
}
|
|
115
|
+
if (input.threadId) {
|
|
116
|
+
span.setAttribute("robotrock.thread_id", input.threadId);
|
|
117
|
+
}
|
|
118
|
+
const eventAttributes = {
|
|
119
|
+
"robotrock.task_id": input.taskId,
|
|
120
|
+
"robotrock.action.id": input.action.id
|
|
121
|
+
};
|
|
122
|
+
if (input.handledBy) {
|
|
123
|
+
eventAttributes["robotrock.handled_by"] = input.handledBy;
|
|
124
|
+
}
|
|
125
|
+
if (humanWaitMs != null) {
|
|
126
|
+
eventAttributes["robotrock.human_wait_ms"] = humanWaitMs;
|
|
127
|
+
}
|
|
128
|
+
if (options.includeActionData && input.action.data != null) {
|
|
129
|
+
const serialized = JSON.stringify(input.action.data);
|
|
130
|
+
const truncated = serialized.length > 512 ? `${serialized.slice(0, 512)}\u2026` : serialized;
|
|
131
|
+
span.setAttribute("robotrock.action.data", truncated);
|
|
132
|
+
eventAttributes["robotrock.action.data"] = truncated;
|
|
133
|
+
}
|
|
134
|
+
span.addEvent(HANDLED_EVENT_NAME, eventAttributes);
|
|
135
|
+
}
|
|
136
|
+
function endRobotRockHumanWaitSpan(span, handled, options = {}) {
|
|
137
|
+
if (!span) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const outcome = options.outcome ?? (handled ? "handled" : "timeout");
|
|
141
|
+
if (handled && outcome === "handled") {
|
|
142
|
+
recordRobotRockHandledToOtel(handled, {
|
|
143
|
+
span,
|
|
144
|
+
handle: options.handle,
|
|
145
|
+
includeActionData: options.includeActionData
|
|
146
|
+
});
|
|
147
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
148
|
+
} else {
|
|
149
|
+
span.setAttribute("robotrock.outcome", outcome);
|
|
150
|
+
span.setStatus({
|
|
151
|
+
code: SpanStatusCode.ERROR,
|
|
152
|
+
message: outcome === "timeout" ? "Human response timed out before validUntil" : "Human wait failed"
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
span.end();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/otel-platform.ts
|
|
159
|
+
function shouldRecordRobotRockOtel(recordOtel) {
|
|
160
|
+
if (recordOtel === true) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (recordOtel === false) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const env = process.env.ROBOTROCK_OTEL_RECORD_HANDLED;
|
|
167
|
+
return env === "true" || env === "1";
|
|
168
|
+
}
|
|
169
|
+
function stripPlatformOtelFields(payload) {
|
|
170
|
+
const { recordOtel: _recordOtel, otelIncludeActionData: _otelIncludeActionData, ...rest } = payload;
|
|
171
|
+
return rest;
|
|
172
|
+
}
|
|
173
|
+
function beginRobotRockHumanWaitOtel(task2, options = {}) {
|
|
174
|
+
const recordOtel = shouldRecordRobotRockOtel(options.recordOtel);
|
|
175
|
+
if (!recordOtel) {
|
|
176
|
+
return { recordOtel: false };
|
|
177
|
+
}
|
|
178
|
+
const handle = captureRobotRockOtelHandle(task2);
|
|
179
|
+
const waitSpan = startRobotRockHumanWaitSpan(handle);
|
|
180
|
+
return {
|
|
181
|
+
recordOtel: true,
|
|
182
|
+
handle,
|
|
183
|
+
waitSpan,
|
|
184
|
+
includeActionData: options.otelIncludeActionData
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function finishRobotRockHumanWaitOtel(session, handled, outcome) {
|
|
188
|
+
if (!session.recordOtel) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
endRobotRockHumanWaitSpan(session.waitSpan, handled, {
|
|
192
|
+
handle: session.handle,
|
|
193
|
+
outcome,
|
|
194
|
+
includeActionData: session.includeActionData
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
4
198
|
// src/schemas/index.ts
|
|
5
199
|
import { z as z2 } from "zod";
|
|
6
200
|
|
|
@@ -167,12 +361,12 @@ function validateUrlValue(value, widget) {
|
|
|
167
361
|
}
|
|
168
362
|
return null;
|
|
169
363
|
}
|
|
170
|
-
function validateContextPublicUrls(
|
|
171
|
-
if (!
|
|
364
|
+
function validateContextPublicUrls(context2) {
|
|
365
|
+
if (!context2?.data) {
|
|
172
366
|
return null;
|
|
173
367
|
}
|
|
174
|
-
for (const [field, value] of Object.entries(
|
|
175
|
-
const widget = widgetType(
|
|
368
|
+
for (const [field, value] of Object.entries(context2.data)) {
|
|
369
|
+
const widget = widgetType(context2.ui, field);
|
|
176
370
|
if (!widget) {
|
|
177
371
|
continue;
|
|
178
372
|
}
|
|
@@ -205,13 +399,15 @@ var triggerHandlerSchema = webhookHandlerSchema.extend({
|
|
|
205
399
|
tokenId: z.string().min(1)
|
|
206
400
|
});
|
|
207
401
|
var handlerSchema = z.discriminatedUnion("type", [webhookHandlerSchema, triggerHandlerSchema]);
|
|
208
|
-
var
|
|
402
|
+
var taskActionInputSchema = z.object({
|
|
209
403
|
id: z.string().min(1),
|
|
210
404
|
title: z.string().min(1),
|
|
211
405
|
description: z.string().optional(),
|
|
212
406
|
schema: jsonSchema7Schema.optional(),
|
|
213
407
|
ui: uiSchemaSchema.optional(),
|
|
214
|
-
data: z.record(z.string(), z.unknown()).optional()
|
|
408
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
409
|
+
});
|
|
410
|
+
var taskActionSchema = taskActionInputSchema.extend({
|
|
215
411
|
// Optional handlers for this action - if present, must have at least 1
|
|
216
412
|
handlers: z.array(handlerSchema).min(1).optional()
|
|
217
413
|
});
|
|
@@ -227,7 +423,8 @@ var contextDataSchema = z.object({
|
|
|
227
423
|
data: z.record(z.string(), z.unknown()),
|
|
228
424
|
ui: contextUiSchema
|
|
229
425
|
}).optional();
|
|
230
|
-
var
|
|
426
|
+
var TASK_CONTEXT_FORMAT_VERSION = 2;
|
|
427
|
+
var taskContextObjectBaseSchema = z.object({
|
|
231
428
|
/** Source application id; omitted tasks are grouped in the default inbox. */
|
|
232
429
|
app: z.string().min(1).optional(),
|
|
233
430
|
type: z.string().min(1),
|
|
@@ -235,9 +432,22 @@ var taskContextObjectSchema = z.object({
|
|
|
235
432
|
description: z.string().optional(),
|
|
236
433
|
validUntil: z.string().optional(),
|
|
237
434
|
context: contextDataSchema,
|
|
435
|
+
/** Task context wire format version. @default 2 */
|
|
436
|
+
contextVersion: z.literal(2).optional(),
|
|
437
|
+
/** @deprecated Use `contextVersion`. Accepted on ingest only. */
|
|
238
438
|
version: z.literal(2).optional(),
|
|
239
439
|
actions: z.array(taskActionSchema).min(1, "At least one action is required")
|
|
240
440
|
});
|
|
441
|
+
function normalizeTaskContextVersion(data) {
|
|
442
|
+
const { version: legacyVersion, contextVersion, ...rest } = data;
|
|
443
|
+
return {
|
|
444
|
+
...rest,
|
|
445
|
+
contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
var taskContextObjectSchema = taskContextObjectBaseSchema.transform(
|
|
449
|
+
normalizeTaskContextVersion
|
|
450
|
+
);
|
|
241
451
|
function refineContextPublicUrls(data, ctx) {
|
|
242
452
|
const error = validateContextPublicUrls(data.context);
|
|
243
453
|
if (error) {
|
|
@@ -281,61 +491,11 @@ var threadUpdateInputSchema = z.object({
|
|
|
281
491
|
});
|
|
282
492
|
var taskPriorities = ["low", "normal", "high", "urgent"];
|
|
283
493
|
var taskPrioritySchema = z.enum(taskPriorities);
|
|
284
|
-
var nonNegativeInt = z.number().int().nonnegative();
|
|
285
|
-
var agentCostTokensSchema = z.object({
|
|
286
|
-
input: nonNegativeInt.optional(),
|
|
287
|
-
output: nonNegativeInt.optional(),
|
|
288
|
-
total: nonNegativeInt.optional()
|
|
289
|
-
});
|
|
290
|
-
var agentCostSchema = z.object({
|
|
291
|
-
tokens: agentCostTokensSchema.optional(),
|
|
292
|
-
eur: z.number().nonnegative().optional(),
|
|
293
|
-
usd: z.number().nonnegative().optional()
|
|
294
|
-
});
|
|
295
|
-
var AGENT_INFO_MAX_KEYS = 32;
|
|
296
|
-
var AGENT_TOOL_CALLS_MAX_KEYS = 64;
|
|
297
|
-
var AGENT_OTEL_SPANS_MAX = 32;
|
|
298
|
-
var agentToolCallsSchema = z.record(z.string().min(1), nonNegativeInt);
|
|
299
|
-
var agentOtelSpanStatusSchema = z.enum(["ok", "error"]);
|
|
300
|
-
var agentOtelSpanSummarySchema = z.object({
|
|
301
|
-
name: z.string().min(1),
|
|
302
|
-
durationMs: z.number().nonnegative(),
|
|
303
|
-
status: agentOtelSpanStatusSchema
|
|
304
|
-
});
|
|
305
|
-
var agentOtelSchema = z.object({
|
|
306
|
-
traceId: z.string().min(1),
|
|
307
|
-
spanId: z.string().min(1).optional(),
|
|
308
|
-
rootDurationMs: z.number().nonnegative().optional(),
|
|
309
|
-
spans: z.array(agentOtelSpanSummarySchema).max(AGENT_OTEL_SPANS_MAX).optional()
|
|
310
|
-
});
|
|
311
494
|
var agentTelemetrySchema = z.object({
|
|
312
495
|
/** Agent or app version (semver, git SHA, deploy tag — caller-defined). */
|
|
313
|
-
version: z.string().min(1)
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
/** Per-tool invocation counts keyed by tool name. */
|
|
317
|
-
toolCalls: agentToolCallsSchema.optional(),
|
|
318
|
-
cost: agentCostSchema.optional(),
|
|
319
|
-
/** Free-form metadata for experiments (model, prompt variant, etc.). */
|
|
320
|
-
info: z.record(z.string(), z.unknown()).optional(),
|
|
321
|
-
/** Structured OpenTelemetry span snapshot for feedback analysis. */
|
|
322
|
-
otel: agentOtelSchema.optional()
|
|
323
|
-
}).refine(
|
|
324
|
-
(data) => {
|
|
325
|
-
const keys = data.info ? Object.keys(data.info) : [];
|
|
326
|
-
return keys.length <= AGENT_INFO_MAX_KEYS;
|
|
327
|
-
},
|
|
328
|
-
{ message: `agent.info may contain at most ${AGENT_INFO_MAX_KEYS} keys` }
|
|
329
|
-
).refine(
|
|
330
|
-
(data) => {
|
|
331
|
-
const keys = data.toolCalls ? Object.keys(data.toolCalls) : [];
|
|
332
|
-
return keys.length <= AGENT_TOOL_CALLS_MAX_KEYS;
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
message: `agent.toolCalls may contain at most ${AGENT_TOOL_CALLS_MAX_KEYS} tool names`
|
|
336
|
-
}
|
|
337
|
-
);
|
|
338
|
-
var createTaskBodySchema = taskContextObjectSchema.extend({
|
|
496
|
+
version: z.string().min(1)
|
|
497
|
+
});
|
|
498
|
+
var createTaskBodySchema = taskContextObjectBaseSchema.extend({
|
|
339
499
|
assignTo: assignToSchema.optional(),
|
|
340
500
|
/**
|
|
341
501
|
* Groups related tasks together. When omitted, the server generates one and
|
|
@@ -352,9 +512,59 @@ var createTaskBodySchema = taskContextObjectSchema.extend({
|
|
|
352
512
|
* the inbox status bar and the thread update log.
|
|
353
513
|
*/
|
|
354
514
|
update: threadUpdateInputSchema.optional(),
|
|
355
|
-
/** Agent
|
|
515
|
+
/** Agent release version — not shown in inbox UI. */
|
|
356
516
|
agent: agentTelemetrySchema.optional()
|
|
357
|
-
}).superRefine(refineContextPublicUrls);
|
|
517
|
+
}).transform(normalizeTaskContextVersion).superRefine(refineContextPublicUrls);
|
|
518
|
+
var agentChatSeedActionSchema = z.object({
|
|
519
|
+
/** Stable action id echoed back on submit; auto-derived from title when omitted. */
|
|
520
|
+
id: z.string().min(1).optional(),
|
|
521
|
+
title: z.string().min(1),
|
|
522
|
+
description: z.string().optional(),
|
|
523
|
+
/** JSON Schema object for the form fields. */
|
|
524
|
+
schema: z.record(z.string(), z.unknown()).optional(),
|
|
525
|
+
/** RJSF ui schema overrides (ui:widget, ui:enumNames, etc.). */
|
|
526
|
+
ui: z.record(z.string(), z.unknown()).optional(),
|
|
527
|
+
/** Optional default field values. */
|
|
528
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
529
|
+
});
|
|
530
|
+
var agentChatSeedMessageSchema = z.object({
|
|
531
|
+
role: z.enum(["user", "assistant"]),
|
|
532
|
+
text: z.string().min(1),
|
|
533
|
+
/** Optional display-name override for the message sender. */
|
|
534
|
+
senderName: z.string().min(1).optional(),
|
|
535
|
+
/**
|
|
536
|
+
* Optional structured input request rendered as a styled RobotRock action
|
|
537
|
+
* widget below the message text. Use this instead of asking the user to reply
|
|
538
|
+
* in plain text so the request is always a proper action form.
|
|
539
|
+
*/
|
|
540
|
+
requestActionInput: z.object({
|
|
541
|
+
prompt: z.string().optional(),
|
|
542
|
+
action: agentChatSeedActionSchema
|
|
543
|
+
}).optional()
|
|
544
|
+
});
|
|
545
|
+
var createAgentChatBodySchema = z.object({
|
|
546
|
+
/** Trigger chat agent id (task slug). Required unless `parentChatId` is set. */
|
|
547
|
+
agentIdentifier: z.string().min(1).optional(),
|
|
548
|
+
/** Inherit tenant/connection/agent from an existing chat (agent-spawned chats). */
|
|
549
|
+
parentChatId: z.string().min(1).optional(),
|
|
550
|
+
/** Convex tenantTriggerConnections id; resolved from the tenant when omitted. */
|
|
551
|
+
connectionId: z.string().min(1).optional(),
|
|
552
|
+
/** Source application id; groups the chat under an inbox section. */
|
|
553
|
+
app: z.string().min(1).optional(),
|
|
554
|
+
assignTo: assignToSchema.optional(),
|
|
555
|
+
title: z.string().min(1),
|
|
556
|
+
messages: z.array(agentChatSeedMessageSchema).default([]),
|
|
557
|
+
/** Provenance label stored on the session ("cron" | "agent" | ...). */
|
|
558
|
+
source: z.string().min(1).optional()
|
|
559
|
+
}).refine((data) => Boolean(data.agentIdentifier || data.parentChatId), {
|
|
560
|
+
message: "Provide either agentIdentifier or parentChatId"
|
|
561
|
+
});
|
|
562
|
+
var agentChatTransportBodySchema = z.object({
|
|
563
|
+
chatId: z.string().min(1),
|
|
564
|
+
publicAccessToken: z.string().min(1),
|
|
565
|
+
lastEventId: z.string().optional(),
|
|
566
|
+
isStreaming: z.boolean().optional()
|
|
567
|
+
});
|
|
358
568
|
|
|
359
569
|
// src/schemas/index.ts
|
|
360
570
|
var safeUrlSchema2 = z2.string().refine((url) => isPublicHttpUrl(url), {
|
|
@@ -377,13 +587,15 @@ var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
|
|
|
377
587
|
tokenId: z2.string().min(1)
|
|
378
588
|
});
|
|
379
589
|
var handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
|
|
380
|
-
var
|
|
590
|
+
var taskActionInputSchema2 = z2.object({
|
|
381
591
|
id: z2.string().min(1),
|
|
382
592
|
title: z2.string().min(1),
|
|
383
593
|
description: z2.string().optional(),
|
|
384
594
|
schema: jsonSchema7Schema2.optional(),
|
|
385
595
|
ui: uiSchemaSchema2.optional(),
|
|
386
|
-
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
596
|
+
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
597
|
+
});
|
|
598
|
+
var taskActionSchema2 = taskActionInputSchema2.extend({
|
|
387
599
|
handlers: z2.array(handlerSchema2).min(1).optional()
|
|
388
600
|
});
|
|
389
601
|
var uiFieldSchemaSchema2 = z2.object({
|
|
@@ -398,16 +610,29 @@ var contextDataSchema2 = z2.object({
|
|
|
398
610
|
data: z2.record(z2.string(), z2.unknown()),
|
|
399
611
|
ui: contextUiSchema2
|
|
400
612
|
}).optional();
|
|
401
|
-
var
|
|
613
|
+
var TASK_CONTEXT_FORMAT_VERSION2 = 2;
|
|
614
|
+
var taskContextObjectBaseSchema2 = z2.object({
|
|
402
615
|
app: z2.string().min(1).optional(),
|
|
403
616
|
type: z2.string().min(1),
|
|
404
617
|
name: z2.string().min(1),
|
|
405
618
|
description: z2.string().optional(),
|
|
406
619
|
validUntil: z2.string().optional(),
|
|
407
620
|
context: contextDataSchema2,
|
|
621
|
+
contextVersion: z2.literal(2).optional(),
|
|
622
|
+
/** @deprecated Use `contextVersion`. Accepted on ingest only. */
|
|
408
623
|
version: z2.literal(2).optional(),
|
|
409
624
|
actions: z2.array(taskActionSchema2).min(1, "At least one action is required")
|
|
410
625
|
});
|
|
626
|
+
function normalizeTaskContextVersion2(data) {
|
|
627
|
+
const { version: legacyVersion, contextVersion, ...rest } = data;
|
|
628
|
+
return {
|
|
629
|
+
...rest,
|
|
630
|
+
contextVersion: contextVersion ?? legacyVersion ?? TASK_CONTEXT_FORMAT_VERSION2
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
var taskContextObjectSchema2 = taskContextObjectBaseSchema2.transform(
|
|
634
|
+
normalizeTaskContextVersion2
|
|
635
|
+
);
|
|
411
636
|
function refineContextPublicUrls2(data, ctx) {
|
|
412
637
|
const error = validateContextPublicUrls(data.context);
|
|
413
638
|
if (error) {
|
|
@@ -451,56 +676,10 @@ var threadUpdateInputSchema2 = z2.object({
|
|
|
451
676
|
});
|
|
452
677
|
var taskPriorities2 = ["low", "normal", "high", "urgent"];
|
|
453
678
|
var taskPrioritySchema2 = z2.enum(taskPriorities2);
|
|
454
|
-
var nonNegativeInt2 = z2.number().int().nonnegative();
|
|
455
|
-
var agentCostTokensSchema2 = z2.object({
|
|
456
|
-
input: nonNegativeInt2.optional(),
|
|
457
|
-
output: nonNegativeInt2.optional(),
|
|
458
|
-
total: nonNegativeInt2.optional()
|
|
459
|
-
});
|
|
460
|
-
var agentCostSchema2 = z2.object({
|
|
461
|
-
tokens: agentCostTokensSchema2.optional(),
|
|
462
|
-
eur: z2.number().nonnegative().optional(),
|
|
463
|
-
usd: z2.number().nonnegative().optional()
|
|
464
|
-
});
|
|
465
|
-
var AGENT_INFO_MAX_KEYS2 = 32;
|
|
466
|
-
var AGENT_TOOL_CALLS_MAX_KEYS2 = 64;
|
|
467
|
-
var AGENT_OTEL_SPANS_MAX2 = 32;
|
|
468
|
-
var agentToolCallsSchema2 = z2.record(z2.string().min(1), nonNegativeInt2);
|
|
469
|
-
var agentOtelSpanStatusSchema2 = z2.enum(["ok", "error"]);
|
|
470
|
-
var agentOtelSpanSummarySchema2 = z2.object({
|
|
471
|
-
name: z2.string().min(1),
|
|
472
|
-
durationMs: z2.number().nonnegative(),
|
|
473
|
-
status: agentOtelSpanStatusSchema2
|
|
474
|
-
});
|
|
475
|
-
var agentOtelSchema2 = z2.object({
|
|
476
|
-
traceId: z2.string().min(1),
|
|
477
|
-
spanId: z2.string().min(1).optional(),
|
|
478
|
-
rootDurationMs: z2.number().nonnegative().optional(),
|
|
479
|
-
spans: z2.array(agentOtelSpanSummarySchema2).max(AGENT_OTEL_SPANS_MAX2).optional()
|
|
480
|
-
});
|
|
481
679
|
var agentTelemetrySchema2 = z2.object({
|
|
482
|
-
version: z2.string().min(1)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
cost: agentCostSchema2.optional(),
|
|
486
|
-
info: z2.record(z2.string(), z2.unknown()).optional(),
|
|
487
|
-
otel: agentOtelSchema2.optional()
|
|
488
|
-
}).refine(
|
|
489
|
-
(data) => {
|
|
490
|
-
const keys = data.info ? Object.keys(data.info) : [];
|
|
491
|
-
return keys.length <= AGENT_INFO_MAX_KEYS2;
|
|
492
|
-
},
|
|
493
|
-
{ message: `agent.info may contain at most ${AGENT_INFO_MAX_KEYS2} keys` }
|
|
494
|
-
).refine(
|
|
495
|
-
(data) => {
|
|
496
|
-
const keys = data.toolCalls ? Object.keys(data.toolCalls) : [];
|
|
497
|
-
return keys.length <= AGENT_TOOL_CALLS_MAX_KEYS2;
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
message: `agent.toolCalls may contain at most ${AGENT_TOOL_CALLS_MAX_KEYS2} tool names`
|
|
501
|
-
}
|
|
502
|
-
);
|
|
503
|
-
var createTaskBodySchema2 = taskContextObjectSchema2.extend({
|
|
680
|
+
version: z2.string().min(1)
|
|
681
|
+
});
|
|
682
|
+
var createTaskBodySchema2 = taskContextObjectBaseSchema2.extend({
|
|
504
683
|
assignTo: assignToSchema2.optional(),
|
|
505
684
|
/**
|
|
506
685
|
* Groups related tasks together. When omitted, the server generates one and
|
|
@@ -518,7 +697,7 @@ var createTaskBodySchema2 = taskContextObjectSchema2.extend({
|
|
|
518
697
|
*/
|
|
519
698
|
update: threadUpdateInputSchema2.optional(),
|
|
520
699
|
agent: agentTelemetrySchema2.optional()
|
|
521
|
-
}).superRefine(refineContextPublicUrls2);
|
|
700
|
+
}).transform(normalizeTaskContextVersion2).superRefine(refineContextPublicUrls2);
|
|
522
701
|
var threadUpdateBodySchema = threadUpdateInputSchema2;
|
|
523
702
|
|
|
524
703
|
// src/approval-result.ts
|
|
@@ -548,12 +727,159 @@ function toDiscriminatedApprovalResult(actions, task2) {
|
|
|
548
727
|
};
|
|
549
728
|
}
|
|
550
729
|
|
|
730
|
+
// src/http.ts
|
|
731
|
+
var RobotRockError = class extends Error {
|
|
732
|
+
constructor(message, statusCode, response) {
|
|
733
|
+
super(message);
|
|
734
|
+
this.statusCode = statusCode;
|
|
735
|
+
this.response = response;
|
|
736
|
+
this.name = "RobotRockError";
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
async function parseResponseBody(response) {
|
|
740
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
741
|
+
const bodyText = await response.text();
|
|
742
|
+
if (!bodyText) {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
if (contentType.toLowerCase().includes("application/json")) {
|
|
746
|
+
try {
|
|
747
|
+
return JSON.parse(bodyText);
|
|
748
|
+
} catch {
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
try {
|
|
752
|
+
return JSON.parse(bodyText);
|
|
753
|
+
} catch {
|
|
754
|
+
return bodyText;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
function getErrorMessage(data, fallback) {
|
|
758
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
759
|
+
const maybeMessage = data.message;
|
|
760
|
+
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
761
|
+
return maybeMessage;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (typeof data === "string" && data.trim()) {
|
|
765
|
+
const compact = data.replace(/\s+/g, " ").trim();
|
|
766
|
+
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
767
|
+
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
768
|
+
}
|
|
769
|
+
return fallback;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// ../core/src/handler-retry.ts
|
|
773
|
+
var HANDLER_RETRY_DELAYS_MS = [
|
|
774
|
+
6e4,
|
|
775
|
+
// 1m
|
|
776
|
+
3e5,
|
|
777
|
+
// 5m
|
|
778
|
+
18e5,
|
|
779
|
+
// 30m
|
|
780
|
+
36e5,
|
|
781
|
+
// 1h
|
|
782
|
+
216e5,
|
|
783
|
+
// 6h
|
|
784
|
+
864e5,
|
|
785
|
+
// 24h
|
|
786
|
+
1728e5
|
|
787
|
+
// 48h
|
|
788
|
+
];
|
|
789
|
+
var HANDLER_MAX_ATTEMPTS = HANDLER_RETRY_DELAYS_MS.length + 1;
|
|
790
|
+
|
|
791
|
+
// ../core/src/attribution/index.ts
|
|
792
|
+
import { z as z3 } from "zod";
|
|
793
|
+
|
|
794
|
+
// ../core/src/app-url.ts
|
|
795
|
+
var PRODUCTION_APP_URL = "https://app.robotrock.io";
|
|
796
|
+
var APP_SIGNUP_URL = `${PRODUCTION_APP_URL}/sign-up`;
|
|
797
|
+
|
|
798
|
+
// ../core/src/attribution/index.ts
|
|
799
|
+
var ATTRIBUTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 90;
|
|
800
|
+
var attributionSchema = z3.object({
|
|
801
|
+
utmSource: z3.string().optional(),
|
|
802
|
+
utmMedium: z3.string().optional(),
|
|
803
|
+
utmCampaign: z3.string().optional(),
|
|
804
|
+
utmContent: z3.string().optional(),
|
|
805
|
+
utmTerm: z3.string().optional(),
|
|
806
|
+
gclid: z3.string().optional(),
|
|
807
|
+
landingUrl: z3.string().optional(),
|
|
808
|
+
referrer: z3.string().optional(),
|
|
809
|
+
capturedAt: z3.number()
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// src/chats.ts
|
|
813
|
+
function createChatsApi(config) {
|
|
814
|
+
const headers = () => ({
|
|
815
|
+
"Content-Type": "application/json",
|
|
816
|
+
"X-Api-Key": config.apiKey
|
|
817
|
+
});
|
|
818
|
+
return {
|
|
819
|
+
async create(input) {
|
|
820
|
+
const bodyPayload = {
|
|
821
|
+
...input,
|
|
822
|
+
app: input.app ?? config.app,
|
|
823
|
+
messages: input.messages ?? []
|
|
824
|
+
};
|
|
825
|
+
const validation = createAgentChatBodySchema.safeParse(bodyPayload);
|
|
826
|
+
if (!validation.success) {
|
|
827
|
+
throw new RobotRockError(
|
|
828
|
+
`Invalid chat: ${validation.error.issues[0]?.message}`,
|
|
829
|
+
400,
|
|
830
|
+
validation.error.issues
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
const response = await fetch(`${config.baseUrl}/agent-chats`, {
|
|
834
|
+
method: "POST",
|
|
835
|
+
headers: headers(),
|
|
836
|
+
body: JSON.stringify(validation.data)
|
|
837
|
+
});
|
|
838
|
+
const data = await parseResponseBody(response);
|
|
839
|
+
if (!response.ok) {
|
|
840
|
+
throw new RobotRockError(
|
|
841
|
+
getErrorMessage(data, "Failed to create chat"),
|
|
842
|
+
response.status,
|
|
843
|
+
data
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
const result = data;
|
|
847
|
+
return { tenantSlug: result.tenantSlug, chats: result.chats };
|
|
848
|
+
},
|
|
849
|
+
async close(chatId, options) {
|
|
850
|
+
if (!chatId) {
|
|
851
|
+
throw new RobotRockError("chatId is required to close a chat", 400);
|
|
852
|
+
}
|
|
853
|
+
const response = await fetch(
|
|
854
|
+
`${config.baseUrl}/agent-chats/${encodeURIComponent(chatId)}/close`,
|
|
855
|
+
{
|
|
856
|
+
method: "POST",
|
|
857
|
+
headers: headers(),
|
|
858
|
+
body: JSON.stringify({ reason: options?.reason })
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
if (!response.ok) {
|
|
862
|
+
const data = await parseResponseBody(response);
|
|
863
|
+
throw new RobotRockError(
|
|
864
|
+
getErrorMessage(data, "Failed to close chat"),
|
|
865
|
+
response.status,
|
|
866
|
+
data
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
551
873
|
// src/client.ts
|
|
552
874
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
553
875
|
var DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
554
876
|
function sleep(ms) {
|
|
555
877
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
556
878
|
}
|
|
879
|
+
function resolveAgentVersionFromEnv() {
|
|
880
|
+
const fromEnv = process.env.AGENT_VERSION?.trim() || process.env.ROBOTROCK_AGENT_VERSION?.trim();
|
|
881
|
+
return fromEnv || void 0;
|
|
882
|
+
}
|
|
557
883
|
function parseValidUntilMs(value) {
|
|
558
884
|
if (value === void 0) {
|
|
559
885
|
return void 0;
|
|
@@ -581,21 +907,18 @@ function serializeValidUntil(value) {
|
|
|
581
907
|
}
|
|
582
908
|
throw new RobotRockError("Invalid validUntil: expected a Date or parseable date string", 400);
|
|
583
909
|
}
|
|
584
|
-
var RobotRockError = class extends Error {
|
|
585
|
-
constructor(message, statusCode, response) {
|
|
586
|
-
super(message);
|
|
587
|
-
this.statusCode = statusCode;
|
|
588
|
-
this.response = response;
|
|
589
|
-
this.name = "RobotRockError";
|
|
590
|
-
}
|
|
591
|
-
};
|
|
592
910
|
var RobotRock = class {
|
|
593
911
|
apiKey;
|
|
594
912
|
baseUrl;
|
|
595
913
|
app;
|
|
596
|
-
|
|
914
|
+
agentVersion;
|
|
915
|
+
contextVersion;
|
|
597
916
|
webhook;
|
|
598
917
|
polling;
|
|
918
|
+
/** Task CRUD: `create`, `get`, `cancel`, `sendUpdate`. */
|
|
919
|
+
tasks;
|
|
920
|
+
/** Chat CRUD: `create`, `close`. */
|
|
921
|
+
chats;
|
|
599
922
|
constructor(config) {
|
|
600
923
|
if (config.webhook && config.polling) {
|
|
601
924
|
throw new Error(
|
|
@@ -612,26 +935,37 @@ var RobotRock = class {
|
|
|
612
935
|
const rawBase = config.baseUrl ?? "https://api.robotrock.io/v1";
|
|
613
936
|
this.baseUrl = rawBase.replace(/\/+$/, "");
|
|
614
937
|
this.app = config.app;
|
|
615
|
-
this.
|
|
938
|
+
this.agentVersion = config.version ?? resolveAgentVersionFromEnv();
|
|
939
|
+
this.contextVersion = config.advanced?.contextVersion ?? TASK_CONTEXT_FORMAT_VERSION2;
|
|
616
940
|
this.webhook = config.webhook;
|
|
617
941
|
this.polling = config.polling ?? {};
|
|
942
|
+
this.tasks = {
|
|
943
|
+
create: (task2) => this.createTaskRequest(task2),
|
|
944
|
+
get: (taskId) => this.getTaskById(taskId),
|
|
945
|
+
cancel: (taskId) => this.cancelTaskRequest(taskId),
|
|
946
|
+
sendUpdate: (input) => this.sendThreadUpdate(input)
|
|
947
|
+
};
|
|
948
|
+
this.chats = createChatsApi({
|
|
949
|
+
baseUrl: this.baseUrl,
|
|
950
|
+
apiKey: this.apiKey,
|
|
951
|
+
app: this.app
|
|
952
|
+
});
|
|
618
953
|
}
|
|
619
|
-
|
|
620
|
-
* Create a task via POST /v1 without waiting for a human response.
|
|
621
|
-
*/
|
|
622
|
-
async createTask(task2) {
|
|
954
|
+
async createTaskRequest(task2) {
|
|
623
955
|
const normalizedTask = normalizeSendToHumanInput(task2, {
|
|
624
956
|
webhook: this.webhook,
|
|
625
957
|
app: this.app,
|
|
626
|
-
|
|
958
|
+
contextVersion: this.contextVersion,
|
|
959
|
+
agentVersion: this.agentVersion
|
|
627
960
|
});
|
|
961
|
+
const agentVersion = task2.version ?? this.agentVersion;
|
|
628
962
|
const bodyPayload = {
|
|
629
963
|
...normalizedTask,
|
|
630
964
|
...task2.assignTo !== void 0 ? { assignTo: task2.assignTo } : {},
|
|
631
965
|
...task2.threadId !== void 0 ? { threadId: task2.threadId } : {},
|
|
632
966
|
...task2.priority !== void 0 ? { priority: task2.priority } : {},
|
|
633
967
|
...task2.update !== void 0 ? { update: task2.update } : {},
|
|
634
|
-
...
|
|
968
|
+
...agentVersion !== void 0 ? { agent: { version: agentVersion } } : {}
|
|
635
969
|
};
|
|
636
970
|
const validation = createTaskBodySchema2.safeParse(bodyPayload);
|
|
637
971
|
if (!validation.success) {
|
|
@@ -667,9 +1001,10 @@ var RobotRock = class {
|
|
|
667
1001
|
const normalizedTask = normalizeSendToHumanInput(task2, {
|
|
668
1002
|
webhook: this.webhook,
|
|
669
1003
|
app: this.app,
|
|
670
|
-
|
|
1004
|
+
contextVersion: this.contextVersion,
|
|
1005
|
+
agentVersion: this.agentVersion
|
|
671
1006
|
});
|
|
672
|
-
const createdTaskTask = await this.
|
|
1007
|
+
const createdTaskTask = await this.createTaskRequest(task2);
|
|
673
1008
|
const hasHandlers = normalizedTask.actions.some(
|
|
674
1009
|
(action) => Array.isArray(action.handlers) && action.handlers.length > 0
|
|
675
1010
|
);
|
|
@@ -686,7 +1021,7 @@ var RobotRock = class {
|
|
|
686
1021
|
const deadline = validUntilMs !== void 0 ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;
|
|
687
1022
|
const taskId = createdTaskTask.taskId;
|
|
688
1023
|
while (Date.now() < deadline) {
|
|
689
|
-
const existing = await this.
|
|
1024
|
+
const existing = await this.getTaskById(taskId);
|
|
690
1025
|
if (existing?.status === "handled" && existing.handled) {
|
|
691
1026
|
return {
|
|
692
1027
|
mode: "handled",
|
|
@@ -708,10 +1043,35 @@ var RobotRock = class {
|
|
|
708
1043
|
}
|
|
709
1044
|
throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);
|
|
710
1045
|
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Create a task via POST /v1 without waiting for a human response.
|
|
1048
|
+
* @deprecated Use `client.tasks.create()` instead.
|
|
1049
|
+
*/
|
|
1050
|
+
async createTask(task2) {
|
|
1051
|
+
return this.tasks.create(task2);
|
|
1052
|
+
}
|
|
711
1053
|
/**
|
|
712
1054
|
* Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).
|
|
1055
|
+
* @deprecated Use `client.tasks.get()` instead.
|
|
713
1056
|
*/
|
|
714
1057
|
async getTask(taskId) {
|
|
1058
|
+
return this.tasks.get(taskId);
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Log a status update against a thread.
|
|
1062
|
+
* @deprecated Use `client.tasks.sendUpdate()` instead.
|
|
1063
|
+
*/
|
|
1064
|
+
async sendUpdate(input) {
|
|
1065
|
+
return this.tasks.sendUpdate(input);
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Cancel a task by public task id.
|
|
1069
|
+
* @deprecated Use `client.tasks.cancel()` instead.
|
|
1070
|
+
*/
|
|
1071
|
+
async cancelTask(taskId) {
|
|
1072
|
+
return this.tasks.cancel(taskId);
|
|
1073
|
+
}
|
|
1074
|
+
async getTaskById(taskId) {
|
|
715
1075
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {
|
|
716
1076
|
method: "GET",
|
|
717
1077
|
headers: {
|
|
@@ -731,11 +1091,11 @@ var RobotRock = class {
|
|
|
731
1091
|
}
|
|
732
1092
|
return data;
|
|
733
1093
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
1094
|
+
async sendThreadUpdate({
|
|
1095
|
+
threadId,
|
|
1096
|
+
message,
|
|
1097
|
+
status
|
|
1098
|
+
}) {
|
|
739
1099
|
if (!threadId) {
|
|
740
1100
|
throw new RobotRockError("threadId is required to send an update", 400);
|
|
741
1101
|
}
|
|
@@ -768,7 +1128,7 @@ var RobotRock = class {
|
|
|
768
1128
|
}
|
|
769
1129
|
return data.update;
|
|
770
1130
|
}
|
|
771
|
-
async
|
|
1131
|
+
async cancelTaskRequest(taskId) {
|
|
772
1132
|
const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {
|
|
773
1133
|
method: "POST",
|
|
774
1134
|
headers: {
|
|
@@ -811,6 +1171,7 @@ function normalizeSendToHumanInput(task2, clientDefaults) {
|
|
|
811
1171
|
threadId: _threadId,
|
|
812
1172
|
priority: _priority,
|
|
813
1173
|
update: _update,
|
|
1174
|
+
version: _version,
|
|
814
1175
|
validUntil,
|
|
815
1176
|
app: taskApp,
|
|
816
1177
|
...rest
|
|
@@ -820,44 +1181,12 @@ function normalizeSendToHumanInput(task2, clientDefaults) {
|
|
|
820
1181
|
const app = taskApp ?? clientDefaults.app;
|
|
821
1182
|
return {
|
|
822
1183
|
...rest,
|
|
823
|
-
|
|
1184
|
+
contextVersion: clientDefaults.contextVersion,
|
|
824
1185
|
...app ? { app } : {},
|
|
825
1186
|
...validUntil !== void 0 ? { validUntil: serializeValidUntil(validUntil) } : {},
|
|
826
1187
|
actions: normalizedActions
|
|
827
1188
|
};
|
|
828
1189
|
}
|
|
829
|
-
async function parseResponseBody(response) {
|
|
830
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
831
|
-
const bodyText = await response.text();
|
|
832
|
-
if (!bodyText) {
|
|
833
|
-
return null;
|
|
834
|
-
}
|
|
835
|
-
if (contentType.toLowerCase().includes("application/json")) {
|
|
836
|
-
try {
|
|
837
|
-
return JSON.parse(bodyText);
|
|
838
|
-
} catch {
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
try {
|
|
842
|
-
return JSON.parse(bodyText);
|
|
843
|
-
} catch {
|
|
844
|
-
return bodyText;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
function getErrorMessage(data, fallback) {
|
|
848
|
-
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
849
|
-
const maybeMessage = data.message;
|
|
850
|
-
if (typeof maybeMessage === "string" && maybeMessage.trim()) {
|
|
851
|
-
return maybeMessage;
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
if (typeof data === "string" && data.trim()) {
|
|
855
|
-
const compact = data.replace(/\s+/g, " ").trim();
|
|
856
|
-
const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;
|
|
857
|
-
return `${fallback}. Server returned non-JSON response: ${snippet}`;
|
|
858
|
-
}
|
|
859
|
-
return fallback;
|
|
860
|
-
}
|
|
861
1190
|
|
|
862
1191
|
// src/env.ts
|
|
863
1192
|
var DEFAULT_BASE_URL = "https://api.robotrock.io/v1";
|
|
@@ -940,7 +1269,7 @@ var APPROVE_BY_HUMAN_ACTIONS = [
|
|
|
940
1269
|
{ id: "decline", title: "Decline" }
|
|
941
1270
|
];
|
|
942
1271
|
async function runSendToHuman(payload) {
|
|
943
|
-
const { validUntil: validUntilInput, ...
|
|
1272
|
+
const { validUntil: validUntilInput, app, recordOtel, otelIncludeActionData, ...taskFields } = payload;
|
|
944
1273
|
const { validUntil, timeout } = resolveWaitTiming(validUntilInput);
|
|
945
1274
|
const token = await wait.createToken({ timeout });
|
|
946
1275
|
const baseConfig = resolveRobotRockConfig();
|
|
@@ -949,40 +1278,68 @@ async function runSendToHuman(payload) {
|
|
|
949
1278
|
baseUrl: baseConfig.baseUrl,
|
|
950
1279
|
...baseConfig.app ? { app: baseConfig.app } : {},
|
|
951
1280
|
...baseConfig.version ? { version: baseConfig.version } : {},
|
|
1281
|
+
...baseConfig.advanced ? { advanced: baseConfig.advanced } : {},
|
|
952
1282
|
webhook: { url: token.url }
|
|
953
1283
|
});
|
|
1284
|
+
const taskInput = stripPlatformOtelFields(taskFields);
|
|
954
1285
|
const sendResult = await client.sendToHuman({
|
|
955
1286
|
...taskInput,
|
|
956
|
-
validUntil
|
|
1287
|
+
validUntil,
|
|
1288
|
+
...app !== void 0 ? { app } : {}
|
|
957
1289
|
});
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
)
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1290
|
+
const otelSession = beginRobotRockHumanWaitOtel(sendResult.task, {
|
|
1291
|
+
recordOtel,
|
|
1292
|
+
otelIncludeActionData
|
|
1293
|
+
});
|
|
1294
|
+
let handledPayload = null;
|
|
1295
|
+
let waitOutcome = "pending";
|
|
1296
|
+
try {
|
|
1297
|
+
const outcome = await wait.forToken(token.id);
|
|
1298
|
+
if (!outcome.ok) {
|
|
1299
|
+
waitOutcome = "timeout";
|
|
1300
|
+
throw new Error(`Human response timed out before validUntil (${timeout})`);
|
|
1301
|
+
}
|
|
1302
|
+
const output = outcome.output;
|
|
1303
|
+
if (!isRobotRockHandlerWebhookPayload(output)) {
|
|
1304
|
+
waitOutcome = "error";
|
|
1305
|
+
throw new Error(
|
|
1306
|
+
"Wait token completed with unexpected payload; expected RobotRock handler body (taskId, action.id, action.data)."
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
handledPayload = output;
|
|
1310
|
+
waitOutcome = "handled";
|
|
1311
|
+
return toDiscriminatedApprovalResult(
|
|
1312
|
+
payload.actions,
|
|
1313
|
+
{
|
|
1314
|
+
id: output.taskId,
|
|
1315
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1316
|
+
status: "handled",
|
|
1317
|
+
context: sendResult.task.context,
|
|
1318
|
+
validUntil: Date.now(),
|
|
1319
|
+
handledAt: new Date(output.handledAt).getTime(),
|
|
1320
|
+
handled: {
|
|
1321
|
+
action: {
|
|
1322
|
+
id: output.action.id,
|
|
1323
|
+
data: output.action.data
|
|
1324
|
+
},
|
|
1325
|
+
handledBy: output.handledBy
|
|
1326
|
+
}
|
|
983
1327
|
}
|
|
1328
|
+
);
|
|
1329
|
+
} catch (error) {
|
|
1330
|
+
if (waitOutcome === "pending") {
|
|
1331
|
+
waitOutcome = "error";
|
|
984
1332
|
}
|
|
985
|
-
|
|
1333
|
+
throw error;
|
|
1334
|
+
} finally {
|
|
1335
|
+
if (waitOutcome !== "pending") {
|
|
1336
|
+
finishRobotRockHumanWaitOtel(
|
|
1337
|
+
otelSession,
|
|
1338
|
+
handledPayload,
|
|
1339
|
+
waitOutcome === "handled" ? "handled" : waitOutcome
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
986
1343
|
}
|
|
987
1344
|
var sendToHumanTask = task({
|
|
988
1345
|
id: "robotrock/send-to-human",
|