@sentry/junior 0.106.0 → 0.107.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 (132) hide show
  1. package/dist/{agent-hooks-KR5BCWOK.js → agent-hooks-ICPIJAFY.js} +9 -7
  2. package/dist/api/conversations/detail.d.ts +1 -1
  3. package/dist/api/conversations/events.d.ts +14 -0
  4. package/dist/api/conversations/schema.d.ts +196 -463
  5. package/dist/api/schema.d.ts +2 -7
  6. package/dist/api/schema.js +10 -8
  7. package/dist/api.js +377 -810
  8. package/dist/app.js +3586 -3614
  9. package/dist/{catalog-runtime-5CVM2DOF.js → catalog-runtime-FOFNPR3P.js} +3 -2
  10. package/dist/chat/agent/prompt.d.ts +1 -1
  11. package/dist/chat/agent/request.d.ts +28 -29
  12. package/dist/chat/agent/resume.d.ts +7 -7
  13. package/dist/chat/agent/session.d.ts +5 -6
  14. package/dist/chat/agent/tools.d.ts +3 -3
  15. package/dist/chat/agent-dispatch/runner.d.ts +2 -0
  16. package/dist/chat/config.d.ts +2 -2
  17. package/dist/chat/conversations/history.d.ts +582 -167
  18. package/dist/chat/conversations/message-projection.d.ts +6 -0
  19. package/dist/chat/conversations/message-summaries.d.ts +9 -0
  20. package/dist/chat/conversations/messages.d.ts +13 -27
  21. package/dist/chat/conversations/projection.d.ts +30 -53
  22. package/dist/chat/conversations/provenance.d.ts +42 -0
  23. package/dist/chat/conversations/search.d.ts +2 -2
  24. package/dist/chat/conversations/sql/conversation-row.d.ts +1 -1
  25. package/dist/chat/conversations/sql/event-lock.d.ts +3 -0
  26. package/dist/chat/conversations/sql/history.d.ts +3 -3
  27. package/dist/chat/conversations/sql/privacy.d.ts +27 -0
  28. package/dist/chat/conversations/sql/purge.d.ts +2 -10
  29. package/dist/chat/conversations/sql/store.d.ts +0 -5
  30. package/dist/chat/conversations/store.d.ts +8 -13
  31. package/dist/chat/conversations/turn-lifecycle.d.ts +41 -0
  32. package/dist/chat/db.d.ts +4 -10
  33. package/dist/chat/model-profile.d.ts +10 -0
  34. package/dist/chat/oauth-flow.d.ts +0 -5
  35. package/dist/chat/pi/conversation-events.d.ts +33 -0
  36. package/dist/chat/pi/sql-model-usage.d.ts +10 -0
  37. package/dist/chat/plugins/agent-hooks.d.ts +4 -2
  38. package/dist/chat/resource-events/ingest.d.ts +0 -13
  39. package/dist/chat/runtime/delivered-turn-state.d.ts +1 -1
  40. package/dist/chat/runtime/generated-artifacts.d.ts +1 -1
  41. package/dist/chat/runtime/reply-executor.d.ts +2 -0
  42. package/dist/chat/runtime/slack-resume.d.ts +23 -28
  43. package/dist/chat/runtime/slack-runtime.d.ts +2 -0
  44. package/dist/chat/runtime/turn.d.ts +14 -1
  45. package/dist/chat/services/context-compaction-marker.d.ts +0 -1
  46. package/dist/chat/services/context-compaction.d.ts +1 -0
  47. package/dist/chat/services/conversation-memory.d.ts +9 -0
  48. package/dist/chat/services/plugin-auth-orchestration.d.ts +1 -4
  49. package/dist/chat/services/subscribed-decision.d.ts +1 -1
  50. package/dist/chat/services/turn-failure-response.d.ts +10 -3
  51. package/dist/chat/services/turn-result.d.ts +7 -12
  52. package/dist/chat/services/{turn-reasoning-level.d.ts → turn-router.d.ts} +12 -8
  53. package/dist/chat/services/turn-session-record.d.ts +15 -16
  54. package/dist/chat/slack/adapter.d.ts +2 -2
  55. package/dist/chat/slack/errors.d.ts +2 -0
  56. package/dist/chat/slack/outbound.d.ts +0 -1
  57. package/dist/chat/slack/reply.d.ts +2 -8
  58. package/dist/chat/slack/tools/channel-capabilities.d.ts +2 -2
  59. package/dist/chat/slack/tools/{send-message.d.ts → send-files.d.ts} +27 -19
  60. package/dist/chat/state/conversation.d.ts +4 -4
  61. package/dist/chat/state/turn-id.d.ts +2 -0
  62. package/dist/chat/state/turn-session-keys.d.ts +6 -0
  63. package/dist/chat/state/turn-session.d.ts +11 -9
  64. package/dist/chat/task-execution/state.d.ts +6 -1
  65. package/dist/chat/task-execution/store.d.ts +1 -1
  66. package/dist/chat/tool-support/pi-tool-adapter.d.ts +1 -1
  67. package/dist/chat/tool-support/tool-execution-report.d.ts +1 -0
  68. package/dist/chat/tools/handoff/tool.d.ts +2 -2
  69. package/dist/chat/tools/sandbox/file-uploads.d.ts +28 -6
  70. package/dist/chat/tools/types.d.ts +6 -9
  71. package/dist/chat/tools/web/image-generate.d.ts +4 -6
  72. package/dist/{chunk-DDRQ4U7I.js → chunk-4YF7Z6IA.js} +390 -270
  73. package/dist/{chunk-AZ5OMSN5.js → chunk-AUUOHQAT.js} +2 -2
  74. package/dist/chunk-B2Z2H66D.js +250 -0
  75. package/dist/{chunk-4W4O4DCV.js → chunk-CQ7KSO2B.js} +75 -45
  76. package/dist/{chunk-MJSJAHBW.js → chunk-DY7TRYB5.js} +1 -1
  77. package/dist/{chunk-GPPUTY5M.js → chunk-EDLNHZH3.js} +861 -891
  78. package/dist/{chunk-R5BFYK2O.js → chunk-IGHMVDWI.js} +134 -18
  79. package/dist/chunk-MU6HHZEN.js +99 -0
  80. package/dist/{chunk-XTKJPSMF.js → chunk-NVOTGWYX.js} +458 -684
  81. package/dist/{chunk-AEWZ7F65.js → chunk-O24R4DCK.js} +2 -179
  82. package/dist/{chunk-CCFROYAV.js → chunk-PUAMO4PI.js} +115 -125
  83. package/dist/{chunk-ZMRLBBD5.js → chunk-RMVOAJRL.js} +30 -13
  84. package/dist/{chunk-3NYUCBLE.js → chunk-SPUAJVVH.js} +6 -4
  85. package/dist/{chunk-4UYIRWDW.js → chunk-SS67LUOK.js} +41 -290
  86. package/dist/{chunk-FXFQNHRU.js → chunk-VFUK3X5B.js} +4 -2
  87. package/dist/{chunk-3MPPVPGZ.js → chunk-VH6KWKG2.js} +2 -2
  88. package/dist/chunk-VIXFG2VC.js +182 -0
  89. package/dist/{chunk-BKM4UXUD.js → chunk-YFQ7CQDE.js} +669 -18
  90. package/dist/{chunk-77LHNQK4.js → chunk-YIPD3L6L.js} +4 -2
  91. package/dist/{chunk-3OUSJPR7.js → chunk-YNP2ATQX.js} +6 -4
  92. package/dist/{chunk-WR7H7VLJ.js → chunk-YT72TOEK.js} +2 -2
  93. package/dist/cli/chat.js +21 -20
  94. package/dist/cli/check.js +4 -3
  95. package/dist/cli/plugins.js +11 -9
  96. package/dist/cli/snapshot-warmup.js +7 -5
  97. package/dist/cli/upgrade.js +2046 -105
  98. package/dist/db/schema/{agent-steps.d.ts → conversation-events.d.ts} +37 -21
  99. package/dist/db/schema.d.ts +28 -159
  100. package/dist/{db-S33LFWG2.js → db-DIGO4TGW.js} +6 -8
  101. package/dist/{runner-HA5XAL6K.js → runner-ACR2HAIC.js} +209 -101
  102. package/dist/{skills-722AXRV5.js → skills-ITNHBARB.js} +4 -3
  103. package/dist/{validation-EUI2UFRM.js → validation-AGQ46ZGV.js} +4 -3
  104. package/migrations/0005_conversation_events.sql +122 -0
  105. package/migrations/README.md +23 -10
  106. package/migrations/meta/0005_snapshot.json +948 -0
  107. package/migrations/meta/_journal.json +7 -0
  108. package/package.json +5 -5
  109. package/dist/api/conversations/activity.d.ts +0 -40
  110. package/dist/api/conversations/detail-projection.d.ts +0 -11
  111. package/dist/api/conversations/detail.query.d.ts +0 -3
  112. package/dist/api/conversations/subagent.d.ts +0 -10
  113. package/dist/api/conversations/transcript.d.ts +0 -28
  114. package/dist/chat/conversations/legacy-advisor-session.d.ts +0 -7
  115. package/dist/chat/conversations/legacy-import.d.ts +0 -38
  116. package/dist/chat/conversations/sql/legacy-history-import.d.ts +0 -55
  117. package/dist/chat/conversations/sql/messages.d.ts +0 -4
  118. package/dist/chat/conversations/visible-compactions.d.ts +0 -11
  119. package/dist/chat/conversations/visible-messages.d.ts +0 -47
  120. package/dist/chat/services/reply-delivery-plan.d.ts +0 -5
  121. package/dist/chat/state/session-log.d.ts +0 -384
  122. package/dist/chunk-P4P7O5WG.js +0 -1072
  123. package/dist/chunk-XIMUQ4IU.js +0 -147
  124. package/dist/db/schema/conversation-messages.d.ts +0 -153
  125. package/dist/handlers/github-webhook/check-suite.d.ts +0 -3
  126. package/dist/handlers/github-webhook/issue-comment.d.ts +0 -3
  127. package/dist/handlers/github-webhook/pull-request-review-comment.d.ts +0 -3
  128. package/dist/handlers/github-webhook/pull-request-review.d.ts +0 -3
  129. package/dist/handlers/github-webhook/pull-request.d.ts +0 -3
  130. package/dist/handlers/github-webhook/resource.d.ts +0 -10
  131. package/dist/handlers/github-webhook.d.ts +0 -15
  132. package/dist/legacy-import-TMJISRKO.js +0 -18
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  getStateAdapter
3
- } from "./chunk-4UYIRWDW.js";
3
+ } from "./chunk-B2Z2H66D.js";
4
4
  import {
5
5
  logException,
6
6
  logInfo,
7
7
  logWarn
8
- } from "./chunk-AEWZ7F65.js";
8
+ } from "./chunk-O24R4DCK.js";
9
9
 
10
10
  // src/chat/plugins/logging.ts
11
11
  function createPluginLogger(plugin) {
@@ -0,0 +1,250 @@
1
+ import {
2
+ getChatConfig
3
+ } from "./chunk-SS67LUOK.js";
4
+
5
+ // src/chat/state/adapter.ts
6
+ import { createMemoryState } from "@chat-adapter/state-memory";
7
+ import { createRedisState } from "@chat-adapter/state-redis";
8
+
9
+ // src/chat/state/locks.ts
10
+ var ACTIVE_LOCK_TTL_MS = 9e4;
11
+ async function acquireActiveLock(state, threadId) {
12
+ return await state.acquireLock(threadId, ACTIVE_LOCK_TTL_MS);
13
+ }
14
+
15
+ // src/chat/state/adapter.ts
16
+ var ACTIVE_LOCK_HEARTBEAT_MS = 3e4;
17
+ var stateAdapter;
18
+ var redisStateAdapter;
19
+ function createPrefixedStateAdapter(base, prefix) {
20
+ const prefixed = (value) => `${prefix}:${value}`;
21
+ const unprefixed = (value) => value.startsWith(`${prefix}:`) ? value.slice(prefix.length + 1) : value;
22
+ const prefixLock = (lock) => ({
23
+ ...lock,
24
+ threadId: prefixed(lock.threadId)
25
+ });
26
+ const unprefixLock = (lock) => ({
27
+ ...lock,
28
+ threadId: unprefixed(lock.threadId)
29
+ });
30
+ return {
31
+ appendToList: (key, value, options) => base.appendToList(prefixed(key), value, options),
32
+ connect: () => base.connect(),
33
+ disconnect: () => base.disconnect(),
34
+ subscribe: (threadId) => base.subscribe(prefixed(threadId)),
35
+ unsubscribe: (threadId) => base.unsubscribe(prefixed(threadId)),
36
+ isSubscribed: (threadId) => base.isSubscribed(prefixed(threadId)),
37
+ acquireLock: async (threadId, ttlMs) => {
38
+ const lock = await base.acquireLock(prefixed(threadId), ttlMs);
39
+ return lock ? unprefixLock(lock) : null;
40
+ },
41
+ releaseLock: (lock) => base.releaseLock(prefixLock(lock)),
42
+ extendLock: async (lock, ttlMs) => {
43
+ const prefixedLock = prefixLock(lock);
44
+ const extended = await base.extendLock(prefixedLock, ttlMs);
45
+ if (extended) {
46
+ lock.expiresAt = prefixedLock.expiresAt;
47
+ }
48
+ return extended;
49
+ },
50
+ forceReleaseLock: (threadId) => base.forceReleaseLock(prefixed(threadId)),
51
+ enqueue: (threadId, entry, maxSize) => base.enqueue(prefixed(threadId), entry, maxSize),
52
+ dequeue: (threadId) => base.dequeue(prefixed(threadId)),
53
+ queueDepth: (threadId) => base.queueDepth(prefixed(threadId)),
54
+ get: (key) => base.get(prefixed(key)),
55
+ getList: (key) => base.getList(prefixed(key)),
56
+ set: (key, value, ttlMs) => base.set(prefixed(key), value, ttlMs),
57
+ setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(prefixed(key), value, ttlMs),
58
+ delete: (key) => base.delete(prefixed(key))
59
+ };
60
+ }
61
+ function createQueuedStateAdapter(base, options) {
62
+ const heartbeats = /* @__PURE__ */ new Map();
63
+ const shouldHeartbeatLock = (ttlMs) => ttlMs === ACTIVE_LOCK_TTL_MS;
64
+ const heartbeatKey = (lock) => `${lock.threadId}:${lock.token}`;
65
+ const stopHeartbeatByKey = (key) => {
66
+ const heartbeat = heartbeats.get(key);
67
+ if (!heartbeat) {
68
+ return;
69
+ }
70
+ clearInterval(heartbeat.timer);
71
+ heartbeats.delete(key);
72
+ };
73
+ const stopHeartbeat = (lock) => {
74
+ stopHeartbeatByKey(heartbeatKey(lock));
75
+ };
76
+ const stopHeartbeatsForThread = (threadId) => {
77
+ for (const [key, heartbeat] of heartbeats) {
78
+ if (heartbeat.lock.threadId === threadId) {
79
+ stopHeartbeatByKey(key);
80
+ }
81
+ }
82
+ };
83
+ const stopAllHeartbeats = () => {
84
+ for (const key of heartbeats.keys()) {
85
+ stopHeartbeatByKey(key);
86
+ }
87
+ };
88
+ const runHeartbeat = async (key) => {
89
+ const heartbeat = heartbeats.get(key);
90
+ if (!heartbeat || heartbeat.inFlight) {
91
+ return;
92
+ }
93
+ heartbeat.inFlight = true;
94
+ try {
95
+ if (Date.now() - heartbeat.startedAtMs >= options.activeLockMaxAgeMs) {
96
+ stopHeartbeatByKey(key);
97
+ return;
98
+ }
99
+ const extended = await base.extendLock(heartbeat.lock, heartbeat.ttlMs);
100
+ if (!extended) {
101
+ stopHeartbeatByKey(key);
102
+ return;
103
+ }
104
+ heartbeat.lock.expiresAt = Date.now() + heartbeat.ttlMs;
105
+ } catch {
106
+ } finally {
107
+ const current = heartbeats.get(key);
108
+ if (current === heartbeat) {
109
+ current.inFlight = false;
110
+ }
111
+ }
112
+ };
113
+ const startOrUpdateHeartbeat = (lock, ttlMs) => {
114
+ const key = heartbeatKey(lock);
115
+ const existing = heartbeats.get(key);
116
+ if (existing) {
117
+ existing.ttlMs = ttlMs;
118
+ return;
119
+ }
120
+ const timer = setInterval(() => {
121
+ void runHeartbeat(key);
122
+ }, ACTIVE_LOCK_HEARTBEAT_MS);
123
+ timer.unref?.();
124
+ heartbeats.set(key, {
125
+ inFlight: false,
126
+ lock,
127
+ startedAtMs: Date.now(),
128
+ timer,
129
+ ttlMs
130
+ });
131
+ };
132
+ const acquireLock = async (threadId, ttlMs) => {
133
+ const lock = await base.acquireLock(threadId, ttlMs);
134
+ if (lock && shouldHeartbeatLock(ttlMs)) {
135
+ startOrUpdateHeartbeat(lock, ttlMs);
136
+ }
137
+ return lock;
138
+ };
139
+ return {
140
+ appendToList: (key, value, options2) => base.appendToList(key, value, options2),
141
+ connect: () => base.connect(),
142
+ disconnect: async () => {
143
+ stopAllHeartbeats();
144
+ await base.disconnect();
145
+ },
146
+ subscribe: (threadId) => base.subscribe(threadId),
147
+ unsubscribe: (threadId) => base.unsubscribe(threadId),
148
+ isSubscribed: (threadId) => base.isSubscribed(threadId),
149
+ acquireLock,
150
+ releaseLock: async (lock) => {
151
+ stopHeartbeat(lock);
152
+ await base.releaseLock(lock);
153
+ },
154
+ extendLock: async (lock, ttlMs) => {
155
+ const extended = await base.extendLock(lock, ttlMs);
156
+ if (extended) {
157
+ lock.expiresAt = Date.now() + ttlMs;
158
+ if (shouldHeartbeatLock(ttlMs)) {
159
+ startOrUpdateHeartbeat(lock, ttlMs);
160
+ } else {
161
+ stopHeartbeat(lock);
162
+ }
163
+ } else {
164
+ stopHeartbeat(lock);
165
+ }
166
+ return extended;
167
+ },
168
+ forceReleaseLock: async (threadId) => {
169
+ stopHeartbeatsForThread(threadId);
170
+ await base.forceReleaseLock(threadId);
171
+ },
172
+ enqueue: (threadId, entry, maxSize) => base.enqueue(threadId, entry, maxSize),
173
+ dequeue: (threadId) => base.dequeue(threadId),
174
+ queueDepth: (threadId) => base.queueDepth(threadId),
175
+ get: (key) => base.get(key),
176
+ getList: (key) => base.getList(key),
177
+ set: (key, value, ttlMs) => base.set(key, value, ttlMs),
178
+ setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(key, value, ttlMs),
179
+ delete: (key) => base.delete(key)
180
+ };
181
+ }
182
+ function withOptionalPrefix(base, prefix) {
183
+ return prefix ? createPrefixedStateAdapter(base, prefix) : base;
184
+ }
185
+ function createStateAdapter() {
186
+ const config = getChatConfig();
187
+ const activeLockMaxAgeMs = config.bot.turnTimeoutMs + ACTIVE_LOCK_TTL_MS;
188
+ if (config.state.adapter === "memory") {
189
+ redisStateAdapter = void 0;
190
+ return createQueuedStateAdapter(
191
+ withOptionalPrefix(createMemoryState(), config.state.keyPrefix),
192
+ { activeLockMaxAgeMs }
193
+ );
194
+ }
195
+ if (!config.state.redisUrl) {
196
+ throw new Error("REDIS_URL is required for durable Slack thread state");
197
+ }
198
+ const redisState = createRedisState({
199
+ url: config.state.redisUrl
200
+ });
201
+ redisStateAdapter = redisState;
202
+ return createQueuedStateAdapter(
203
+ withOptionalPrefix(redisState, config.state.keyPrefix),
204
+ { activeLockMaxAgeMs }
205
+ );
206
+ }
207
+ function getOptionalRedisStateAdapter() {
208
+ getStateAdapter();
209
+ return redisStateAdapter;
210
+ }
211
+ async function getConnectedStateContext() {
212
+ const adapter = getStateAdapter();
213
+ await adapter.connect();
214
+ return {
215
+ redisStateAdapter: getOptionalRedisStateAdapter(),
216
+ stateAdapter: adapter
217
+ };
218
+ }
219
+ async function getDefaultRedisStateAdapterFor(adapter) {
220
+ if (adapter !== stateAdapter) {
221
+ return void 0;
222
+ }
223
+ const context = await getConnectedStateContext();
224
+ return context.stateAdapter === adapter ? context.redisStateAdapter : void 0;
225
+ }
226
+ function getStateAdapter() {
227
+ if (!stateAdapter) {
228
+ stateAdapter = createStateAdapter();
229
+ }
230
+ return stateAdapter;
231
+ }
232
+ async function disconnectStateAdapter() {
233
+ if (!stateAdapter) {
234
+ return;
235
+ }
236
+ try {
237
+ await stateAdapter.disconnect();
238
+ } finally {
239
+ stateAdapter = void 0;
240
+ redisStateAdapter = void 0;
241
+ }
242
+ }
243
+
244
+ export {
245
+ acquireActiveLock,
246
+ getConnectedStateContext,
247
+ getDefaultRedisStateAdapterFor,
248
+ getStateAdapter,
249
+ disconnectStateAdapter
250
+ };
@@ -7,48 +7,42 @@ import {
7
7
  clearPendingAuth,
8
8
  getInterruptionMarker,
9
9
  getPersistedThreadState,
10
+ hydrateConversationMessages,
11
+ markConversationMessage,
10
12
  markTurnCompleted,
11
- mergeArtifactsState
12
- } from "./chunk-BKM4UXUD.js";
13
- import {
14
- coerceThreadConversationState
15
- } from "./chunk-XIMUQ4IU.js";
13
+ mergeArtifactsState,
14
+ updateConversationStats
15
+ } from "./chunk-YFQ7CQDE.js";
16
16
  import {
17
+ coerceThreadConversationState,
17
18
  getAgentTurnSessionRecord
18
- } from "./chunk-DDRQ4U7I.js";
19
- import {
20
- generateConversationId,
21
- hydrateConversationMessages,
22
- markConversationMessage,
23
- normalizeConversationText,
24
- updateConversationStats,
25
- upsertConversationMessage
26
- } from "./chunk-P4P7O5WG.js";
19
+ } from "./chunk-4YF7Z6IA.js";
27
20
  import {
28
21
  createPluginEmbedder,
29
22
  createPluginModel,
30
23
  getPlugins
31
- } from "./chunk-ZMRLBBD5.js";
24
+ } from "./chunk-RMVOAJRL.js";
32
25
  import {
33
26
  createPluginLogger,
34
27
  createPluginState
35
- } from "./chunk-AZ5OMSN5.js";
28
+ } from "./chunk-AUUOHQAT.js";
29
+ import {
30
+ getStateAdapter
31
+ } from "./chunk-B2Z2H66D.js";
36
32
  import {
37
33
  getDb
38
- } from "./chunk-XTKJPSMF.js";
34
+ } from "./chunk-NVOTGWYX.js";
39
35
  import {
40
- botConfig,
41
36
  getPiMessageRole,
42
- getStateAdapter,
43
37
  instructionTextForProjection,
44
38
  isToolResultError,
45
39
  isToolResultMessage,
46
40
  normalizeToolNameFromResult,
47
41
  stripRuntimeTurnContext
48
- } from "./chunk-4UYIRWDW.js";
42
+ } from "./chunk-SS67LUOK.js";
49
43
  import {
50
44
  buildTurnFailureResponse
51
- } from "./chunk-AEWZ7F65.js";
45
+ } from "./chunk-O24R4DCK.js";
52
46
  import {
53
47
  parseSlackMessageTs
54
48
  } from "./chunk-7FBGKXPE.js";
@@ -111,9 +105,9 @@ function getAgentTurnDiagnosticsAttributes(reply) {
111
105
  ...reply.diagnostics.errorMessage ? { "exception.message": reply.diagnostics.errorMessage } : {}
112
106
  };
113
107
  }
114
- function finalizeFailedTurnReply(args) {
108
+ function finalizeFailedTurnReplyWithEvent(args) {
115
109
  if (args.reply.diagnostics.outcome === "success") {
116
- return args.reply;
110
+ return { reply: args.reply };
117
111
  }
118
112
  const capture = getFailureCapture(args.reply);
119
113
  const eventId = requireTurnFailureEventId(
@@ -132,16 +126,66 @@ function finalizeFailedTurnReply(args) {
132
126
  );
133
127
  const providerPartialText = args.reply.diagnostics.outcome === "provider_error" && args.reply.diagnostics.assistantMessageCount > 0 ? args.reply.text.trim() : "";
134
128
  return {
135
- ...args.reply,
136
- text: providerPartialText ? `${providerPartialText}${getInterruptionMarker()}` : buildTurnFailureResponse(eventId),
137
- deliveryMode: "thread",
138
- deliveryPlan: {
139
- mode: "thread",
140
- postThreadText: true
129
+ eventId,
130
+ reply: {
131
+ ...args.reply,
132
+ text: providerPartialText ? `${providerPartialText}${getInterruptionMarker()}` : buildTurnFailureResponse(eventId)
141
133
  }
142
134
  };
143
135
  }
144
136
 
137
+ // src/chat/conversations/turn-lifecycle.ts
138
+ var ConversationTurnLifecycleService = class {
139
+ constructor(events) {
140
+ this.events = events;
141
+ }
142
+ events;
143
+ /** Record the turn start once after every input message is durable. */
144
+ async start(input) {
145
+ await this.events.append(input.conversationId, [
146
+ {
147
+ idempotencyKey: `turn:${input.turnId}:started`,
148
+ createdAtMs: input.createdAtMs,
149
+ data: {
150
+ type: "turn_started",
151
+ turnId: input.turnId,
152
+ inputMessageIds: input.inputMessageIds,
153
+ surface: input.surface
154
+ }
155
+ }
156
+ ]);
157
+ }
158
+ /** Record successful or intentional-silence completion once. */
159
+ async complete(input) {
160
+ await this.events.append(input.conversationId, [
161
+ {
162
+ idempotencyKey: `turn:${input.turnId}:terminal`,
163
+ createdAtMs: input.createdAtMs,
164
+ data: {
165
+ type: "turn_completed",
166
+ turnId: input.turnId,
167
+ outcome: input.outcome
168
+ }
169
+ }
170
+ ]);
171
+ }
172
+ /** Record a classified failure once without accepting raw error details. */
173
+ async fail(input) {
174
+ await this.events.append(input.conversationId, [
175
+ {
176
+ idempotencyKey: `turn:${input.turnId}:terminal`,
177
+ createdAtMs: input.createdAtMs,
178
+ data: {
179
+ type: "turn_failed",
180
+ turnId: input.turnId,
181
+ failureCode: input.failureCode,
182
+ ...input.eventId ? { eventId: input.eventId } : {}
183
+ }
184
+ }
185
+ ]);
186
+ }
187
+ };
188
+
145
189
  // src/chat/plugins/task-runner.ts
146
190
  import {
147
191
  isPrivateSource,
@@ -453,7 +497,6 @@ async function processPluginTask(message, options = {}) {
453
497
  }
454
498
 
455
499
  // src/chat/runtime/delivered-turn-state.ts
456
- var NO_VISIBLE_REPLY_CONVERSATION_TEXT = "[no visible reply]";
457
500
  function buildDeliveredTurnStatePatch(args) {
458
501
  const conversation = structuredClone(args.conversation);
459
502
  const artifactStatePatch = {
@@ -462,24 +505,10 @@ function buildDeliveredTurnStatePatch(args) {
462
505
  };
463
506
  const artifacts = Object.keys(artifactStatePatch).length > 0 ? mergeArtifactsState(args.artifacts, artifactStatePatch) : void 0;
464
507
  clearPendingAuth(conversation, args.sessionId);
465
- const assistantText = normalizeConversationText(args.reply.text) || (args.reply.deliveryPlan?.postThreadText === false ? NO_VISIBLE_REPLY_CONVERSATION_TEXT : "[empty response]");
466
508
  markConversationMessage(conversation, args.userMessageId, {
467
509
  replied: true,
468
510
  skippedReason: void 0
469
511
  });
470
- upsertConversationMessage(conversation, {
471
- id: generateConversationId("assistant"),
472
- role: "assistant",
473
- text: assistantText,
474
- createdAtMs: Date.now(),
475
- author: {
476
- userName: botConfig.userName,
477
- isBot: true
478
- },
479
- meta: {
480
- replied: true
481
- }
482
- });
483
512
  markTurnCompleted({
484
513
  conversation,
485
514
  nowMs: Date.now(),
@@ -497,7 +526,8 @@ function buildDeliveredTurnStatePatch(args) {
497
526
  export {
498
527
  requireTurnFailureEventId,
499
528
  getAgentTurnDiagnosticsAttributes,
500
- finalizeFailedTurnReply,
529
+ finalizeFailedTurnReplyWithEvent,
530
+ ConversationTurnLifecycleService,
501
531
  scheduleSessionCompletedPluginTasks,
502
532
  processPluginTask,
503
533
  buildDeliveredTurnStatePatch
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-77LHNQK4.js";
3
+ } from "./chunk-YIPD3L6L.js";
4
4
 
5
5
  // src/chat/plugins/validation.ts
6
6
  import { isDeepStrictEqual } from "util";