robotrock 0.4.0 → 0.6.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/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { R as RobotRockConfig, b as RobotRock } from './client-BOm2Ce2f.js';
2
- export { c as RobotRockError, g as RobotRockPollingClientConfig, i as RobotRockPollingOptions, f as RobotRockWebhookClientConfig, h as RobotRockWebhookConfig, S as SendToHumanActionInput, a as SendToHumanInput, k as SendToHumanResult, j as SendToHumanValidUntil, l as SendUpdateInput, d as attachWebhookToActions, e as createClient } from './client-BOm2Ce2f.js';
1
+ import { R as RobotRockConfig, b as RobotRock } from './client-CLcHdjOz.js';
2
+ export { c as RobotRockError, g as RobotRockPollingClientConfig, i as RobotRockPollingOptions, f as RobotRockWebhookClientConfig, h as RobotRockWebhookConfig, S as SendToHumanActionInput, a as SendToHumanInput, k as SendToHumanResult, j as SendToHumanValidUntil, l as SendUpdateInput, d as attachWebhookToActions, e as createClient } from './client-CLcHdjOz.js';
3
3
  import { Task, DiscriminatedApprovalResult } from './schemas/index.js';
4
- export { ApprovalResult, AssignToInput, CreateTaskBody, CreateTaskBodyInput, DEFAULT_THREAD_UPDATE_STATUS, Handler, InferActionData, TaskAction, TaskContext, TaskContextInput, TaskResponse, TaskResult, TaskStatus, ThreadUpdate, ThreadUpdateBody, ThreadUpdateBodyInput, ThreadUpdateInput, ThreadUpdateResponse, ThreadUpdateSource, ThreadUpdateStatus, TriggerHandler, TupleElementIndices, WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateStatusSchema, threadUpdateStatuses } from './schemas/index.js';
4
+ export { 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, 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
7
 
package/dist/index.js CHANGED
@@ -8,17 +8,22 @@ import {
8
8
  resolveRobotRockClient,
9
9
  resolveRobotRockConfig,
10
10
  toDiscriminatedApprovalResult
11
- } from "./chunk-PZTTI6MW.js";
11
+ } from "./chunk-ZCMXX7IG.js";
12
12
  import {
13
+ DEFAULT_TASK_PRIORITY,
13
14
  DEFAULT_THREAD_UPDATE_STATUS,
15
+ LOWEST_TASK_PRIORITY,
16
+ TASK_PRIORITY_RANK,
14
17
  assignToSchema,
15
18
  createTaskBodySchema,
16
19
  taskContextSchema,
20
+ taskPriorities,
21
+ taskPrioritySchema,
17
22
  threadUpdateBodySchema,
18
23
  threadUpdateInputSchema,
19
24
  threadUpdateStatusSchema,
20
25
  threadUpdateStatuses
21
- } from "./chunk-2KFY7ZJV.js";
26
+ } from "./chunk-TAWMIQAM.js";
22
27
 
23
28
  // src/webhook.ts
24
29
  import { createHmac, timingSafeEqual } from "crypto";
@@ -126,10 +131,13 @@ function normalizeHeaders(headers) {
126
131
  return result;
127
132
  }
128
133
  export {
134
+ DEFAULT_TASK_PRIORITY,
129
135
  DEFAULT_THREAD_UPDATE_STATUS,
136
+ LOWEST_TASK_PRIORITY,
130
137
  RobotRock,
131
138
  RobotRockError,
132
139
  RobotRockWebhookError,
140
+ TASK_PRIORITY_RANK,
133
141
  TaskExpiredError,
134
142
  TaskTimeoutError,
135
143
  assignToSchema,
@@ -139,6 +147,8 @@ export {
139
147
  resolveRobotRockClient,
140
148
  resolveRobotRockConfig,
141
149
  taskContextSchema,
150
+ taskPriorities,
151
+ taskPrioritySchema,
142
152
  threadUpdateBodySchema,
143
153
  threadUpdateInputSchema,
144
154
  threadUpdateStatusSchema,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/webhook.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\n\nconst ROBOTROCK_SIGNATURE_HEADER = \"x-robotrock-signature\";\n\nconst robotRockWebhookPayloadBodySchema = z.object({\n taskId: z.string().min(1),\n action: z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n data: z.unknown(),\n }),\n handledBy: z.string().min(1).optional(),\n handledAt: z.string().min(1),\n handlerType: z.string().min(1),\n});\n\nconst robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({\n headers: z.record(z.string()),\n});\n\nexport type RobotRockWebhookErrorCode =\n | \"MISSING_WEBHOOK_SECRET\"\n | \"MISSING_SIGNATURE\"\n | \"INVALID_SIGNATURE\"\n | \"INVALID_JSON\"\n | \"INVALID_PAYLOAD\";\n\nexport class RobotRockWebhookError extends Error {\n constructor(\n message: string,\n public readonly code: RobotRockWebhookErrorCode,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = \"RobotRockWebhookError\";\n }\n}\n\nexport type RobotRockWebhookPayload = z.infer<typeof robotRockWebhookPayloadSchema>;\n\nexport interface VerifyRobotRockWebhookOptions {\n /**\n * Override shared secret (defaults to ROBOTROCK_WEBHOOK_SECRET).\n * Keep undefined in production to enforce the canonical env var.\n */\n secret?: string;\n /**\n * Resolve the tenant signing secret by public task id (hosted MCP uses Convex).\n * Used when secret is not passed explicitly.\n */\n resolveSecret?: (taskId: string) => Promise<string | undefined>;\n /** Signature header to read. @default \"x-robotrock-signature\" */\n signatureHeader?: string;\n}\n\n/**\n * Verify a RobotRock webhook request and return a validated payload.\n * Throws RobotRockWebhookError with machine-readable `code` for audit logging.\n */\nexport async function verifyRobotRockWebhook(\n request: Request,\n options: VerifyRobotRockWebhookOptions = {}\n): Promise<RobotRockWebhookPayload> {\n const signatureHeaderName = options.signatureHeader ?? ROBOTROCK_SIGNATURE_HEADER;\n const signature = request.headers.get(signatureHeaderName);\n\n if (!signature) {\n throw new RobotRockWebhookError(\n `Missing webhook signature header: ${signatureHeaderName}`,\n \"MISSING_SIGNATURE\"\n );\n }\n\n const rawBody = await request.text();\n const secret = await resolveWebhookSigningSecret(rawBody, options);\n\n if (!secret) {\n throw new RobotRockWebhookError(\n \"Missing webhook signing secret for verification\",\n \"MISSING_WEBHOOK_SECRET\"\n );\n }\n\n assertValidSignature(rawBody, signature, secret);\n\n let parsedBody: unknown;\n try {\n parsedBody = JSON.parse(rawBody);\n } catch (error) {\n throw new RobotRockWebhookError(\"Webhook body is not valid JSON\", \"INVALID_JSON\", {\n cause: error instanceof Error ? error.message : String(error),\n });\n }\n\n const payloadResult = robotRockWebhookPayloadBodySchema.safeParse(parsedBody);\n if (!payloadResult.success) {\n throw new RobotRockWebhookError(\n \"Webhook payload schema validation failed\",\n \"INVALID_PAYLOAD\",\n payloadResult.error.flatten()\n );\n }\n\n return {\n ...payloadResult.data,\n headers: normalizeHeaders(request.headers),\n };\n}\n\nasync function resolveWebhookSigningSecret(\n rawBody: string,\n options: VerifyRobotRockWebhookOptions\n): Promise<string | undefined> {\n if (options.secret) {\n return options.secret;\n }\n\n if (options.resolveSecret) {\n const taskId = peekWebhookTaskId(rawBody);\n if (taskId) {\n const resolved = await options.resolveSecret(taskId);\n if (resolved) {\n return resolved;\n }\n }\n }\n\n return process.env.ROBOTROCK_WEBHOOK_SECRET;\n}\n\nfunction peekWebhookTaskId(rawBody: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(rawBody);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n \"taskId\" in parsed &&\n typeof (parsed as { taskId: unknown }).taskId === \"string\"\n ) {\n return (parsed as { taskId: string }).taskId;\n }\n } catch {\n // fall through\n }\n return undefined;\n}\n\nfunction assertValidSignature(rawBody: string, signature: string, secret: string): void {\n const expected = `sha256=${createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\")}`;\n const expectedBuffer = Buffer.from(expected);\n const receivedBuffer = Buffer.from(signature);\n\n if (\n expectedBuffer.length !== receivedBuffer.length ||\n !timingSafeEqual(expectedBuffer, receivedBuffer)\n ) {\n throw new RobotRockWebhookError(\"Webhook signature verification failed\", \"INVALID_SIGNATURE\");\n }\n}\n\nfunction normalizeHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/webhook.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\n\nconst ROBOTROCK_SIGNATURE_HEADER = \"x-robotrock-signature\";\n\nconst robotRockWebhookPayloadBodySchema = z.object({\n taskId: z.string().min(1),\n action: z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n data: z.unknown(),\n }),\n handledBy: z.string().min(1).optional(),\n handledAt: z.string().min(1),\n handlerType: z.string().min(1),\n});\n\nconst robotRockWebhookPayloadSchema = robotRockWebhookPayloadBodySchema.extend({\n headers: z.record(z.string()),\n});\n\nexport type RobotRockWebhookErrorCode =\n | \"MISSING_WEBHOOK_SECRET\"\n | \"MISSING_SIGNATURE\"\n | \"INVALID_SIGNATURE\"\n | \"INVALID_JSON\"\n | \"INVALID_PAYLOAD\";\n\nexport class RobotRockWebhookError extends Error {\n constructor(\n message: string,\n public readonly code: RobotRockWebhookErrorCode,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = \"RobotRockWebhookError\";\n }\n}\n\nexport type RobotRockWebhookPayload = z.infer<typeof robotRockWebhookPayloadSchema>;\n\nexport interface VerifyRobotRockWebhookOptions {\n /**\n * Override shared secret (defaults to ROBOTROCK_WEBHOOK_SECRET).\n * Keep undefined in production to enforce the canonical env var.\n */\n secret?: string;\n /**\n * Resolve the tenant signing secret by public task id (hosted MCP uses Convex).\n * Used when secret is not passed explicitly.\n */\n resolveSecret?: (taskId: string) => Promise<string | undefined>;\n /** Signature header to read. @default \"x-robotrock-signature\" */\n signatureHeader?: string;\n}\n\n/**\n * Verify a RobotRock webhook request and return a validated payload.\n * Throws RobotRockWebhookError with machine-readable `code` for audit logging.\n */\nexport async function verifyRobotRockWebhook(\n request: Request,\n options: VerifyRobotRockWebhookOptions = {}\n): Promise<RobotRockWebhookPayload> {\n const signatureHeaderName = options.signatureHeader ?? ROBOTROCK_SIGNATURE_HEADER;\n const signature = request.headers.get(signatureHeaderName);\n\n if (!signature) {\n throw new RobotRockWebhookError(\n `Missing webhook signature header: ${signatureHeaderName}`,\n \"MISSING_SIGNATURE\"\n );\n }\n\n const rawBody = await request.text();\n const secret = await resolveWebhookSigningSecret(rawBody, options);\n\n if (!secret) {\n throw new RobotRockWebhookError(\n \"Missing webhook signing secret for verification\",\n \"MISSING_WEBHOOK_SECRET\"\n );\n }\n\n assertValidSignature(rawBody, signature, secret);\n\n let parsedBody: unknown;\n try {\n parsedBody = JSON.parse(rawBody);\n } catch (error) {\n throw new RobotRockWebhookError(\"Webhook body is not valid JSON\", \"INVALID_JSON\", {\n cause: error instanceof Error ? error.message : String(error),\n });\n }\n\n const payloadResult = robotRockWebhookPayloadBodySchema.safeParse(parsedBody);\n if (!payloadResult.success) {\n throw new RobotRockWebhookError(\n \"Webhook payload schema validation failed\",\n \"INVALID_PAYLOAD\",\n payloadResult.error.flatten()\n );\n }\n\n return {\n ...payloadResult.data,\n headers: normalizeHeaders(request.headers),\n };\n}\n\nasync function resolveWebhookSigningSecret(\n rawBody: string,\n options: VerifyRobotRockWebhookOptions\n): Promise<string | undefined> {\n if (options.secret) {\n return options.secret;\n }\n\n if (options.resolveSecret) {\n const taskId = peekWebhookTaskId(rawBody);\n if (taskId) {\n const resolved = await options.resolveSecret(taskId);\n if (resolved) {\n return resolved;\n }\n }\n }\n\n return process.env.ROBOTROCK_WEBHOOK_SECRET;\n}\n\nfunction peekWebhookTaskId(rawBody: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(rawBody);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n \"taskId\" in parsed &&\n typeof (parsed as { taskId: unknown }).taskId === \"string\"\n ) {\n return (parsed as { taskId: string }).taskId;\n }\n } catch {\n // fall through\n }\n return undefined;\n}\n\nfunction assertValidSignature(rawBody: string, signature: string, secret: string): void {\n const expected = `sha256=${createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\")}`;\n const expectedBuffer = Buffer.from(expected);\n const receivedBuffer = Buffer.from(signature);\n\n if (\n expectedBuffer.length !== receivedBuffer.length ||\n !timingSafeEqual(expectedBuffer, receivedBuffer)\n ) {\n throw new RobotRockWebhookError(\"Webhook signature verification failed\", \"INVALID_SIGNATURE\");\n }\n}\n\nfunction normalizeHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n"],"mappings":"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","names":[]}
@@ -376,6 +376,13 @@ declare const threadUpdateInputSchema: z.ZodObject<{
376
376
  message: string;
377
377
  status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
378
378
  }>;
379
+ /** Thread priority levels for inbox ordering and display. */
380
+ declare const taskPriorities: readonly ["low", "normal", "high", "urgent"];
381
+ declare const taskPrioritySchema: z.ZodEnum<["low", "normal", "high", "urgent"]>;
382
+ type TaskPriority = (typeof taskPriorities)[number];
383
+ declare const DEFAULT_TASK_PRIORITY: TaskPriority;
384
+ declare const LOWEST_TASK_PRIORITY: TaskPriority;
385
+ declare const TASK_PRIORITY_RANK: Record<TaskPriority, number>;
379
386
  declare const createTaskBodySchema: z.ZodObject<{
380
387
  app: z.ZodOptional<z.ZodString>;
381
388
  type: z.ZodString;
@@ -486,6 +493,11 @@ declare const createTaskBodySchema: z.ZodObject<{
486
493
  * returns it so the caller can reuse it on later tasks in the same thread.
487
494
  */
488
495
  threadId: z.ZodOptional<z.ZodString>;
496
+ /**
497
+ * Optional thread priority. When set, applies to the whole thread and
498
+ * overwrites any previous priority. Omit on later tasks to leave unchanged.
499
+ */
500
+ priority: z.ZodOptional<z.ZodEnum<["low", "normal", "high", "urgent"]>>;
489
501
  /**
490
502
  * Optional initial status update logged against the task's thread. Shows in
491
503
  * the inbox status bar and the thread update log.
@@ -534,6 +546,7 @@ declare const createTaskBodySchema: z.ZodObject<{
534
546
  groups?: string[] | undefined;
535
547
  } | undefined;
536
548
  threadId?: string | undefined;
549
+ priority?: "low" | "normal" | "high" | "urgent" | undefined;
537
550
  update?: {
538
551
  message: string;
539
552
  status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
@@ -572,6 +585,7 @@ declare const createTaskBodySchema: z.ZodObject<{
572
585
  groups?: string[] | undefined;
573
586
  } | undefined;
574
587
  threadId?: string | undefined;
588
+ priority?: "low" | "normal" | "high" | "urgent" | undefined;
575
589
  update?: {
576
590
  message: string;
577
591
  status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
@@ -715,4 +729,4 @@ type DiscriminatedApprovalResult<TActions extends readonly {
715
729
  } : never;
716
730
  }[TupleElementIndices<TActions>];
717
731
 
718
- export { type ApprovalResult, type AssignToInput, type CreateTaskBody, type CreateTaskBodyInput, DEFAULT_THREAD_UPDATE_STATUS, type DiscriminatedApprovalResult, type ExtendedJSONSchema7, type Handler, type InferActionData, type InferJsonSchema7, type JSONSchema7, type JSONSchema7TypeName, type Task, type TaskAction, type TaskContext, type TaskContextInput, type TaskContextOutput, type TaskResponse, type TaskResult, type TaskStatus, type ThreadUpdate, type ThreadUpdateBody, type ThreadUpdateBodyInput, type ThreadUpdateInput, type ThreadUpdateResponse, type ThreadUpdateSource, type ThreadUpdateStatus, type TriggerHandler, type TupleElementIndices, type UiSchema, type WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateMessageSchema, threadUpdateStatusSchema, threadUpdateStatuses };
732
+ export { type ApprovalResult, type AssignToInput, type CreateTaskBody, type CreateTaskBodyInput, DEFAULT_TASK_PRIORITY, DEFAULT_THREAD_UPDATE_STATUS, type DiscriminatedApprovalResult, type ExtendedJSONSchema7, type Handler, type InferActionData, type InferJsonSchema7, type JSONSchema7, type JSONSchema7TypeName, LOWEST_TASK_PRIORITY, TASK_PRIORITY_RANK, type Task, type TaskAction, type TaskContext, type TaskContextInput, type TaskContextOutput, type TaskPriority, type TaskResponse, type TaskResult, type TaskStatus, type ThreadUpdate, type ThreadUpdateBody, type ThreadUpdateBodyInput, type ThreadUpdateInput, type ThreadUpdateResponse, type ThreadUpdateSource, type ThreadUpdateStatus, type TriggerHandler, type TupleElementIndices, type UiSchema, type WebhookHandler, assignToSchema, createTaskBodySchema, taskContextSchema, taskPriorities, taskPrioritySchema, threadUpdateBodySchema, threadUpdateInputSchema, threadUpdateMessageSchema, threadUpdateStatusSchema, threadUpdateStatuses };
@@ -1,19 +1,29 @@
1
1
  import {
2
+ DEFAULT_TASK_PRIORITY,
2
3
  DEFAULT_THREAD_UPDATE_STATUS,
4
+ LOWEST_TASK_PRIORITY,
5
+ TASK_PRIORITY_RANK,
3
6
  assignToSchema,
4
7
  createTaskBodySchema,
5
8
  taskContextSchema,
9
+ taskPriorities,
10
+ taskPrioritySchema,
6
11
  threadUpdateBodySchema,
7
12
  threadUpdateInputSchema,
8
13
  threadUpdateMessageSchema,
9
14
  threadUpdateStatusSchema,
10
15
  threadUpdateStatuses
11
- } from "../chunk-2KFY7ZJV.js";
16
+ } from "../chunk-TAWMIQAM.js";
12
17
  export {
18
+ DEFAULT_TASK_PRIORITY,
13
19
  DEFAULT_THREAD_UPDATE_STATUS,
20
+ LOWEST_TASK_PRIORITY,
21
+ TASK_PRIORITY_RANK,
14
22
  assignToSchema,
15
23
  createTaskBodySchema,
16
24
  taskContextSchema,
25
+ taskPriorities,
26
+ taskPrioritySchema,
17
27
  threadUpdateBodySchema,
18
28
  threadUpdateInputSchema,
19
29
  threadUpdateMessageSchema,
@@ -1,5 +1,5 @@
1
1
  import * as _trigger_dev_sdk from '@trigger.dev/sdk';
2
- import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-BOm2Ce2f.js';
2
+ import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-CLcHdjOz.js';
3
3
  export { R as RobotRockHandlerWebhookPayload } from '../handler-webhook-BqEi6Bk-.js';
4
4
  export { ApprovalResult, DiscriminatedApprovalResult, TaskContextInput, TaskResult } from '../schemas/index.js';
5
5
  import 'zod';
@@ -6,8 +6,8 @@ import {
6
6
  createClient,
7
7
  resolveRobotRockConfig,
8
8
  toDiscriminatedApprovalResult
9
- } from "../chunk-PZTTI6MW.js";
10
- import "../chunk-2KFY7ZJV.js";
9
+ } from "../chunk-ZCMXX7IG.js";
10
+ import "../chunk-TAWMIQAM.js";
11
11
 
12
12
  // src/trigger/index.ts
13
13
  import { task, wait } from "@trigger.dev/sdk";
@@ -1,6 +1,6 @@
1
- import { DiscriminatedApprovalResult } from '../schemas/index.js';
1
+ import { DiscriminatedApprovalResult, ThreadUpdateStatus, ThreadUpdate } from '../schemas/index.js';
2
2
  export { ApprovalResult, TaskContextInput, TaskResult } from '../schemas/index.js';
3
- import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-BOm2Ce2f.js';
3
+ import { S as SendToHumanActionInput, a as SendToHumanInput } from '../client-CLcHdjOz.js';
4
4
  export { R as RobotRockHandlerWebhookPayload } from '../handler-webhook-BqEi6Bk-.js';
5
5
  import 'zod';
6
6
 
@@ -31,5 +31,25 @@ declare function sendToHumanInWorkflow<const A extends readonly SendToHumanActio
31
31
  * Approve / decline gate for Vercel Workflow (`sendToHumanInWorkflow` with fixed actions).
32
32
  */
33
33
  declare function approveByHumanInWorkflow(payload: ApproveByHumanWorkflowPayload): Promise<Expand<DiscriminatedApprovalResult<typeof APPROVE_BY_HUMAN_ACTIONS>>>;
34
+ type SendUpdateWorkflowPayload = {
35
+ /** Thread to log the update against (from a prior task's `threadId`). */
36
+ threadId: string;
37
+ /** Short status update (1-2 sentences) shown in the inbox status bar. */
38
+ message: string;
39
+ /** Lifecycle status driving the status-bar icon/color. @default "info" */
40
+ status?: ThreadUpdateStatus;
41
+ /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */
42
+ app?: string;
43
+ };
44
+ /**
45
+ * Durable thread update for Vercel Workflow.
46
+ *
47
+ * Wraps {@link createClient}'s `sendUpdate` in a `"use step"` so progress
48
+ * reports are retried and recorded in the run. Fire-and-forget: returns the
49
+ * created update without suspending the workflow (no human wait involved).
50
+ *
51
+ * Call from a function with `"use workflow"` as its first statement.
52
+ */
53
+ declare function sendUpdateInWorkflow(payload: SendUpdateWorkflowPayload): Promise<ThreadUpdate>;
34
54
 
35
- export { type ApproveByHumanWorkflowPayload, DiscriminatedApprovalResult, type SendToHumanWorkflowPayload, approveByHumanInWorkflow, sendToHumanInWorkflow };
55
+ export { type ApproveByHumanWorkflowPayload, DiscriminatedApprovalResult, type SendToHumanWorkflowPayload, type SendUpdateWorkflowPayload, ThreadUpdate, ThreadUpdateStatus, approveByHumanInWorkflow, sendToHumanInWorkflow, sendUpdateInWorkflow };
@@ -7,11 +7,11 @@ import {
7
7
  createClient,
8
8
  resolveRobotRockConfig,
9
9
  toDiscriminatedApprovalResult
10
- } from "../chunk-PZTTI6MW.js";
10
+ } from "../chunk-ZCMXX7IG.js";
11
11
  import {
12
12
  __callDispose,
13
13
  __using
14
- } from "../chunk-2KFY7ZJV.js";
14
+ } from "../chunk-TAWMIQAM.js";
15
15
 
16
16
  // src/workflow/index.ts
17
17
  import { createWebhook, sleep } from "workflow";
@@ -92,8 +92,24 @@ async function approveByHumanInWorkflow(payload) {
92
92
  actions: APPROVE_BY_HUMAN_ACTIONS
93
93
  });
94
94
  }
95
+ async function sendRobotRockUpdate(payload) {
96
+ "use step";
97
+ const { app, ...update } = payload;
98
+ const baseConfig = resolveRobotRockConfig();
99
+ const client = createClient({
100
+ apiKey: baseConfig.apiKey,
101
+ baseUrl: baseConfig.baseUrl,
102
+ ...app ?? baseConfig.app ? { app: app ?? baseConfig.app } : {},
103
+ ...baseConfig.version ? { version: baseConfig.version } : {}
104
+ });
105
+ return client.sendUpdate(update);
106
+ }
107
+ async function sendUpdateInWorkflow(payload) {
108
+ return sendRobotRockUpdate(payload);
109
+ }
95
110
  export {
96
111
  approveByHumanInWorkflow,
97
- sendToHumanInWorkflow
112
+ sendToHumanInWorkflow,
113
+ sendUpdateInWorkflow
98
114
  };
99
115
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/workflow/index.ts"],"sourcesContent":["import { createWebhook, sleep } from \"workflow\";\nimport type { DiscriminatedApprovalResult } from \"../schemas/index.js\";\nimport {\n createClient,\n type SendToHumanActionInput,\n type SendToHumanInput,\n} from \"../client.js\";\nimport { resolveRobotRockConfig } from \"../env.js\";\nimport { toDiscriminatedApprovalResult } from \"../approval-result.js\";\nimport {\n isRobotRockHandlerWebhookPayload,\n type RobotRockHandlerWebhookPayload,\n} from \"../handler-webhook.js\";\nimport { parseValidUntilMs, resolveWaitTiming } from \"../wait-timing.js\";\n\nexport type SendToHumanWorkflowPayload<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = SendToHumanInput<A> & {\n /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */\n app?: string;\n};\n\nexport type ApproveByHumanWorkflowPayload = Omit<SendToHumanWorkflowPayload, \"actions\">;\n\ntype Expand<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;\n\nconst APPROVE_BY_HUMAN_ACTIONS = [\n { id: \"approve\", title: \"Approve\" },\n { id: \"decline\", title: \"Decline\" },\n] as const;\n\ntype CreateTaskStepInput = {\n webhookUrl: string;\n app?: string;\n validUntil: Date | string;\n taskInput: Omit<SendToHumanWorkflowPayload, \"validUntil\" | \"app\">;\n};\n\n/**\n * Creates the RobotRock inbox task with the workflow webhook URL as the handler.\n * Marked as a step so API calls run in full Node.js with retries.\n */\nasync function createRobotRockTaskForWebhook(input: CreateTaskStepInput) {\n \"use step\";\n\n const baseConfig = resolveRobotRockConfig();\n const client = createClient({\n apiKey: baseConfig.apiKey,\n baseUrl: baseConfig.baseUrl,\n ...((input.app ?? baseConfig.app) ? { app: input.app ?? baseConfig.app } : {}),\n ...(baseConfig.version ? { version: baseConfig.version } : {}),\n webhook: { url: input.webhookUrl },\n });\n\n return client.sendToHuman({\n ...input.taskInput,\n validUntil: input.validUntil,\n });\n}\n\nasync function parseRobotRockWebhookRequest(request: Request) {\n \"use step\";\n\n const body: unknown = await request.json();\n if (!isRobotRockHandlerWebhookPayload(body)) {\n throw new Error(\n \"Workflow webhook completed with unexpected payload; expected RobotRock handler body (taskId, action.id, action.data).\"\n );\n }\n\n return body;\n}\n\n/**\n * Durable human-in-the-loop wait for Vercel Workflow.\n *\n * Call from a function with `\"use workflow\"` as its first statement. Creates a\n * {@link createWebhook} URL, registers it as the RobotRock task webhook, and\n * suspends until a human handles an action or `validUntil` passes.\n */\nexport async function sendToHumanInWorkflow<\n const A extends readonly SendToHumanActionInput[],\n>(\n payload: SendToHumanWorkflowPayload<A>\n): Promise<Expand<DiscriminatedApprovalResult<A>>> {\n const { validUntil: validUntilInput, app, ...taskInput } = payload;\n const { validUntil, timeout } = resolveWaitTiming(validUntilInput);\n const timeoutMs = parseValidUntilMs(validUntil) - Date.now();\n\n using webhook = createWebhook();\n\n const sendResult = await createRobotRockTaskForWebhook({\n webhookUrl: webhook.url,\n app,\n validUntil,\n taskInput,\n });\n\n const outcome = await Promise.race([\n webhook.then((request) => parseRobotRockWebhookRequest(request)),\n sleep(timeoutMs).then(() => ({ timedOut: true }) as const),\n ]);\n\n if (\"timedOut\" in outcome) {\n throw new Error(`Human response timed out before validUntil (${timeout})`);\n }\n\n const output: RobotRockHandlerWebhookPayload = outcome;\n\n return toDiscriminatedApprovalResult(payload.actions, {\n id: output.taskId,\n createdAt: new Date(),\n status: \"handled\",\n context: sendResult.task.context,\n validUntil: Date.now(),\n handledAt: new Date(output.handledAt).getTime(),\n handled: {\n action: {\n id: output.action.id,\n data: output.action.data,\n },\n handledBy: output.handledBy,\n },\n }) as unknown as Expand<DiscriminatedApprovalResult<A>>;\n}\n\n/**\n * Approve / decline gate for Vercel Workflow (`sendToHumanInWorkflow` with fixed actions).\n */\nexport async function approveByHumanInWorkflow(\n payload: ApproveByHumanWorkflowPayload\n): Promise<Expand<DiscriminatedApprovalResult<typeof APPROVE_BY_HUMAN_ACTIONS>>> {\n return sendToHumanInWorkflow({\n ...payload,\n actions: APPROVE_BY_HUMAN_ACTIONS,\n });\n}\n\nexport type { RobotRockHandlerWebhookPayload } from \"../handler-webhook.js\";\nexport type {\n ApprovalResult,\n DiscriminatedApprovalResult,\n TaskContextInput,\n TaskResult,\n} from \"../schemas/index.js\";\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAS,eAAe,aAAa;AA0BrC,IAAM,2BAA2B;AAAA,EAC/B,EAAE,IAAI,WAAW,OAAO,UAAU;AAAA,EAClC,EAAE,IAAI,WAAW,OAAO,UAAU;AACpC;AAaA,eAAe,8BAA8B,OAA4B;AACvE;AAEA,QAAM,aAAa,uBAAuB;AAC1C,QAAM,SAAS,aAAa;AAAA,IAC1B,QAAQ,WAAW;AAAA,IACnB,SAAS,WAAW;AAAA,IACpB,GAAK,MAAM,OAAO,WAAW,MAAO,EAAE,KAAK,MAAM,OAAO,WAAW,IAAI,IAAI,CAAC;AAAA,IAC5E,GAAI,WAAW,UAAU,EAAE,SAAS,WAAW,QAAQ,IAAI,CAAC;AAAA,IAC5D,SAAS,EAAE,KAAK,MAAM,WAAW;AAAA,EACnC,CAAC;AAED,SAAO,OAAO,YAAY;AAAA,IACxB,GAAG,MAAM;AAAA,IACT,YAAY,MAAM;AAAA,EACpB,CAAC;AACH;AAEA,eAAe,6BAA6B,SAAkB;AAC5D;AAEA,QAAM,OAAgB,MAAM,QAAQ,KAAK;AACzC,MAAI,CAAC,iCAAiC,IAAI,GAAG;AAC3C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,eAAsB,sBAGpB,SACiD;AAKjD;AAAA;AAJA,UAAM,EAAE,YAAY,iBAAiB,KAAK,GAAG,UAAU,IAAI;AAC3D,UAAM,EAAE,YAAY,QAAQ,IAAI,kBAAkB,eAAe;AACjE,UAAM,YAAY,kBAAkB,UAAU,IAAI,KAAK,IAAI;AAE3D,UAAM,UAAU,8BAAc;AAE9B,UAAM,aAAa,MAAM,8BAA8B;AAAA,MACrD,YAAY,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,UAAU,MAAM,QAAQ,KAAK;AAAA,MACjC,QAAQ,KAAK,CAAC,YAAY,6BAA6B,OAAO,CAAC;AAAA,MAC/D,MAAM,SAAS,EAAE,KAAK,OAAO,EAAE,UAAU,KAAK,EAAW;AAAA,IAC3D,CAAC;AAED,QAAI,cAAc,SAAS;AACzB,YAAM,IAAI,MAAM,+CAA+C,OAAO,GAAG;AAAA,IAC3E;AAEA,UAAM,SAAyC;AAE/C,WAAO,8BAA8B,QAAQ,SAAS;AAAA,MACpD,IAAI,OAAO;AAAA,MACX,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ;AAAA,MACR,SAAS,WAAW,KAAK;AAAA,MACzB,YAAY,KAAK,IAAI;AAAA,MACrB,WAAW,IAAI,KAAK,OAAO,SAAS,EAAE,QAAQ;AAAA,MAC9C,SAAS;AAAA,QACP,QAAQ;AAAA,UACN,IAAI,OAAO,OAAO;AAAA,UAClB,MAAM,OAAO,OAAO;AAAA,QACtB;AAAA,QACA,WAAW,OAAO;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,WAlCD;AAAA;AAAA;AAAA;AAAA;AAmCF;AAKA,eAAsB,yBACpB,SAC+E;AAC/E,SAAO,sBAAsB;AAAA,IAC3B,GAAG;AAAA,IACH,SAAS;AAAA,EACX,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../src/workflow/index.ts"],"sourcesContent":["import { createWebhook, sleep } from \"workflow\";\nimport type {\n DiscriminatedApprovalResult,\n ThreadUpdate,\n ThreadUpdateStatus,\n} from \"../schemas/index.js\";\nimport {\n createClient,\n type SendToHumanActionInput,\n type SendToHumanInput,\n} from \"../client.js\";\nimport { resolveRobotRockConfig } from \"../env.js\";\nimport { toDiscriminatedApprovalResult } from \"../approval-result.js\";\nimport {\n isRobotRockHandlerWebhookPayload,\n type RobotRockHandlerWebhookPayload,\n} from \"../handler-webhook.js\";\nimport { parseValidUntilMs, resolveWaitTiming } from \"../wait-timing.js\";\n\nexport type SendToHumanWorkflowPayload<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = SendToHumanInput<A> & {\n /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */\n app?: string;\n};\n\nexport type ApproveByHumanWorkflowPayload = Omit<SendToHumanWorkflowPayload, \"actions\">;\n\ntype Expand<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;\n\nconst APPROVE_BY_HUMAN_ACTIONS = [\n { id: \"approve\", title: \"Approve\" },\n { id: \"decline\", title: \"Decline\" },\n] as const;\n\ntype CreateTaskStepInput = {\n webhookUrl: string;\n app?: string;\n validUntil: Date | string;\n taskInput: Omit<SendToHumanWorkflowPayload, \"validUntil\" | \"app\">;\n};\n\n/**\n * Creates the RobotRock inbox task with the workflow webhook URL as the handler.\n * Marked as a step so API calls run in full Node.js with retries.\n */\nasync function createRobotRockTaskForWebhook(input: CreateTaskStepInput) {\n \"use step\";\n\n const baseConfig = resolveRobotRockConfig();\n const client = createClient({\n apiKey: baseConfig.apiKey,\n baseUrl: baseConfig.baseUrl,\n ...((input.app ?? baseConfig.app) ? { app: input.app ?? baseConfig.app } : {}),\n ...(baseConfig.version ? { version: baseConfig.version } : {}),\n webhook: { url: input.webhookUrl },\n });\n\n return client.sendToHuman({\n ...input.taskInput,\n validUntil: input.validUntil,\n });\n}\n\nasync function parseRobotRockWebhookRequest(request: Request) {\n \"use step\";\n\n const body: unknown = await request.json();\n if (!isRobotRockHandlerWebhookPayload(body)) {\n throw new Error(\n \"Workflow webhook completed with unexpected payload; expected RobotRock handler body (taskId, action.id, action.data).\"\n );\n }\n\n return body;\n}\n\n/**\n * Durable human-in-the-loop wait for Vercel Workflow.\n *\n * Call from a function with `\"use workflow\"` as its first statement. Creates a\n * {@link createWebhook} URL, registers it as the RobotRock task webhook, and\n * suspends until a human handles an action or `validUntil` passes.\n */\nexport async function sendToHumanInWorkflow<\n const A extends readonly SendToHumanActionInput[],\n>(\n payload: SendToHumanWorkflowPayload<A>\n): Promise<Expand<DiscriminatedApprovalResult<A>>> {\n const { validUntil: validUntilInput, app, ...taskInput } = payload;\n const { validUntil, timeout } = resolveWaitTiming(validUntilInput);\n const timeoutMs = parseValidUntilMs(validUntil) - Date.now();\n\n using webhook = createWebhook();\n\n const sendResult = await createRobotRockTaskForWebhook({\n webhookUrl: webhook.url,\n app,\n validUntil,\n taskInput,\n });\n\n const outcome = await Promise.race([\n webhook.then((request) => parseRobotRockWebhookRequest(request)),\n sleep(timeoutMs).then(() => ({ timedOut: true }) as const),\n ]);\n\n if (\"timedOut\" in outcome) {\n throw new Error(`Human response timed out before validUntil (${timeout})`);\n }\n\n const output: RobotRockHandlerWebhookPayload = outcome;\n\n return toDiscriminatedApprovalResult(payload.actions, {\n id: output.taskId,\n createdAt: new Date(),\n status: \"handled\",\n context: sendResult.task.context,\n validUntil: Date.now(),\n handledAt: new Date(output.handledAt).getTime(),\n handled: {\n action: {\n id: output.action.id,\n data: output.action.data,\n },\n handledBy: output.handledBy,\n },\n }) as unknown as Expand<DiscriminatedApprovalResult<A>>;\n}\n\n/**\n * Approve / decline gate for Vercel Workflow (`sendToHumanInWorkflow` with fixed actions).\n */\nexport async function approveByHumanInWorkflow(\n payload: ApproveByHumanWorkflowPayload\n): Promise<Expand<DiscriminatedApprovalResult<typeof APPROVE_BY_HUMAN_ACTIONS>>> {\n return sendToHumanInWorkflow({\n ...payload,\n actions: APPROVE_BY_HUMAN_ACTIONS,\n });\n}\n\nexport type SendUpdateWorkflowPayload = {\n /** Thread to log the update against (from a prior task's `threadId`). */\n threadId: string;\n /** Short status update (1-2 sentences) shown in the inbox status bar. */\n message: string;\n /** Lifecycle status driving the status-bar icon/color. @default \"info\" */\n status?: ThreadUpdateStatus;\n /** Inbox app bucket. Overrides `ROBOTROCK_APP` when set. */\n app?: string;\n};\n\n/**\n * Posts a thread update via `client.sendUpdate()`. Marked as a step so the API\n * call runs in full Node.js with retries and is recorded in the workflow run.\n */\nasync function sendRobotRockUpdate(payload: SendUpdateWorkflowPayload): Promise<ThreadUpdate> {\n \"use step\";\n\n const { app, ...update } = payload;\n const baseConfig = resolveRobotRockConfig();\n const client = createClient({\n apiKey: baseConfig.apiKey,\n baseUrl: baseConfig.baseUrl,\n ...((app ?? baseConfig.app) ? { app: app ?? baseConfig.app } : {}),\n ...(baseConfig.version ? { version: baseConfig.version } : {}),\n });\n\n return client.sendUpdate(update);\n}\n\n/**\n * Durable thread update for Vercel Workflow.\n *\n * Wraps {@link createClient}'s `sendUpdate` in a `\"use step\"` so progress\n * reports are retried and recorded in the run. Fire-and-forget: returns the\n * created update without suspending the workflow (no human wait involved).\n *\n * Call from a function with `\"use workflow\"` as its first statement.\n */\nexport async function sendUpdateInWorkflow(\n payload: SendUpdateWorkflowPayload\n): Promise<ThreadUpdate> {\n return sendRobotRockUpdate(payload);\n}\n\nexport type { RobotRockHandlerWebhookPayload } from \"../handler-webhook.js\";\nexport type {\n ApprovalResult,\n DiscriminatedApprovalResult,\n TaskContextInput,\n TaskResult,\n ThreadUpdate,\n ThreadUpdateStatus,\n} from \"../schemas/index.js\";\n"],"mappings":"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","names":[]}
@@ -1,8 +1,8 @@
1
1
  import * as ai from 'ai';
2
2
  import { ToolApprovalResponse } from 'ai';
3
3
  import { z } from 'zod';
4
- import { b as RobotRock, a as SendToHumanInput, S as SendToHumanActionInput } from './client-BOm2Ce2f.js';
5
- import { DiscriminatedApprovalResult } from './schemas/index.js';
4
+ import { b as RobotRock, a as SendToHumanInput, S as SendToHumanActionInput, l as SendUpdateInput } from './client-CLcHdjOz.js';
5
+ import { DiscriminatedApprovalResult, ThreadUpdate } from './schemas/index.js';
6
6
 
7
7
  declare const APPROVE_BY_HUMAN_ACTIONS$1: readonly [{
8
8
  readonly id: "approve";
@@ -35,6 +35,14 @@ type RobotRockAiWorkflowContext = {
35
35
  type RobotRockAiContext = RobotRockAiPollingContext | RobotRockAiTriggerContext | RobotRockAiWorkflowContext;
36
36
  declare function normalizeRobotRockAiContext(clientOrContext: RobotRock | RobotRockAiContext): RobotRockAiContext;
37
37
  declare function sendToHumanForAi<A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[]>(context: RobotRockAiContext, payload: SendToHumanInput<A>): Promise<DiscriminatedApprovalResult<A>>;
38
+ /**
39
+ * Posts a thread update for an AI tool, routing by execution mode.
40
+ *
41
+ * `sendUpdate` is fire-and-forget (no human wait), so only the workflow path
42
+ * needs durability — it runs inside a `"use step"`. Trigger and polling modes
43
+ * issue the request directly.
44
+ */
45
+ declare function sendUpdateForAi(context: RobotRockAiContext, payload: SendUpdateInput): Promise<ThreadUpdate>;
38
46
  declare function approveByHumanForAi(context: RobotRockAiContext, payload: Omit<SendToHumanInput, "actions"> & {
39
47
  app?: string;
40
48
  }): Promise<DiscriminatedApprovalResult<typeof APPROVE_BY_HUMAN_ACTIONS$1>>;
@@ -196,6 +204,11 @@ type CreateSendToHumanToolOptions<A extends readonly SendToHumanActionInput[] =
196
204
  defaultType?: string;
197
205
  description?: string;
198
206
  toolName?: string;
207
+ /**
208
+ * Group every task this tool creates onto a shared thread. Pass the same
209
+ * value to {@link createSendUpdateTool} so updates land on the same thread.
210
+ */
211
+ threadId?: string;
199
212
  };
200
213
  type CreateSendToHumanToolDurableOptions<A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[]> = CreateSendToHumanToolOptions<A> & RobotRockAiContext & {
201
214
  mode: "trigger" | "workflow";
@@ -222,11 +235,77 @@ declare function createSendToHumanTool<A extends readonly SendToHumanActionInput
222
235
  } | undefined;
223
236
  }, HumanToolResult>;
224
237
 
238
+ /**
239
+ * Result returned to the model by {@link createSendUpdateTool}.
240
+ *
241
+ * Updates are fire-and-forget, so a missing thread (no task created yet) is
242
+ * reported as `{ posted: false }` instead of throwing — that way an agent loop
243
+ * is never aborted by a non-critical progress update. Genuine failures (auth,
244
+ * validation, server errors) still throw.
245
+ */
246
+ type SendUpdateToolResult = {
247
+ posted: true;
248
+ threadId: string;
249
+ update: ThreadUpdate;
250
+ } | {
251
+ posted: false;
252
+ threadId: string;
253
+ reason: "thread_not_found";
254
+ message: string;
255
+ };
256
+ declare const sendUpdateToolInputSchema: z.ZodObject<{
257
+ threadId: z.ZodOptional<z.ZodString>;
258
+ message: z.ZodString;
259
+ status: z.ZodOptional<z.ZodEnum<["info", "queued", "running", "waiting", "succeeded", "failed", "cancelled"]>>;
260
+ }, "strip", z.ZodTypeAny, {
261
+ message: string;
262
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
263
+ threadId?: string | undefined;
264
+ }, {
265
+ message: string;
266
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
267
+ threadId?: string | undefined;
268
+ }>;
269
+ type CreateSendUpdateToolOptions = {
270
+ /**
271
+ * Session thread to post updates to when the model does not supply `threadId`.
272
+ * Pass the same value to {@link createSendToHumanTool} to auto-thread tasks
273
+ * and updates together.
274
+ */
275
+ threadId?: string;
276
+ description?: string;
277
+ };
278
+ type CreateSendUpdateToolDurableOptions = CreateSendUpdateToolOptions & RobotRockAiContext & {
279
+ mode: "trigger" | "workflow";
280
+ };
281
+ /**
282
+ * AI SDK tool that posts a progress update to a RobotRock thread.
283
+ *
284
+ * Fire-and-forget (no human wait): the agent reports status as it works.
285
+ *
286
+ * - `createSendUpdateTool(robotrock, options?)` — polling client (default).
287
+ * - `createSendUpdateTool({ mode: "trigger", app?: "my-agent" })` — Trigger.dev worker.
288
+ * - `createSendUpdateTool({ mode: "workflow", app?: "my-agent" })` — Vercel Workflow (durable step).
289
+ *
290
+ * The thread is resolved from the tool input `threadId`, falling back to a
291
+ * session `threadId` in the options. Provide at least one.
292
+ */
293
+ declare function createSendUpdateTool(clientOrOptions: RobotRock | CreateSendUpdateToolDurableOptions, maybeOptions?: CreateSendUpdateToolOptions): ai.Tool<{
294
+ message: string;
295
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
296
+ threadId?: string | undefined;
297
+ }, SendUpdateToolResult>;
298
+
225
299
  type CreateRobotRockAiToolsOptions = {
226
300
  /** @default "polling" when `client` is passed; `"trigger"` or `"workflow"` for durable waits. */
227
301
  mode?: "polling" | "trigger" | "workflow";
228
302
  client?: RobotRock;
229
303
  app?: string;
304
+ /**
305
+ * Shared thread for tasks and updates these tools create. Enables the
306
+ * `sendUpdate` tool to auto-thread onto tasks made by the `sendToHuman` tool.
307
+ */
308
+ threadId?: string;
230
309
  };
231
310
  /**
232
311
  * Build AI SDK tools for a given RobotRock execution mode.
@@ -268,6 +347,11 @@ declare function createRobotRockAiTools(options: CreateRobotRockAiToolsOptions):
268
347
  groups?: string[] | undefined;
269
348
  } | undefined;
270
349
  }, HumanToolResult>;
350
+ sendUpdate: (toolOptions?: CreateSendUpdateToolOptions) => ai.Tool<{
351
+ message: string;
352
+ status?: "info" | "queued" | "running" | "waiting" | "succeeded" | "failed" | "cancelled" | undefined;
353
+ threadId?: string | undefined;
354
+ }, SendUpdateToolResult>;
271
355
  };
272
356
  /** Shorthand for `{ mode: "trigger", app }`. */
273
357
  declare function createRobotRockAiTriggerContext(options?: Omit<RobotRockAiTriggerContext, "mode">): RobotRockAiContext;
@@ -306,4 +390,4 @@ declare function resolveToolApprovalsViaRobotRock(clientOrContext: RobotRock | R
306
390
  */
307
391
  declare function runWithRobotRockApprovals<T>(options: RunWithRobotRockApprovalsOptions<T>): Promise<T>;
308
392
 
309
- export { APPROVE_BY_HUMAN_ACTIONS as A, type ResolveToolApprovalsOptions as B, type CreateSendToHumanToolOptions as C, type RobotRockToolApprovalConfig as D, type RunWithRobotRockApprovalsOptions as E, type FormatToolApprovalTaskOptions as F, type HumanToolResult as H, type RobotRockToolCallInfo as R, type ToolApprovalRequestPart as T, approveByHumanTool as a, approveByHumanInputSchema as b, type ApproveByHumanToolOptions as c, type ApproveByHumanToolDurableOptions as d, createSendToHumanTool as e, type CreateSendToHumanToolDurableOptions as f, approveByHumanForAi as g, sendToHumanForAi as h, type RobotRockAiContext as i, type RobotRockAiMode as j, type RobotRockAiPollingContext as k, type RobotRockAiTriggerContext as l, type RobotRockAiWorkflowContext as m, normalizeRobotRockAiContext as n, createRobotRockAiTools as o, createRobotRockAiTriggerContext as p, createRobotRockAiWorkflowContext as q, type CreateRobotRockAiToolsOptions as r, sendToHumanToolInputSchema as s, applyRobotRockToolApprovalToTools as t, collectApprovalRequests as u, createRobotRockNeedsApproval as v, createRobotRockToolApproval as w, resolveToolApprovalsViaRobotRock as x, runWithRobotRockApprovals as y, type RobotRockToolApprovalDecision as z };
393
+ export { APPROVE_BY_HUMAN_ACTIONS as A, createRobotRockNeedsApproval as B, type CreateSendToHumanToolOptions as C, createRobotRockToolApproval as D, resolveToolApprovalsViaRobotRock as E, type FormatToolApprovalTaskOptions as F, runWithRobotRockApprovals as G, type HumanToolResult as H, type RobotRockToolApprovalDecision as I, type ResolveToolApprovalsOptions as J, type RobotRockToolApprovalConfig as K, type RunWithRobotRockApprovalsOptions as L, type RobotRockToolCallInfo as R, type SendUpdateToolResult as S, type ToolApprovalRequestPart as T, approveByHumanTool as a, approveByHumanInputSchema as b, type ApproveByHumanToolOptions as c, type ApproveByHumanToolDurableOptions as d, createSendToHumanTool as e, type CreateSendToHumanToolDurableOptions as f, createSendUpdateTool as g, sendUpdateToolInputSchema as h, type CreateSendUpdateToolOptions as i, type CreateSendUpdateToolDurableOptions as j, approveByHumanForAi as k, sendToHumanForAi as l, sendUpdateForAi as m, normalizeRobotRockAiContext as n, type RobotRockAiContext as o, type RobotRockAiMode as p, type RobotRockAiPollingContext as q, type RobotRockAiTriggerContext as r, sendToHumanToolInputSchema as s, type RobotRockAiWorkflowContext as t, createRobotRockAiTools as u, createRobotRockAiTriggerContext as v, createRobotRockAiWorkflowContext as w, type CreateRobotRockAiToolsOptions as x, applyRobotRockToolApprovalToTools as y, collectApprovalRequests as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robotrock",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Human-in-the-loop approval workflows for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,9 +54,13 @@
54
54
  "ai-sdk"
55
55
  ],
56
56
  "license": "MIT",
57
+ "homepage": "https://docs.robotrock.io",
57
58
  "repository": {
58
59
  "type": "git",
59
- "url": "git+https://github.com/robotrock/robotrock.git"
60
+ "url": "git+https://github.com/quintenb/robotrock-sdk.git"
61
+ },
62
+ "bugs": {
63
+ "url": "https://github.com/quintenb/robotrock-sdk/issues"
60
64
  },
61
65
  "dependencies": {
62
66
  "zod": "^3.25.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/schemas/index.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport interface JSONSchema7 {\n $id?: string;\n $ref?: string;\n $schema?: string;\n $comment?: string;\n type?: JSONSchema7TypeName | JSONSchema7TypeName[];\n enum?: unknown[];\n const?: unknown;\n multipleOf?: number;\n maximum?: number;\n exclusiveMaximum?: number;\n minimum?: number;\n exclusiveMinimum?: number;\n maxLength?: number;\n minLength?: number;\n pattern?: string;\n format?: string;\n items?: JSONSchema7 | JSONSchema7[];\n additionalItems?: JSONSchema7 | boolean;\n maxItems?: number;\n minItems?: number;\n uniqueItems?: boolean;\n contains?: JSONSchema7;\n maxProperties?: number;\n minProperties?: number;\n required?: string[];\n properties?: Record<string, JSONSchema7>;\n patternProperties?: Record<string, JSONSchema7>;\n additionalProperties?: JSONSchema7 | boolean;\n dependencies?: Record<string, JSONSchema7 | string[]>;\n propertyNames?: JSONSchema7;\n if?: JSONSchema7;\n then?: JSONSchema7;\n else?: JSONSchema7;\n allOf?: JSONSchema7[];\n anyOf?: JSONSchema7[];\n oneOf?: JSONSchema7[];\n not?: JSONSchema7;\n title?: string;\n description?: string;\n default?: unknown;\n readOnly?: boolean;\n writeOnly?: boolean;\n examples?: unknown[];\n}\n\nexport type JSONSchema7TypeName =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\nexport type ExtendedJSONSchema7 = JSONSchema7 & {\n enumNames?: string[];\n [key: string]: unknown;\n};\n\nexport type UiSchema = {\n \"ui:widget\"?: string;\n \"ui:title\"?: string;\n \"ui:description\"?: string;\n \"ui:placeholder\"?: string;\n \"ui:options\"?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nconst safeUrlSchema = z\n .string()\n .refine((url) => url.startsWith(\"http://\") || url.startsWith(\"https://\"), {\n message: \"URL must start with http:// or https://\",\n });\n\nconst jsonSchema7Schema = z.custom<ExtendedJSONSchema7>(\n (val) => typeof val === \"object\" && val !== null,\n { message: \"Must be a valid JSON Schema object\" }\n);\n\nconst uiSchemaSchema = z.custom<UiSchema>((val) => typeof val === \"object\" && val !== null, {\n message: \"Must be a valid UiSchema object\",\n});\n\nconst webhookHandlerSchema = z.object({\n type: z.literal(\"webhook\"),\n url: safeUrlSchema,\n headers: z.record(z.string()),\n});\n\nconst triggerHandlerSchema = webhookHandlerSchema.extend({\n type: z.literal(\"trigger\"),\n tokenId: z.string().min(1),\n});\n\nconst handlerSchema = z.discriminatedUnion(\"type\", [webhookHandlerSchema, triggerHandlerSchema]);\n\nconst taskActionSchema = z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n description: z.string().optional(),\n schema: jsonSchema7Schema.optional(),\n ui: uiSchemaSchema.optional(),\n data: z.record(z.unknown()).optional(),\n handlers: z.array(handlerSchema).min(1).optional(),\n});\n\nconst uiFieldSchemaSchema: z.ZodType<Record<string, unknown>> = z\n .object({\n \"ui:widget\": z.string().optional(),\n \"ui:title\": z.string().optional(),\n \"ui:description\": z.string().optional(),\n \"ui:options\": z.record(z.unknown()).optional(),\n items: z.lazy(() => z.record(uiFieldSchemaSchema)).optional(),\n })\n .passthrough();\n\nconst contextUiSchema = z.record(uiFieldSchemaSchema).optional();\n\nconst contextDataSchema = z\n .object({\n data: z.record(z.unknown()),\n ui: contextUiSchema,\n })\n .optional();\n\nexport const taskContextSchema = z.object({\n app: z.string().min(1).optional(),\n type: z.string().min(1),\n name: z.string().min(1),\n description: z.string().optional(),\n validUntil: z.string().optional(),\n context: contextDataSchema,\n version: z.literal(2).optional(),\n actions: z.array(taskActionSchema).min(1, \"At least one action is required\"),\n});\n\n/**\n * Assignment targets at task create (not stored in task context JSON).\n * Unknown user emails are auto-provisioned as assignee memberships (not full team seats).\n */\nexport const assignToSchema = z\n .object({\n users: z.array(z.string().email()).optional(),\n groups: z.array(z.string().min(1)).optional(),\n })\n .refine(\n (data) => {\n const groups = data.groups ?? [];\n if (groups.includes(\"all\") && groups.length > 1) {\n return false;\n }\n return true;\n },\n { message: 'Cannot combine \"all\" with other group slugs' }\n );\n\n/** A short thread-scoped status update message (1-2 sentences). */\nexport const threadUpdateMessageSchema = z.string().min(1).max(500);\n\n/**\n * Lifecycle status carried by a thread update. Drives the icon and color shown\n * in the inbox status bar. Defaults to `info` when omitted.\n */\nexport const threadUpdateStatuses = [\n \"info\",\n \"queued\",\n \"running\",\n \"waiting\",\n \"succeeded\",\n \"failed\",\n \"cancelled\",\n] as const;\n\nexport const threadUpdateStatusSchema = z.enum(threadUpdateStatuses);\n\n/** The default status applied when an update omits one. */\nexport const DEFAULT_THREAD_UPDATE_STATUS: ThreadUpdateStatus = \"info\";\n\n/** Shared shape for a thread update (standalone and at task creation). */\nexport const threadUpdateInputSchema = z.object({\n message: threadUpdateMessageSchema,\n status: threadUpdateStatusSchema.optional(),\n});\n\nexport const createTaskBodySchema = taskContextSchema.extend({\n assignTo: assignToSchema.optional(),\n /**\n * Groups related tasks together. When omitted, the server generates one and\n * returns it so the caller can reuse it on later tasks in the same thread.\n */\n threadId: z.string().min(1).optional(),\n /**\n * Optional initial status update logged against the task's thread. Shows in\n * the inbox status bar and the thread update log.\n */\n update: threadUpdateInputSchema.optional(),\n});\n\n/** POST /v1/threads/:threadId/updates body: a standalone thread update. */\nexport const threadUpdateBodySchema = threadUpdateInputSchema;\n\n/** Where a thread update originated. */\nexport type ThreadUpdateSource = \"api\" | \"task_create\" | \"dashboard\";\n\n/** Lifecycle status carried by a thread update. */\nexport type ThreadUpdateStatus = (typeof threadUpdateStatuses)[number];\n\n/** A logged thread update as returned by the API. */\nexport interface ThreadUpdate {\n id: string;\n threadId: string;\n message: string;\n status: ThreadUpdateStatus;\n source: ThreadUpdateSource;\n createdAt: number;\n}\n\nexport type AssignToInput = z.infer<typeof assignToSchema>;\nexport type CreateTaskBodyInput = z.input<typeof createTaskBodySchema>;\nexport type CreateTaskBody = z.output<typeof createTaskBodySchema>;\nexport type ThreadUpdateBodyInput = z.input<typeof threadUpdateBodySchema>;\nexport type ThreadUpdateBody = z.output<typeof threadUpdateBodySchema>;\nexport type ThreadUpdateInput = z.input<typeof threadUpdateInputSchema>;\nexport type TaskContextInput = z.input<typeof taskContextSchema>;\nexport type TaskContextOutput = z.output<typeof taskContextSchema>;\nexport type TaskContext = TaskContextOutput;\nexport type TaskAction = z.infer<typeof taskActionSchema>;\nexport type WebhookHandler = z.infer<typeof webhookHandlerSchema>;\nexport type TriggerHandler = z.infer<typeof triggerHandlerSchema>;\nexport type Handler = z.infer<typeof handlerSchema>;\n\ntype InferObjectProperties<\n Props,\n Req extends PropertyKey,\n> = Props extends Record<string, unknown>\n ? ({\n [K in keyof Props as K extends Req ? K : never]-?: InferJsonSchema7<Props[K]>;\n } & {\n [K in keyof Props as K extends Req ? never : K]?: InferJsonSchema7<Props[K]>;\n } extends infer O\n ? { [K in keyof O]: O[K] }\n : never)\n : Record<string, unknown>;\n\ntype RequiredKeys<S> =\n S extends { readonly required: readonly string[] } ? S[\"required\"][number] : never;\n\nexport type InferJsonSchema7<S> = [S] extends [undefined]\n ? Record<string, never>\n : S extends { readonly const: infer C }\n ? C\n : S extends {\n readonly enum: readonly (infer E)[];\n }\n ? E\n : S extends {\n readonly type: \"object\";\n readonly properties?: infer Props;\n }\n ? InferObjectProperties<Props, RequiredKeys<S>>\n : S extends {\n readonly type: \"object\";\n readonly properties?: undefined;\n }\n ? Record<string, unknown>\n : S extends {\n readonly type: \"array\";\n readonly items?: infer Items;\n }\n ? Items extends readonly unknown[]\n ? InferJsonSchema7<Items[number]>[]\n : Items extends object\n ? InferJsonSchema7<Items>[]\n : unknown[]\n : S extends { readonly type: \"string\" }\n ? string\n : S extends { readonly type: \"number\" } | { readonly type: \"integer\" }\n ? number\n : S extends { readonly type: \"boolean\" }\n ? boolean\n : unknown;\n\nexport type TaskStatus = \"pending\" | \"open\" | \"handled\" | \"expired\";\n\nexport interface TaskResponse {\n success: boolean;\n task: {\n taskId: string;\n threadId: string;\n status: \"pending\" | \"open\";\n context: TaskContext;\n validUntil: string;\n submittedAt: string;\n };\n message: string;\n}\n\nexport interface ThreadUpdateResponse {\n success: boolean;\n update: ThreadUpdate;\n message: string;\n}\n\nexport interface Task {\n id: string;\n threadId?: string;\n createdAt: Date;\n status: TaskStatus;\n context: TaskContext;\n validUntil: number;\n handledAt?: number;\n handled?: {\n action: {\n id: string;\n data: unknown;\n };\n handledBy?: string;\n userId?: string;\n token?: string;\n };\n}\n\nexport type InferActionData<T extends { schema?: unknown }> = [\n Exclude<T[\"schema\"], undefined>,\n] extends [\n never,\n]\n ? Record<string, never>\n : Exclude<T[\"schema\"], undefined> extends infer S\n ? InferJsonSchema7<S>\n : Record<string, never>;\n\nexport type TupleElementIndices<T extends readonly unknown[]> = T extends readonly [\n unknown,\n ...unknown[],\n]\n ? Exclude<keyof T, keyof unknown[]>\n : number;\n\nexport interface TaskResult<T = Record<string, unknown>> {\n actionId: string;\n data: T;\n handledBy?: string;\n handledAt: Date;\n}\n\nexport interface ApprovalResult<T = Record<string, unknown>> extends TaskResult<T> {\n taskId: string;\n}\n\nexport type DiscriminatedApprovalResult<\n TActions extends readonly { id: string; schema?: unknown }[],\n> = {\n [I in TupleElementIndices<TActions>]: TActions[I] extends { id: string; schema?: unknown }\n ? Omit<ApprovalResult<InferActionData<TActions[I]>>, \"actionId\" | \"data\"> & {\n actionId: TActions[I][\"id\"];\n data: InferActionData<TActions[I]>;\n }\n : never\n}[TupleElementIndices<TActions>];\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/approval-result.ts","../src/client.ts","../src/env.ts"],"sourcesContent":["import type { DiscriminatedApprovalResult, Task } from \"./schemas/index.js\";\n\nexport class TaskTimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TaskTimeoutError\";\n }\n}\n\nexport class TaskExpiredError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TaskExpiredError\";\n }\n}\n\n/**\n * Map a handled API task to a discriminated approval result.\n * Runtime validation is minimal; TypeScript narrows via `task.actions` at the call site.\n */\nexport function toDiscriminatedApprovalResult<A extends readonly { id: string; schema?: unknown }[]>(\n actions: A,\n task: Task\n): DiscriminatedApprovalResult<A> {\n void actions;\n\n if (!task.handled) {\n throw new Error(\"Task has no handled result\");\n }\n\n return {\n actionId: task.handled.action.id,\n data: task.handled.action.data,\n handledBy: task.handled.handledBy,\n handledAt: new Date(task.handledAt ?? Date.now()),\n taskId: task.id,\n } as DiscriminatedApprovalResult<A>;\n}\n","import {\n type AssignToInput,\n type TaskContextInput,\n createTaskBodySchema,\n threadUpdateBodySchema,\n} from \"./schemas/index.js\";\nimport {\n TaskExpiredError,\n TaskTimeoutError,\n toDiscriminatedApprovalResult,\n} from \"./approval-result.js\";\nimport type {\n DiscriminatedApprovalResult,\n Task,\n TaskResponse,\n ThreadUpdate,\n ThreadUpdateResponse,\n ThreadUpdateStatus,\n} from \"./schemas/index.js\";\n\nexport type RobotRockWebhookConfig = {\n url: string;\n headers?: Record<string, string>;\n};\n\nexport interface RobotRockPollingOptions {\n /** Poll interval when no webhook is configured (ms). @default 2000 */\n intervalMs?: number;\n /**\n * Max time to poll when no webhook is configured (ms).\n * Polling also stops when the task's `validUntil` passes, whichever is sooner.\n * @default 86400000 (24h)\n */\n timeoutMs?: number;\n}\n\ntype RobotRockClientBaseConfig = {\n /** Optional override for API key. Falls back to ROBOTROCK_API_KEY. */\n apiKey?: string;\n /**\n * Base URL for the RobotRock API\n * @default \"https://api.robotrock.io/v1\"\n */\n baseUrl?: string;\n /**\n * Default inbox app bucket for every task from this client.\n * When omitted, the API uses your API key name.\n */\n app?: string;\n /**\n * Task context format version sent on every `sendToHuman` request.\n * @default 2\n */\n version?: 2;\n};\n\n/** Client config with a webhook (mutually exclusive with `polling`). */\nexport type RobotRockWebhookClientConfig = RobotRockClientBaseConfig & {\n webhook: RobotRockWebhookConfig;\n polling?: never;\n};\n\n/** Client config without a webhook; optional `polling` controls the wait loop. */\nexport type RobotRockPollingClientConfig = RobotRockClientBaseConfig & {\n webhook?: never;\n polling?: RobotRockPollingOptions;\n};\n\nexport type RobotRockConfig = RobotRockWebhookClientConfig | RobotRockPollingClientConfig;\n\nexport type SendToHumanActionInput = Omit<TaskContextInput[\"actions\"][number], \"handlers\">;\n\nexport type SendToHumanValidUntil = Date | string;\n\nexport type SendToHumanInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = Omit<TaskContextInput, \"app\" | \"actions\" | \"version\" | \"validUntil\"> & {\n actions: A;\n /** Task deadline; serialized to an ISO 8601 string on the wire. */\n validUntil?: SendToHumanValidUntil;\n /** Optional idempotency key to prevent duplicate tasks */\n idempotencyKey?: string;\n /** Assign to tenant users (email) and/or groups (slug). Narrows inbox visibility. */\n assignTo?: AssignToInput;\n /**\n * Groups related tasks together in the inbox. Omit to let the server generate\n * one (returned as `task.threadId`) and reuse it on later tasks in the thread.\n */\n threadId?: string;\n /**\n * Optional initial status update logged against the task's thread. Shows in\n * the inbox status bar and the thread update log.\n */\n update?: {\n /** A short status update (1-2 sentences). */\n message: string;\n /** Lifecycle status for the icon/color in the status bar. @default \"info\" */\n status?: ThreadUpdateStatus;\n };\n};\n\ntype SendToHumanWithAppInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> = (SendToHumanInput<A> | Readonly<SendToHumanInput<A>>) & {\n /** Inbox app bucket. Overrides the client `app` when set. */\n app?: string;\n};\n\nexport type SendUpdateInput = {\n /** The thread to log the update against (from `task.threadId`). */\n threadId: string;\n /** A short status update (1-2 sentences). */\n message: string;\n /** Lifecycle status for the icon/color in the status bar. @default \"info\" */\n status?: ThreadUpdateStatus;\n};\n\nexport type SendToHumanResult<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n> =\n | {\n mode: \"created\";\n task: TaskResponse[\"task\"];\n }\n | ({\n mode: \"handled\";\n task: TaskResponse[\"task\"];\n } & DiscriminatedApprovalResult<A>);\n\nconst DEFAULT_POLL_INTERVAL_MS = 2_000;\nconst DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseValidUntilMs(value: string | number | Date | undefined): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (value instanceof Date) {\n const ms = value.getTime();\n return Number.isNaN(ms) ? undefined : ms;\n }\n\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : undefined;\n }\n\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction serializeValidUntil(value: SendToHumanValidUntil): string {\n if (value instanceof Date) {\n const ms = value.getTime();\n if (Number.isNaN(ms)) {\n throw new RobotRockError(\"Invalid validUntil: Date is invalid\", 400);\n }\n return value.toISOString();\n }\n\n if (typeof value === \"string\" && !Number.isNaN(Date.parse(value))) {\n return new Date(value).toISOString();\n }\n\n throw new RobotRockError(\"Invalid validUntil: expected a Date or parseable date string\", 400);\n}\n\nexport class RobotRockError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly response?: unknown\n ) {\n super(message);\n this.name = \"RobotRockError\";\n }\n}\n\n/**\n * RobotRock API client for creating and querying human-in-the-loop tasks.\n */\nexport class RobotRock {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly app?: string;\n private readonly version: 2;\n private readonly webhook?: RobotRockWebhookConfig;\n private readonly polling: RobotRockPollingOptions;\n\n constructor(config: RobotRockConfig) {\n if (config.webhook && config.polling) {\n throw new Error(\n \"RobotRock client cannot configure both webhook and polling. Use webhook for callbacks or polling to block until handled.\"\n );\n }\n\n const apiKey = config.apiKey ?? process.env.ROBOTROCK_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client.\"\n );\n }\n this.apiKey = apiKey;\n const rawBase = config.baseUrl ?? \"https://api.robotrock.io/v1\";\n this.baseUrl = rawBase.replace(/\\/+$/, \"\");\n this.app = config.app;\n this.version = config.version ?? 2;\n this.webhook = config.webhook;\n this.polling = config.polling ?? {};\n }\n\n /**\n * Create a task via POST /v1 without waiting for a human response.\n */\n async createTask<const A extends readonly SendToHumanActionInput[]>(\n task: SendToHumanWithAppInput<A>\n ): Promise<TaskResponse[\"task\"]> {\n const normalizedTask = normalizeSendToHumanInput(task, {\n webhook: this.webhook,\n app: this.app,\n version: this.version,\n });\n const bodyPayload = {\n ...normalizedTask,\n ...(task.assignTo !== undefined ? { assignTo: task.assignTo } : {}),\n ...(task.threadId !== undefined ? { threadId: task.threadId } : {}),\n ...(task.update !== undefined ? { update: task.update } : {}),\n };\n const validation = createTaskBodySchema.safeParse(bodyPayload);\n if (!validation.success) {\n throw new RobotRockError(\n `Invalid task: ${validation.error.errors[0]?.message}`,\n 400,\n validation.error.errors\n );\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n };\n\n if (task.idempotencyKey) {\n headers[\"Idempotency-Key\"] = task.idempotencyKey;\n }\n\n const response = await fetch(`${this.baseUrl}/`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(validation.data),\n });\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to create task\"),\n response.status,\n data\n );\n }\n\n return (data as unknown as TaskResponse).task;\n }\n\n async sendToHuman<const A extends readonly SendToHumanActionInput[]>(\n task: SendToHumanWithAppInput<A>\n ): Promise<SendToHumanResult<A>> {\n const normalizedTask = normalizeSendToHumanInput(task, {\n webhook: this.webhook,\n app: this.app,\n version: this.version,\n });\n const createdTaskTask = await this.createTask(task);\n const hasHandlers = normalizedTask.actions.some(\n (action) => Array.isArray(action.handlers) && action.handlers.length > 0\n );\n\n if (hasHandlers) {\n return {\n mode: \"created\",\n task: createdTaskTask,\n };\n }\n\n const timeoutMs = this.polling.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const pollIntervalMs = this.polling.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const pollingDeadline = Date.now() + timeoutMs;\n const validUntilMs = parseValidUntilMs(createdTaskTask.validUntil);\n const deadline =\n validUntilMs !== undefined ? Math.min(pollingDeadline, validUntilMs) : pollingDeadline;\n const taskId = createdTaskTask.taskId;\n\n while (Date.now() < deadline) {\n const existing = await this.getTask(taskId);\n\n if (existing?.status === \"handled\" && existing.handled) {\n return {\n mode: \"handled\",\n task: createdTaskTask,\n ...(toDiscriminatedApprovalResult(\n normalizedTask.actions as unknown as A,\n existing\n ) as DiscriminatedApprovalResult<A>),\n };\n }\n\n if (existing?.status === \"expired\" || (existing && Date.now() >= existing.validUntil)) {\n throw new TaskExpiredError(\"Task reached validUntil before a human completed it\");\n }\n\n const remainingMs = deadline - Date.now();\n await sleep(Math.min(pollIntervalMs, Math.max(0, remainingMs)));\n }\n\n if (validUntilMs !== undefined && Date.now() >= validUntilMs) {\n throw new TaskExpiredError(\"Task reached validUntil before a human completed it\");\n }\n\n throw new TaskTimeoutError(`No human response within ${timeoutMs}ms`);\n }\n\n /**\n * Get a task by public task id (returned as `task.taskId` from {@link sendToHuman}).\n */\n async getTask(taskId: string): Promise<Task | null> {\n const response = await fetch(`${this.baseUrl}/tasks/${taskId}`, {\n method: \"GET\",\n headers: {\n \"X-Api-Key\": this.apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to get task\"),\n response.status,\n data\n );\n }\n\n return data as unknown as Task;\n }\n\n /**\n * Log a status update against a thread. The update shows in the inbox status\n * bar and thread update log for every task in the thread.\n */\n async sendUpdate({ threadId, message, status }: SendUpdateInput): Promise<ThreadUpdate> {\n if (!threadId) {\n throw new RobotRockError(\"threadId is required to send an update\", 400);\n }\n\n const validation = threadUpdateBodySchema.safeParse({ message, status });\n if (!validation.success) {\n throw new RobotRockError(\n `Invalid update: ${validation.error.errors[0]?.message}`,\n 400,\n validation.error.errors\n );\n }\n\n const response = await fetch(\n `${this.baseUrl}/threads/${encodeURIComponent(threadId)}/updates`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key\": this.apiKey,\n },\n body: JSON.stringify(validation.data),\n }\n );\n\n const data = await parseResponseBody(response);\n\n if (!response.ok) {\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to send update\"),\n response.status,\n data\n );\n }\n\n return (data as unknown as ThreadUpdateResponse).update;\n }\n\n async cancelTask(taskId: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/tasks/${taskId}/cancel`, {\n method: \"POST\",\n headers: {\n \"X-Api-Key\": this.apiKey,\n },\n });\n\n if (!response.ok) {\n const data = await parseResponseBody(response);\n throw new RobotRockError(\n getErrorMessage(data, \"Failed to cancel task\"),\n response.status,\n data\n );\n }\n }\n}\n\nexport function createClient(config: RobotRockConfig): RobotRock {\n return new RobotRock(config);\n}\n\nexport function attachWebhookToActions(\n actions: readonly SendToHumanActionInput[],\n webhook: RobotRockWebhookConfig\n): TaskContextInput[\"actions\"] {\n return actions.map((action) => ({\n ...action,\n handlers: webhookToHandlers(webhook),\n }));\n}\n\nfunction webhookToHandlers(\n webhook: RobotRockWebhookConfig\n): TaskContextInput[\"actions\"][number][\"handlers\"] {\n return [\n {\n type: \"webhook\" as const,\n url: webhook.url,\n headers: webhook.headers ?? {},\n },\n ];\n}\n\nfunction normalizeSendToHumanInput<\n A extends readonly SendToHumanActionInput[] = readonly SendToHumanActionInput[],\n>(\n task: SendToHumanWithAppInput<A>,\n clientDefaults: { webhook?: RobotRockWebhookConfig; app?: string; version: 2 }\n): TaskContextInput {\n const {\n actions,\n idempotencyKey: _idempotencyKey,\n assignTo: _assignTo,\n threadId: _threadId,\n update: _update,\n validUntil,\n app: taskApp,\n ...rest\n } = task;\n\n const webhook = clientDefaults.webhook;\n const normalizedActions: TaskContextInput[\"actions\"] = webhook\n ? attachWebhookToActions(actions, webhook)\n : (actions as unknown as TaskContextInput[\"actions\"]);\n\n const app = taskApp ?? clientDefaults.app;\n\n return {\n ...rest,\n version: clientDefaults.version,\n ...(app ? { app } : {}),\n ...(validUntil !== undefined ? { validUntil: serializeValidUntil(validUntil) } : {}),\n actions: normalizedActions,\n };\n}\n\ntype ParsedResponseBody = Record<string, unknown> | unknown[] | string | null;\n\nasync function parseResponseBody(response: Response): Promise<ParsedResponseBody> {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const bodyText = await response.text();\n\n if (!bodyText) {\n return null;\n }\n\n if (contentType.toLowerCase().includes(\"application/json\")) {\n try {\n return JSON.parse(bodyText) as ParsedResponseBody;\n } catch {\n // Fall through and return text body below so error messages stay useful.\n }\n }\n\n try {\n return JSON.parse(bodyText) as ParsedResponseBody;\n } catch {\n return bodyText;\n }\n}\n\nfunction getErrorMessage(data: ParsedResponseBody, fallback: string): string {\n if (data && typeof data === \"object\" && !Array.isArray(data)) {\n const maybeMessage = (data as Record<string, unknown>).message;\n if (typeof maybeMessage === \"string\" && maybeMessage.trim()) {\n return maybeMessage;\n }\n }\n\n if (typeof data === \"string\" && data.trim()) {\n const compact = data.replace(/\\s+/g, \" \").trim();\n const snippet = compact.length > 180 ? `${compact.slice(0, 180)}...` : compact;\n return `${fallback}. Server returned non-JSON response: ${snippet}`;\n }\n\n return fallback;\n}\n","import { createClient, type RobotRock, type RobotRockConfig } from \"./client.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.robotrock.io/v1\";\n\n/**\n * Read RobotRock client config from environment variables.\n *\n * - `ROBOTROCK_API_KEY` (required when not passed explicitly)\n * - `ROBOTROCK_BASE_URL` or `ROBOTROCK_API_URL` (optional)\n * - `ROBOTROCK_APP` (optional inbox app bucket)\n */\nexport function resolveRobotRockConfig(\n overrides?: Partial<RobotRockConfig>\n): RobotRockConfig {\n const apiKey = overrides?.apiKey ?? process.env.ROBOTROCK_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"RobotRock API key is required. Set ROBOTROCK_API_KEY or pass apiKey when creating the client.\"\n );\n }\n\n const baseUrl =\n overrides?.baseUrl ??\n process.env.ROBOTROCK_BASE_URL ??\n process.env.ROBOTROCK_API_URL ??\n DEFAULT_BASE_URL;\n\n const app = overrides?.app ?? process.env.ROBOTROCK_APP;\n\n return app ? { apiKey, baseUrl, app } : { apiKey, baseUrl };\n}\n\n/** Use an explicit client or create one from env / optional config overrides. */\nexport function resolveRobotRockClient(\n client?: RobotRock,\n configOverrides?: Partial<RobotRockConfig>\n): RobotRock {\n if (client) {\n return client;\n }\n return createClient(resolveRobotRockConfig(configOverrides));\n}\n"],"mappings":"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","names":[]}