@sentry/junior 0.202.0 → 0.204.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.
Files changed (174) hide show
  1. package/dist/agent-CMyTD4DD.js +17509 -0
  2. package/dist/agent-hooks-Bbcp9e33.js +4040 -0
  3. package/dist/agent-runner-DNb1A49M.js +678 -0
  4. package/dist/api/schema.d.ts +2728 -2639
  5. package/dist/api/schema.js +4 -169
  6. package/dist/api.d.ts +23 -17
  7. package/dist/api.js +3881 -5326
  8. package/dist/app-B1TOqBI8.d.ts +246 -0
  9. package/dist/app.d.ts +4 -520
  10. package/dist/app.js +9522 -11875
  11. package/dist/auth-pause-state-DosEalIG.js +168 -0
  12. package/dist/catalog-runtime-BReos-D4.js +7 -0
  13. package/dist/checkpoint-CNrPyRJN.js +2450 -0
  14. package/dist/cli/chat.d.ts +20 -0
  15. package/dist/cli/chat.js +229 -336
  16. package/dist/cli/check.d.ts +8 -0
  17. package/dist/cli/check.js +513 -806
  18. package/dist/cli/env.d.ts +13 -0
  19. package/dist/cli/env.js +63 -12
  20. package/dist/cli/init.d.ts +3 -0
  21. package/dist/cli/init.js +90 -159
  22. package/dist/cli/main.d.ts +6 -0
  23. package/dist/cli/main.js +43 -64
  24. package/dist/cli/plugins.d.ts +13 -0
  25. package/dist/cli/plugins.js +148 -227
  26. package/dist/cli/run.d.ts +16 -0
  27. package/dist/cli/run.js +52 -8
  28. package/dist/cli/snapshot-create.d.ts +4 -0
  29. package/dist/cli/snapshot-create.js +71 -125
  30. package/dist/cli/upgrade.d.ts +15 -0
  31. package/dist/cli/upgrade.js +232 -335
  32. package/dist/config-nGCW1OTG.js +941 -0
  33. package/dist/context-B45_WqVX.js +298 -0
  34. package/dist/conversation-privacy-B4voFRSm.js +182 -0
  35. package/dist/conversation-work-C6y3T5Hx.js +51 -0
  36. package/dist/credential-sync-kXr1hvO1.js +2660 -0
  37. package/dist/db-BeyXKJOI.d.ts +5 -0
  38. package/dist/destinations-BeBiJeEM.js +29 -0
  39. package/dist/execution-stats-DWfSihcH.js +373 -0
  40. package/dist/executor-DcMSlI5c.js +721 -0
  41. package/dist/experimental-CIXf7Uye.js +46 -0
  42. package/dist/history-ClE4toxe.d.ts +32 -0
  43. package/dist/history-CqTuSAdI.js +441 -0
  44. package/dist/instrumentation.d.ts +3 -3
  45. package/dist/instrumentation.js +130 -176
  46. package/dist/job-queue-Drn_LXlM.js +63 -0
  47. package/dist/logging-BzAk1S_s.js +1210 -0
  48. package/dist/model-profile-CZmVoGdX.js +49 -0
  49. package/dist/nitro.d.ts +31 -36
  50. package/dist/nitro.js +275 -456
  51. package/dist/oauth-callback-server-JiftokvA.js +130 -0
  52. package/dist/oauth-relay-CdCnu80W.js +62 -0
  53. package/dist/package-discovery-7a9YqLhE.js +455 -0
  54. package/dist/pending-auth-CWmSdZVg.js +185 -0
  55. package/dist/plugin-module-BKGOXca2.js +81 -0
  56. package/dist/plugins-BI9A1vKA.d.ts +95 -0
  57. package/dist/plugins-egKWjgue.js +99 -0
  58. package/dist/private-trace-result-BLvBjy_e.js +16 -0
  59. package/dist/profile-CrT5nXbw.js +861 -0
  60. package/dist/registry-DH1xUo2N.js +1419 -0
  61. package/dist/reporting-schema-DosTN__Q.js +105 -0
  62. package/dist/resolve-CZHnfxaS.js +546 -0
  63. package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
  64. package/dist/runner-CZV2sC46.js +392 -0
  65. package/dist/sandbox-egress-signals-bHZfmhbd.js +46 -0
  66. package/dist/schema-Rn8-XEaN.js +1140 -0
  67. package/dist/sentry-CD3SdJl-.js +26 -0
  68. package/dist/skills-CIcDQSgM.js +316 -0
  69. package/dist/spawn-DdkUFRmq.js +29 -0
  70. package/dist/stats-DTUbAb88.js +2634 -0
  71. package/dist/store-C5qxF2ac.d.ts +208 -0
  72. package/dist/task-queue-CJIR4RF7.js +136 -0
  73. package/dist/task-runner-D-O3A-Cp.js +639 -0
  74. package/dist/thread-state-CRc9jTJS.js +431 -0
  75. package/dist/turn-execution-BkinIdJF.js +47 -0
  76. package/dist/turn-lifecycle-DQV19VTW.js +54 -0
  77. package/dist/usage-D3EbSO7w.js +296 -0
  78. package/dist/usage-schema-CKaDkH_j.js +20 -0
  79. package/dist/validation-C2CR-OX3.js +40 -0
  80. package/dist/vercel-queue-DIkVcfK4.js +167 -0
  81. package/dist/vercel.d.ts +6 -6
  82. package/dist/vercel.js +14 -6
  83. package/dist/version-CnXZ614E.d.ts +5 -0
  84. package/dist/version-DxcWdoKa.js +8 -0
  85. package/dist/version.d.ts +2 -4
  86. package/dist/version.js +2 -6
  87. package/dist/web-authorization-RMBxAR_t.js +76 -0
  88. package/dist/web-input-3EPfpf55.js +494 -0
  89. package/dist/work-fGofI7Op.js +509 -0
  90. package/dist/worker-CsOLq-mR.js +625 -0
  91. package/package.json +9 -9
  92. package/dist/agent-hooks-UXITLYOK.js +0 -51
  93. package/dist/catalog-runtime-BG3JLLK2.js +0 -14
  94. package/dist/chunk-2LYHWMR4.js +0 -46
  95. package/dist/chunk-2MK3QBGA.js +0 -321
  96. package/dist/chunk-3PGQSKJV.js +0 -692
  97. package/dist/chunk-3UI3WFTX.js +0 -519
  98. package/dist/chunk-3Y47VMHV.js +0 -6
  99. package/dist/chunk-4UO6FK4G.js +0 -64
  100. package/dist/chunk-5NOPO64K.js +0 -198
  101. package/dist/chunk-5PKWYPFT.js +0 -2943
  102. package/dist/chunk-63NKKFJL.js +0 -1228
  103. package/dist/chunk-6AYH6252.js +0 -787
  104. package/dist/chunk-6Y5B5PEX.js +0 -80
  105. package/dist/chunk-7DHZP5KJ.js +0 -333
  106. package/dist/chunk-7H2VZTWN.js +0 -103
  107. package/dist/chunk-7NL7T6VU.js +0 -406
  108. package/dist/chunk-A76OIMYN.js +0 -102
  109. package/dist/chunk-AWMS3SPP.js +0 -58
  110. package/dist/chunk-B3LY5RCL.js +0 -229
  111. package/dist/chunk-BD2KT3OB.js +0 -36
  112. package/dist/chunk-BXCX5QKA.js +0 -2086
  113. package/dist/chunk-C6VVF43U.js +0 -81
  114. package/dist/chunk-CEMMLV5L.js +0 -98
  115. package/dist/chunk-CM5HNV2W.js +0 -131
  116. package/dist/chunk-DA2KGZZI.js +0 -13
  117. package/dist/chunk-DBVY6HLX.js +0 -64
  118. package/dist/chunk-DIB4GX3G.js +0 -8
  119. package/dist/chunk-DKIJ2RP5.js +0 -68
  120. package/dist/chunk-DL2KLKVH.js +0 -931
  121. package/dist/chunk-DWPN6SCH.js +0 -172
  122. package/dist/chunk-ELWOYVOY.js +0 -206
  123. package/dist/chunk-EWT7H65X.js +0 -506
  124. package/dist/chunk-FA6POGLH.js +0 -70
  125. package/dist/chunk-HMREVIO2.js +0 -135
  126. package/dist/chunk-IIWUT4FO.js +0 -820
  127. package/dist/chunk-JAL3CH4G.js +0 -27
  128. package/dist/chunk-JSJQEWBJ.js +0 -3295
  129. package/dist/chunk-KHKKHDLD.js +0 -387
  130. package/dist/chunk-LA6R4A7Q.js +0 -706
  131. package/dist/chunk-LOOU2DUR.js +0 -20428
  132. package/dist/chunk-M6FHWXE3.js +0 -700
  133. package/dist/chunk-M76HMB7M.js +0 -1856
  134. package/dist/chunk-MAGNK5J4.js +0 -1520
  135. package/dist/chunk-MTM5IFCY.js +0 -1190
  136. package/dist/chunk-N7TMSOZH.js +0 -235
  137. package/dist/chunk-NHJU2ZAL.js +0 -56
  138. package/dist/chunk-NSXKRGRT.js +0 -717
  139. package/dist/chunk-OWMPFXJA.js +0 -1764
  140. package/dist/chunk-PDO5BLNM.js +0 -22
  141. package/dist/chunk-PEQXYSSE.js +0 -45
  142. package/dist/chunk-PW4P4JYF.js +0 -1135
  143. package/dist/chunk-QB54UQUS.js +0 -320
  144. package/dist/chunk-QP3OGJXF.js +0 -105
  145. package/dist/chunk-RC745GGZ.js +0 -122
  146. package/dist/chunk-REOIRYPR.js +0 -37
  147. package/dist/chunk-SCOZRLZ4.js +0 -164
  148. package/dist/chunk-TXJSXBV5.js +0 -1433
  149. package/dist/chunk-TXKUKMVO.js +0 -417
  150. package/dist/chunk-U2GPUYAL.js +0 -3656
  151. package/dist/chunk-UIE3R5XU.js +0 -17
  152. package/dist/chunk-UXPG6ZIN.js +0 -84
  153. package/dist/chunk-VFUK3X5B.js +0 -50
  154. package/dist/chunk-WQSHDTTI.js +0 -1163
  155. package/dist/chunk-X6GDDWQH.js +0 -60
  156. package/dist/chunk-Y2CM7HXH.js +0 -111
  157. package/dist/chunk-Y7X25LFY.js +0 -15
  158. package/dist/chunk-YDUR3ZYW.js +0 -10
  159. package/dist/conversation-work-VIOQ5ZF3.js +0 -54
  160. package/dist/db-3L2MCVRI.js +0 -26
  161. package/dist/discovery-DWVDM7UK.js +0 -44
  162. package/dist/experimental-P5FZM4CU.js +0 -12
  163. package/dist/oauth-callback-server-YVV6C6T2.js +0 -243
  164. package/dist/oauth-relay-5XPVRPYB.js +0 -8
  165. package/dist/plugins-YTYJMMJF.js +0 -14
  166. package/dist/runner-LQ7RETDP.js +0 -522
  167. package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
  168. package/dist/sentry-MB3NL3IR.js +0 -42
  169. package/dist/skills-XRWYEDCD.js +0 -27
  170. package/dist/spawn-RC6SJUAI.js +0 -42
  171. package/dist/task-runner-7DY7ARYH.js +0 -36
  172. package/dist/validation-7MNQGCJA.js +0 -17
  173. package/dist/work-COALHUCG.js +0 -51
  174. package/dist/worker-6MURZIPD.js +0 -24
@@ -1,820 +0,0 @@
1
- import {
2
- coerceThreadConversationState,
3
- getPersistedThreadState
4
- } from "./chunk-3UI3WFTX.js";
5
- import {
6
- recordTaskExecution
7
- } from "./chunk-EWT7H65X.js";
8
- import {
9
- pluginTaskId,
10
- pluginTaskParamsSchema,
11
- sendVercelPluginTask
12
- } from "./chunk-SCOZRLZ4.js";
13
- import {
14
- getPiMessageRole,
15
- getTurnRecord,
16
- hydrateConversationMessages,
17
- instructionTextForProjection,
18
- isToolResultError,
19
- isToolResultMessage,
20
- normalizeToolNameFromResult,
21
- stripRuntimeTurnContext
22
- } from "./chunk-5PKWYPFT.js";
23
- import {
24
- createPluginConversationEvents,
25
- createPluginEmbedder,
26
- createPluginLogger,
27
- createPluginModel,
28
- createPluginState,
29
- getPlugins,
30
- readActorIdentity
31
- } from "./chunk-U2GPUYAL.js";
32
- import {
33
- JUNIOR_THREAD_STATE_TTL_MS
34
- } from "./chunk-3Y47VMHV.js";
35
- import {
36
- getConversationStore,
37
- getDb
38
- } from "./chunk-M76HMB7M.js";
39
- import {
40
- getStateAdapter
41
- } from "./chunk-2MK3QBGA.js";
42
- import {
43
- sameActorIdentity
44
- } from "./chunk-7NL7T6VU.js";
45
- import {
46
- credentialSubjectSchema
47
- } from "./chunk-CEMMLV5L.js";
48
- import {
49
- parseSlackMessageTs
50
- } from "./chunk-N7TMSOZH.js";
51
-
52
- // src/chat/plugins/task-runner.ts
53
- import { pluginRunContextSchema } from "@sentry/junior-plugin-api";
54
-
55
- // src/chat/services/turn-session-routing.ts
56
- async function loadConversationChain(conversationId, conversationStore) {
57
- const chain = [];
58
- const seen = /* @__PURE__ */ new Set();
59
- let cursor = conversationId;
60
- while (cursor && !seen.has(cursor)) {
61
- seen.add(cursor);
62
- const conversation = await conversationStore.get({
63
- conversationId: cursor
64
- });
65
- if (!conversation) {
66
- break;
67
- }
68
- chain.push(conversation);
69
- cursor = conversation.parentConversationId;
70
- }
71
- return chain;
72
- }
73
- function slackSourceForDestination(args) {
74
- if (args.source?.kind !== "slack" || args.source.channelId !== args.destination.channelId) {
75
- return void 0;
76
- }
77
- const threadTs = args.source.threadTs?.trim();
78
- return {
79
- kind: "slack",
80
- visibility: args.source.visibility ?? "public",
81
- teamId: args.source.teamId?.trim() || args.destination.teamId,
82
- channelId: args.source.channelId,
83
- ...threadTs ? { threadTs } : void 0
84
- };
85
- }
86
- async function resolveConversationRouting(args) {
87
- const conversationStore = args.conversationStore ?? (await import("./db-3L2MCVRI.js")).getConversationStore();
88
- const chain = await loadConversationChain(
89
- args.conversationId,
90
- conversationStore
91
- );
92
- let destination;
93
- let source;
94
- let location;
95
- for (const conversation of chain) {
96
- destination ??= conversation.destination;
97
- source ??= conversation.sessionSource;
98
- location ??= conversation.location;
99
- if (destination && source) {
100
- break;
101
- }
102
- }
103
- if (!destination) {
104
- return void 0;
105
- }
106
- if (destination.platform === "slack") {
107
- const slackSource = slackSourceForDestination({ destination, source });
108
- return {
109
- destination,
110
- ...location ? { location } : void 0,
111
- ...slackSource ? { source: slackSource } : void 0
112
- };
113
- }
114
- return {
115
- destination,
116
- ...location ? { location } : void 0,
117
- ...source ? { source } : void 0
118
- };
119
- }
120
- async function resolveTurnSessionRouting(args) {
121
- const routing = await resolveConversationRouting(args);
122
- if (!routing?.destination || !routing.source) {
123
- throw new Error(
124
- `Conversation ${args.conversationId} is missing durable routing metadata`
125
- );
126
- }
127
- return {
128
- destination: routing.destination,
129
- ...routing.location ? { location: routing.location } : void 0,
130
- source: routing.source
131
- };
132
- }
133
-
134
- // src/chat/agent-dispatch/store.ts
135
- import { createHash } from "crypto";
136
- import {
137
- destinationSchema,
138
- destinationVisibilitySchema,
139
- isSlackDestination,
140
- replyAttributionSchema,
141
- sourceSchema
142
- } from "@sentry/junior-plugin-api";
143
- import { z } from "zod";
144
- var DISPATCH_PREFIX = "junior:agent_dispatch";
145
- var DISPATCH_LOCK_TTL_MS = 10 * 60 * 1e3;
146
- var DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS = 1e4;
147
- var DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH = 1e4;
148
- var nonEmptyExactStringSchema = z.string().min(1).refine(
149
- (value) => value === value.trim() && value.toLowerCase() !== "unknown"
150
- );
151
- var pendingDispatchMailboxAppendIndexSchema = z.array(
152
- nonEmptyExactStringSchema
153
- );
154
- var dispatchStatusSchema = z.enum([
155
- "pending",
156
- "running",
157
- "awaiting_resume",
158
- "completed",
159
- "failed",
160
- "blocked"
161
- ]);
162
- var dispatchActorSchema = z.object({
163
- platform: z.literal("system"),
164
- name: nonEmptyExactStringSchema
165
- }).strict();
166
- var dispatchRecordSchema = z.object({
167
- actor: dispatchActorSchema,
168
- createdAtMs: z.number().finite(),
169
- credentialSubject: credentialSubjectSchema.optional(),
170
- destination: destinationSchema,
171
- destinationVisibility: destinationVisibilitySchema,
172
- errorMessage: z.string().optional(),
173
- id: nonEmptyExactStringSchema,
174
- idempotencyKey: z.string().min(1),
175
- input: z.string().min(1),
176
- metadata: z.record(z.string(), z.string()).optional(),
177
- plugin: nonEmptyExactStringSchema,
178
- replyAttribution: replyAttributionSchema.optional(),
179
- resultMessageTs: z.string().optional(),
180
- source: sourceSchema,
181
- status: dispatchStatusSchema,
182
- updatedAtMs: z.number().finite()
183
- }).strict().superRefine((record, ctx) => {
184
- if (!isSlackDestination(record.destination)) {
185
- ctx.addIssue({
186
- code: z.ZodIssueCode.custom,
187
- message: "Dispatch destination platform must be slack",
188
- path: ["destination"]
189
- });
190
- return;
191
- }
192
- const subject = record.credentialSubject;
193
- if (!subject) {
194
- return;
195
- }
196
- if (subject.allowedWhen === "private-direct-conversation") {
197
- if (!record.destination.channelId.startsWith("D")) {
198
- ctx.addIssue({
199
- code: z.ZodIssueCode.custom,
200
- message: "Dispatch credentialSubject requires a private direct Slack destination",
201
- path: ["credentialSubject"]
202
- });
203
- return;
204
- }
205
- if (subject.binding.type !== "slack-direct-conversation" || subject.binding.teamId !== record.destination.teamId || subject.binding.channelId !== record.destination.channelId) {
206
- ctx.addIssue({
207
- code: z.ZodIssueCode.custom,
208
- message: "Dispatch credentialSubject binding must match destination",
209
- path: ["credentialSubject", "binding"]
210
- });
211
- }
212
- return;
213
- }
214
- if (subject.binding.type !== subject.allowedWhen || subject.binding.plugin !== record.plugin || subject.binding.taskId !== subject.taskId) {
215
- ctx.addIssue({
216
- code: z.ZodIssueCode.custom,
217
- message: "Dispatch credentialSubject binding must match task",
218
- path: ["credentialSubject", "binding"]
219
- });
220
- }
221
- });
222
- function getDispatchStorageKey(id) {
223
- return `${DISPATCH_PREFIX}:record:${id}`;
224
- }
225
- function dispatchLockKey(id) {
226
- return `${DISPATCH_PREFIX}:lock:${id}`;
227
- }
228
- function pendingDispatchMailboxAppendIndexKey() {
229
- return `${DISPATCH_PREFIX}:incomplete`;
230
- }
231
- function pendingDispatchMailboxAppendIndexLockKey() {
232
- return `${DISPATCH_PREFIX}:incomplete:lock`;
233
- }
234
- function normalizeMetadata(metadata) {
235
- if (!metadata) {
236
- return void 0;
237
- }
238
- const entries = Object.entries(metadata).filter(
239
- (entry) => typeof entry[0] === "string" && typeof entry[1] === "string"
240
- );
241
- return entries.length > 0 ? Object.fromEntries(entries) : void 0;
242
- }
243
- function buildDispatchId(plugin, idempotencyKey) {
244
- const digest = createHash("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32);
245
- return `dispatch_${digest}`;
246
- }
247
- function parseDispatchRecord(value) {
248
- const parsed = dispatchRecordSchema.safeParse(value);
249
- return parsed.success ? parsed.data : void 0;
250
- }
251
- function getDispatchConversationId(dispatch) {
252
- return `agent-dispatch:${dispatch.id}`;
253
- }
254
- function getDispatchInputMessageId(dispatchId) {
255
- return `agent-dispatch:${dispatchId}`;
256
- }
257
- function getDispatchTurnId(dispatchId) {
258
- return `dispatch:${dispatchId}`;
259
- }
260
- function toDispatchProjection(record) {
261
- return {
262
- id: record.id,
263
- status: record.status,
264
- ...record.resultMessageTs ? { resultMessageTs: record.resultMessageTs } : void 0,
265
- ...record.errorMessage ? { errorMessage: record.errorMessage } : void 0
266
- };
267
- }
268
- function isTerminalDispatchStatus(status) {
269
- return status === "completed" || status === "failed" || status === "blocked";
270
- }
271
- async function withDispatchLock(dispatchId, task) {
272
- const state = getStateAdapter();
273
- await state.connect();
274
- const lock = await state.acquireLock(
275
- dispatchLockKey(dispatchId),
276
- DISPATCH_LOCK_TTL_MS
277
- );
278
- if (!lock) {
279
- throw new Error(`Could not acquire dispatch lock for ${dispatchId}`);
280
- }
281
- try {
282
- return await task(state);
283
- } finally {
284
- await state.releaseLock(lock);
285
- }
286
- }
287
- async function putRecord(state, record) {
288
- const parsed = dispatchRecordSchema.safeParse(record);
289
- if (!parsed.success) {
290
- throw new Error(
291
- `Dispatch record is invalid: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`
292
- );
293
- }
294
- const next = parsed.data;
295
- await state.set(
296
- getDispatchStorageKey(next.id),
297
- next,
298
- JUNIOR_THREAD_STATE_TTL_MS
299
- );
300
- }
301
- async function updatePendingDispatchMailboxAppendIndex(state, update) {
302
- const lock = await state.acquireLock(
303
- pendingDispatchMailboxAppendIndexLockKey(),
304
- DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS
305
- );
306
- if (!lock) {
307
- throw new Error("Could not acquire dispatch mailbox append index lock");
308
- }
309
- try {
310
- const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
311
- const ids = stored === void 0 || stored === null ? [] : pendingDispatchMailboxAppendIndexSchema.parse(stored);
312
- const next = [...new Set(update([...new Set(ids)]))].slice(
313
- -DISPATCH_MAILBOX_APPEND_INDEX_MAX_LENGTH
314
- );
315
- if (next.length === ids.length && next.every((id, index) => id === ids[index])) {
316
- return;
317
- }
318
- await state.set(
319
- pendingDispatchMailboxAppendIndexKey(),
320
- next,
321
- JUNIOR_THREAD_STATE_TTL_MS
322
- );
323
- } finally {
324
- await state.releaseLock(lock);
325
- }
326
- }
327
- async function getDispatchRecord(id) {
328
- const state = getStateAdapter();
329
- await state.connect();
330
- return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
331
- }
332
- async function createOrGetDispatch(args) {
333
- const id = buildDispatchId(args.plugin, args.options.idempotencyKey);
334
- return await withDispatchLock(id, async (state) => {
335
- const existing = parseDispatchRecord(
336
- await state.get(getDispatchStorageKey(id))
337
- );
338
- if (existing) {
339
- return { record: existing, status: "already_exists" };
340
- }
341
- const metadata = normalizeMetadata(args.options.metadata);
342
- const record = {
343
- actor: { platform: "system", name: args.plugin },
344
- createdAtMs: args.nowMs,
345
- ...args.options.credentialSubject ? { credentialSubject: args.options.credentialSubject } : void 0,
346
- destination: args.options.destination,
347
- destinationVisibility: args.options.destinationVisibility,
348
- id,
349
- idempotencyKey: args.options.idempotencyKey,
350
- input: args.options.input,
351
- ...metadata ? { metadata } : void 0,
352
- plugin: args.plugin,
353
- ...args.options.replyAttribution ? { replyAttribution: args.options.replyAttribution } : void 0,
354
- status: "pending",
355
- source: args.options.source,
356
- updatedAtMs: args.nowMs
357
- };
358
- await updatePendingDispatchMailboxAppendIndex(
359
- state,
360
- (ids) => ids.includes(id) ? ids : [...ids, id]
361
- );
362
- await putRecord(state, record);
363
- return { record, status: "created" };
364
- });
365
- }
366
- async function transitionDispatch(id, transition) {
367
- return await withDispatchLock(id, async (state) => {
368
- const current = parseDispatchRecord(
369
- await state.get(getDispatchStorageKey(id))
370
- );
371
- if (!current) {
372
- return void 0;
373
- }
374
- const transitioned = transition(current);
375
- if (transitioned === current) {
376
- return current;
377
- }
378
- const next = {
379
- ...transitioned,
380
- updatedAtMs: Date.now()
381
- };
382
- await putRecord(state, next);
383
- return next;
384
- });
385
- }
386
- async function markDispatchRunning(id) {
387
- return await transitionDispatch(
388
- id,
389
- (record) => isTerminalDispatchStatus(record.status) ? record : { ...record, status: "running", errorMessage: void 0 }
390
- );
391
- }
392
- async function markDispatchAwaitingResume(id) {
393
- return await transitionDispatch(
394
- id,
395
- (record) => isTerminalDispatchStatus(record.status) ? record : {
396
- ...record,
397
- status: "awaiting_resume"
398
- }
399
- );
400
- }
401
- async function recordEventTaskExecution(previous, next, status) {
402
- if (!next || next.status !== status || previous?.status === status) return;
403
- if (next.plugin !== "junior") return;
404
- const eventTaskId = next.metadata?.eventTaskId;
405
- if (!eventTaskId) return;
406
- const conversationId = getDispatchConversationId(next);
407
- const conversation = await getConversationStore().get({ conversationId });
408
- await recordTaskExecution("event", eventTaskId, {
409
- ...conversation ? { conversationId } : void 0,
410
- executionId: next.id,
411
- nowMs: next.updatedAtMs,
412
- status
413
- });
414
- }
415
- async function markDispatchBlocked(id, errorMessage, resultMessageTs) {
416
- const previous = await getDispatchRecord(id);
417
- const next = await transitionDispatch(
418
- id,
419
- (record) => isTerminalDispatchStatus(record.status) ? record : {
420
- ...record,
421
- errorMessage,
422
- ...resultMessageTs ? { resultMessageTs } : void 0,
423
- status: "blocked"
424
- }
425
- );
426
- await recordEventTaskExecution(previous, next, "blocked");
427
- return next;
428
- }
429
- async function markDispatchCompleted(id, resultMessageTs) {
430
- const previous = await getDispatchRecord(id);
431
- const next = await transitionDispatch(
432
- id,
433
- (record) => isTerminalDispatchStatus(record.status) ? record : {
434
- ...record,
435
- errorMessage: void 0,
436
- ...resultMessageTs ? { resultMessageTs } : void 0,
437
- status: "completed"
438
- }
439
- );
440
- await recordEventTaskExecution(previous, next, "completed");
441
- return next;
442
- }
443
- async function markDispatchFailed(id, errorMessage, resultMessageTs) {
444
- const previous = await getDispatchRecord(id);
445
- const next = await transitionDispatch(
446
- id,
447
- (record) => isTerminalDispatchStatus(record.status) ? record : {
448
- ...record,
449
- errorMessage,
450
- ...resultMessageTs ? { resultMessageTs } : void 0,
451
- status: "failed"
452
- }
453
- );
454
- await recordEventTaskExecution(previous, next, "failed");
455
- return next;
456
- }
457
- async function confirmDispatchMailboxAppend(id) {
458
- const state = getStateAdapter();
459
- await state.connect();
460
- await updatePendingDispatchMailboxAppendIndex(
461
- state,
462
- (ids) => ids.filter((candidate) => candidate !== id)
463
- );
464
- }
465
- async function listPendingDispatchMailboxAppends() {
466
- const state = getStateAdapter();
467
- await state.connect();
468
- const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
469
- return stored === void 0 || stored === null ? [] : [...new Set(pendingDispatchMailboxAppendIndexSchema.parse(stored))];
470
- }
471
- async function claimDispatchMailboxAppend(id) {
472
- return await withDispatchLock(id, async (state) => {
473
- return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
474
- });
475
- }
476
- async function getPluginDispatchProjection(args) {
477
- const record = await getDispatchRecord(args.id);
478
- if (!record || record.plugin !== args.plugin) {
479
- return void 0;
480
- }
481
- return toDispatchProjection(record);
482
- }
483
-
484
- // src/chat/plugins/task-runner.ts
485
- var PLUGIN_TASK_LOCK_TTL_MS = 5 * 60 * 1e3;
486
- function isRecord(value) {
487
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
488
- }
489
- function textPart(value) {
490
- if (isRecord(value) && value.type === "text" && typeof value.text === "string") {
491
- return value.text;
492
- }
493
- return void 0;
494
- }
495
- function messageText(message) {
496
- const content = message.content;
497
- if (typeof content === "string") {
498
- return sanitizeText(content);
499
- }
500
- if (!Array.isArray(content)) {
501
- return "";
502
- }
503
- return sanitizeText(content.map(textPart).filter(Boolean).join("\n"));
504
- }
505
- function toolResultText(message) {
506
- const record = message;
507
- const parts = [
508
- messageText(message),
509
- record.output,
510
- record.result,
511
- record.stdout,
512
- record.stderr,
513
- record.toolResult
514
- ].filter(
515
- (value) => typeof value === "string" && value.length > 0
516
- );
517
- return sanitizeText(parts.join("\n"));
518
- }
519
- function sanitizeText(text) {
520
- return text.replace(
521
- /<data_base64>[\s\S]*?<\/data_base64>/g,
522
- "<data_base64>[omitted]</data_base64>"
523
- ).replace(
524
- /data:image\/[a-z0-9.+-]+;base64,[a-z0-9+/=]+/gi,
525
- "[image data omitted]"
526
- ).replaceAll("\0", " ").trim();
527
- }
528
- function messageProvenance(provenance) {
529
- return {
530
- authority: provenance.authority,
531
- ...provenance.actor ? { actor: provenance.actor } : void 0
532
- };
533
- }
534
- function runTranscriptEntry(message, provenance, runActor) {
535
- const role = getPiMessageRole(message);
536
- if (role === "user" || role === "assistant") {
537
- const text2 = role === "user" ? instructionTextForProjection(messageText(message)) : messageText(message);
538
- if (!text2) {
539
- return void 0;
540
- }
541
- if (role === "assistant") {
542
- return { type: "message", role, text: text2 };
543
- }
544
- return {
545
- type: "message",
546
- role,
547
- text: text2,
548
- provenance: messageProvenance(provenance),
549
- isRunActor: sameActorIdentity(provenance.actor, runActor)
550
- };
551
- }
552
- if (!isToolResultMessage(message)) {
553
- return void 0;
554
- }
555
- const toolName = normalizeToolNameFromResult(message);
556
- if (!toolName) {
557
- return void 0;
558
- }
559
- const text = toolResultText(message);
560
- return {
561
- type: "toolResult",
562
- toolName,
563
- isError: isToolResultError(message),
564
- ...text ? { text } : void 0
565
- };
566
- }
567
- function turnMessagesWithProvenance(record) {
568
- const startIndex = record.turnStartMessageIndex ?? 0;
569
- const messages = record.piMessages.slice(startIndex);
570
- const provenance = record.piMessageProvenance.slice(startIndex);
571
- const paired = [];
572
- for (const [index, message] of messages.entries()) {
573
- for (const stripped of stripRuntimeTurnContext([message])) {
574
- paired.push({
575
- message: stripped,
576
- provenance: provenance[index] ?? { authority: "context" }
577
- });
578
- }
579
- }
580
- return paired;
581
- }
582
- function slackContextAuthor(location, message) {
583
- const userId = message.author?.userId?.trim();
584
- if (!userId) {
585
- return void 0;
586
- }
587
- return {
588
- platform: "slack",
589
- teamId: location.teamId,
590
- userId,
591
- ...message.author?.userName ? { userName: message.author.userName } : void 0,
592
- ...message.author?.fullName ? { fullName: message.author.fullName } : void 0
593
- };
594
- }
595
- function slackTimestampMs(value) {
596
- const timestamp = parseSlackMessageTs(value);
597
- if (!timestamp) {
598
- return void 0;
599
- }
600
- const timestampMs = Number(timestamp) * 1e3;
601
- return Number.isFinite(timestampMs) ? timestampMs : void 0;
602
- }
603
- function conversationMessageTimestampMs(message) {
604
- if (message.meta?.slackTs !== void 0) {
605
- return slackTimestampMs(message.meta.slackTs);
606
- }
607
- return Number.isFinite(message.createdAtMs) ? message.createdAtMs : void 0;
608
- }
609
- function messageExistedAtRunCompletion(message, completedAtMs) {
610
- const messageTimestampMs = conversationMessageTimestampMs(message);
611
- return messageTimestampMs !== void 0 && messageTimestampMs <= completedAtMs;
612
- }
613
- async function loadConversationContextTranscriptEntries(record, location, visibility, runActor) {
614
- if (location?.provider !== "slack" || visibility !== "public") {
615
- return [];
616
- }
617
- const state = await getPersistedThreadState(record.conversationId);
618
- const conversation = coerceThreadConversationState(state);
619
- await hydrateConversationMessages({
620
- conversation,
621
- conversationId: record.conversationId
622
- });
623
- const entries = [];
624
- for (const message of conversation.messages) {
625
- if (message.role !== "user") {
626
- continue;
627
- }
628
- if (!messageExistedAtRunCompletion(message, record.updatedAtMs)) {
629
- continue;
630
- }
631
- const text = sanitizeText(message.text);
632
- if (!text) {
633
- continue;
634
- }
635
- const author = slackContextAuthor(location, message);
636
- entries.push({
637
- type: "message",
638
- role: "user",
639
- text,
640
- provenance: {
641
- authority: "context",
642
- ...author ? { actor: author } : void 0
643
- },
644
- isRunActor: sameActorIdentity(author, runActor)
645
- });
646
- }
647
- return entries;
648
- }
649
- async function withPluginTaskLock(taskId, callback) {
650
- const state = getStateAdapter();
651
- await state.connect();
652
- const lock = await state.acquireLock(
653
- `plugin:task:${taskId}`,
654
- PLUGIN_TASK_LOCK_TTL_MS
655
- );
656
- if (!lock) {
657
- throw new Error(`Could not acquire plugin task lock for ${taskId}`);
658
- }
659
- try {
660
- return await callback();
661
- } finally {
662
- await state.releaseLock(lock);
663
- }
664
- }
665
- async function loadPluginRun(params) {
666
- const record = await getTurnRecord(params.conversationId, params.sessionId);
667
- if (!record) {
668
- throw new Error("Completed plugin task session record is unavailable");
669
- }
670
- if (record.state !== "completed") {
671
- throw new Error("Completed plugin task session record is not completed");
672
- }
673
- const conversationStore = getConversationStore();
674
- const routing = await resolveConversationRouting({
675
- conversationId: params.conversationId,
676
- conversationStore
677
- });
678
- if (!routing) {
679
- throw new Error(
680
- `Conversation ${params.conversationId} is missing durable routing metadata`
681
- );
682
- }
683
- const source = record.source ?? routing.source;
684
- if (!source) {
685
- throw new Error("Completed plugin task session record is missing Source");
686
- }
687
- const conversation = await conversationStore.get({
688
- conversationId: params.conversationId
689
- });
690
- const runActor = record.actor ?? record.actors[0] ?? (record.dispatchId ? (await getDispatchRecord(record.dispatchId))?.actor : void 0);
691
- const actorUser = runActor ? (await readActorIdentity(runActor))?.user : void 0;
692
- const runEntries = turnMessagesWithProvenance(record).map(
693
- ({ message, provenance }) => runTranscriptEntry(message, provenance, runActor)
694
- ).filter((entry) => Boolean(entry));
695
- const runMessageTexts = new Set(
696
- runEntries.filter((entry) => entry.type === "message").map((entry) => entry.text)
697
- );
698
- const contextEntries = (await loadConversationContextTranscriptEntries(
699
- record,
700
- conversation?.location,
701
- conversation?.visibility,
702
- runActor
703
- )).filter(
704
- (entry) => entry.type !== "message" || !runMessageTexts.has(entry.text)
705
- );
706
- return pluginRunContextSchema.parse({
707
- ...actorUser ? { actorUserId: actorUser.id } : void 0,
708
- completedAtMs: record.updatedAtMs,
709
- conversationId: record.conversationId,
710
- destination: routing.destination,
711
- ...routing.location ? { locationId: routing.location.id } : void 0,
712
- // Read Actors from the full run record, not the shorter transcript.
713
- // This includes every Actor that supplied an instruction.
714
- actors: record.actors,
715
- ...runActor ? { actor: runActor } : void 0,
716
- runId: record.turnId,
717
- source,
718
- transcript: [...contextEntries, ...runEntries]
719
- });
720
- }
721
- function taskPluginContext(plugin, message, options = {}) {
722
- const pluginName = plugin.manifest.name;
723
- const sessionParams = pluginTaskParamsSchema.parse(message.params);
724
- return {
725
- db: getDb(),
726
- embedder: createPluginEmbedder(pluginName, {
727
- signal: options.signal
728
- }),
729
- events: createPluginConversationEvents({
730
- conversationId: sessionParams.conversationId,
731
- operationId: pluginTaskId(message),
732
- plugin,
733
- turnId: sessionParams.sessionId
734
- }),
735
- id: pluginTaskId(message),
736
- log: createPluginLogger(pluginName),
737
- model: createPluginModel(pluginName, plugin.model, {
738
- signal: options.signal
739
- }),
740
- name: message.name,
741
- plugin: { name: pluginName },
742
- run: {
743
- async load() {
744
- return await loadPluginRun(sessionParams);
745
- }
746
- },
747
- state: createPluginState(pluginName)
748
- };
749
- }
750
- function findPluginTask(message) {
751
- const plugin = getPlugins().find(
752
- (candidate) => candidate.manifest.name === message.plugin
753
- );
754
- if (!plugin?.tasks || !Object.hasOwn(plugin.tasks, message.name)) {
755
- return void 0;
756
- }
757
- const task = plugin.tasks[message.name];
758
- return { plugin, task };
759
- }
760
- async function scheduleSessionCompletedPluginTasks(params, options = {}) {
761
- const coreParams = pluginTaskParamsSchema.parse(params);
762
- const taskRegistrations = getPlugins().flatMap(
763
- (plugin) => Object.keys(plugin.tasks ?? {}).map((name) => ({ name, plugin }))
764
- );
765
- if (taskRegistrations.length === 0) {
766
- return;
767
- }
768
- const record = await getTurnRecord(
769
- coreParams.conversationId,
770
- coreParams.sessionId
771
- );
772
- if (!record || record.state !== "completed") {
773
- throw new Error("Completed plugin task session record is not ready");
774
- }
775
- const send = options.send ?? sendVercelPluginTask;
776
- const messages = taskRegistrations.map(({ name, plugin }) => ({
777
- name,
778
- params: coreParams,
779
- plugin: plugin.manifest.name
780
- }));
781
- await Promise.all(
782
- messages.map(async (message) => {
783
- await send(message);
784
- })
785
- );
786
- }
787
- async function processPluginTask(message, options = {}) {
788
- await withPluginTaskLock(pluginTaskId(message), async () => {
789
- const resolved = findPluginTask(message);
790
- if (!resolved) {
791
- throw new Error(
792
- `Plugin task "${message.plugin}.${message.name}" is not registered`
793
- );
794
- }
795
- await resolved.task.run(
796
- taskPluginContext(resolved.plugin, message, options)
797
- );
798
- });
799
- }
800
-
801
- export {
802
- getDispatchConversationId,
803
- getDispatchInputMessageId,
804
- getDispatchTurnId,
805
- isTerminalDispatchStatus,
806
- getDispatchRecord,
807
- createOrGetDispatch,
808
- markDispatchRunning,
809
- markDispatchAwaitingResume,
810
- markDispatchBlocked,
811
- markDispatchCompleted,
812
- markDispatchFailed,
813
- confirmDispatchMailboxAppend,
814
- listPendingDispatchMailboxAppends,
815
- claimDispatchMailboxAppend,
816
- getPluginDispatchProjection,
817
- resolveTurnSessionRouting,
818
- scheduleSessionCompletedPluginTasks,
819
- processPluginTask
820
- };