@sentry/junior 0.266.0 → 0.268.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 (87) hide show
  1. package/dist/{actor-tlxzqaRe.js → actor-CP9K2Idu.js} +9 -1
  2. package/dist/{adapter-eRFA_naf.js → adapter-04AcD2SO.js} +5 -7
  3. package/dist/{admin-tILpP51p.js → admin-DIU1QyG3.js} +1 -1
  4. package/dist/{agent-invocations-CxKldAeB.js → agent-invocations-C1RNOCs8.js} +2 -0
  5. package/dist/{agent-runner-BtYK7bht.js → agent-runner-CAYfFmU7.js} +2636 -601
  6. package/dist/api/schema.d.ts +2 -5454
  7. package/dist/api/schema.js +6 -5
  8. package/dist/api.d.ts +6 -1
  9. package/dist/api.js +255 -1208
  10. package/dist/{app-Csbi9dW7.d.ts → app-z6Uuyq3j.d.ts} +23 -4
  11. package/dist/app.d.ts +2 -2
  12. package/dist/app.js +1869 -378
  13. package/dist/{automation-BKpY9LPa.js → automation-CmeFBSEh.js} +42 -14
  14. package/dist/{briefs-DgfWMU7e.js → briefs-DQbV2jNr.js} +4 -4
  15. package/dist/{catalog-runtime-DAJjAbSx.js → catalog-runtime-BD9GSpc6.js} +1 -1
  16. package/dist/cli/chat.js +15 -15
  17. package/dist/cli/check.js +3 -3
  18. package/dist/cli/init.js +0 -1
  19. package/dist/cli/main.js +3 -3
  20. package/dist/cli/plugins.js +4 -4
  21. package/dist/cli/snapshot-create.js +4 -4
  22. package/dist/cli/upgrade.d.ts +1 -1
  23. package/dist/cli/upgrade.js +3 -3
  24. package/dist/{client-B0YZfxNy.js → client-C1yDYjoS.js} +2 -2
  25. package/dist/{config-C0UwYqDK.js → config-DrTeF80T.js} +32 -10
  26. package/dist/{connections-Bwu3VORi.js → connections-D46f8vvi.js} +12 -12
  27. package/dist/{conversation-DF4rUcjb.js → conversation-DSo310Ps.js} +8 -1
  28. package/dist/{conversation-privacy-CY7JVjxn.js → conversation-privacy-CxlOCiUo.js} +1 -1
  29. package/dist/{credential-sync-VGAMUTGp.js → credential-sync-sm9fegLY.js} +29 -34
  30. package/dist/{credentialed-enF5Bf3y.js → credentialed-lukuD-cc.js} +2933 -1026
  31. package/dist/db-BU4LQD8s.d.ts +6 -0
  32. package/dist/{executor-TnWbvL09.js → executor-4vhvsMZJ.js} +83 -6
  33. package/dist/instrumentation.js +6 -2
  34. package/dist/{assistant-reply-UyzAfZQo.js → interruption-marker-CkncDT8d.js} +8 -2
  35. package/dist/{job-queue-DBpHmKnd.js → job-queue-In9QKz-I.js} +128 -3
  36. package/dist/{web-input-B-bMjD1V.js → list-BkgnXEEB.js} +1611 -817
  37. package/dist/{logging-Ce0mXZ8J.js → logging-DLSpkSSr.js} +11 -3
  38. package/dist/{message-VZ3DFpGb.js → message-BObyg59s.js} +4 -4
  39. package/dist/nitro.d.ts +1 -1
  40. package/dist/nitro.js +3 -3
  41. package/dist/{oauth-callback-server-CpqWLjVY.js → oauth-callback-server-B-WbSdoH.js} +2 -2
  42. package/dist/{prompt-BcCGlmg2.js → prompt-BW9jFsqZ.js} +1 -1
  43. package/dist/{registry-1BEIPdbT.js → registry-BgecKva0.js} +2 -2
  44. package/dist/{web-message-id-CJSUiksE.js → reporting-window-DVCD_10C.js} +1 -10
  45. package/dist/{resolve-BSHHkEGE.js → resolve-Cpa4Bu1O.js} +3 -3
  46. package/dist/{result-CwOpzqdh.js → result-D3TSmZZ8.js} +9 -9
  47. package/dist/{runner-CEaX04kz.js → runner-DS5OKhEp.js} +11 -11
  48. package/dist/{sandbox-egress-signals-BwtGHwqa.js → sandbox-egress-signals-CnDjY5rx.js} +1 -1
  49. package/dist/{schema-RsaBHxRH.js → schema-0050HFnB.js} +82 -5
  50. package/dist/schema-ZngqcOWM.d.ts +5813 -0
  51. package/dist/{service-account-6wC76eBZ.js → service-account-CKV2WTY7.js} +3 -3
  52. package/dist/{service-account-Dg4lIbHm.js → service-account-DGjnDw9y.js} +3 -3
  53. package/dist/{session-stop-tZOw9AJD.js → session-stop-Dam1EI7B.js} +527 -134
  54. package/dist/{skills-DzyGN7wd.js → skills-CfAnfImD.js} +2 -2
  55. package/dist/{spawn-6rokq7l_.js → spawn-cmq9p4Ly.js} +2 -2
  56. package/dist/{store-DcKkzrdt.js → store-C5PN02QO.js} +4 -4
  57. package/dist/{store-CG0VJyye.d.ts → store-xMuuXRE0.d.ts} +23 -9
  58. package/dist/store-zPEoJPBB.js +295 -0
  59. package/dist/{task-queue-Bg4RS2Gy.js → task-queue-_mf28dSu.js} +10 -5
  60. package/dist/{task-runner-8N5LIkSg.js → task-runner-DMI2prDO.js} +25 -14
  61. package/dist/{tasks-DDT-J3Rf.js → tasks-SB9z-VTU.js} +1551 -54
  62. package/dist/{thread-state-cprEaxgl.js → thread-state-BbbPh0Sn.js} +8 -18
  63. package/dist/{turn-failure-response-C8sMdsdX.js → turn-failure-response-BKKmnMB5.js} +11 -16
  64. package/dist/{turn-lifecycle-DaBVoz7h.js → turn-lifecycle-oP0kVeGz.js} +1 -1
  65. package/dist/{validation-C2lllinq.js → validation--JsAGLwc.js} +1 -1
  66. package/dist/{version-oaLfxxnf.js → version-jHwJp4hC.js} +1 -1
  67. package/dist/version.js +1 -1
  68. package/dist/{viewer-BpE6Z3qf.js → viewer-CpXTGlep.js} +329 -230
  69. package/dist/web-message-id-DlHNANtd.js +132 -0
  70. package/dist/{work-VX1SHWha.js → work-3N-GHY9m.js} +10 -10
  71. package/dist/{worker-hook-y_Y.js → worker-CCdbcItd.js} +30 -19
  72. package/migrations/0064_any_resource_event_triggers.sql +2 -0
  73. package/migrations/0065_user_customization.sql +1 -0
  74. package/migrations/0066_review_items.sql +53 -0
  75. package/migrations/0067_review_item_dedupe_tenant.sql +2 -0
  76. package/migrations/0068_review_item_slack_cards.sql +10 -0
  77. package/migrations/meta/0064_snapshot.json +3505 -0
  78. package/migrations/meta/0065_snapshot.json +3511 -0
  79. package/migrations/meta/0066_snapshot.json +4099 -0
  80. package/migrations/meta/0067_snapshot.json +3921 -0
  81. package/migrations/meta/0068_snapshot.json +4176 -0
  82. package/migrations/meta/_journal.json +36 -1
  83. package/package.json +19 -4
  84. package/dist/db-BnRqQ7G5.d.ts +0 -5
  85. package/dist/images-BKQqSi5W.js +0 -64
  86. package/dist/store-FALy-JQb.js +0 -1424
  87. package/dist/turn-session-routing-a9CHX-w6.js +0 -76
@@ -0,0 +1,132 @@
1
+ import { z } from "zod";
2
+ // src/api/schema/user-customization.ts
3
+ /** Longest customization text one user can save. */
4
+ const USER_CUSTOMIZATION_MAX_CHARS = 1e3;
5
+ /** Saved customization text. An empty string means none. */
6
+ const userCustomizationTextSchema = z.string().trim().max(USER_CUSTOMIZATION_MAX_CHARS);
7
+ /** Request and response body for the viewer's customization. */
8
+ const userCustomizationSchema = z.object({ customization: userCustomizationTextSchema }).strict();
9
+ // src/chat/tools/runtime/user-input-request.ts
10
+ const USER_INPUT_LIMITS = {
11
+ maxButtonOptions: 5,
12
+ maxDescriptionChars: 200,
13
+ maxFields: 4,
14
+ maxLabelChars: 75,
15
+ maxOptions: 10,
16
+ maxTextChars: 3e3,
17
+ maxQuestionChars: 3e3,
18
+ minOptions: 2
19
+ };
20
+ const labelSchema = z.string().trim().min(1).max(USER_INPUT_LIMITS.maxLabelChars);
21
+ const descriptionSchema = z.string().trim().min(1).max(USER_INPUT_LIMITS.maxDescriptionChars).optional();
22
+ const optionSchema = z.object({
23
+ label: labelSchema.describe("Short choice text, such as `Accept` or `Decline`. The answer uses this exact text."),
24
+ description: descriptionSchema.describe("Optional short note about what this choice does.")
25
+ });
26
+ const fieldBase = {
27
+ id: z.string().regex(/^[a-z][a-z0-9_]{0,31}$/).describe("Stable key for this field, such as `approach`."),
28
+ label: labelSchema.describe("Short field name, such as `Approach`."),
29
+ description: descriptionSchema.describe("Optional short help text for this field.")
30
+ };
31
+ const optionsSchema = z.array(optionSchema).min(USER_INPUT_LIMITS.minOptions).max(USER_INPUT_LIMITS.maxOptions).describe("Choices in display order.");
32
+ const userInputFieldSchema = z.discriminatedUnion("kind", [
33
+ z.object({
34
+ ...fieldBase,
35
+ kind: z.literal("choice").describe("The person picks one option."),
36
+ options: optionsSchema
37
+ }),
38
+ z.object({
39
+ ...fieldBase,
40
+ kind: z.literal("multi_choice").describe("The person picks any number of options."),
41
+ options: optionsSchema
42
+ }),
43
+ z.object({
44
+ ...fieldBase,
45
+ kind: z.literal("text").describe("The person types a short answer.")
46
+ })
47
+ ]);
48
+ const userInputRequestSchema = z.object({
49
+ question: z.string().trim().min(1).max(USER_INPUT_LIMITS.maxQuestionChars).describe("The question, in markdown. Include the facts the person needs to decide."),
50
+ fields: z.array(userInputFieldSchema).min(1).max(USER_INPUT_LIMITS.maxFields).describe("What to ask, in display order. Use one `choice` field for a simple decision.")
51
+ }).superRefine((request, context) => {
52
+ const ids = /* @__PURE__ */ new Set();
53
+ for (const field of request.fields) {
54
+ if (ids.has(field.id)) context.addIssue({
55
+ code: "custom",
56
+ message: "Each field needs a different id."
57
+ });
58
+ ids.add(field.id);
59
+ if (field.kind === "text") continue;
60
+ const labels = field.options.map((option) => option.label.toLowerCase());
61
+ if (new Set(labels).size !== labels.length) context.addIssue({
62
+ code: "custom",
63
+ message: "Each choice of a field needs a different label."
64
+ });
65
+ }
66
+ });
67
+ /**
68
+ * Return the single choice field of a request that a surface can show as
69
+ * one row of buttons, where one click is the whole answer.
70
+ */
71
+ function buttonUserInputField(request) {
72
+ const [field, ...rest] = request.fields;
73
+ if (rest.length || field?.kind !== "choice") return void 0;
74
+ return field.options.length <= USER_INPUT_LIMITS.maxButtonOptions ? field : void 0;
75
+ }
76
+ /**
77
+ * Keep only answer values that match the request: known field ids, known
78
+ * option labels, one value for a `choice` field, and trimmed text.
79
+ */
80
+ function normalizeUserInputAnswer(request, answer) {
81
+ const values = {};
82
+ for (const field of request.fields) {
83
+ const raw = (answer.values[field.id] ?? []).map((value) => value.trim()).filter(Boolean);
84
+ if (field.kind === "text") {
85
+ const text = raw.join("\n").slice(0, USER_INPUT_LIMITS.maxTextChars);
86
+ if (text) values[field.id] = [text];
87
+ continue;
88
+ }
89
+ const picked = field.options.map((option) => option.label).filter((label) => raw.includes(label));
90
+ const kept = field.kind === "choice" ? picked.slice(0, 1) : picked;
91
+ if (kept.length) values[field.id] = kept;
92
+ }
93
+ const other = answer.other?.trim().slice(0, USER_INPUT_LIMITS.maxTextChars);
94
+ return {
95
+ requestId: answer.requestId,
96
+ values,
97
+ ...other ? { other } : void 0
98
+ };
99
+ }
100
+ /** Return true when an answer has no value and no free text. */
101
+ function isEmptyUserInputAnswer(answer) {
102
+ return !answer.other && Object.keys(answer.values).length === 0;
103
+ }
104
+ function answerLine(text) {
105
+ return text.split("\n").map((line) => line.trim()).filter(Boolean).join("\n");
106
+ }
107
+ /**
108
+ * Write an answer as the text of the person's message. Slack and the web
109
+ * dashboard both send this text, so the model reads one format. The first
110
+ * line names the request, and each field starts its own line.
111
+ */
112
+ function formatUserInputAnswer(request, answer) {
113
+ const normalized = normalizeUserInputAnswer(request, answer);
114
+ const lines = [`Answer to request ${normalized.requestId}:`];
115
+ for (const field of request.fields) {
116
+ const values = normalized.values[field.id];
117
+ const value = values?.length ? values.join(", ") : "(no answer)";
118
+ lines.push(answerLine(`${field.label} (${field.id}): ${value}`));
119
+ }
120
+ if (normalized.other) lines.push(answerLine(`Other: ${normalized.other}`));
121
+ return lines.join("\n");
122
+ }
123
+ // src/chat/conversations/web-message-id.ts
124
+ /**
125
+ * Build the retry-stable Message id shared by web ingress and browser sends.
126
+ * Keep the existing hash and prefix so retries still address stored Messages.
127
+ */
128
+ async function webMessageId(args) {
129
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${args.conversationId}\u0000${args.idempotencyKey}`));
130
+ return `api-msg:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 24)}`;
131
+ }
132
+ export { isEmptyUserInputAnswer as a, USER_CUSTOMIZATION_MAX_CHARS as c, formatUserInputAnswer as i, userCustomizationSchema as l, USER_INPUT_LIMITS as n, normalizeUserInputAnswer as o, buttonUserInputField as r, userInputRequestSchema as s, webMessageId as t, userCustomizationTextSchema as u };
@@ -1,15 +1,15 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-nwUcYXjP.js";
2
- import { At as abandonTurnRecord, Ht as isTurnExecutionLimitExceededError, Kt as getTerminalAssistantMessages, Mt as failTurnRecord, Nt as getTurnRecord, R as openConversationProjection, bt as AuthorizationFlowDisabledError, gt as PluginCredentialFailureError, kt as saveTurnCheckpoint } from "./tasks-DDT-J3Rf.js";
3
- import { n as botConfig } from "./config-C0UwYqDK.js";
4
- import { d as getConversationStore, l as getConversationEventStore } from "./viewer-BpE6Z3qf.js";
2
+ import { Fn as isTurnExecutionLimitExceededError, Gt as saveTurnCheckpoint, It as AuthorizationFlowDisabledError, Jt as failTurnRecord, Kt as abandonTurnRecord, Mt as PluginCredentialFailureError, Yt as getTurnRecord, et as openConversationProjection, zn as getTerminalAssistantMessages } from "./tasks-SB9z-VTU.js";
3
+ import { n as botConfig } from "./config-DrTeF80T.js";
4
+ import { d as getConversationEventStore, p as getConversationStore } from "./viewer-CpXTGlep.js";
5
5
  import { m as sameActorIdentity, u as agentInstructionProvenance } from "./history-C84mlAwO.js";
6
- import { B as stopChildAgentsOf, H as recordSubagentEnded, U as recordSubagentStarted, X as buildSteeringPiMessage, Z as withoutSavedSteeringMessages, tt as readBlockedReport } from "./agent-runner-BtYK7bht.js";
7
- import { E as markAgentInvocationSteered, H as TurnInputCommitLostError, K as isTurnInputCommitLostError, L as agentTypeInstructions, O as reportReplacedAgentInvocation, R as agentTypeStartsWithParentHistory, S as markAgentInvocationMailboxAppended, T as markAgentInvocationRunning, W as getConversationTurnBoundaryError, _ as getLatestAgentInvocationForConversation, c as getAgentInvocation, f as getAgentInvocationMessageId, m as getAgentInvocationTurnId, n as completeAgentInvocation, r as createAgentInvocation, s as getActiveAgentInvocationForConversation, w as markAgentInvocationPaused, y as isTerminalAgentInvocation } from "./store-DcKkzrdt.js";
8
- import { n as getAssistantReplyText } from "./assistant-reply-UyzAfZQo.js";
9
- import { F as recordFinishedTurnForAutomatedLimit, I as resetAutomatedTurnLimit, P as maybePostAutomatedTurnLimitNotice } from "./session-stop-tZOw9AJD.js";
10
- import { r as appendAndEnqueueInboundMessage } from "./store-FALy-JQb.js";
11
- import { t as ConversationTurnLifecycleService } from "./turn-lifecycle-DaBVoz7h.js";
12
- import { n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState } from "./thread-state-cprEaxgl.js";
6
+ import { Dt as recordSubagentEnded, Ft as buildSteeringPiMessage, Ht as readBlockedReport, It as withoutSavedSteeringMessages, Ot as recordSubagentStarted, Tt as stopChildAgentsOf } from "./agent-runner-CAYfFmU7.js";
7
+ import { E as markAgentInvocationSteered, H as TurnInputCommitLostError, K as isTurnInputCommitLostError, L as agentTypeInstructions, O as reportReplacedAgentInvocation, R as agentTypeStartsWithParentHistory, S as markAgentInvocationMailboxAppended, T as markAgentInvocationRunning, W as getConversationTurnBoundaryError, _ as getLatestAgentInvocationForConversation, c as getAgentInvocation, f as getAgentInvocationMessageId, m as getAgentInvocationTurnId, n as completeAgentInvocation, r as createAgentInvocation, s as getActiveAgentInvocationForConversation, w as markAgentInvocationPaused, y as isTerminalAgentInvocation } from "./store-C5PN02QO.js";
8
+ import { r as getAssistantReplyText } from "./interruption-marker-CkncDT8d.js";
9
+ import { C as maybePostAutomatedTurnLimitNotice, D as recordFinishedTurnForAutomatedLimit, O as resetAutomatedTurnLimit } from "./session-stop-Dam1EI7B.js";
10
+ import { r as appendAndEnqueueInboundMessage } from "./store-zPEoJPBB.js";
11
+ import { t as ConversationTurnLifecycleService } from "./turn-lifecycle-oP0kVeGz.js";
12
+ import { a as persistThreadStateById, n as getPersistedSandboxState, r as getPersistedThreadState } from "./thread-state-BbbPh0Sn.js";
13
13
  import { isDeepStrictEqual } from "node:util";
14
14
  import { z } from "zod";
15
15
  // src/chat/runtime/turn-execution.ts
@@ -1,34 +1,45 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-nwUcYXjP.js";
2
- import { y as isProviderRetryError } from "./client-B0YZfxNy.js";
3
- import { i as getChatConfig } from "./config-C0UwYqDK.js";
4
- import { f as logException, m as logWarn, p as logInfo, w as withLogContext, y as setSpanAttributes } from "./logging-Ce0mXZ8J.js";
5
- import { f as getTurnRequestDeadline, m as ConversationQueueMessageRejectedError } from "./job-queue-DBpHmKnd.js";
6
- import { C as requestAnotherSlice, M as isInvalidConversationRecordError, T as startConversationWork, b as recordConversationRetry, d as countPendingConversationMessages, f as deadLetterAttempt, g as getConversationWorkState, i as beginConversationResume, j as isFinalAttempt, k as hasConversationStop, l as completeConversationStop, m as ensureConversationWake, o as checkInConversationWork, p as drainConversationMailbox, s as clearConsumedConversationWake, t as ackMessages, u as completeConversationWork, x as releaseConversationWork, y as recordAttemptFailure } from "./store-FALy-JQb.js";
7
- // src/chat/task-execution/worker.ts
8
- var worker_exports = /* @__PURE__ */ __exportAll({
9
- CONVERSATION_WORK_DEFER_DELAY_MS: () => CONVERSATION_WORK_DEFER_DELAY_MS,
10
- processConversationWork: () => processConversationWork
11
- });
12
- const CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
13
- const CONVERSATION_STOP_CHECK_INTERVAL_MS = 500;
14
- function now(options) {
15
- return options.nowMs?.() ?? Date.now();
16
- }
2
+ import { _n as isInvalidConversationRecordError, gn as isFinalAttempt, mn as hasConversationStop } from "./tasks-SB9z-VTU.js";
3
+ import { y as isProviderRetryError } from "./client-C1yDYjoS.js";
4
+ import { i as getChatConfig } from "./config-DrTeF80T.js";
5
+ import { T as withLogContext, b as setSpanAttributes, h as logWarn, m as logInfo, p as logException } from "./logging-DLSpkSSr.js";
6
+ import { f as getTurnRequestDeadline, m as ConversationQueueMessageRejectedError } from "./job-queue-In9QKz-I.js";
7
+ import { C as requestAnotherSlice, T as startConversationWork, b as recordConversationRetry, d as countPendingConversationMessages, f as deadLetterAttempt, g as getConversationWorkState, i as beginConversationResume, l as completeConversationStop, m as ensureConversationWake, o as checkInConversationWork, p as drainConversationMailbox, s as clearConsumedConversationWake, t as ackMessages, u as completeConversationWork, x as releaseConversationWork, y as recordAttemptFailure } from "./store-zPEoJPBB.js";
8
+ // src/chat/task-execution/attempt-selection.ts
17
9
  function selectContiguousTurnBatch(messages) {
18
10
  const first = messages[0];
19
11
  if (!first) return [];
20
12
  const nextTurnIndex = messages.findIndex((message) => message.input.authorId !== first.input.authorId || message.source !== first.source);
21
13
  return messages.slice(0, nextTurnIndex === -1 ? messages.length : nextTurnIndex);
22
14
  }
15
+ /**
16
+ * True when an interrupt can start its own attempt.
17
+ *
18
+ * A steered web message must not start a second Turn while a yielded Turn
19
+ * waits to resume. It stays pending for that Turn's drain or the next attempt.
20
+ */
21
+ function isAttemptInterrupt(message, work) {
22
+ return message.delivery === "interrupt" && !(work.execution.status === "paused" && message.source === "web");
23
+ }
23
24
  /** Prioritize interrupts while keeping each attempt to one Actor and Source. */
24
25
  function selectAttemptMessages(work) {
25
26
  const messages = work.messages;
26
- const interrupts = messages.filter((message) => message.delivery === "interrupt");
27
+ const interrupts = messages.filter((message) => isAttemptInterrupt(message, work));
27
28
  if (interrupts.length > 0) return selectContiguousTurnBatch(interrupts);
28
29
  if (work.execution.status === "paused") return [];
29
30
  const nonEventMessages = messages.filter((message) => message.source !== "event");
30
31
  return selectContiguousTurnBatch(nonEventMessages.length > 0 ? nonEventMessages : messages);
31
32
  }
33
+ // src/chat/task-execution/worker.ts
34
+ var worker_exports = /* @__PURE__ */ __exportAll({
35
+ CONVERSATION_WORK_DEFER_DELAY_MS: () => CONVERSATION_WORK_DEFER_DELAY_MS,
36
+ processConversationWork: () => processConversationWork
37
+ });
38
+ const CONVERSATION_WORK_DEFER_DELAY_MS = 15e3;
39
+ const CONVERSATION_STOP_CHECK_INTERVAL_MS = 500;
40
+ function now(options) {
41
+ return options.nowMs?.() ?? Date.now();
42
+ }
32
43
  function nudgeIdempotencyKey(reason, conversationId, nowMs) {
33
44
  return `${reason}:${conversationId}:${nowMs}`;
34
45
  }
@@ -248,7 +259,7 @@ async function processConversationWorkInContext(message, options) {
248
259
  const softYieldDeadlineMs = startedAtMs + (options.softYieldAfterMs ?? getChatConfig().conversationWorkSoftYieldAfterMs);
249
260
  let attemptMessageIds = [];
250
261
  let attemptSelectedMessageIds = /* @__PURE__ */ new Set();
251
- let attemptStartMessageIds = /* @__PURE__ */ new Set();
262
+ let attemptStartInterruptIds = /* @__PURE__ */ new Set();
252
263
  let failedWithoutProgress = false;
253
264
  let leaseLost = false;
254
265
  const markLeaseLost = () => {
@@ -269,7 +280,7 @@ async function processConversationWorkInContext(message, options) {
269
280
  leaseToken: lease.leaseToken,
270
281
  conversationStore: options.conversationStore,
271
282
  handle: async (messages) => {
272
- const candidates = drainOptions?.deferred ? messages : messages.filter((message) => message.delivery === "interrupt" && (attemptSelectedMessageIds.has(message.inboundMessageId) || !attemptStartMessageIds.has(message.inboundMessageId)));
283
+ const candidates = drainOptions?.deferred ? messages : messages.filter((message) => message.delivery === "interrupt" && (attemptSelectedMessageIds.has(message.inboundMessageId) || !attemptStartInterruptIds.has(message.inboundMessageId)));
273
284
  if (candidates.length === 0) return [];
274
285
  return await handle(candidates) ?? candidates.map((message) => message.inboundMessageId);
275
286
  },
@@ -337,7 +348,7 @@ async function processConversationWorkInContext(message, options) {
337
348
  const attemptMessages = selectAttemptMessages(leasedWork);
338
349
  const runId = leasedWork.execution.runId;
339
350
  if (!runId) throw new Error(`Conversation run is missing for ${conversationId}`);
340
- attemptStartMessageIds = new Set(leasedWork.messages.map((message) => message.inboundMessageId));
351
+ attemptStartInterruptIds = new Set(leasedWork.messages.filter((message) => isAttemptInterrupt(message, leasedWork)).map((message) => message.inboundMessageId));
341
352
  if (hasRun && shouldYield()) {
342
353
  if (resumePending) return await yieldWork();
343
354
  break;
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "junior_automations" DROP CONSTRAINT "junior_automations_trigger_check";--> statement-breakpoint
2
+ ALTER TABLE "junior_automations" ADD CONSTRAINT "junior_automations_trigger_check" CHECK (("junior_automations"."kind" = 'scheduled' and "junior_automations"."namespace" is null and "junior_automations"."identifier" is null) or ("junior_automations"."kind" = 'event' and "junior_automations"."namespace" is not null and "junior_automations"."next_run_at_ms" is null and "junior_automations"."run_now_at_ms" is null and "junior_automations"."status" <> 'completed'));
@@ -0,0 +1 @@
1
+ ALTER TABLE "junior_users" ADD COLUMN "customization" text;
@@ -0,0 +1,53 @@
1
+ CREATE TABLE "junior_review_item_assignees" (
2
+ "item_id" text NOT NULL,
3
+ "user_id" text NOT NULL,
4
+ CONSTRAINT "junior_review_item_assignees_item_id_user_id_pk" PRIMARY KEY("item_id","user_id")
5
+ );
6
+ --> statement-breakpoint
7
+ CREATE TABLE "junior_review_item_conversations" (
8
+ "item_id" text NOT NULL,
9
+ "conversation_id" text NOT NULL,
10
+ CONSTRAINT "junior_review_item_conversations_item_id_conversation_id_pk" PRIMARY KEY("item_id","conversation_id")
11
+ );
12
+ --> statement-breakpoint
13
+ CREATE TABLE "junior_review_items" (
14
+ "id" text PRIMARY KEY NOT NULL,
15
+ "kind" text NOT NULL,
16
+ "status" text NOT NULL,
17
+ "visibility" text NOT NULL,
18
+ "title" text NOT NULL,
19
+ "body" text NOT NULL,
20
+ "request" jsonb,
21
+ "answer" jsonb,
22
+ "assigned_to_everyone" boolean DEFAULT false NOT NULL,
23
+ "dedupe_key" text NOT NULL,
24
+ "subject_id" text,
25
+ "subject_title" text,
26
+ "subject_url" text,
27
+ "added_by_conversation_id" text NOT NULL,
28
+ "provider" text,
29
+ "provider_tenant_id" text,
30
+ "automation_id" text,
31
+ "closed_at" timestamp with time zone,
32
+ "closed_by_user_id" text,
33
+ "close_reason" text,
34
+ "created_at" timestamp with time zone NOT NULL,
35
+ "updated_at" timestamp with time zone NOT NULL,
36
+ CONSTRAINT "junior_review_items_kind_check" CHECK (("junior_review_items"."kind" = 'notice' and "junior_review_items"."request" is null and "junior_review_items"."answer" is null) or ("junior_review_items"."kind" = 'action' and "junior_review_items"."request" is not null)),
37
+ CONSTRAINT "junior_review_items_status_check" CHECK (("junior_review_items"."status" = 'open' and "junior_review_items"."closed_at" is null) or ("junior_review_items"."status" in ('done', 'dismissed') and "junior_review_items"."closed_at" is not null)),
38
+ CONSTRAINT "junior_review_items_tenant_check" CHECK (("junior_review_items"."provider" is null) = ("junior_review_items"."provider_tenant_id" is null)),
39
+ CONSTRAINT "junior_review_items_visibility_check" CHECK ("junior_review_items"."visibility" = 'public' or not "junior_review_items"."assigned_to_everyone")
40
+ );
41
+ --> statement-breakpoint
42
+ ALTER TABLE "junior_review_item_assignees" ADD CONSTRAINT "junior_review_item_assignees_item_id_junior_review_items_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."junior_review_items"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
43
+ ALTER TABLE "junior_review_item_assignees" ADD CONSTRAINT "junior_review_item_assignees_user_id_junior_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."junior_users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
44
+ ALTER TABLE "junior_review_item_conversations" ADD CONSTRAINT "junior_review_item_conversations_item_id_junior_review_items_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."junior_review_items"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
45
+ ALTER TABLE "junior_review_item_conversations" ADD CONSTRAINT "junior_review_item_conversations_conversation_id_junior_conversations_conversation_id_fk" FOREIGN KEY ("conversation_id") REFERENCES "public"."junior_conversations"("conversation_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
46
+ ALTER TABLE "junior_review_items" ADD CONSTRAINT "junior_review_items_automation_id_junior_automations_id_fk" FOREIGN KEY ("automation_id") REFERENCES "public"."junior_automations"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
47
+ ALTER TABLE "junior_review_items" ADD CONSTRAINT "junior_review_items_closed_by_user_id_junior_users_id_fk" FOREIGN KEY ("closed_by_user_id") REFERENCES "public"."junior_users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
48
+ CREATE INDEX "junior_review_item_assignees_user_idx" ON "junior_review_item_assignees" USING btree ("user_id");--> statement-breakpoint
49
+ CREATE INDEX "junior_review_item_conversations_conversation_idx" ON "junior_review_item_conversations" USING btree ("conversation_id");--> statement-breakpoint
50
+ CREATE UNIQUE INDEX "junior_review_items_open_dedupe_uidx" ON "junior_review_items" USING btree ("dedupe_key") WHERE "junior_review_items"."status" = 'open';--> statement-breakpoint
51
+ CREATE INDEX "junior_review_items_status_idx" ON "junior_review_items" USING btree ("status","updated_at","id");--> statement-breakpoint
52
+ CREATE INDEX "junior_review_items_subject_idx" ON "junior_review_items" USING btree ("subject_id","status");--> statement-breakpoint
53
+ CREATE INDEX "junior_review_items_automation_idx" ON "junior_review_items" USING btree ("automation_id","status");
@@ -0,0 +1,2 @@
1
+ DROP INDEX "junior_review_items_open_dedupe_uidx";--> statement-breakpoint
2
+ CREATE UNIQUE INDEX "junior_review_items_open_dedupe_uidx" ON "junior_review_items" USING btree (coalesce("provider", ''),coalesce("provider_tenant_id", ''),"dedupe_key") WHERE "junior_review_items"."status" = 'open';
@@ -0,0 +1,10 @@
1
+ CREATE TABLE "junior_review_item_slack_cards" (
2
+ "item_id" text NOT NULL,
3
+ "conversation_id" text NOT NULL,
4
+ "team_id" text NOT NULL,
5
+ "channel_id" text NOT NULL,
6
+ "message_ts" text NOT NULL,
7
+ CONSTRAINT "junior_review_item_slack_cards_item_id_conversation_id_pk" PRIMARY KEY("item_id","conversation_id")
8
+ );
9
+ --> statement-breakpoint
10
+ ALTER TABLE "junior_review_item_slack_cards" ADD CONSTRAINT "junior_review_item_slack_cards_item_id_junior_review_items_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."junior_review_items"("id") ON DELETE cascade ON UPDATE no action;