robotrock 0.8.1 → 0.8.4

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/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { R as RobotRock, b as RobotRockConfig } from './client-D-XEBOWd.js';
2
2
  export { c as RobotRockError, d as RobotRockPollingClientConfig, e as RobotRockPollingOptions, f as RobotRockWebhookClientConfig, g as RobotRockWebhookConfig, S as SendToHumanActionInput, a as SendToHumanInput, h as SendToHumanResult, i as SendToHumanValidUntil, j as SendUpdateInput, k as attachWebhookToActions, l as createClient } from './client-D-XEBOWd.js';
3
3
  import { Task, DiscriminatedApprovalResult } from './schemas/index.js';
4
- export { AgentCost, AgentCostTokens, AgentTelemetry, AgentTelemetryInput, ApprovalResult, AssignToInput, CreateTaskBody, CreateTaskBodyInput, DEFAULT_TASK_PRIORITY, DEFAULT_THREAD_UPDATE_STATUS, Handler, InferActionData, LOWEST_TASK_PRIORITY, TASK_PRIORITY_RANK, TaskAction, TaskContext, TaskContextInput, TaskPriority, TaskResponse, TaskResult, TaskStatus, ThreadUpdate, ThreadUpdateBody, ThreadUpdateBodyInput, ThreadUpdateInput, ThreadUpdateResponse, ThreadUpdateSource, ThreadUpdateStatus, TriggerHandler, TupleElementIndices, WebhookHandler, agentCostSchema, agentCostTokensSchema, agentTelemetrySchema, assignToSchema, createTaskBodySchema, taskContextSchema, taskPriorities, taskPrioritySchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateStatusSchema, threadUpdateStatuses } from './schemas/index.js';
4
+ export { AGENT_OTEL_SPANS_MAX, AgentCost, AgentCostTokens, AgentOtel, AgentOtelSpanStatus, AgentOtelSpanSummary, AgentTelemetry, AgentTelemetryInput, AgentToolCalls, ApprovalResult, AssignToInput, CreateTaskBody, CreateTaskBodyInput, DEFAULT_TASK_PRIORITY, DEFAULT_THREAD_UPDATE_STATUS, Handler, InferActionData, LOWEST_TASK_PRIORITY, TASK_PRIORITY_RANK, TaskAction, TaskContext, TaskContextInput, TaskPriority, TaskResponse, TaskResult, TaskStatus, ThreadUpdate, ThreadUpdateBody, ThreadUpdateBodyInput, ThreadUpdateInput, ThreadUpdateResponse, ThreadUpdateSource, ThreadUpdateStatus, TriggerHandler, TupleElementIndices, WebhookHandler, agentCostSchema, agentCostTokensSchema, agentOtelSchema, agentOtelSpanStatusSchema, agentOtelSpanSummarySchema, agentTelemetrySchema, agentToolCallsSchema, assignToSchema, createTaskBodySchema, taskContextSchema, taskPriorities, taskPrioritySchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateStatusSchema, threadUpdateStatuses } from './schemas/index.js';
5
5
  import { z } from 'zod';
6
6
  export { R as RobotRockHandlerWebhookPayload } from './handler-webhook-BqEi6Bk-.js';
7
+ export { AgentTelemetryFromOtelOptions, OtelSpanLike, OtelSpanSummaryInput, agentTelemetryFromOtel, toolCallsFromOtelSpans } from './otel/index.js';
7
8
 
8
9
  /**
9
10
  * Read RobotRock client config from environment variables.
package/dist/index.js CHANGED
@@ -1,10 +1,187 @@
1
1
  // src/schemas/index.ts
2
+ import { z as z2 } from "zod";
3
+
4
+ // ../core/src/utils/safe-url.ts
5
+ var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
6
+ "localhost",
7
+ "metadata.google.internal",
8
+ "metadata.goog"
9
+ ]);
10
+ function normalizeHostname(hostname) {
11
+ return hostname.toLowerCase().replace(/^\[|\]$/g, "");
12
+ }
13
+ function isBlockedIpv4(host) {
14
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
15
+ if (!match) {
16
+ return false;
17
+ }
18
+ const octets = match.slice(1, 5).map((part) => Number(part));
19
+ if (octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255)) {
20
+ return true;
21
+ }
22
+ const [a, b, _c, _d] = octets;
23
+ if (a === void 0 || b === void 0) {
24
+ return true;
25
+ }
26
+ if (a === 127 || a === 0) return true;
27
+ if (a === 10) return true;
28
+ if (a === 169 && b === 254) return true;
29
+ if (a === 192 && b === 168) return true;
30
+ if (a === 172 && b >= 16 && b <= 31) return true;
31
+ if (a === 100 && b >= 64 && b <= 127) return true;
32
+ return false;
33
+ }
34
+ function ipv4FromNumericHost(host) {
35
+ if (/^\d+$/.test(host)) {
36
+ const num = Number(host);
37
+ if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
38
+ return null;
39
+ }
40
+ const a = num >>> 24 & 255;
41
+ const b = num >>> 16 & 255;
42
+ const c = num >>> 8 & 255;
43
+ const d = num & 255;
44
+ return `${a}.${b}.${c}.${d}`;
45
+ }
46
+ const hexMatch = /^0x([0-9a-f]{1,8})$/i.exec(host);
47
+ if (hexMatch) {
48
+ const num = Number.parseInt(hexMatch[1], 16);
49
+ if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
50
+ return null;
51
+ }
52
+ const a = num >>> 24 & 255;
53
+ const b = num >>> 16 & 255;
54
+ const c = num >>> 8 & 255;
55
+ const d = num & 255;
56
+ return `${a}.${b}.${c}.${d}`;
57
+ }
58
+ return null;
59
+ }
60
+ function isBlockedIpv4Mapped(host) {
61
+ const mappedDotted = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(host);
62
+ if (mappedDotted) {
63
+ return isBlockedIpv4(mappedDotted[1]);
64
+ }
65
+ const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(host);
66
+ if (mappedHex) {
67
+ const high = Number.parseInt(mappedHex[1], 16);
68
+ const low = Number.parseInt(mappedHex[2], 16);
69
+ if (Number.isFinite(high) && Number.isFinite(low)) {
70
+ const a = high >> 8 & 255;
71
+ const b = high & 255;
72
+ const c = low >> 8 & 255;
73
+ const d = low & 255;
74
+ return isBlockedIpv4(`${a}.${b}.${c}.${d}`);
75
+ }
76
+ }
77
+ return false;
78
+ }
79
+ function isBlockedIpv6(host) {
80
+ if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
81
+ return true;
82
+ }
83
+ if (host.startsWith("fc") || host.startsWith("fd")) {
84
+ return true;
85
+ }
86
+ if (host.startsWith("fe80:")) {
87
+ return true;
88
+ }
89
+ if (isBlockedIpv4Mapped(host)) {
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ function isBlockedHostname(hostname) {
95
+ const host = normalizeHostname(hostname);
96
+ if (!host) {
97
+ return true;
98
+ }
99
+ if (BLOCKED_HOSTNAMES.has(host)) {
100
+ return true;
101
+ }
102
+ if (host.endsWith(".localhost") || host.endsWith(".local")) {
103
+ return true;
104
+ }
105
+ const numericIpv4 = ipv4FromNumericHost(host);
106
+ if (numericIpv4 && isBlockedIpv4(numericIpv4)) {
107
+ return true;
108
+ }
109
+ return isBlockedIpv4(host) || isBlockedIpv6(host);
110
+ }
111
+ function isPublicHttpUrl(urlString) {
112
+ let url;
113
+ try {
114
+ url = new URL(urlString);
115
+ } catch {
116
+ return false;
117
+ }
118
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
119
+ return false;
120
+ }
121
+ if (url.username || url.password) {
122
+ return false;
123
+ }
124
+ return !isBlockedHostname(url.hostname);
125
+ }
126
+ var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
127
+
128
+ // ../core/src/schemas/task.ts
2
129
  import { z } from "zod";
3
- import {
4
- isPublicHttpUrl,
5
- PUBLIC_HTTP_URL_ERROR
6
- } from "@robotrock/core/utils";
7
- import { validateContextPublicUrls } from "@robotrock/core/schemas";
130
+
131
+ // ../core/src/schemas/context-urls.ts
132
+ function resolveLinkUrl(value) {
133
+ return value.startsWith("http://") || value.startsWith("https://") ? value : `https://${value}`;
134
+ }
135
+ function widgetType(ui, field) {
136
+ const fieldUi = ui?.[field];
137
+ if (typeof fieldUi !== "object" || fieldUi === null) {
138
+ return void 0;
139
+ }
140
+ const widget = fieldUi["ui:widget"];
141
+ return typeof widget === "string" ? widget : void 0;
142
+ }
143
+ function validateUrlValue(value, widget) {
144
+ if (widget === "image" || widget === "link") {
145
+ if (typeof value !== "string") {
146
+ return PUBLIC_HTTP_URL_ERROR;
147
+ }
148
+ const url = widget === "link" ? resolveLinkUrl(value) : value;
149
+ if (!isPublicHttpUrl(url)) {
150
+ return PUBLIC_HTTP_URL_ERROR;
151
+ }
152
+ return null;
153
+ }
154
+ if (widget === "attachments" && Array.isArray(value)) {
155
+ for (const item of value) {
156
+ if (typeof item !== "object" || item === null) {
157
+ continue;
158
+ }
159
+ const url = item.url;
160
+ if (typeof url === "string" && !isPublicHttpUrl(resolveLinkUrl(url))) {
161
+ return PUBLIC_HTTP_URL_ERROR;
162
+ }
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+ function validateContextPublicUrls(context) {
168
+ if (!context?.data) {
169
+ return null;
170
+ }
171
+ for (const [field, value] of Object.entries(context.data)) {
172
+ const widget = widgetType(context.ui, field);
173
+ if (!widget) {
174
+ continue;
175
+ }
176
+ const error = validateUrlValue(value, widget);
177
+ if (error) {
178
+ return `context.data.${field}: ${error}`;
179
+ }
180
+ }
181
+ return null;
182
+ }
183
+
184
+ // ../core/src/schemas/task.ts
8
185
  var safeUrlSchema = z.string().refine((url) => isPublicHttpUrl(url), {
9
186
  message: PUBLIC_HTTP_URL_ERROR
10
187
  });
@@ -32,6 +209,7 @@ var taskActionSchema = z.object({
32
209
  schema: jsonSchema7Schema.optional(),
33
210
  ui: uiSchemaSchema.optional(),
34
211
  data: z.record(z.string(), z.unknown()).optional(),
212
+ // Optional handlers for this action - if present, must have at least 1
35
213
  handlers: z.array(handlerSchema).min(1).optional()
36
214
  });
37
215
  var uiFieldSchemaSchema = z.object({
@@ -47,6 +225,7 @@ var contextDataSchema = z.object({
47
225
  ui: contextUiSchema
48
226
  }).optional();
49
227
  var taskContextObjectSchema = z.object({
228
+ /** Source application id; omitted tasks are grouped in the default inbox. */
50
229
  app: z.string().min(1).optional(),
51
230
  type: z.string().min(1),
52
231
  name: z.string().min(1),
@@ -93,21 +272,12 @@ var threadUpdateStatuses = [
93
272
  "cancelled"
94
273
  ];
95
274
  var threadUpdateStatusSchema = z.enum(threadUpdateStatuses);
96
- var DEFAULT_THREAD_UPDATE_STATUS = "info";
97
275
  var threadUpdateInputSchema = z.object({
98
276
  message: threadUpdateMessageSchema,
99
277
  status: threadUpdateStatusSchema.optional()
100
278
  });
101
279
  var taskPriorities = ["low", "normal", "high", "urgent"];
102
280
  var taskPrioritySchema = z.enum(taskPriorities);
103
- var DEFAULT_TASK_PRIORITY = "normal";
104
- var LOWEST_TASK_PRIORITY = "low";
105
- var TASK_PRIORITY_RANK = {
106
- low: 1,
107
- normal: 2,
108
- high: 3,
109
- urgent: 4
110
- };
111
281
  var nonNegativeInt = z.number().int().nonnegative();
112
282
  var agentCostTokensSchema = z.object({
113
283
  input: nonNegativeInt.optional(),
@@ -120,17 +290,47 @@ var agentCostSchema = z.object({
120
290
  usd: z.number().nonnegative().optional()
121
291
  });
122
292
  var AGENT_INFO_MAX_KEYS = 32;
293
+ var AGENT_TOOL_CALLS_MAX_KEYS = 64;
294
+ var AGENT_OTEL_SPANS_MAX = 32;
295
+ var agentToolCallsSchema = z.record(z.string().min(1), nonNegativeInt);
296
+ var agentOtelSpanStatusSchema = z.enum(["ok", "error"]);
297
+ var agentOtelSpanSummarySchema = z.object({
298
+ name: z.string().min(1),
299
+ durationMs: z.number().nonnegative(),
300
+ status: agentOtelSpanStatusSchema
301
+ });
302
+ var agentOtelSchema = z.object({
303
+ traceId: z.string().min(1),
304
+ spanId: z.string().min(1).optional(),
305
+ rootDurationMs: z.number().nonnegative().optional(),
306
+ spans: z.array(agentOtelSpanSummarySchema).max(AGENT_OTEL_SPANS_MAX).optional()
307
+ });
123
308
  var agentTelemetrySchema = z.object({
309
+ /** Agent or app version (semver, git SHA, deploy tag — caller-defined). */
124
310
  version: z.string().min(1).optional(),
311
+ /** Total tool invocations. When omitted but `toolCalls` is set, the sum of counts is used. */
125
312
  toolCallCount: nonNegativeInt.optional(),
313
+ /** Per-tool invocation counts keyed by tool name. */
314
+ toolCalls: agentToolCallsSchema.optional(),
126
315
  cost: agentCostSchema.optional(),
127
- info: z.record(z.string(), z.unknown()).optional()
316
+ /** Free-form metadata for experiments (model, prompt variant, etc.). */
317
+ info: z.record(z.string(), z.unknown()).optional(),
318
+ /** Structured OpenTelemetry span snapshot for feedback analysis. */
319
+ otel: agentOtelSchema.optional()
128
320
  }).refine(
129
321
  (data) => {
130
322
  const keys = data.info ? Object.keys(data.info) : [];
131
323
  return keys.length <= AGENT_INFO_MAX_KEYS;
132
324
  },
133
325
  { message: `agent.info may contain at most ${AGENT_INFO_MAX_KEYS} keys` }
326
+ ).refine(
327
+ (data) => {
328
+ const keys = data.toolCalls ? Object.keys(data.toolCalls) : [];
329
+ return keys.length <= AGENT_TOOL_CALLS_MAX_KEYS;
330
+ },
331
+ {
332
+ message: `agent.toolCalls may contain at most ${AGENT_TOOL_CALLS_MAX_KEYS} tool names`
333
+ }
134
334
  );
135
335
  var createTaskBodySchema = taskContextObjectSchema.extend({
136
336
  assignTo: assignToSchema.optional(),
@@ -149,9 +349,183 @@ var createTaskBodySchema = taskContextObjectSchema.extend({
149
349
  * the inbox status bar and the thread update log.
150
350
  */
151
351
  update: threadUpdateInputSchema.optional(),
352
+ /** Agent telemetry (version, cost, tool calls) — not shown in inbox UI. */
152
353
  agent: agentTelemetrySchema.optional()
153
354
  }).superRefine(refineContextPublicUrls);
154
- var threadUpdateBodySchema = threadUpdateInputSchema;
355
+
356
+ // src/schemas/index.ts
357
+ var safeUrlSchema2 = z2.string().refine((url) => isPublicHttpUrl(url), {
358
+ message: PUBLIC_HTTP_URL_ERROR
359
+ });
360
+ var jsonSchema7Schema2 = z2.custom(
361
+ (val) => typeof val === "object" && val !== null,
362
+ { message: "Must be a valid JSON Schema object" }
363
+ );
364
+ var uiSchemaSchema2 = z2.custom((val) => typeof val === "object" && val !== null, {
365
+ message: "Must be a valid UiSchema object"
366
+ });
367
+ var webhookHandlerSchema2 = z2.object({
368
+ type: z2.literal("webhook"),
369
+ url: safeUrlSchema2,
370
+ headers: z2.record(z2.string(), z2.string())
371
+ });
372
+ var triggerHandlerSchema2 = webhookHandlerSchema2.extend({
373
+ type: z2.literal("trigger"),
374
+ tokenId: z2.string().min(1)
375
+ });
376
+ var handlerSchema2 = z2.discriminatedUnion("type", [webhookHandlerSchema2, triggerHandlerSchema2]);
377
+ var taskActionSchema2 = z2.object({
378
+ id: z2.string().min(1),
379
+ title: z2.string().min(1),
380
+ description: z2.string().optional(),
381
+ schema: jsonSchema7Schema2.optional(),
382
+ ui: uiSchemaSchema2.optional(),
383
+ data: z2.record(z2.string(), z2.unknown()).optional(),
384
+ handlers: z2.array(handlerSchema2).min(1).optional()
385
+ });
386
+ var uiFieldSchemaSchema2 = z2.object({
387
+ "ui:widget": z2.string().optional(),
388
+ "ui:title": z2.string().optional(),
389
+ "ui:description": z2.string().optional(),
390
+ "ui:options": z2.record(z2.string(), z2.unknown()).optional(),
391
+ items: z2.lazy(() => z2.record(z2.string(), uiFieldSchemaSchema2)).optional()
392
+ }).passthrough();
393
+ var contextUiSchema2 = z2.record(z2.string(), uiFieldSchemaSchema2).optional();
394
+ var contextDataSchema2 = z2.object({
395
+ data: z2.record(z2.string(), z2.unknown()),
396
+ ui: contextUiSchema2
397
+ }).optional();
398
+ var taskContextObjectSchema2 = z2.object({
399
+ app: z2.string().min(1).optional(),
400
+ type: z2.string().min(1),
401
+ name: z2.string().min(1),
402
+ description: z2.string().optional(),
403
+ validUntil: z2.string().optional(),
404
+ context: contextDataSchema2,
405
+ version: z2.literal(2).optional(),
406
+ actions: z2.array(taskActionSchema2).min(1, "At least one action is required")
407
+ });
408
+ function refineContextPublicUrls2(data, ctx) {
409
+ const error = validateContextPublicUrls(data.context);
410
+ if (error) {
411
+ ctx.addIssue({
412
+ code: z2.ZodIssueCode.custom,
413
+ message: error,
414
+ path: ["context"]
415
+ });
416
+ }
417
+ }
418
+ var taskContextSchema2 = taskContextObjectSchema2.superRefine(
419
+ refineContextPublicUrls2
420
+ );
421
+ var assignToSchema2 = z2.object({
422
+ users: z2.array(z2.string().email()).optional(),
423
+ groups: z2.array(z2.string().min(1)).optional()
424
+ }).refine(
425
+ (data) => {
426
+ const groups = data.groups ?? [];
427
+ if (groups.includes("all") && groups.length > 1) {
428
+ return false;
429
+ }
430
+ return true;
431
+ },
432
+ { message: 'Cannot combine "all" with other group slugs' }
433
+ );
434
+ var threadUpdateMessageSchema2 = z2.string().min(1).max(500);
435
+ var threadUpdateStatuses2 = [
436
+ "info",
437
+ "queued",
438
+ "running",
439
+ "waiting",
440
+ "succeeded",
441
+ "failed",
442
+ "cancelled"
443
+ ];
444
+ var threadUpdateStatusSchema2 = z2.enum(threadUpdateStatuses2);
445
+ var DEFAULT_THREAD_UPDATE_STATUS = "info";
446
+ var threadUpdateInputSchema2 = z2.object({
447
+ message: threadUpdateMessageSchema2,
448
+ status: threadUpdateStatusSchema2.optional()
449
+ });
450
+ var taskPriorities2 = ["low", "normal", "high", "urgent"];
451
+ var taskPrioritySchema2 = z2.enum(taskPriorities2);
452
+ var DEFAULT_TASK_PRIORITY = "normal";
453
+ var LOWEST_TASK_PRIORITY = "low";
454
+ var TASK_PRIORITY_RANK = {
455
+ low: 1,
456
+ normal: 2,
457
+ high: 3,
458
+ urgent: 4
459
+ };
460
+ var nonNegativeInt2 = z2.number().int().nonnegative();
461
+ var agentCostTokensSchema2 = z2.object({
462
+ input: nonNegativeInt2.optional(),
463
+ output: nonNegativeInt2.optional(),
464
+ total: nonNegativeInt2.optional()
465
+ });
466
+ var agentCostSchema2 = z2.object({
467
+ tokens: agentCostTokensSchema2.optional(),
468
+ eur: z2.number().nonnegative().optional(),
469
+ usd: z2.number().nonnegative().optional()
470
+ });
471
+ var AGENT_INFO_MAX_KEYS2 = 32;
472
+ var AGENT_TOOL_CALLS_MAX_KEYS2 = 64;
473
+ var AGENT_OTEL_SPANS_MAX2 = 32;
474
+ var agentToolCallsSchema2 = z2.record(z2.string().min(1), nonNegativeInt2);
475
+ var agentOtelSpanStatusSchema2 = z2.enum(["ok", "error"]);
476
+ var agentOtelSpanSummarySchema2 = z2.object({
477
+ name: z2.string().min(1),
478
+ durationMs: z2.number().nonnegative(),
479
+ status: agentOtelSpanStatusSchema2
480
+ });
481
+ var agentOtelSchema2 = z2.object({
482
+ traceId: z2.string().min(1),
483
+ spanId: z2.string().min(1).optional(),
484
+ rootDurationMs: z2.number().nonnegative().optional(),
485
+ spans: z2.array(agentOtelSpanSummarySchema2).max(AGENT_OTEL_SPANS_MAX2).optional()
486
+ });
487
+ var agentTelemetrySchema2 = z2.object({
488
+ version: z2.string().min(1).optional(),
489
+ toolCallCount: nonNegativeInt2.optional(),
490
+ toolCalls: agentToolCallsSchema2.optional(),
491
+ cost: agentCostSchema2.optional(),
492
+ info: z2.record(z2.string(), z2.unknown()).optional(),
493
+ otel: agentOtelSchema2.optional()
494
+ }).refine(
495
+ (data) => {
496
+ const keys = data.info ? Object.keys(data.info) : [];
497
+ return keys.length <= AGENT_INFO_MAX_KEYS2;
498
+ },
499
+ { message: `agent.info may contain at most ${AGENT_INFO_MAX_KEYS2} keys` }
500
+ ).refine(
501
+ (data) => {
502
+ const keys = data.toolCalls ? Object.keys(data.toolCalls) : [];
503
+ return keys.length <= AGENT_TOOL_CALLS_MAX_KEYS2;
504
+ },
505
+ {
506
+ message: `agent.toolCalls may contain at most ${AGENT_TOOL_CALLS_MAX_KEYS2} tool names`
507
+ }
508
+ );
509
+ var createTaskBodySchema2 = taskContextObjectSchema2.extend({
510
+ assignTo: assignToSchema2.optional(),
511
+ /**
512
+ * Groups related tasks together. When omitted, the server generates one and
513
+ * returns it so the caller can reuse it on later tasks in the same thread.
514
+ */
515
+ threadId: z2.string().min(1).optional(),
516
+ /**
517
+ * Optional thread priority. When set, applies to the whole thread and
518
+ * overwrites any previous priority. Omit on later tasks to leave unchanged.
519
+ */
520
+ priority: taskPrioritySchema2.optional(),
521
+ /**
522
+ * Optional initial status update logged against the task's thread. Shows in
523
+ * the inbox status bar and the thread update log.
524
+ */
525
+ update: threadUpdateInputSchema2.optional(),
526
+ agent: agentTelemetrySchema2.optional()
527
+ }).superRefine(refineContextPublicUrls2);
528
+ var threadUpdateBodySchema = threadUpdateInputSchema2;
155
529
 
156
530
  // src/approval-result.ts
157
531
  var TaskTimeoutError = class extends Error {
@@ -265,7 +639,7 @@ var RobotRock = class {
265
639
  ...task.update !== void 0 ? { update: task.update } : {},
266
640
  ...task.agent !== void 0 ? { agent: task.agent } : {}
267
641
  };
268
- const validation = createTaskBodySchema.safeParse(bodyPayload);
642
+ const validation = createTaskBodySchema2.safeParse(bodyPayload);
269
643
  if (!validation.success) {
270
644
  throw new RobotRockError(
271
645
  `Invalid task: ${validation.error.issues[0]?.message}`,
@@ -513,21 +887,21 @@ function resolveRobotRockClient(client, configOverrides) {
513
887
 
514
888
  // src/webhook.ts
515
889
  import { createHmac, timingSafeEqual } from "crypto";
516
- import { z as z2 } from "zod";
890
+ import { z as z3 } from "zod";
517
891
  var ROBOTROCK_SIGNATURE_HEADER = "x-robotrock-signature";
518
- var robotRockWebhookPayloadBodySchema = z2.object({
519
- taskId: z2.string().min(1),
520
- action: z2.object({
521
- id: z2.string().min(1),
522
- title: z2.string().min(1),
523
- data: z2.unknown()
892
+ var robotRockWebhookPayloadBodySchema = z3.object({
893
+ taskId: z3.string().min(1),
894
+ action: z3.object({
895
+ id: z3.string().min(1),
896
+ title: z3.string().min(1),
897
+ data: z3.unknown()
524
898
  }),
525
- handledBy: z2.string().min(1).optional(),
526
- handledAt: z2.string().min(1),
527
- handlerType: z2.string().min(1)
899
+ handledBy: z3.string().min(1).optional(),
900
+ handledAt: z3.string().min(1),
901
+ handlerType: z3.string().min(1)
528
902
  });
529
903
  var robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({
530
- headers: z2.record(z2.string(), z2.string())
904
+ headers: z3.record(z3.string(), z3.string())
531
905
  });
532
906
  var RobotRockWebhookError = class extends Error {
533
907
  constructor(message, code, details) {
@@ -616,7 +990,116 @@ function normalizeHeaders(headers) {
616
990
  });
617
991
  return result;
618
992
  }
993
+
994
+ // src/agent-telemetry-from-otel.ts
995
+ import { trace } from "@opentelemetry/api";
996
+ var AGENT_INFO_MAX_KEYS3 = 32;
997
+ function sumToolCalls(toolCalls) {
998
+ return Object.values(toolCalls).reduce((sum, count) => sum + count, 0);
999
+ }
1000
+ function isValidTraceId(traceId) {
1001
+ return typeof traceId === "string" && traceId.length > 0 && traceId !== "00000000000000000000000000000000";
1002
+ }
1003
+ function resolveSpanContext(span) {
1004
+ const active = span ?? trace.getActiveSpan();
1005
+ const ctx = active?.spanContext();
1006
+ if (!ctx || !isValidTraceId(ctx.traceId)) {
1007
+ return void 0;
1008
+ }
1009
+ return { traceId: ctx.traceId, spanId: ctx.spanId };
1010
+ }
1011
+ function countErrorSpans(spans) {
1012
+ if (!spans) return 0;
1013
+ return spans.filter((entry) => entry.status === "error").length;
1014
+ }
1015
+ function buildInfo(options, spanCtx) {
1016
+ const info = { ...options.extraInfo };
1017
+ if (spanCtx) {
1018
+ info.traceId = spanCtx.traceId;
1019
+ info.spanId = spanCtx.spanId;
1020
+ }
1021
+ if (options.runStartedAt != null) {
1022
+ const durationMs = Date.now() - options.runStartedAt;
1023
+ if (durationMs >= 0) {
1024
+ info.durationMs = durationMs;
1025
+ }
1026
+ }
1027
+ const errorCount = countErrorSpans(options.otel?.spans);
1028
+ if (errorCount > 0) {
1029
+ info.errorCount = errorCount;
1030
+ }
1031
+ const keys = Object.keys(info);
1032
+ if (keys.length === 0) {
1033
+ return void 0;
1034
+ }
1035
+ if (keys.length > AGENT_INFO_MAX_KEYS3) {
1036
+ const trimmed = {};
1037
+ for (const key of keys.slice(0, AGENT_INFO_MAX_KEYS3)) {
1038
+ trimmed[key] = info[key];
1039
+ }
1040
+ return trimmed;
1041
+ }
1042
+ return info;
1043
+ }
1044
+ function buildOtelBlock(options, spanCtx) {
1045
+ const traceId = options.otel?.traceId ?? spanCtx?.traceId;
1046
+ if (!isValidTraceId(traceId)) {
1047
+ return void 0;
1048
+ }
1049
+ const spans = options.otel?.spans;
1050
+ const rootDurationMs = options.otel?.rootDurationMs ?? (options.runStartedAt != null ? Math.max(0, Date.now() - options.runStartedAt) : void 0);
1051
+ const block = { traceId };
1052
+ const spanId = options.otel?.spanId ?? spanCtx?.spanId;
1053
+ if (spanId) {
1054
+ block.spanId = spanId;
1055
+ }
1056
+ if (rootDurationMs != null) {
1057
+ block.rootDurationMs = rootDurationMs;
1058
+ }
1059
+ if (spans && spans.length > 0) {
1060
+ block.spans = spans;
1061
+ }
1062
+ return block;
1063
+ }
1064
+ function agentTelemetryFromOtel(options = {}) {
1065
+ const spanCtx = resolveSpanContext(options.span);
1066
+ const telemetry = {};
1067
+ if (options.version) {
1068
+ telemetry.version = options.version;
1069
+ }
1070
+ if (options.toolCalls && Object.keys(options.toolCalls).length > 0) {
1071
+ telemetry.toolCalls = options.toolCalls;
1072
+ }
1073
+ if (options.toolCallCount !== void 0) {
1074
+ telemetry.toolCallCount = options.toolCallCount;
1075
+ } else if (telemetry.toolCalls) {
1076
+ const sum = sumToolCalls(telemetry.toolCalls);
1077
+ if (sum > 0) {
1078
+ telemetry.toolCallCount = sum;
1079
+ }
1080
+ }
1081
+ if (options.cost) {
1082
+ telemetry.cost = options.cost;
1083
+ }
1084
+ const info = buildInfo(options, spanCtx);
1085
+ if (info) {
1086
+ telemetry.info = info;
1087
+ }
1088
+ const otel = buildOtelBlock(options, spanCtx);
1089
+ if (otel) {
1090
+ telemetry.otel = otel;
1091
+ }
1092
+ return agentTelemetrySchema2.parse(telemetry);
1093
+ }
1094
+ function toolCallsFromOtelSpans(spans) {
1095
+ const counts = {};
1096
+ for (const span of spans) {
1097
+ counts[span.name] = (counts[span.name] ?? 0) + 1;
1098
+ }
1099
+ return counts;
1100
+ }
619
1101
  export {
1102
+ AGENT_OTEL_SPANS_MAX2 as AGENT_OTEL_SPANS_MAX,
620
1103
  DEFAULT_TASK_PRIORITY,
621
1104
  DEFAULT_THREAD_UPDATE_STATUS,
622
1105
  LOWEST_TASK_PRIORITY,
@@ -626,23 +1109,29 @@ export {
626
1109
  TASK_PRIORITY_RANK,
627
1110
  TaskExpiredError,
628
1111
  TaskTimeoutError,
629
- agentCostSchema,
630
- agentCostTokensSchema,
631
- agentTelemetrySchema,
632
- assignToSchema,
1112
+ agentCostSchema2 as agentCostSchema,
1113
+ agentCostTokensSchema2 as agentCostTokensSchema,
1114
+ agentOtelSchema2 as agentOtelSchema,
1115
+ agentOtelSpanStatusSchema2 as agentOtelSpanStatusSchema,
1116
+ agentOtelSpanSummarySchema2 as agentOtelSpanSummarySchema,
1117
+ agentTelemetryFromOtel,
1118
+ agentTelemetrySchema2 as agentTelemetrySchema,
1119
+ agentToolCallsSchema2 as agentToolCallsSchema,
1120
+ assignToSchema2 as assignToSchema,
633
1121
  attachWebhookToActions,
634
1122
  createClient,
635
- createTaskBodySchema,
1123
+ createTaskBodySchema2 as createTaskBodySchema,
636
1124
  resolveRobotRockClient,
637
1125
  resolveRobotRockConfig,
638
- taskContextSchema,
639
- taskPriorities,
640
- taskPrioritySchema,
1126
+ taskContextSchema2 as taskContextSchema,
1127
+ taskPriorities2 as taskPriorities,
1128
+ taskPrioritySchema2 as taskPrioritySchema,
641
1129
  threadUpdateBodySchema,
642
- threadUpdateInputSchema,
643
- threadUpdateStatusSchema,
644
- threadUpdateStatuses,
1130
+ threadUpdateInputSchema2 as threadUpdateInputSchema,
1131
+ threadUpdateStatusSchema2 as threadUpdateStatusSchema,
1132
+ threadUpdateStatuses2 as threadUpdateStatuses,
645
1133
  toDiscriminatedApprovalResult,
1134
+ toolCallsFromOtelSpans,
646
1135
  verifyRobotRockWebhook
647
1136
  };
648
1137
  //# sourceMappingURL=index.js.map