@sentry/junior 0.136.1 → 0.138.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 (103) hide show
  1. package/dist/{agent-hooks-2KDSPPO4.js → agent-hooks-SCR74Q3E.js} +11 -9
  2. package/dist/api/conversations/projection.d.ts +1 -0
  3. package/dist/api/conversations/stats.d.ts +1 -0
  4. package/dist/api/schema/conversation.d.ts +2 -0
  5. package/dist/api/schema.js +1 -1
  6. package/dist/api.js +187 -46
  7. package/dist/app.d.ts +8 -1
  8. package/dist/app.js +519 -860
  9. package/dist/{catalog-runtime-WSZQGC4D.js → catalog-runtime-IU3QF4GG.js} +5 -5
  10. package/dist/chat/agent/request.d.ts +32 -2
  11. package/dist/chat/agent-dispatch/heartbeat.d.ts +5 -0
  12. package/dist/chat/agent-dispatch/types.d.ts +1 -1
  13. package/dist/chat/agent-invocations/errors.d.ts +8 -0
  14. package/dist/chat/agent-invocations/spawn.d.ts +12 -0
  15. package/dist/chat/agent-invocations/store.d.ts +44 -0
  16. package/dist/chat/agent-invocations/types.d.ts +449 -0
  17. package/dist/chat/agent-invocations/work.d.ts +31 -0
  18. package/dist/chat/config.d.ts +1 -0
  19. package/dist/chat/configuration/defaults.d.ts +1 -1
  20. package/dist/chat/conversations/sql/store.d.ts +8 -0
  21. package/dist/chat/conversations/store.d.ts +9 -1
  22. package/dist/chat/experimental.d.ts +16 -0
  23. package/dist/chat/pi/client.d.ts +1 -8
  24. package/dist/chat/pi/gateway-auth.d.ts +16 -0
  25. package/dist/chat/runtime/agent-runner.d.ts +2 -1
  26. package/dist/chat/sandbox/docker.d.ts +17 -0
  27. package/dist/chat/services/agent-continue.d.ts +2 -0
  28. package/dist/chat/services/auth-pause.d.ts +0 -1
  29. package/dist/chat/services/mcp-auth-orchestration.d.ts +3 -2
  30. package/dist/chat/services/plugin-auth-orchestration.d.ts +3 -2
  31. package/dist/chat/services/subscribed-reply-router-policy.d.ts +12 -0
  32. package/dist/chat/services/turn-session-routing.d.ts +17 -0
  33. package/dist/chat/slack/message.d.ts +6 -1
  34. package/dist/chat/slack/source-link.d.ts +8 -2
  35. package/dist/chat/slack/team-domain.d.ts +4 -0
  36. package/dist/chat/source.d.ts +5 -5
  37. package/dist/chat/state/turn-session.d.ts +0 -2
  38. package/dist/chat/task-execution/state.d.ts +23 -11
  39. package/dist/chat/task-execution/store.d.ts +20 -11
  40. package/dist/chat/task-execution/worker.d.ts +2 -2
  41. package/dist/chat/tools/runtime/spawn-agent.d.ts +31 -0
  42. package/dist/chat/tools/types.d.ts +2 -0
  43. package/dist/chunk-3Y47VMHV.js +6 -0
  44. package/dist/chunk-5IDFPCON.js +46 -0
  45. package/dist/chunk-5LTJ4ITU.js +1523 -0
  46. package/dist/{chunk-KLBYCSLJ.js → chunk-5MXWHTCK.js} +17 -434
  47. package/dist/{chunk-CZZDCH3Q.js → chunk-A7WCHXZV.js} +206 -78
  48. package/dist/{chunk-4YQ6I6VF.js → chunk-BOLJOV5T.js} +2 -56
  49. package/dist/{chunk-XCZ6COFO.js → chunk-BYW4B4PR.js} +90 -54
  50. package/dist/{chunk-JQRTXJHD.js → chunk-C7ZVPO4Z.js} +2 -1
  51. package/dist/{chunk-MW2QRPGW.js → chunk-DCLLQGS6.js} +119 -50
  52. package/dist/{chunk-CDVCCOMF.js → chunk-E5UYAIKJ.js} +75 -1475
  53. package/dist/{chunk-3SUK3UXX.js → chunk-ELKW5FIB.js} +5 -5
  54. package/dist/chunk-EM225ITJ.js +56 -0
  55. package/dist/{chunk-Y6JNHTRD.js → chunk-FEUNPTGV.js} +34 -70
  56. package/dist/{chunk-TYNMSQKA.js → chunk-FNLBTB4K.js} +1 -1
  57. package/dist/{chunk-TRZSM67C.js → chunk-HCIVH3JS.js} +1 -0
  58. package/dist/chunk-HIWJWWMT.js +668 -0
  59. package/dist/chunk-IUFM5JWV.js +24 -0
  60. package/dist/{chunk-XWPA5KZF.js → chunk-JNNJZURV.js} +1 -1
  61. package/dist/{chunk-6ZK6FZIV.js → chunk-KCBZSJRU.js} +6 -27
  62. package/dist/{chunk-BG3KWWDJ.js → chunk-KDCHVT25.js} +1 -1
  63. package/dist/{chunk-VH6MI4L7.js → chunk-KFRHRSCJ.js} +1 -1
  64. package/dist/chunk-LPVUNO2W.js +320 -0
  65. package/dist/{chunk-G66RYKRS.js → chunk-N7WARMC6.js} +16 -776
  66. package/dist/chunk-PB3CXNVL.js +41 -0
  67. package/dist/chunk-Q6QZTTLS.js +55 -0
  68. package/dist/{chunk-3QNJOHKG.js → chunk-QS527AV5.js} +1 -1
  69. package/dist/chunk-R776HKPK.js +81 -0
  70. package/dist/{chunk-OTJMQYVP.js → chunk-RZIBSCYC.js} +517 -608
  71. package/dist/chunk-SD3OFRWY.js +714 -0
  72. package/dist/{chunk-HIRIWTWD.js → chunk-SIPKWSXK.js} +58 -10
  73. package/dist/chunk-TCS76X5D.js +441 -0
  74. package/dist/{chunk-UX2TNH5D.js → chunk-TDJCLNDH.js} +3 -3
  75. package/dist/{chunk-NVVBEJUB.js → chunk-TUUDXEXU.js} +336 -300
  76. package/dist/{chunk-22Z6MGMK.js → chunk-VPZFVJND.js} +1 -1
  77. package/dist/{chunk-RFDD3Z2I.js → chunk-YU5QUF67.js} +1 -1
  78. package/dist/chunk-ZBSMCXKV.js +710 -0
  79. package/dist/{chunk-FSYXYBWU.js → chunk-ZXNTJJIE.js} +2 -2
  80. package/dist/cli/chat.js +65 -26
  81. package/dist/cli/check.js +7 -7
  82. package/dist/cli/plugins.js +14 -12
  83. package/dist/cli/snapshot-create.js +10 -9
  84. package/dist/cli/upgrade.js +7 -7
  85. package/dist/conversation-work-KATFHLG3.js +56 -0
  86. package/dist/db/schema/agent-invocations.d.ts +544 -0
  87. package/dist/db/schema.d.ts +543 -1
  88. package/dist/{db-Z2NNL2JC.js → db-UO2IWXGA.js} +7 -7
  89. package/dist/experimental-HH6OM6UH.js +13 -0
  90. package/dist/instrumentation.js +4 -4
  91. package/dist/nitro.js +4 -3
  92. package/dist/{oauth-callback-server-PO3M5JMG.js → oauth-callback-server-MAQI43LX.js} +26 -18
  93. package/dist/{runner-QHQYZYJA.js → runner-PIUQEXKE.js} +26 -14
  94. package/dist/{skills-KXMT3DRA.js → skills-4ARJADHQ.js} +6 -6
  95. package/dist/spawn-G2AWPMCT.js +38 -0
  96. package/dist/{validation-Y42ULTT6.js → validation-S3EE3HWL.js} +6 -6
  97. package/dist/version.js +1 -1
  98. package/dist/work-UARRUAW3.js +46 -0
  99. package/dist/worker-DOCIRVD3.js +24 -0
  100. package/migrations/0021_first_warhawk.sql +35 -0
  101. package/migrations/meta/0021_snapshot.json +2176 -0
  102. package/migrations/meta/_journal.json +8 -1
  103. package/package.json +6 -5
@@ -2,7 +2,10 @@ import {
2
2
  relayLocalOAuthCallback
3
3
  } from "./chunk-FA6POGLH.js";
4
4
  import {
5
- ConversationTurnLifecycleService,
5
+ ensureConversationWake,
6
+ requestConversationWork
7
+ } from "./chunk-5LTJ4ITU.js";
8
+ import {
6
9
  buildDeliveredTurnStatePatch,
7
10
  finalizeFailedTurnReplyWithEvent,
8
11
  getInterruptionMarker,
@@ -12,37 +15,44 @@ import {
12
15
  getTurnUserSlackMessageTs,
13
16
  persistAuthPauseTurnState,
14
17
  requireTurnFailureEventId,
18
+ resolveTurnSessionRouting,
15
19
  scheduleSessionCompletedPluginTasks
16
- } from "./chunk-Y6JNHTRD.js";
20
+ } from "./chunk-FEUNPTGV.js";
21
+ import {
22
+ ConversationTurnLifecycleService
23
+ } from "./chunk-Q6QZTTLS.js";
17
24
  import {
18
25
  buildSentryConversationUrl
19
26
  } from "./chunk-4CODA7P5.js";
20
27
  import {
21
28
  getVercelConversationWorkQueue
22
- } from "./chunk-6ZK6FZIV.js";
29
+ } from "./chunk-KCBZSJRU.js";
23
30
  import {
24
- RetryableDeliveryError,
25
- addReactionToMessage,
26
31
  createUserTokenStore,
27
32
  deleteMcpAuthSession,
28
- escapeSlackMrkdwnText,
29
33
  finalizeMcpAuthorization,
30
- formatProviderLabel,
31
- formatSlackLink,
32
34
  getMcpAuthSession,
33
35
  getMcpProviderErrorAttributes,
34
36
  getMcpStoredOAuthCredentials,
37
+ resolvePluginOAuthAccount
38
+ } from "./chunk-N7WARMC6.js";
39
+ import {
40
+ RetryableDeliveryError
41
+ } from "./chunk-R776HKPK.js";
42
+ import {
43
+ addReactionToMessage,
44
+ escapeSlackMrkdwnText,
45
+ formatProviderLabel,
46
+ formatSlackLink,
35
47
  normalizeSlackReplyMarkdown,
36
48
  normalizeSlackStatusText,
37
49
  parseOAuthStatePayload,
38
50
  postSlackMessage,
39
51
  removeReactionFromMessage,
40
52
  resolveBaseUrl,
41
- resolvePluginOAuthAccount,
42
53
  truncateStatusText
43
- } from "./chunk-G66RYKRS.js";
54
+ } from "./chunk-SD3OFRWY.js";
44
55
  import {
45
- JUNIOR_THREAD_STATE_TTL_MS,
46
56
  TurnSliceLimitExceededError,
47
57
  abandonAgentTurnSessionRecord,
48
58
  buildConversationContext,
@@ -72,34 +82,32 @@ import {
72
82
  recordDeliveredAssistantMessage,
73
83
  turnHasReply,
74
84
  updateConversationStats
75
- } from "./chunk-NVVBEJUB.js";
85
+ } from "./chunk-TUUDXEXU.js";
76
86
  import {
77
87
  parseSlackThreadId,
78
88
  readSlackRawMessageContext,
79
89
  resolveSlackChannelIdFromMessage,
80
90
  resolveSlackChannelIdFromThreadId
81
- } from "./chunk-TYNMSQKA.js";
91
+ } from "./chunk-FNLBTB4K.js";
82
92
  import {
83
- SlackActionError,
84
93
  getDashboardConversationLink,
94
+ getPluginSlackConversationLink
95
+ } from "./chunk-5MXWHTCK.js";
96
+ import {
97
+ SlackActionError,
85
98
  getHeaderString,
86
- getPluginSlackConversationLink,
87
99
  getSlackClient,
88
100
  isDmChannel,
89
101
  normalizeSlackConversationId
90
- } from "./chunk-KLBYCSLJ.js";
102
+ } from "./chunk-TCS76X5D.js";
91
103
  import {
92
104
  getConversationEventStore,
93
- getConversationStore,
94
- parseDestination,
95
- requireSlackDestination,
96
- sameDestination
97
- } from "./chunk-HIRIWTWD.js";
105
+ requireSlackDestination
106
+ } from "./chunk-SIPKWSXK.js";
98
107
  import {
99
108
  acquireActiveLock,
100
- getDefaultRedisStateAdapterFor,
101
109
  getStateAdapter
102
- } from "./chunk-4YQ6I6VF.js";
110
+ } from "./chunk-BOLJOV5T.js";
103
111
  import {
104
112
  FUNCTION_TIMEOUT_BUFFER_SECONDS,
105
113
  botConfig,
@@ -108,37 +116,34 @@ import {
108
116
  getRuntimeMetadata,
109
117
  normalizeSlackEmojiName,
110
118
  standardModelId
111
- } from "./chunk-XCZ6COFO.js";
119
+ } from "./chunk-BYW4B4PR.js";
112
120
  import {
113
121
  discoverSkills
114
- } from "./chunk-FSYXYBWU.js";
122
+ } from "./chunk-ZXNTJJIE.js";
115
123
  import {
116
124
  pluginCatalogRuntime
117
- } from "./chunk-3QNJOHKG.js";
125
+ } from "./chunk-QS527AV5.js";
118
126
  import {
119
127
  buildOAuthTokenRequest,
120
128
  hasRequiredOAuthScope,
121
129
  parseOAuthTokenResponse
122
- } from "./chunk-VH6MI4L7.js";
130
+ } from "./chunk-KFRHRSCJ.js";
123
131
  import {
124
132
  createSlackResumeActor,
125
- isUserActor,
126
- parseStoredSlackActor
133
+ isUserActor
127
134
  } from "./chunk-HZF5P5UN.js";
128
135
  import {
129
136
  parseSlackMessageTs
130
137
  } from "./chunk-F3B2YJ76.js";
131
138
  import {
132
139
  buildTurnFailureResponse,
133
- isRecord,
134
140
  logException,
135
141
  logInfo,
136
142
  logWarn,
137
143
  setTags,
138
- toOptionalNumber,
139
144
  toOptionalString,
140
145
  withLogContext
141
- } from "./chunk-XWPA5KZF.js";
146
+ } from "./chunk-JNNJZURV.js";
142
147
  import {
143
148
  homeDir
144
149
  } from "./chunk-H4HBKISO.js";
@@ -203,7 +208,7 @@ var STATUS_UPDATE_DEBOUNCE_MS = 1e3;
203
208
  var STATUS_MIN_VISIBLE_MS = 1200;
204
209
  var STATUS_ROTATION_INTERVAL_MS = 3e4;
205
210
  function createAssistantStatusScheduler(args) {
206
- const now3 = args.now ?? (() => Date.now());
211
+ const now = args.now ?? (() => Date.now());
207
212
  const setTimer = args.setTimer ?? ((callback, delayMs) => setTimeout(callback, delayMs));
208
213
  const clearTimer = args.clearTimer ?? ((timer) => clearTimeout(timer));
209
214
  const random = args.random ?? Math.random;
@@ -267,7 +272,7 @@ function createAssistantStatusScheduler(args) {
267
272
  }
268
273
  currentVisibleStatus = text;
269
274
  currentLoadingMessages = nextLoadingMessages;
270
- lastStatusAt = now3();
275
+ lastStatusAt = now();
271
276
  scheduleRotation();
272
277
  await enqueueStatusUpdate(async () => {
273
278
  await args.sendStatus(text, nextLoadingMessages);
@@ -354,7 +359,7 @@ function createAssistantStatusScheduler(args) {
354
359
  }
355
360
  return;
356
361
  }
357
- const elapsed = now3() - lastStatusAt;
362
+ const elapsed = now() - lastStatusAt;
358
363
  const waitMs = Math.max(
359
364
  STATUS_UPDATE_DEBOUNCE_MS - elapsed,
360
365
  STATUS_MIN_VISIBLE_MS - elapsed,
@@ -1739,1410 +1744,6 @@ async function resumeSlackTurnInContext(args) {
1739
1744
  return true;
1740
1745
  }
1741
1746
 
1742
- // src/chat/task-execution/state.ts
1743
- import { randomUUID } from "crypto";
1744
- import { destinationSchema } from "@sentry/junior-plugin-api";
1745
- import { z } from "zod";
1746
- var CONVERSATION_PREFIX = "junior:conversation";
1747
- var CONVERSATION_SCHEMA_VERSION = 2;
1748
- var CONVERSATION_ACTIVITY_INDEX_MAX_LENGTH = 1e4;
1749
- var CONVERSATION_INDEX_LOCK_TTL_MS = 1e4;
1750
- var CONVERSATION_INDEX_LOCK_WAIT_MS = 2e3;
1751
- var CONVERSATION_INDEX_LOCK_RETRY_MS = 25;
1752
- var CONVERSATION_MUTATION_LOCK_TTL_MS = 1e4;
1753
- var CONVERSATION_MUTATION_WAIT_MS = 1e4;
1754
- var CONVERSATION_MUTATION_RETRY_MS = 25;
1755
- var InvalidConversationRecordError = class extends Error {
1756
- constructor(conversationId) {
1757
- super(`Conversation record is invalid for ${conversationId}`);
1758
- this.name = "InvalidConversationRecordError";
1759
- }
1760
- };
1761
- function isInvalidConversationRecordError(error) {
1762
- return error instanceof InvalidConversationRecordError;
1763
- }
1764
- var ConversationMutationFencedError = class extends Error {
1765
- constructor(conversationId) {
1766
- super(
1767
- `Conversation mutation lock was lost before write for ${conversationId}`
1768
- );
1769
- this.name = "ConversationMutationFencedError";
1770
- }
1771
- };
1772
- var CONVERSATION_BY_ACTIVITY_INDEX_KEY = `${CONVERSATION_PREFIX}:by-activity`;
1773
- var CONVERSATION_ACTIVE_INDEX_KEY = `${CONVERSATION_PREFIX}:active`;
1774
- var CONVERSATION_WORK_LEASE_TTL_MS = 9e4;
1775
- var CONVERSATION_WORK_CHECK_IN_INTERVAL_MS = 15e3;
1776
- var CONVERSATION_WORK_STALE_ENQUEUE_MS = 6e4;
1777
- var CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS = 5;
1778
- var inboundMessageSourceSchema = z.enum([
1779
- "api",
1780
- "internal",
1781
- "local",
1782
- "plugin",
1783
- "resource_event",
1784
- "scheduler",
1785
- "slack"
1786
- ]);
1787
- var agentInputSchema = z.object({
1788
- attachments: z.array(z.unknown()).optional(),
1789
- authorId: z.string().min(1).optional(),
1790
- metadata: z.record(z.string(), z.unknown()).optional(),
1791
- text: z.string()
1792
- }).strict().refine((input) => input.text.trim() || input.attachments?.length, {
1793
- message: "agent input requires text or attachments"
1794
- });
1795
- var inboundMessageDeliverySchema = z.enum(["defer", "interrupt"]);
1796
- var inboundMessageSchema = z.object({
1797
- attemptCount: z.number().finite().optional(),
1798
- conversationId: z.string().refine((value) => value.trim().length > 0),
1799
- createdAtMs: z.number().finite(),
1800
- delivery: inboundMessageDeliverySchema,
1801
- destination: destinationSchema,
1802
- inboundMessageId: z.string().refine((value) => value.trim().length > 0),
1803
- injectedAtMs: z.number().finite().optional(),
1804
- input: agentInputSchema,
1805
- receivedAtMs: z.number().finite(),
1806
- source: inboundMessageSourceSchema
1807
- }).strict();
1808
- function conversationKey(conversationId) {
1809
- return `${CONVERSATION_PREFIX}:${conversationId}`;
1810
- }
1811
- function indexLockKey(indexKey) {
1812
- return `${indexKey}:lock`;
1813
- }
1814
- function mutationLockKey(conversationId) {
1815
- return `${CONVERSATION_PREFIX}:mutation:${conversationId}`;
1816
- }
1817
- function now() {
1818
- return Date.now();
1819
- }
1820
- function compareMessages(left, right) {
1821
- return left.createdAtMs - right.createdAtMs || left.receivedAtMs - right.receivedAtMs || left.inboundMessageId.localeCompare(right.inboundMessageId);
1822
- }
1823
- function inputHasAttachments(input) {
1824
- return Array.isArray(input.attachments) && input.attachments.length > 0;
1825
- }
1826
- function upgradedPendingMessage(stored, duplicate) {
1827
- const promotesInterrupt = stored.delivery === "defer" && duplicate.delivery === "interrupt";
1828
- const delivery = promotesInterrupt ? "interrupt" : stored.delivery;
1829
- const input = promotesInterrupt ? {
1830
- ...duplicate.input,
1831
- ...inputHasAttachments(duplicate.input) || !inputHasAttachments(stored.input) ? {} : { attachments: stored.input.attachments }
1832
- } : inputHasAttachments(duplicate.input) && !inputHasAttachments(stored.input) ? duplicate.input : stored.input;
1833
- if (input === stored.input && delivery === stored.delivery) {
1834
- return stored;
1835
- }
1836
- return { ...stored, delivery, input };
1837
- }
1838
- function compareIndexDescending(left, right) {
1839
- return right.score - left.score || right.conversationId.localeCompare(left.conversationId);
1840
- }
1841
- function compareIndexAscending(left, right) {
1842
- return left.score - right.score || left.conversationId.localeCompare(right.conversationId);
1843
- }
1844
- function uniqueStrings(values) {
1845
- return [...new Set(values)];
1846
- }
1847
- function normalizeSource(value) {
1848
- const parsed = inboundMessageSourceSchema.safeParse(value);
1849
- return parsed.success ? parsed.data : void 0;
1850
- }
1851
- function normalizeExecutionStatus(value) {
1852
- if (value === "awaiting_resume" || value === "failed" || value === "idle" || value === "pending" || value === "running") {
1853
- return value;
1854
- }
1855
- return void 0;
1856
- }
1857
- function normalizeMessage(value, schemaVersion) {
1858
- const candidate = schemaVersion === 1 && isRecord(value) && value.delivery === void 0 ? {
1859
- ...value,
1860
- delivery: "defer"
1861
- } : value;
1862
- const parsed = inboundMessageSchema.safeParse(candidate);
1863
- return parsed.success ? parsed.data : void 0;
1864
- }
1865
- function isFinalAttempt(message) {
1866
- return (message.attemptCount ?? 0) >= CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS - 1;
1867
- }
1868
- function normalizeActor(value) {
1869
- return parseStoredSlackActor(value);
1870
- }
1871
- function normalizeLease(value) {
1872
- if (!isRecord(value)) {
1873
- return void 0;
1874
- }
1875
- const token = toOptionalString(value.token);
1876
- const acquiredAtMs = toOptionalNumber(value.acquiredAtMs);
1877
- const lastCheckInAtMs = toOptionalNumber(value.lastCheckInAtMs);
1878
- const expiresAtMs = toOptionalNumber(value.expiresAtMs);
1879
- if (!token || typeof acquiredAtMs !== "number" || typeof lastCheckInAtMs !== "number" || typeof expiresAtMs !== "number") {
1880
- return void 0;
1881
- }
1882
- return {
1883
- token,
1884
- acquiredAtMs,
1885
- lastCheckInAtMs,
1886
- expiresAtMs
1887
- };
1888
- }
1889
- function normalizeExecution(conversationId, value, schemaVersion) {
1890
- if (!isRecord(value)) {
1891
- return void 0;
1892
- }
1893
- const status = normalizeExecutionStatus(value.status);
1894
- if (!status) {
1895
- return void 0;
1896
- }
1897
- const pendingMessages2 = [];
1898
- if (Array.isArray(value.pendingMessages)) {
1899
- for (const rawMessage of value.pendingMessages) {
1900
- const message = normalizeMessage(rawMessage, schemaVersion);
1901
- if (!message || message.conversationId !== conversationId) {
1902
- return void 0;
1903
- }
1904
- if (message.injectedAtMs !== void 0) {
1905
- continue;
1906
- }
1907
- pendingMessages2.push(message);
1908
- }
1909
- pendingMessages2.sort(compareMessages);
1910
- }
1911
- const inboundMessageIds = Array.isArray(value.inboundMessageIds) ? uniqueStrings(
1912
- value.inboundMessageIds.map((id) => typeof id === "string" ? id : void 0).filter((id) => Boolean(id))
1913
- ) : [];
1914
- const lease = normalizeLease(value.lease);
1915
- const normalizedStatus = status === "idle" && lease ? "running" : status === "idle" && pendingMessages2.length > 0 ? "pending" : status;
1916
- return {
1917
- status: normalizedStatus,
1918
- inboundMessageIds: uniqueStrings([
1919
- ...inboundMessageIds,
1920
- ...pendingMessages2.map((message) => message.inboundMessageId)
1921
- ]),
1922
- pendingCount: pendingMessages2.length,
1923
- pendingMessages: pendingMessages2,
1924
- lease,
1925
- lastCheckpointAtMs: toOptionalNumber(value.lastCheckpointAtMs),
1926
- lastEnqueuedAtMs: toOptionalNumber(value.lastEnqueuedAtMs),
1927
- runId: toOptionalString(value.runId),
1928
- updatedAtMs: toOptionalNumber(value.updatedAtMs)
1929
- };
1930
- }
1931
- function normalizeConversation(conversationId, value) {
1932
- if (!isRecord(value) || value.schemaVersion !== 1 && value.schemaVersion !== CONVERSATION_SCHEMA_VERSION) {
1933
- return void 0;
1934
- }
1935
- const schemaVersion = value.schemaVersion;
1936
- const storedConversationId = toOptionalString(value.conversationId);
1937
- const createdAtMs = toOptionalNumber(value.createdAtMs);
1938
- const lastActivityAtMs = toOptionalNumber(value.lastActivityAtMs);
1939
- const updatedAtMs = toOptionalNumber(value.updatedAtMs);
1940
- const execution = normalizeExecution(
1941
- conversationId,
1942
- value.execution,
1943
- schemaVersion
1944
- );
1945
- const destination = value.destination === void 0 ? void 0 : parseDestination(value.destination);
1946
- if (storedConversationId !== conversationId || typeof createdAtMs !== "number" || typeof lastActivityAtMs !== "number" || typeof updatedAtMs !== "number" || !execution || value.destination !== void 0 && !destination) {
1947
- return void 0;
1948
- }
1949
- if (execution.pendingMessages.length > 0 && (!destination || execution.pendingMessages.some(
1950
- (message) => !sameDestination(message.destination, destination)
1951
- ))) {
1952
- return void 0;
1953
- }
1954
- return {
1955
- schemaVersion: CONVERSATION_SCHEMA_VERSION,
1956
- conversationId,
1957
- createdAtMs,
1958
- lastActivityAtMs,
1959
- updatedAtMs,
1960
- execution,
1961
- ...destination ? { destination } : {},
1962
- ...toOptionalString(value.title) ? { title: toOptionalString(value.title) } : {},
1963
- ...toOptionalString(value.channelName) ? { channelName: toOptionalString(value.channelName) } : {},
1964
- ...normalizeActor(value.actor) ? { actor: normalizeActor(value.actor) } : {},
1965
- ...normalizeSource(value.source) ? { source: normalizeSource(value.source) } : {}
1966
- };
1967
- }
1968
- function emptyConversation(args) {
1969
- return {
1970
- schemaVersion: CONVERSATION_SCHEMA_VERSION,
1971
- conversationId: args.conversationId,
1972
- createdAtMs: args.nowMs,
1973
- lastActivityAtMs: args.nowMs,
1974
- updatedAtMs: args.nowMs,
1975
- ...args.destination ? { destination: args.destination } : {},
1976
- ...args.source ? { source: args.source } : {},
1977
- execution: {
1978
- status: "idle",
1979
- inboundMessageIds: [],
1980
- pendingCount: 0,
1981
- pendingMessages: [],
1982
- updatedAtMs: args.nowMs
1983
- }
1984
- };
1985
- }
1986
- function isLeaseActive(lease, nowMs) {
1987
- return Boolean(lease && lease.expiresAtMs > nowMs);
1988
- }
1989
- function pendingMessages(conversation) {
1990
- return [...conversation.execution.pendingMessages].sort(compareMessages);
1991
- }
1992
- function isRunnableStatus(status) {
1993
- return status !== "failed" && status !== "idle";
1994
- }
1995
- function hasRunnableWork(conversation) {
1996
- return isRunnableStatus(conversation.execution.status) || pendingMessages(conversation).length > 0;
1997
- }
1998
- function executionWithPendingMessages(execution, pending) {
1999
- const pendingMessages2 = [...pending].sort(compareMessages);
2000
- const status = execution.status === "idle" && execution.lease ? "running" : execution.status === "idle" && pendingMessages2.length > 0 ? "pending" : execution.status;
2001
- return {
2002
- ...execution,
2003
- status,
2004
- inboundMessageIds: uniqueStrings([
2005
- ...execution.inboundMessageIds,
2006
- ...pendingMessages2.map((message) => message.inboundMessageId)
2007
- ]),
2008
- pendingMessages: pendingMessages2,
2009
- pendingCount: pendingMessages2.length
2010
- };
2011
- }
2012
- function withExecutionUpdate(conversation, execution, nowMs) {
2013
- return {
2014
- ...conversation,
2015
- updatedAtMs: nowMs,
2016
- execution: {
2017
- ...executionWithPendingMessages(execution, execution.pendingMessages),
2018
- updatedAtMs: nowMs
2019
- }
2020
- };
2021
- }
2022
- async function getConnectedState(stateAdapter) {
2023
- const state = stateAdapter ?? getStateAdapter();
2024
- await state.connect();
2025
- return state;
2026
- }
2027
- async function sleep(ms) {
2028
- await new Promise((resolve) => {
2029
- const timer = setTimeout(resolve, ms);
2030
- timer.unref?.();
2031
- });
2032
- }
2033
- async function withIndexLock(state, indexKey, callback) {
2034
- const startedAtMs = now();
2035
- let lock;
2036
- while (true) {
2037
- lock = await state.acquireLock(
2038
- indexLockKey(indexKey),
2039
- CONVERSATION_INDEX_LOCK_TTL_MS
2040
- );
2041
- if (lock) {
2042
- break;
2043
- }
2044
- if (now() - startedAtMs >= CONVERSATION_INDEX_LOCK_WAIT_MS) {
2045
- throw new Error(
2046
- `Could not acquire conversation index lock for ${indexKey}`
2047
- );
2048
- }
2049
- await sleep(CONVERSATION_INDEX_LOCK_RETRY_MS);
2050
- }
2051
- try {
2052
- return await callback();
2053
- } finally {
2054
- await state.releaseLock(lock);
2055
- }
2056
- }
2057
- function normalizeIndexEntry(value) {
2058
- if (!isRecord(value)) {
2059
- return void 0;
2060
- }
2061
- const conversationId = toOptionalString(value.conversationId);
2062
- const score = toOptionalNumber(value.score);
2063
- if (!conversationId || typeof score !== "number") {
2064
- return void 0;
2065
- }
2066
- return { conversationId, score };
2067
- }
2068
- function uniqueIndexEntries(value) {
2069
- if (!Array.isArray(value)) {
2070
- return [];
2071
- }
2072
- const entries = /* @__PURE__ */ new Map();
2073
- for (const item of value) {
2074
- const entry = normalizeIndexEntry(item);
2075
- if (!entry) {
2076
- continue;
2077
- }
2078
- const existing = entries.get(entry.conversationId);
2079
- if (!existing || entry.score > existing.score) {
2080
- entries.set(entry.conversationId, entry);
2081
- }
2082
- }
2083
- return [...entries.values()];
2084
- }
2085
- function retainedIndexEntries(indexKey, entries) {
2086
- if (indexKey === CONVERSATION_BY_ACTIVITY_INDEX_KEY) {
2087
- return entries.sort(compareIndexDescending).slice(0, CONVERSATION_ACTIVITY_INDEX_MAX_LENGTH);
2088
- }
2089
- if (indexKey === CONVERSATION_ACTIVE_INDEX_KEY) {
2090
- return entries.sort(compareIndexAscending);
2091
- }
2092
- throw new Error(`Unknown conversation index ${indexKey}`);
2093
- }
2094
- function redisIndexKey(indexKey) {
2095
- const prefix = getChatConfig().state.keyPrefix;
2096
- return [...prefix ? [prefix] : [], indexKey].join(":");
2097
- }
2098
- function parseRedisIndexEntries(values) {
2099
- if (!Array.isArray(values)) {
2100
- return [];
2101
- }
2102
- const entries = [];
2103
- for (let index = 0; index < values.length; index += 2) {
2104
- const conversationId = toOptionalString(values[index]);
2105
- const score = typeof values[index + 1] === "number" ? values[index + 1] : Number(values[index + 1]);
2106
- if (!conversationId || !Number.isFinite(score)) {
2107
- continue;
2108
- }
2109
- entries.push({ conversationId, score });
2110
- }
2111
- return entries;
2112
- }
2113
- function redisConversationIndexStore(client) {
2114
- const upsertBoundedActivityScript = `
2115
- redis.call("ZADD", KEYS[1], ARGV[1], ARGV[2])
2116
- redis.call("PEXPIRE", KEYS[1], ARGV[3])
2117
- local extra = redis.call("ZCARD", KEYS[1]) - tonumber(ARGV[4])
2118
- if extra > 0 then
2119
- redis.call("ZREMRANGEBYRANK", KEYS[1], 0, extra - 1)
2120
- end
2121
- return 1
2122
- `;
2123
- return {
2124
- async list(args) {
2125
- const key = redisIndexKey(args.indexKey);
2126
- const limit = args.limit;
2127
- const offset = Math.max(0, args.offset ?? 0);
2128
- if (limit === 0) {
2129
- return [];
2130
- }
2131
- const values = args.scoreMax !== void 0 ? await client.sendCommand([
2132
- "ZRANGEBYSCORE",
2133
- key,
2134
- "-inf",
2135
- String(args.scoreMax),
2136
- "WITHSCORES",
2137
- ...limit !== void 0 || offset > 0 ? ["LIMIT", String(offset), String(limit ?? 1e9)] : []
2138
- ]) : await client.sendCommand([
2139
- args.order === "asc" ? "ZRANGE" : "ZREVRANGE",
2140
- key,
2141
- String(offset),
2142
- String(
2143
- limit === void 0 ? -1 : offset + Math.max(0, limit - 1)
2144
- ),
2145
- "WITHSCORES"
2146
- ]);
2147
- return parseRedisIndexEntries(values);
2148
- },
2149
- async remove(args) {
2150
- await client.sendCommand([
2151
- "ZREM",
2152
- redisIndexKey(args.indexKey),
2153
- args.conversationId
2154
- ]);
2155
- },
2156
- async upsert(args) {
2157
- const key = redisIndexKey(args.indexKey);
2158
- if (args.indexKey === CONVERSATION_BY_ACTIVITY_INDEX_KEY) {
2159
- await client.sendCommand([
2160
- "EVAL",
2161
- upsertBoundedActivityScript,
2162
- "1",
2163
- key,
2164
- String(args.score),
2165
- args.conversationId,
2166
- String(JUNIOR_THREAD_STATE_TTL_MS),
2167
- String(CONVERSATION_ACTIVITY_INDEX_MAX_LENGTH)
2168
- ]);
2169
- return;
2170
- }
2171
- if (args.indexKey === CONVERSATION_ACTIVE_INDEX_KEY) {
2172
- await client.sendCommand([
2173
- "ZADD",
2174
- key,
2175
- String(args.score),
2176
- args.conversationId
2177
- ]);
2178
- await client.sendCommand([
2179
- "PEXPIRE",
2180
- key,
2181
- String(JUNIOR_THREAD_STATE_TTL_MS)
2182
- ]);
2183
- return;
2184
- }
2185
- throw new Error(`Unknown conversation index ${args.indexKey}`);
2186
- }
2187
- };
2188
- }
2189
- function emulatedConversationIndexStore(state) {
2190
- const readIndex = async (indexKey) => uniqueIndexEntries(await state.get(indexKey));
2191
- const writeIndex = async (indexKey, entries) => {
2192
- await state.set(indexKey, entries, JUNIOR_THREAD_STATE_TTL_MS);
2193
- };
2194
- return {
2195
- async list(args) {
2196
- const entries = (await readIndex(args.indexKey)).filter(
2197
- (entry) => args.scoreMax === void 0 ? true : entry.score <= args.scoreMax
2198
- ).sort(
2199
- args.order === "asc" ? compareIndexAscending : compareIndexDescending
2200
- );
2201
- const offset = Math.max(0, args.offset ?? 0);
2202
- return entries.slice(
2203
- offset,
2204
- args.limit === void 0 ? entries.length : offset + args.limit
2205
- );
2206
- },
2207
- async remove(args) {
2208
- await withIndexLock(state, args.indexKey, async () => {
2209
- const entries = await readIndex(args.indexKey);
2210
- const next = entries.filter(
2211
- (entry) => entry.conversationId !== args.conversationId
2212
- );
2213
- if (next.length === entries.length) {
2214
- return;
2215
- }
2216
- await writeIndex(args.indexKey, next);
2217
- });
2218
- },
2219
- async upsert(args) {
2220
- await withIndexLock(state, args.indexKey, async () => {
2221
- const entries = await readIndex(args.indexKey);
2222
- const withoutCurrent = entries.filter(
2223
- (entry) => entry.conversationId !== args.conversationId
2224
- );
2225
- const next = retainedIndexEntries(args.indexKey, [
2226
- ...withoutCurrent,
2227
- { conversationId: args.conversationId, score: args.score }
2228
- ]);
2229
- await writeIndex(args.indexKey, next);
2230
- });
2231
- }
2232
- };
2233
- }
2234
- async function getConversationIndexStore(state) {
2235
- const redisStateAdapter = await getDefaultRedisStateAdapterFor(state);
2236
- if (redisStateAdapter) {
2237
- return redisConversationIndexStore(redisStateAdapter.getClient());
2238
- }
2239
- return emulatedConversationIndexStore(state);
2240
- }
2241
- async function upsertIndexEntry(args) {
2242
- const index = await getConversationIndexStore(args.state);
2243
- await index.upsert({
2244
- conversationId: args.conversationId,
2245
- indexKey: args.indexKey,
2246
- score: args.score
2247
- });
2248
- }
2249
- async function removeIndexEntry(args) {
2250
- const index = await getConversationIndexStore(args.state);
2251
- await index.remove({
2252
- conversationId: args.conversationId,
2253
- indexKey: args.indexKey
2254
- });
2255
- }
2256
- async function acquireMutationLock(state, conversationId) {
2257
- const startedAtMs = now();
2258
- while (true) {
2259
- const lock = await state.acquireLock(
2260
- mutationLockKey(conversationId),
2261
- CONVERSATION_MUTATION_LOCK_TTL_MS
2262
- );
2263
- if (lock) {
2264
- return lock;
2265
- }
2266
- if (now() - startedAtMs >= CONVERSATION_MUTATION_WAIT_MS) {
2267
- throw new Error(
2268
- `Could not acquire conversation mutation lock for ${conversationId}`
2269
- );
2270
- }
2271
- await sleep(CONVERSATION_MUTATION_RETRY_MS);
2272
- }
2273
- }
2274
- async function withConversationMutation(args, callback) {
2275
- const state = await getConnectedState(args.state);
2276
- const lock = await acquireMutationLock(state, args.conversationId);
2277
- try {
2278
- return await callback(state, lock);
2279
- } finally {
2280
- await state.releaseLock(lock);
2281
- }
2282
- }
2283
- async function readConversation(state, conversationId) {
2284
- const raw = await state.get(conversationKey(conversationId));
2285
- if (raw == null) {
2286
- return void 0;
2287
- }
2288
- const conversation = normalizeConversation(conversationId, raw);
2289
- if (!conversation) {
2290
- throw new InvalidConversationRecordError(conversationId);
2291
- }
2292
- return conversation;
2293
- }
2294
- async function writeConversation(state, lock, conversation) {
2295
- const execution = executionWithPendingMessages(
2296
- conversation.execution,
2297
- conversation.execution.pendingMessages
2298
- );
2299
- const next = {
2300
- ...conversation,
2301
- execution
2302
- };
2303
- const fenced = await state.extendLock(
2304
- lock,
2305
- CONVERSATION_MUTATION_LOCK_TTL_MS
2306
- );
2307
- if (!fenced) {
2308
- throw new ConversationMutationFencedError(next.conversationId);
2309
- }
2310
- await state.set(
2311
- conversationKey(next.conversationId),
2312
- next,
2313
- JUNIOR_THREAD_STATE_TTL_MS
2314
- );
2315
- await upsertIndexEntry({
2316
- state,
2317
- indexKey: CONVERSATION_BY_ACTIVITY_INDEX_KEY,
2318
- conversationId: next.conversationId,
2319
- score: next.lastActivityAtMs
2320
- });
2321
- if (!hasRunnableWork(next)) {
2322
- await removeIndexEntry({
2323
- state,
2324
- indexKey: CONVERSATION_ACTIVE_INDEX_KEY,
2325
- conversationId: next.conversationId
2326
- });
2327
- return;
2328
- }
2329
- await upsertIndexEntry({
2330
- state,
2331
- indexKey: CONVERSATION_ACTIVE_INDEX_KEY,
2332
- conversationId: next.conversationId,
2333
- score: next.execution.updatedAtMs ?? next.updatedAtMs
2334
- });
2335
- }
2336
- function assertSameConversationDestination(args) {
2337
- if (!args.current || sameDestination(args.current, args.next)) {
2338
- return;
2339
- }
2340
- throw new Error(
2341
- `Conversation destination changed for ${args.conversationId}`
2342
- );
2343
- }
2344
- function conversationWorkState(conversation) {
2345
- const lease = conversation.execution.lease;
2346
- return {
2347
- ...conversation,
2348
- lastEnqueuedAtMs: conversation.execution.lastEnqueuedAtMs,
2349
- ...lease ? {
2350
- lease: {
2351
- acquiredAtMs: lease.acquiredAtMs,
2352
- lastCheckInAtMs: lease.lastCheckInAtMs,
2353
- leaseExpiresAtMs: lease.expiresAtMs,
2354
- leaseToken: lease.token
2355
- }
2356
- } : {},
2357
- messages: pendingMessages(conversation),
2358
- needsRun: hasRunnableWork(conversation)
2359
- };
2360
- }
2361
- async function getConversation(args) {
2362
- const state = await getConnectedState(args.state);
2363
- return await readConversation(state, args.conversationId);
2364
- }
2365
- async function getConversationWorkState(args) {
2366
- const conversation = await getConversation(args);
2367
- return conversation ? conversationWorkState(conversation) : void 0;
2368
- }
2369
- async function appendInboundMessage(args) {
2370
- const nowMs = args.nowMs ?? now();
2371
- return await withConversationMutation(
2372
- { conversationId: args.message.conversationId, state: args.state },
2373
- async (state, lock) => {
2374
- const current = await readConversation(state, args.message.conversationId) ?? emptyConversation({
2375
- conversationId: args.message.conversationId,
2376
- destination: args.message.destination,
2377
- nowMs,
2378
- source: args.message.source
2379
- });
2380
- assertSameConversationDestination({
2381
- conversationId: args.message.conversationId,
2382
- current: current.destination,
2383
- next: args.message.destination
2384
- });
2385
- const existingPending = current.execution.pendingMessages.some(
2386
- (message) => message.inboundMessageId === args.message.inboundMessageId
2387
- );
2388
- const existing = current.execution.inboundMessageIds.includes(
2389
- args.message.inboundMessageId
2390
- );
2391
- if (existing) {
2392
- if (!existingPending) {
2393
- return { status: "duplicate" };
2394
- }
2395
- const nextStatus = current.execution.status === "idle" ? "pending" : current.execution.status;
2396
- await writeConversation(
2397
- state,
2398
- lock,
2399
- withExecutionUpdate(
2400
- current,
2401
- {
2402
- ...current.execution,
2403
- status: nextStatus,
2404
- pendingMessages: current.execution.pendingMessages.map(
2405
- (message) => message.inboundMessageId === args.message.inboundMessageId ? upgradedPendingMessage(message, args.message) : message
2406
- )
2407
- },
2408
- nowMs
2409
- )
2410
- );
2411
- return { status: "duplicate" };
2412
- }
2413
- const status = current.execution.lease && current.execution.status === "running" ? "running" : current.execution.lease ? "awaiting_resume" : "pending";
2414
- const next = {
2415
- ...current,
2416
- destination: current.destination ?? args.message.destination,
2417
- source: current.source ?? args.message.source,
2418
- lastActivityAtMs: nowMs
2419
- };
2420
- await writeConversation(
2421
- state,
2422
- lock,
2423
- withExecutionUpdate(
2424
- next,
2425
- {
2426
- ...current.execution,
2427
- status,
2428
- inboundMessageIds: [
2429
- ...current.execution.inboundMessageIds,
2430
- args.message.inboundMessageId
2431
- ],
2432
- pendingMessages: [
2433
- ...current.execution.pendingMessages,
2434
- args.message
2435
- ].sort(compareMessages)
2436
- },
2437
- nowMs
2438
- )
2439
- );
2440
- return { status: "appended" };
2441
- }
2442
- );
2443
- }
2444
- async function requestConversationWork(args) {
2445
- const nowMs = args.nowMs ?? now();
2446
- return await withConversationMutation(args, async (state, lock) => {
2447
- const existing = await readConversation(state, args.conversationId);
2448
- if (existing) {
2449
- assertSameConversationDestination({
2450
- conversationId: args.conversationId,
2451
- current: existing.destination,
2452
- next: args.destination
2453
- });
2454
- }
2455
- const current = existing ?? emptyConversation({
2456
- conversationId: args.conversationId,
2457
- destination: args.destination,
2458
- nowMs
2459
- });
2460
- const status = current.execution.lease ? "awaiting_resume" : "pending";
2461
- await writeConversation(
2462
- state,
2463
- lock,
2464
- withExecutionUpdate(
2465
- {
2466
- ...current,
2467
- destination: current.destination ?? args.destination
2468
- },
2469
- {
2470
- ...current.execution,
2471
- status
2472
- },
2473
- nowMs
2474
- )
2475
- );
2476
- return { status: existing === void 0 ? "created" : "updated" };
2477
- });
2478
- }
2479
- async function markConversationWorkEnqueued(args) {
2480
- const nowMs = args.nowMs ?? now();
2481
- await withConversationMutation(args, async (state, lock) => {
2482
- const current = await readConversation(state, args.conversationId);
2483
- if (!current) {
2484
- return;
2485
- }
2486
- await writeConversation(
2487
- state,
2488
- lock,
2489
- withExecutionUpdate(
2490
- current,
2491
- {
2492
- ...current.execution,
2493
- lastEnqueuedAtMs: nowMs
2494
- },
2495
- nowMs
2496
- )
2497
- );
2498
- });
2499
- }
2500
- async function clearConsumedConversationWake(args) {
2501
- const nowMs = args.nowMs ?? now();
2502
- return await withConversationMutation(args, async (state, lock) => {
2503
- const current = await readConversation(state, args.conversationId);
2504
- if (!current || hasRunnableWork(current) || current.execution.lastEnqueuedAtMs === void 0) {
2505
- return false;
2506
- }
2507
- await writeConversation(
2508
- state,
2509
- lock,
2510
- withExecutionUpdate(
2511
- current,
2512
- {
2513
- ...current.execution,
2514
- lastEnqueuedAtMs: void 0
2515
- },
2516
- nowMs
2517
- )
2518
- );
2519
- return true;
2520
- });
2521
- }
2522
- async function startConversationWork(args) {
2523
- const nowMs = args.nowMs ?? now();
2524
- return await withConversationMutation(args, async (state, lock) => {
2525
- const current = await readConversation(state, args.conversationId);
2526
- if (!current) {
2527
- return { status: "no_work" };
2528
- }
2529
- if (isLeaseActive(current.execution.lease, nowMs)) {
2530
- return {
2531
- status: "active",
2532
- leaseExpiresAtMs: current.execution.lease.expiresAtMs
2533
- };
2534
- }
2535
- if (!hasRunnableWork(current)) {
2536
- return { status: "no_work" };
2537
- }
2538
- const lease = {
2539
- token: randomUUID(),
2540
- acquiredAtMs: nowMs,
2541
- lastCheckInAtMs: nowMs,
2542
- expiresAtMs: nowMs + CONVERSATION_WORK_LEASE_TTL_MS
2543
- };
2544
- await writeConversation(
2545
- state,
2546
- lock,
2547
- withExecutionUpdate(
2548
- current,
2549
- {
2550
- ...current.execution,
2551
- lease,
2552
- status: current.execution.status === "awaiting_resume" ? "awaiting_resume" : "running",
2553
- runId: current.execution.runId ?? randomUUID(),
2554
- lastEnqueuedAtMs: void 0
2555
- },
2556
- nowMs
2557
- )
2558
- );
2559
- return {
2560
- status: "acquired",
2561
- leaseToken: lease.token,
2562
- leaseExpiresAtMs: lease.expiresAtMs
2563
- };
2564
- });
2565
- }
2566
- async function checkInConversationWork(args) {
2567
- const nowMs = args.nowMs ?? now();
2568
- return await withConversationMutation(args, async (state, lock) => {
2569
- const current = await readConversation(state, args.conversationId);
2570
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2571
- return false;
2572
- }
2573
- await writeConversation(
2574
- state,
2575
- lock,
2576
- withExecutionUpdate(
2577
- current,
2578
- {
2579
- ...current.execution,
2580
- lease: {
2581
- ...current.execution.lease,
2582
- lastCheckInAtMs: nowMs,
2583
- expiresAtMs: nowMs + CONVERSATION_WORK_LEASE_TTL_MS
2584
- }
2585
- },
2586
- nowMs
2587
- )
2588
- );
2589
- return true;
2590
- });
2591
- }
2592
- async function drainConversationMailbox(args) {
2593
- const nowMs = args.nowMs ?? now();
2594
- const pending = await withConversationMutation(args, async (state) => {
2595
- const current = await readConversation(state, args.conversationId);
2596
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2597
- throw new Error(
2598
- `Conversation lease is not held for ${args.conversationId}`
2599
- );
2600
- }
2601
- return pendingMessages(current);
2602
- });
2603
- if (pending.length === 0) {
2604
- return { changed: false, messages: [] };
2605
- }
2606
- const result = await args.handle(pending);
2607
- const pendingIds = new Set(
2608
- pending.map((message) => message.inboundMessageId)
2609
- );
2610
- const acknowledgedIds = new Set(
2611
- result ?? pending.map((message) => message.inboundMessageId)
2612
- );
2613
- for (const inboundMessageId of acknowledgedIds) {
2614
- if (!pendingIds.has(inboundMessageId)) {
2615
- throw new Error(
2616
- `Conversation mailbox drain result is not pending for ${args.conversationId}`
2617
- );
2618
- }
2619
- }
2620
- if (acknowledgedIds.size === 0) {
2621
- return { changed: false, messages: [] };
2622
- }
2623
- await withConversationMutation(args, async (state, lock) => {
2624
- const current = await readConversation(state, args.conversationId);
2625
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2626
- throw new Error(
2627
- `Conversation lease is not held for ${args.conversationId}`
2628
- );
2629
- }
2630
- const pendingMessages2 = current.execution.pendingMessages.filter(
2631
- (message) => !acknowledgedIds.has(message.inboundMessageId)
2632
- );
2633
- await writeConversation(
2634
- state,
2635
- lock,
2636
- withExecutionUpdate(
2637
- current,
2638
- {
2639
- ...current.execution,
2640
- status: current.execution.status === "pending" && pendingMessages2.length === 0 ? "running" : current.execution.status,
2641
- pendingMessages: pendingMessages2
2642
- },
2643
- nowMs
2644
- )
2645
- );
2646
- });
2647
- return {
2648
- changed: true,
2649
- messages: pending.filter(
2650
- (message) => acknowledgedIds.has(message.inboundMessageId)
2651
- )
2652
- };
2653
- }
2654
- async function ackMessages(args) {
2655
- const nowMs = args.nowMs ?? now();
2656
- const inboundMessageIds = new Set(args.inboundMessageIds);
2657
- return await withConversationMutation(args, async (state, lock) => {
2658
- const current = await readConversation(state, args.conversationId);
2659
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2660
- return false;
2661
- }
2662
- if (inboundMessageIds.size === 0) {
2663
- return true;
2664
- }
2665
- const pendingMessages2 = current.execution.pendingMessages.filter(
2666
- (message) => !inboundMessageIds.has(message.inboundMessageId)
2667
- );
2668
- if (pendingMessages2.length === current.execution.pendingMessages.length) {
2669
- return true;
2670
- }
2671
- await writeConversation(
2672
- state,
2673
- lock,
2674
- withExecutionUpdate(
2675
- current,
2676
- {
2677
- ...current.execution,
2678
- pendingMessages: pendingMessages2
2679
- },
2680
- nowMs
2681
- )
2682
- );
2683
- return true;
2684
- });
2685
- }
2686
- async function requestConversationContinuation(args) {
2687
- const nowMs = args.nowMs ?? now();
2688
- return await withConversationMutation(args, async (state, lock) => {
2689
- const current = await readConversation(state, args.conversationId);
2690
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2691
- return false;
2692
- }
2693
- assertSameConversationDestination({
2694
- conversationId: args.conversationId,
2695
- current: current.destination,
2696
- next: args.destination
2697
- });
2698
- await writeConversation(
2699
- state,
2700
- lock,
2701
- withExecutionUpdate(
2702
- current,
2703
- {
2704
- ...current.execution,
2705
- status: "awaiting_resume"
2706
- },
2707
- nowMs
2708
- )
2709
- );
2710
- return true;
2711
- });
2712
- }
2713
- async function beginConversationResume(args) {
2714
- const nowMs = args.nowMs ?? now();
2715
- return await withConversationMutation(args, async (state, lock) => {
2716
- const current = await readConversation(state, args.conversationId);
2717
- if (!current || current.execution.lease?.token !== args.leaseToken || current.execution.status !== "awaiting_resume") {
2718
- return false;
2719
- }
2720
- await writeConversation(
2721
- state,
2722
- lock,
2723
- withExecutionUpdate(
2724
- current,
2725
- {
2726
- ...current.execution,
2727
- status: "running"
2728
- },
2729
- nowMs
2730
- )
2731
- );
2732
- return true;
2733
- });
2734
- }
2735
- async function releaseConversationWork(args) {
2736
- const nowMs = args.nowMs ?? now();
2737
- return await withConversationMutation(args, async (state, lock) => {
2738
- const current = await readConversation(state, args.conversationId);
2739
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2740
- return false;
2741
- }
2742
- await writeConversation(
2743
- state,
2744
- lock,
2745
- withExecutionUpdate(
2746
- current,
2747
- {
2748
- ...current.execution,
2749
- lease: void 0,
2750
- status: current.execution.status === "running" ? "pending" : current.execution.status
2751
- },
2752
- nowMs
2753
- )
2754
- );
2755
- return true;
2756
- });
2757
- }
2758
- async function completeConversationWork(args) {
2759
- const nowMs = args.nowMs ?? now();
2760
- return await withConversationMutation(args, async (state, lock) => {
2761
- const current = await readConversation(state, args.conversationId);
2762
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2763
- return "lost_lease";
2764
- }
2765
- const hasPending = pendingMessages(current).length > 0;
2766
- const needsRun = current.execution.status === "awaiting_resume";
2767
- const runnable = needsRun || hasPending;
2768
- await writeConversation(
2769
- state,
2770
- lock,
2771
- withExecutionUpdate(
2772
- current,
2773
- {
2774
- ...current.execution,
2775
- lease: void 0,
2776
- status: needsRun ? "awaiting_resume" : hasPending ? "pending" : "idle",
2777
- runId: runnable ? current.execution.runId : void 0
2778
- },
2779
- nowMs
2780
- )
2781
- );
2782
- return runnable ? "pending" : "completed";
2783
- });
2784
- }
2785
- async function recordAttemptFailure(args) {
2786
- const nowMs = args.nowMs ?? now();
2787
- return await withConversationMutation(args, async (state, lock) => {
2788
- const current = await readConversation(state, args.conversationId);
2789
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2790
- return {
2791
- status: "lost_lease",
2792
- pendingCount: 0,
2793
- deadLetteredMessages: []
2794
- };
2795
- }
2796
- const pendingIds = new Set(
2797
- current.execution.pendingMessages.map(
2798
- (message) => message.inboundMessageId
2799
- )
2800
- );
2801
- if (args.inboundMessageIds.length === 0 || args.inboundMessageIds.some((id) => !pendingIds.has(id))) {
2802
- return {
2803
- status: "skipped",
2804
- pendingCount: current.execution.pendingMessages.length,
2805
- deadLetteredMessages: []
2806
- };
2807
- }
2808
- const attemptedIds = new Set(args.inboundMessageIds);
2809
- const deadLetteredMessages = [];
2810
- const pendingMessages2 = [];
2811
- for (const message of current.execution.pendingMessages) {
2812
- if (!attemptedIds.has(message.inboundMessageId)) {
2813
- pendingMessages2.push(message);
2814
- continue;
2815
- }
2816
- const attempted = {
2817
- ...message,
2818
- attemptCount: (message.attemptCount ?? 0) + 1
2819
- };
2820
- if (attempted.attemptCount >= CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS) {
2821
- deadLetteredMessages.push(attempted);
2822
- continue;
2823
- }
2824
- pendingMessages2.push(attempted);
2825
- }
2826
- await writeConversation(
2827
- state,
2828
- lock,
2829
- withExecutionUpdate(
2830
- current,
2831
- {
2832
- ...current.execution,
2833
- pendingMessages: pendingMessages2
2834
- },
2835
- nowMs
2836
- )
2837
- );
2838
- return {
2839
- status: "recorded",
2840
- pendingCount: pendingMessages2.length,
2841
- deadLetteredMessages
2842
- };
2843
- });
2844
- }
2845
- async function deadLetterAttempt(args) {
2846
- const nowMs = args.nowMs ?? now();
2847
- return await withConversationMutation(args, async (state, lock) => {
2848
- const current = await readConversation(state, args.conversationId);
2849
- if (!current || current.execution.lease?.token !== args.leaseToken) {
2850
- return "lost_lease";
2851
- }
2852
- const runnable = pendingMessages(current).length > 0;
2853
- await writeConversation(
2854
- state,
2855
- lock,
2856
- withExecutionUpdate(
2857
- current,
2858
- {
2859
- ...current.execution,
2860
- lease: void 0,
2861
- status: runnable ? "pending" : "failed",
2862
- runId: runnable ? current.execution.runId : void 0
2863
- },
2864
- nowMs
2865
- )
2866
- );
2867
- return runnable ? "pending" : "failed";
2868
- });
2869
- }
2870
- async function clearExpiredConversationLease(args) {
2871
- const nowMs = args.nowMs ?? now();
2872
- return await withConversationMutation(args, async (state, lock) => {
2873
- const current = await readConversation(state, args.conversationId);
2874
- if (!current?.execution.lease || current.execution.lease.expiresAtMs > nowMs) {
2875
- return false;
2876
- }
2877
- await writeConversation(
2878
- state,
2879
- lock,
2880
- withExecutionUpdate(
2881
- current,
2882
- {
2883
- ...current.execution,
2884
- lease: void 0,
2885
- status: "awaiting_resume"
2886
- },
2887
- nowMs
2888
- )
2889
- );
2890
- return true;
2891
- });
2892
- }
2893
- async function removeActiveConversation(args) {
2894
- const state = await getConnectedState(args.state);
2895
- await removeIndexEntry({
2896
- state,
2897
- indexKey: CONVERSATION_ACTIVE_INDEX_KEY,
2898
- conversationId: args.conversationId
2899
- });
2900
- }
2901
- async function listActiveConversationIds(args = {}) {
2902
- const state = await getConnectedState(args.state);
2903
- const index = await getConversationIndexStore(state);
2904
- const entries = await index.list({
2905
- indexKey: CONVERSATION_ACTIVE_INDEX_KEY,
2906
- limit: args.limit,
2907
- order: "asc",
2908
- scoreMax: args.staleBeforeMs
2909
- });
2910
- return entries.map((entry) => entry.conversationId);
2911
- }
2912
-
2913
- // src/chat/task-execution/store.ts
2914
- function metadataStore(options) {
2915
- return options.conversationStore ?? getConversationStore();
2916
- }
2917
- function duplicateInboundNudgeIdempotencyKey(message, nowMs) {
2918
- return `duplicate:${message.conversationId}:${message.inboundMessageId}:${nowMs}`;
2919
- }
2920
- function hasRecentEnqueueMarker(conversation, nowMs) {
2921
- const lastEnqueuedAtMs = conversation.execution.lastEnqueuedAtMs;
2922
- return typeof lastEnqueuedAtMs === "number" && lastEnqueuedAtMs + CONVERSATION_WORK_STALE_ENQUEUE_MS > nowMs;
2923
- }
2924
- function now2() {
2925
- return Date.now();
2926
- }
2927
- async function recordExecutionMetadata(args) {
2928
- const conversation = await getConversation({
2929
- conversationId: args.conversationId,
2930
- state: args.state
2931
- });
2932
- if (!conversation) {
2933
- return;
2934
- }
2935
- await metadataStore(args).recordExecution({
2936
- channelName: conversation.channelName,
2937
- conversationId: conversation.conversationId,
2938
- createdAtMs: conversation.createdAtMs,
2939
- destination: conversation.destination,
2940
- execution: {
2941
- lastCheckpointAtMs: conversation.execution.lastCheckpointAtMs,
2942
- lastEnqueuedAtMs: conversation.execution.lastEnqueuedAtMs,
2943
- runId: conversation.execution.runId,
2944
- status: conversation.execution.status,
2945
- updatedAtMs: conversation.execution.updatedAtMs
2946
- },
2947
- lastActivityAtMs: conversation.lastActivityAtMs,
2948
- metrics: null,
2949
- actor: conversation.actor,
2950
- source: conversation.source,
2951
- title: conversation.title,
2952
- updatedAtMs: conversation.updatedAtMs
2953
- });
2954
- }
2955
- async function getConversationWorkState2(args) {
2956
- return await getConversationWorkState(args);
2957
- }
2958
- function countPendingConversationMessages(conversation) {
2959
- return conversation.execution.pendingMessages.length;
2960
- }
2961
- function hasRunnableConversationWork(conversation) {
2962
- return conversation.execution.status !== "idle" || countPendingConversationMessages(conversation) > 0;
2963
- }
2964
- async function ensureConversationWake(args) {
2965
- const nowMs = args.nowMs ?? now2();
2966
- const conversation = await getConversation({
2967
- conversationId: args.conversationId,
2968
- state: args.state
2969
- });
2970
- if (!conversation || !hasRunnableConversationWork(conversation)) {
2971
- return { status: "no_work" };
2972
- }
2973
- if (!conversation.destination) {
2974
- return { status: "no_work" };
2975
- }
2976
- if (args.replaceExistingWake !== true && conversation.execution.lease && conversation.execution.lease.expiresAtMs > nowMs) {
2977
- return { status: "lease_active" };
2978
- }
2979
- if (args.replaceExistingWake !== true && hasRecentEnqueueMarker(conversation, nowMs)) {
2980
- return { status: "already_enqueued" };
2981
- }
2982
- const queueResult = await args.queue.send(
2983
- {
2984
- conversationId: args.conversationId
2985
- },
2986
- {
2987
- delayMs: args.delayMs,
2988
- idempotencyKey: args.idempotencyKey
2989
- }
2990
- );
2991
- await markConversationWorkEnqueued2({
2992
- conversationId: args.conversationId,
2993
- conversationStore: args.conversationStore,
2994
- nowMs,
2995
- state: args.state
2996
- });
2997
- return { status: "enqueued", queueMessageId: queueResult?.messageId };
2998
- }
2999
- async function appendAndEnqueueInboundMessage(args) {
3000
- const nowMs = args.nowMs ?? now2();
3001
- const appendResult = await appendInboundMessage({
3002
- message: args.message,
3003
- nowMs,
3004
- state: args.state
3005
- });
3006
- let idempotencyKey = args.message.inboundMessageId;
3007
- if (appendResult.status === "duplicate") {
3008
- const conversation = await getConversation({
3009
- conversationId: args.message.conversationId,
3010
- state: args.state
3011
- });
3012
- if (!conversation) {
3013
- return appendResult;
3014
- }
3015
- if (hasRecentEnqueueMarker(conversation, nowMs)) {
3016
- await recordExecutionMetadata({
3017
- conversationId: args.message.conversationId,
3018
- conversationStore: args.conversationStore,
3019
- state: args.state
3020
- });
3021
- return appendResult;
3022
- }
3023
- const duplicateStillPending = conversation.execution.pendingMessages.some(
3024
- (message) => message.inboundMessageId === args.message.inboundMessageId
3025
- );
3026
- if (!duplicateStillPending) {
3027
- await recordExecutionMetadata({
3028
- conversationId: args.message.conversationId,
3029
- conversationStore: args.conversationStore,
3030
- state: args.state
3031
- });
3032
- return appendResult;
3033
- }
3034
- idempotencyKey = duplicateInboundNudgeIdempotencyKey(args.message, nowMs);
3035
- }
3036
- const wake = await ensureConversationWake({
3037
- conversationId: args.message.conversationId,
3038
- conversationStore: args.conversationStore,
3039
- idempotencyKey,
3040
- nowMs,
3041
- queue: args.queue,
3042
- state: args.state
3043
- });
3044
- if (wake.status !== "enqueued") {
3045
- await recordExecutionMetadata({
3046
- conversationId: args.message.conversationId,
3047
- conversationStore: args.conversationStore,
3048
- state: args.state
3049
- });
3050
- }
3051
- return {
3052
- ...appendResult,
3053
- ...wake.status === "enqueued" ? { queueMessageId: wake.queueMessageId } : {}
3054
- };
3055
- }
3056
- async function clearConsumedConversationWake2(args) {
3057
- const result = await clearConsumedConversationWake(args);
3058
- if (result) {
3059
- await recordExecutionMetadata(args);
3060
- }
3061
- return result;
3062
- }
3063
- async function requestConversationWork2(args) {
3064
- const result = await requestConversationWork(args);
3065
- await recordExecutionMetadata({
3066
- conversationId: args.conversationId,
3067
- conversationStore: args.conversationStore,
3068
- state: args.state
3069
- });
3070
- return result;
3071
- }
3072
- async function markConversationWorkEnqueued2(args) {
3073
- await markConversationWorkEnqueued(args);
3074
- await recordExecutionMetadata(args);
3075
- }
3076
- async function startConversationWork2(args) {
3077
- const result = await startConversationWork(args);
3078
- await recordExecutionMetadata(args);
3079
- return result;
3080
- }
3081
- async function checkInConversationWork2(args) {
3082
- const result = await checkInConversationWork(args);
3083
- if (result) {
3084
- await recordExecutionMetadata(args);
3085
- }
3086
- return result;
3087
- }
3088
- async function drainConversationMailbox2(args) {
3089
- const result = await drainConversationMailbox(args);
3090
- if (result.changed) {
3091
- await recordExecutionMetadata(args);
3092
- }
3093
- return result.messages;
3094
- }
3095
- async function ackMessages2(args) {
3096
- const result = await ackMessages(args);
3097
- await recordExecutionMetadata(args);
3098
- return result;
3099
- }
3100
- async function requestConversationContinuation2(args) {
3101
- const result = await requestConversationContinuation(args);
3102
- await recordExecutionMetadata(args);
3103
- return result;
3104
- }
3105
- async function beginConversationResume2(args) {
3106
- const result = await beginConversationResume(args);
3107
- if (result) {
3108
- await recordExecutionMetadata(args);
3109
- }
3110
- return result;
3111
- }
3112
- async function releaseConversationWork2(args) {
3113
- const result = await releaseConversationWork(args);
3114
- await recordExecutionMetadata(args);
3115
- return result;
3116
- }
3117
- async function completeConversationWork2(args) {
3118
- const result = await completeConversationWork(args);
3119
- await recordExecutionMetadata(args);
3120
- return result;
3121
- }
3122
- async function recordAttemptFailure2(args) {
3123
- const result = await recordAttemptFailure(args);
3124
- if (result.status === "recorded") {
3125
- await recordExecutionMetadata(args);
3126
- }
3127
- return result;
3128
- }
3129
- async function deadLetterAttempt2(args) {
3130
- const result = await deadLetterAttempt(args);
3131
- await recordExecutionMetadata(args);
3132
- return result;
3133
- }
3134
- async function clearExpiredConversationLease2(args) {
3135
- const result = await clearExpiredConversationLease(args);
3136
- await recordExecutionMetadata(args);
3137
- return result;
3138
- }
3139
- async function removeActiveConversation2(args) {
3140
- return await removeActiveConversation(args);
3141
- }
3142
- async function listActiveConversationIds2(args = {}) {
3143
- return await listActiveConversationIds(args);
3144
- }
3145
-
3146
1747
  // src/chat/services/agent-continue.ts
3147
1748
  async function getAwaitingAgentContinueRequest(args) {
3148
1749
  const sessionRecord = await getAgentTurnSessionRecord(
@@ -3152,19 +1753,31 @@ async function getAwaitingAgentContinueRequest(args) {
3152
1753
  if (!sessionRecord || sessionRecord.state !== "awaiting_resume" || sessionRecord.resumeReason !== "timeout" && sessionRecord.resumeReason !== "yield" && sessionRecord.resumeReason !== "retry" || sessionRecord.resumeReason === "timeout" && sessionRecord.sliceId < 2) {
3153
1754
  return void 0;
3154
1755
  }
3155
- if (!sessionRecord.destination) {
1756
+ let routing;
1757
+ try {
1758
+ routing = await resolveTurnSessionRouting({
1759
+ conversationId: args.conversationId,
1760
+ conversationStore: args.conversationStore
1761
+ });
1762
+ } catch (error) {
1763
+ await failAgentTurnSessionRecord({
1764
+ conversationId: args.conversationId,
1765
+ expectedVersion: sessionRecord.version,
1766
+ sessionId: args.sessionId,
1767
+ errorMessage: error instanceof Error ? error.message : String(error)
1768
+ });
3156
1769
  return void 0;
3157
1770
  }
3158
1771
  return {
3159
1772
  conversationId: args.conversationId,
3160
- destination: sessionRecord.destination,
1773
+ destination: routing.destination,
3161
1774
  sessionId: args.sessionId,
3162
1775
  expectedVersion: sessionRecord.version
3163
1776
  };
3164
1777
  }
3165
1778
  async function scheduleAgentContinue(request, options = {}) {
3166
1779
  const nowMs = options.nowMs ?? Date.now();
3167
- await requestConversationWork2({
1780
+ await requestConversationWork({
3168
1781
  conversationId: request.conversationId,
3169
1782
  destination: request.destination,
3170
1783
  nowMs,
@@ -3444,12 +2057,17 @@ async function resumeAuthorizedMcpTurn(args) {
3444
2057
  });
3445
2058
  return false;
3446
2059
  }
3447
- if (!lockedSessionRecord.source) {
2060
+ let routing;
2061
+ try {
2062
+ routing = await resolveTurnSessionRouting({
2063
+ conversationId: authSession.conversationId
2064
+ });
2065
+ } catch (error) {
3448
2066
  await failAgentTurnSessionRecord({
3449
2067
  conversationId: authSession.conversationId,
3450
2068
  expectedVersion: lockedSessionRecord.version,
3451
2069
  sessionId: lockedSessionId,
3452
- errorMessage: "Stored Slack source missing for MCP OAuth resume"
2070
+ errorMessage: error instanceof Error ? error.message : String(error)
3453
2071
  });
3454
2072
  return false;
3455
2073
  }
@@ -3483,7 +2101,7 @@ async function resumeAuthorizedMcpTurn(args) {
3483
2101
  },
3484
2102
  actor,
3485
2103
  destination,
3486
- source: lockedSessionRecord.source,
2104
+ source: routing.source,
3487
2105
  toolChannelId: authSession.toolChannelId ?? lockedArtifacts.assistantContextChannelId ?? authSession.channelId
3488
2106
  },
3489
2107
  policy: {
@@ -4073,12 +2691,17 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4073
2691
  });
4074
2692
  return false;
4075
2693
  }
4076
- if (!lockedSessionRecord.source) {
2694
+ let routing;
2695
+ try {
2696
+ routing = await resolveTurnSessionRouting({
2697
+ conversationId: stored.resumeConversationId
2698
+ });
2699
+ } catch (error) {
4077
2700
  await failAgentTurnSessionRecord({
4078
2701
  conversationId: stored.resumeConversationId,
4079
2702
  expectedVersion: lockedSessionRecord.version,
4080
2703
  sessionId: lockedSessionId,
4081
- errorMessage: "Stored Slack source missing for OAuth resume"
2704
+ errorMessage: error instanceof Error ? error.message : String(error)
4082
2705
  });
4083
2706
  return false;
4084
2707
  }
@@ -4117,7 +2740,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
4117
2740
  },
4118
2741
  actor,
4119
2742
  destination,
4120
- source: lockedSessionRecord.source,
2743
+ source: routing.source,
4121
2744
  toolChannelId: lockedArtifacts.assistantContextChannelId ?? stored.channelId
4122
2745
  },
4123
2746
  policy: {
@@ -4436,12 +3059,12 @@ import { createHmac, createSecretKey, timingSafeEqual } from "crypto";
4436
3059
  import {
4437
3060
  pluginStoredTokensSchema
4438
3061
  } from "@sentry/junior-plugin-api";
4439
- import { z as z2 } from "zod";
3062
+ import { z } from "zod";
4440
3063
  var LOCAL_CREDENTIAL_SYNC_CONTEXT = "junior.local-credential-sync.v1";
4441
3064
  var LOCAL_CREDENTIAL_SYNC_MAX_AGE_MS = 6e4;
4442
- var localCredentialSyncSchema = z2.object({
4443
- createdAtMs: z2.number().finite(),
4444
- provider: z2.string().regex(/^[a-z][a-z0-9-]*$/),
3065
+ var localCredentialSyncSchema = z.object({
3066
+ createdAtMs: z.number().finite(),
3067
+ provider: z.string().regex(/^[a-z][a-z0-9-]*$/),
4445
3068
  tokens: pluginStoredTokensSchema
4446
3069
  }).strict();
4447
3070
  function syncSecret() {
@@ -4515,29 +3138,6 @@ async function receiveLocalOAuthCredential(request) {
4515
3138
  }
4516
3139
 
4517
3140
  export {
4518
- isInvalidConversationRecordError,
4519
- CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
4520
- CONVERSATION_WORK_STALE_ENQUEUE_MS,
4521
- isFinalAttempt,
4522
- getConversationWorkState2 as getConversationWorkState,
4523
- countPendingConversationMessages,
4524
- hasRunnableConversationWork,
4525
- ensureConversationWake,
4526
- appendAndEnqueueInboundMessage,
4527
- clearConsumedConversationWake2 as clearConsumedConversationWake,
4528
- startConversationWork2 as startConversationWork,
4529
- checkInConversationWork2 as checkInConversationWork,
4530
- drainConversationMailbox2 as drainConversationMailbox,
4531
- ackMessages2 as ackMessages,
4532
- requestConversationContinuation2 as requestConversationContinuation,
4533
- beginConversationResume2 as beginConversationResume,
4534
- releaseConversationWork2 as releaseConversationWork,
4535
- completeConversationWork2 as completeConversationWork,
4536
- recordAttemptFailure2 as recordAttemptFailure,
4537
- deadLetterAttempt2 as deadLetterAttempt,
4538
- clearExpiredConversationLease2 as clearExpiredConversationLease,
4539
- removeActiveConversation2 as removeActiveConversation,
4540
- listActiveConversationIds2 as listActiveConversationIds,
4541
3141
  createSlackAdapterAssistantStatusSession,
4542
3142
  splitSlackReplyText,
4543
3143
  buildSlackOutputMessage,