@sentry/junior 0.88.0 → 0.90.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 (158) hide show
  1. package/README.md +16 -5
  2. package/dist/{agent-hooks-RIJ5TSWP.js → agent-hooks-MXAF7RQL.js} +10 -10
  3. package/dist/api/people/list.js +8 -8
  4. package/dist/api/people/profile.js +8 -8
  5. package/dist/api-reference.d.ts +1 -1
  6. package/dist/app.js +716 -732
  7. package/dist/{catalog-runtime-MW7XERSU.js → catalog-runtime-DXE6NXHT.js} +5 -5
  8. package/dist/chat/agent/index.d.ts +4 -0
  9. package/dist/chat/agent/prompt.d.ts +78 -0
  10. package/dist/chat/{respond.d.ts → agent/request.d.ts} +98 -55
  11. package/dist/chat/agent/resume.d.ts +65 -0
  12. package/dist/chat/agent/sandbox.d.ts +15 -0
  13. package/dist/chat/agent/session.d.ts +20 -0
  14. package/dist/chat/agent/skills.d.ts +26 -0
  15. package/dist/chat/agent/tools.d.ts +78 -0
  16. package/dist/chat/agent-dispatch/runner.d.ts +3 -5
  17. package/dist/chat/app/production.d.ts +3 -1
  18. package/dist/chat/app/services.d.ts +1 -4
  19. package/dist/chat/logging.d.ts +2 -0
  20. package/dist/chat/mcp/tool-manager.d.ts +1 -6
  21. package/dist/chat/pi/messages.d.ts +18 -2
  22. package/dist/chat/pi/transcript.d.ts +31 -0
  23. package/dist/chat/plugins/agent-hooks.d.ts +2 -2
  24. package/dist/chat/prompt.d.ts +1 -1
  25. package/dist/chat/runtime/agent-continue-runner.d.ts +5 -5
  26. package/dist/chat/runtime/agent-run-outcome.d.ts +21 -0
  27. package/dist/chat/runtime/agent-runner.d.ts +11 -0
  28. package/dist/chat/runtime/delivered-turn-state.d.ts +2 -2
  29. package/dist/chat/runtime/generated-artifacts.d.ts +16 -0
  30. package/dist/chat/runtime/reply-executor.d.ts +2 -2
  31. package/dist/chat/runtime/slack-resume.d.ts +21 -12
  32. package/dist/chat/runtime/turn.d.ts +5 -39
  33. package/dist/chat/services/reply-delivery-plan.d.ts +0 -8
  34. package/dist/chat/services/turn-failure-response.d.ts +4 -4
  35. package/dist/chat/services/turn-result.d.ts +4 -7
  36. package/dist/chat/slack/channel.d.ts +9 -5
  37. package/dist/chat/slack/client.d.ts +3 -1
  38. package/dist/chat/slack/context.d.ts +17 -5
  39. package/dist/chat/slack/id-param.d.ts +25 -0
  40. package/dist/chat/slack/ids.d.ts +18 -4
  41. package/dist/chat/slack/outbound.d.ts +16 -0
  42. package/dist/chat/slack/output.d.ts +3 -3
  43. package/dist/chat/slack/reply.d.ts +4 -7
  44. package/dist/chat/slack/timestamp-param.d.ts +25 -0
  45. package/dist/chat/slack/tools/canvas/context.d.ts +18 -0
  46. package/dist/chat/slack/tools/canvas/create.d.ts +4 -0
  47. package/dist/chat/slack/tools/canvas/edit.d.ts +3 -0
  48. package/dist/chat/slack/tools/canvas/read.d.ts +6 -0
  49. package/dist/chat/slack/tools/canvas/write.d.ts +3 -0
  50. package/dist/chat/{tools/slack → slack/tools}/channel-access.d.ts +4 -3
  51. package/dist/chat/{tools → slack/tools}/channel-capabilities.d.ts +2 -0
  52. package/dist/chat/slack/tools/channel-list-messages.d.ts +3 -0
  53. package/dist/chat/{tools/slack → slack/tools}/context.d.ts +5 -4
  54. package/dist/chat/slack/tools/list/add-items.d.ts +3 -0
  55. package/dist/chat/{tools/slack/lists.d.ts → slack/tools/list/api.d.ts} +2 -1
  56. package/dist/chat/slack/tools/list/create.d.ts +3 -0
  57. package/dist/chat/slack/tools/list/get-items.d.ts +3 -0
  58. package/dist/chat/slack/tools/list/update-item.d.ts +3 -0
  59. package/dist/chat/slack/tools/message-add-reaction.d.ts +4 -0
  60. package/dist/chat/slack/tools/send-message.d.ts +11 -0
  61. package/dist/chat/{tools/slack → slack/tools}/slack-message-url.d.ts +5 -5
  62. package/dist/chat/slack/tools/thread-read.d.ts +6 -0
  63. package/dist/chat/slack/tools/user-lookup.d.ts +2 -0
  64. package/dist/chat/slack/users.d.ts +2 -1
  65. package/dist/chat/{services → slack}/vision-context.d.ts +4 -2
  66. package/dist/chat/state/session-log.d.ts +1 -1
  67. package/dist/chat/tool-exposure.d.ts +10 -0
  68. package/dist/chat/tool-support/catalog-tool-call.d.ts +10 -0
  69. package/dist/chat/{tools/execution → tool-support}/normalize-result.d.ts +4 -1
  70. package/dist/chat/{tools/agent-tools.d.ts → tool-support/pi-tool-adapter.d.ts} +3 -9
  71. package/dist/chat/tool-support/schema-summary.d.ts +2 -0
  72. package/dist/chat/{tools → tool-support}/skill/mcp-tool-summary.d.ts +0 -6
  73. package/dist/chat/tool-support/structured-result.d.ts +73 -0
  74. package/dist/chat/tool-support/text-range-result.d.ts +58 -0
  75. package/dist/chat/tool-support/tool-execution-report.d.ts +7 -0
  76. package/dist/chat/tool-support/zod-tool.d.ts +27 -0
  77. package/dist/chat/tools/advisor/tool.d.ts +9 -18
  78. package/dist/chat/tools/definition.d.ts +56 -9
  79. package/dist/chat/tools/execute-tool.d.ts +3 -0
  80. package/dist/chat/tools/index.d.ts +3 -2
  81. package/dist/chat/tools/resource-events.d.ts +3 -13
  82. package/dist/chat/tools/runtime/report-progress.d.ts +1 -3
  83. package/dist/chat/tools/sandbox/bash.d.ts +1 -4
  84. package/dist/chat/tools/sandbox/edit-file.d.ts +25 -7
  85. package/dist/chat/tools/sandbox/file-uploads.d.ts +30 -0
  86. package/dist/chat/tools/sandbox/file-utils.d.ts +10 -1
  87. package/dist/chat/tools/sandbox/find-files.d.ts +12 -11
  88. package/dist/chat/tools/sandbox/grep.d.ts +18 -12
  89. package/dist/chat/tools/sandbox/list-dir.d.ts +15 -7
  90. package/dist/chat/tools/sandbox/read-file.d.ts +2 -31
  91. package/dist/chat/tools/sandbox/write-file.d.ts +1 -4
  92. package/dist/chat/tools/search-tools.d.ts +4 -0
  93. package/dist/chat/tools/skill/call-mcp-tool.d.ts +1 -4
  94. package/dist/chat/tools/skill/load-skill.d.ts +4 -5
  95. package/dist/chat/tools/skill/search-mcp-tools.d.ts +1 -5
  96. package/dist/chat/tools/system-time.d.ts +1 -1
  97. package/dist/chat/tools/types.d.ts +15 -5
  98. package/dist/chat/tools/web/fetch-content.d.ts +4 -2
  99. package/dist/chat/tools/web/fetch-tool.d.ts +4 -4
  100. package/dist/chat/tools/web/image-generate.d.ts +4 -3
  101. package/dist/chat/tools/web/search.d.ts +1 -4
  102. package/dist/{chunk-4IXHIV37.js → chunk-2S7M37HY.js} +6 -8
  103. package/dist/{chunk-L7OHKDOX.js → chunk-3MPOMK3K.js} +58 -7
  104. package/dist/{chunk-V6XDCS3X.js → chunk-5GBUZI6M.js} +4 -4
  105. package/dist/{chunk-7ES37H6U.js → chunk-AN2437E3.js} +4 -4
  106. package/dist/chunk-AOISHLSF.js +747 -0
  107. package/dist/{chunk-NYJLQI42.js → chunk-BKSZL4QO.js} +11257 -11957
  108. package/dist/{chunk-XS6NLQPA.js → chunk-DACFZ5CI.js} +474 -33
  109. package/dist/chunk-GCWD2VHP.js +1216 -0
  110. package/dist/chunk-GHGPTPBL.js +53 -0
  111. package/dist/{chunk-S35CPNPT.js → chunk-HXL2ZV74.js} +40 -216
  112. package/dist/{chunk-PBV4ZIVM.js → chunk-IRRMABQD.js} +1 -1
  113. package/dist/{chunk-2DPZRS3B.js → chunk-IX76WFJV.js} +8 -8
  114. package/dist/{chunk-66NX7MNW.js → chunk-KC42JAAQ.js} +1 -1
  115. package/dist/chunk-LFLTJQVR.js +90 -0
  116. package/dist/{chunk-IATAYWFU.js → chunk-NW7AXDA5.js} +2 -2
  117. package/dist/{chunk-F22AM3OW.js → chunk-NYWPISSO.js} +1 -1
  118. package/dist/chunk-OB42YVAE.js +16 -0
  119. package/dist/chunk-ONFOWI2D.js +955 -0
  120. package/dist/chunk-PHZHJTCK.js +1062 -0
  121. package/dist/{chunk-6UPQ5GTJ.js → chunk-QCKGI74V.js} +7 -7
  122. package/dist/{chunk-YPAE5RH3.js → chunk-RS6ANWVT.js} +1 -1
  123. package/dist/{chunk-C5NCV3OB.js → chunk-TYUXD3FN.js} +1 -1
  124. package/dist/{chunk-KBFQXJL4.js → chunk-XP7F4LYB.js} +5 -7
  125. package/dist/{chunk-VMBZFPZM.js → chunk-ZUK7BL63.js} +187 -9
  126. package/dist/cli/chat.js +55 -40
  127. package/dist/cli/check.js +6 -6
  128. package/dist/cli/init.js +30 -36
  129. package/dist/cli/plugins.js +16 -16
  130. package/dist/cli/snapshot-warmup.js +9 -9
  131. package/dist/cli/upgrade.js +21 -21
  132. package/dist/db-CXI7PR5U.js +18 -0
  133. package/dist/handlers/agent-dispatch.d.ts +3 -3
  134. package/dist/handlers/mcp-oauth-callback.d.ts +3 -3
  135. package/dist/handlers/oauth-callback.d.ts +3 -3
  136. package/dist/instrumentation.js +6 -5
  137. package/dist/nitro.js +3 -7
  138. package/dist/reporting.js +23 -25
  139. package/dist/{runner-BCRF2FCI.js → runner-FKL3RAHA.js} +89 -77
  140. package/dist/{validation-FMJO3L5P.js → validation-I7GD2YWS.js} +6 -6
  141. package/package.json +6 -6
  142. package/dist/chat/respond-helpers.d.ts +0 -82
  143. package/dist/chat/services/attachment-claims.d.ts +0 -2
  144. package/dist/chat/services/channel-intent.d.ts +0 -2
  145. package/dist/chat/tools/sandbox/attach-file.d.ts +0 -7
  146. package/dist/chat/tools/slack/canvas-tools.d.ts +0 -30
  147. package/dist/chat/tools/slack/channel-list-messages.d.ts +0 -9
  148. package/dist/chat/tools/slack/channel-post-message.d.ts +0 -5
  149. package/dist/chat/tools/slack/list-tools.d.ts +0 -21
  150. package/dist/chat/tools/slack/message-add-reaction.d.ts +0 -5
  151. package/dist/chat/tools/slack/thread-read.d.ts +0 -12
  152. package/dist/chat/tools/slack/user-lookup.d.ts +0 -8
  153. package/dist/chunk-AHLSXMOU.js +0 -506
  154. package/dist/chunk-FTMXFBDC.js +0 -49
  155. package/dist/chunk-KBSLCOGE.js +0 -2226
  156. package/dist/chunk-KQKIA4CU.js +0 -186
  157. package/dist/db-37HOGLI7.js +0 -18
  158. /package/dist/chat/{tools/slack/canvases.d.ts → slack/tools/canvas/api.d.ts} +0 -0
@@ -0,0 +1,955 @@
1
+ import {
2
+ JUNIOR_THREAD_STATE_TTL_MS,
3
+ buildConversationStatePatch
4
+ } from "./chunk-KC42JAAQ.js";
5
+ import {
6
+ abandonAgentTurnSessionRecord,
7
+ getAgentTurnSessionRecord,
8
+ upsertAgentTurnSessionRecord
9
+ } from "./chunk-GCWD2VHP.js";
10
+ import {
11
+ getStateAdapter
12
+ } from "./chunk-RS6ANWVT.js";
13
+ import {
14
+ getPiMessageRole,
15
+ trimTrailingAssistantMessages
16
+ } from "./chunk-HXL2ZV74.js";
17
+ import {
18
+ getActiveTraceId,
19
+ logException
20
+ } from "./chunk-ZUK7BL63.js";
21
+ import {
22
+ isRecord,
23
+ toOptionalString
24
+ } from "./chunk-OB42YVAE.js";
25
+
26
+ // src/chat/state/turn-id.ts
27
+ function buildDeterministicTurnId(messageId) {
28
+ const sanitized = messageId.replace(/[^a-zA-Z0-9_-]/g, "_");
29
+ return `turn_${sanitized}`;
30
+ }
31
+
32
+ // src/chat/runtime/turn.ts
33
+ var CooperativeTurnYieldError = class extends Error {
34
+ code = "cooperative_turn_yield";
35
+ constructor(message = "Agent turn yielded at a safe boundary") {
36
+ super(message);
37
+ this.name = "CooperativeTurnYieldError";
38
+ }
39
+ };
40
+ function isCooperativeTurnYieldError(error) {
41
+ return error instanceof CooperativeTurnYieldError;
42
+ }
43
+ var TurnInputCommitLostError = class extends Error {
44
+ code = "turn_input_commit_lost";
45
+ constructor(message = "Turn input commit lost its durable owner") {
46
+ super(message);
47
+ this.name = "TurnInputCommitLostError";
48
+ }
49
+ };
50
+ function isTurnInputCommitLostError(error) {
51
+ return error instanceof TurnInputCommitLostError;
52
+ }
53
+ var TurnInputDeferredError = class extends Error {
54
+ code = "turn_input_deferred";
55
+ constructor(message = "Turn input is deferred until the active resume ends") {
56
+ super(message);
57
+ this.name = "TurnInputDeferredError";
58
+ }
59
+ };
60
+ function isTurnInputDeferredError(error) {
61
+ return error instanceof TurnInputDeferredError;
62
+ }
63
+ function startActiveTurn(args) {
64
+ args.conversation.processing.activeTurnId = args.nextTurnId;
65
+ args.updateConversationStats(args.conversation);
66
+ }
67
+ function clearActiveTurn(conversation, sessionId) {
68
+ if (!sessionId || conversation.processing.activeTurnId === sessionId) {
69
+ conversation.processing.activeTurnId = void 0;
70
+ }
71
+ }
72
+ function markTurnClosed(args) {
73
+ clearActiveTurn(args.conversation, args.sessionId);
74
+ args.conversation.processing.lastCompletedAtMs = args.nowMs;
75
+ args.updateConversationStats(args.conversation);
76
+ }
77
+ function markTurnCompleted(args) {
78
+ clearActiveTurn(args.conversation, args.sessionId);
79
+ args.conversation.processing.lastCompletedAtMs = args.nowMs;
80
+ args.updateConversationStats(args.conversation);
81
+ }
82
+ function markTurnFailed(args) {
83
+ clearActiveTurn(args.conversation, args.sessionId);
84
+ args.conversation.processing.lastCompletedAtMs = args.nowMs;
85
+ args.markConversationMessage(args.conversation, args.userMessageId, {
86
+ replied: false,
87
+ skippedReason: "reply failed"
88
+ });
89
+ args.updateConversationStats(args.conversation);
90
+ }
91
+
92
+ // src/chat/usage.ts
93
+ var COMPONENT_USAGE_FIELDS = [
94
+ "inputTokens",
95
+ "outputTokens",
96
+ "cachedInputTokens",
97
+ "cacheCreationTokens"
98
+ ];
99
+ function hasAgentTurnUsage(usage) {
100
+ return Boolean(
101
+ usage && Object.values(usage).some(
102
+ (value) => typeof value === "number" && Number.isFinite(value)
103
+ )
104
+ );
105
+ }
106
+ function getFiniteCount(value) {
107
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : void 0;
108
+ }
109
+ function getComponentTotal(usage) {
110
+ let total;
111
+ for (const field of COMPONENT_USAGE_FIELDS) {
112
+ const value = getFiniteCount(usage[field]);
113
+ if (value === void 0) continue;
114
+ total = (total ?? 0) + value;
115
+ }
116
+ return total;
117
+ }
118
+ function addAgentTurnUsage(...usages) {
119
+ const components = {};
120
+ let componentTotal;
121
+ let totalOnlyTokens;
122
+ for (const usage of usages) {
123
+ if (!usage) continue;
124
+ const usageComponentTotal = getComponentTotal(usage);
125
+ if (usageComponentTotal !== void 0) {
126
+ componentTotal = (componentTotal ?? 0) + usageComponentTotal;
127
+ for (const field of COMPONENT_USAGE_FIELDS) {
128
+ const value = getFiniteCount(usage[field]);
129
+ if (value === void 0) continue;
130
+ components[field] = (components[field] ?? 0) + value;
131
+ }
132
+ continue;
133
+ }
134
+ const totalTokens = getFiniteCount(usage.totalTokens);
135
+ if (totalTokens !== void 0) {
136
+ totalOnlyTokens = (totalOnlyTokens ?? 0) + totalTokens;
137
+ }
138
+ }
139
+ if (totalOnlyTokens !== void 0) {
140
+ return {
141
+ totalTokens: totalOnlyTokens + (componentTotal ?? 0)
142
+ };
143
+ }
144
+ return hasAgentTurnUsage(components) ? components : void 0;
145
+ }
146
+
147
+ // src/chat/services/turn-session-record.ts
148
+ var AGENT_CONTINUE_MAX_SLICES = 48;
149
+ function logSessionRecordError(error, eventName, args, attributes, message) {
150
+ logException(
151
+ error,
152
+ eventName,
153
+ {
154
+ slackThreadId: args.logContext.threadId,
155
+ slackUserId: args.logContext.requesterId,
156
+ slackChannelId: args.logContext.channelId,
157
+ runId: args.logContext.runId,
158
+ assistantUserName: args.logContext.assistantUserName,
159
+ modelId: args.logContext.modelId
160
+ },
161
+ {
162
+ "app.ai.resume_conversation_id": args.conversationId,
163
+ "app.ai.resume_session_id": args.sessionId,
164
+ ...attributes
165
+ },
166
+ message
167
+ );
168
+ }
169
+ function addDurationMs(prior, current) {
170
+ const total = [prior, current].reduce((sum, value) => {
171
+ if (typeof value !== "number" || !Number.isFinite(value)) {
172
+ return sum;
173
+ }
174
+ return (sum ?? 0) + Math.max(0, Math.floor(value));
175
+ }, void 0);
176
+ return total;
177
+ }
178
+ function isContinuableBoundary(messages) {
179
+ const lastRole = getPiMessageRole(messages.at(-1));
180
+ return lastRole === "user" || lastRole === "toolResult";
181
+ }
182
+ function resumableBoundary(messages, fallbackMessages) {
183
+ const current = trimTrailingAssistantMessages(messages);
184
+ if (current.length > 0 && isContinuableBoundary(current)) {
185
+ return current;
186
+ }
187
+ return trimTrailingAssistantMessages(fallbackMessages ?? []);
188
+ }
189
+ async function loadTurnSessionRecord(ctx) {
190
+ const canUseTurnSession = Boolean(ctx.conversationId && ctx.sessionId);
191
+ const existingSessionRecord = canUseTurnSession && ctx.conversationId && ctx.sessionId ? await getAgentTurnSessionRecord(ctx.conversationId, ctx.sessionId) : void 0;
192
+ const hasAwaitingResumeRecord = Boolean(
193
+ existingSessionRecord && existingSessionRecord.state === "awaiting_resume"
194
+ );
195
+ return {
196
+ canUseTurnSession,
197
+ resumedFromSessionRecord: hasAwaitingResumeRecord,
198
+ currentSliceId: hasAwaitingResumeRecord ? existingSessionRecord.sliceId : 1,
199
+ existingSessionRecord
200
+ };
201
+ }
202
+ async function persistRunningSessionRecord(args) {
203
+ if (args.messages.length === 0 || !isContinuableBoundary(args.messages)) {
204
+ return false;
205
+ }
206
+ try {
207
+ const latestSessionRecord = await getAgentTurnSessionRecord(
208
+ args.conversationId,
209
+ args.sessionId
210
+ );
211
+ await upsertAgentTurnSessionRecord({
212
+ ...args.channelName ?? latestSessionRecord?.channelName ? { channelName: args.channelName ?? latestSessionRecord?.channelName } : {},
213
+ conversationId: args.conversationId,
214
+ cumulativeDurationMs: latestSessionRecord?.cumulativeDurationMs,
215
+ cumulativeUsage: latestSessionRecord?.cumulativeUsage,
216
+ ...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
217
+ ...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
218
+ sessionId: args.sessionId,
219
+ sliceId: args.sliceId,
220
+ state: "running",
221
+ piMessages: args.messages,
222
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
223
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
224
+ ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
225
+ ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {},
226
+ ...(args.turnStartMessageIndex ?? latestSessionRecord?.turnStartMessageIndex) !== void 0 ? {
227
+ turnStartMessageIndex: args.turnStartMessageIndex ?? latestSessionRecord?.turnStartMessageIndex
228
+ } : {}
229
+ });
230
+ return true;
231
+ } catch (recordError) {
232
+ logSessionRecordError(
233
+ recordError,
234
+ "agent_turn_running_session_record_failed",
235
+ args,
236
+ {
237
+ "app.ai.resume_slice_id": args.sliceId
238
+ },
239
+ "Failed to persist running turn session record"
240
+ );
241
+ return false;
242
+ }
243
+ }
244
+ async function persistCompletedSessionRecord(args) {
245
+ let sliceId = args.sliceId;
246
+ try {
247
+ const latestSessionRecord = await getAgentTurnSessionRecord(
248
+ args.conversationId,
249
+ args.sessionId
250
+ );
251
+ sliceId = sliceId ?? latestSessionRecord?.sliceId;
252
+ if (sliceId === void 0) {
253
+ throw new Error(
254
+ "Completed session record requires a slice id from the caller or the latest stored record"
255
+ );
256
+ }
257
+ await upsertAgentTurnSessionRecord({
258
+ ...args.channelName ?? latestSessionRecord?.channelName ? { channelName: args.channelName ?? latestSessionRecord?.channelName } : {},
259
+ conversationId: args.conversationId,
260
+ cumulativeDurationMs: addDurationMs(
261
+ latestSessionRecord?.cumulativeDurationMs,
262
+ args.currentDurationMs
263
+ ),
264
+ cumulativeUsage: addAgentTurnUsage(
265
+ latestSessionRecord?.cumulativeUsage,
266
+ args.currentUsage
267
+ ),
268
+ ...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
269
+ ...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
270
+ ...args.destinationVisibility ? { destinationVisibility: args.destinationVisibility } : {},
271
+ sessionId: args.sessionId,
272
+ sliceId,
273
+ state: "completed",
274
+ piMessages: args.allMessages,
275
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
276
+ ...args.loadedSkillNames ?? latestSessionRecord?.loadedSkillNames ? {
277
+ loadedSkillNames: args.loadedSkillNames ?? latestSessionRecord?.loadedSkillNames
278
+ } : {},
279
+ ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
280
+ ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {},
281
+ ...(args.turnStartMessageIndex ?? latestSessionRecord?.turnStartMessageIndex) !== void 0 ? {
282
+ turnStartMessageIndex: args.turnStartMessageIndex ?? latestSessionRecord?.turnStartMessageIndex
283
+ } : {}
284
+ });
285
+ } catch (recordError) {
286
+ logSessionRecordError(
287
+ recordError,
288
+ "agent_turn_completed_session_record_failed",
289
+ args,
290
+ sliceId !== void 0 ? { "app.ai.resume_slice_id": sliceId } : {},
291
+ "Failed to persist completed turn session record"
292
+ );
293
+ }
294
+ }
295
+ async function completeDeliveredTurn(args) {
296
+ await persistCompletedSessionRecord({
297
+ channelName: args.channelName,
298
+ conversationId: args.conversationId,
299
+ currentDurationMs: args.durationMs,
300
+ currentUsage: args.usage,
301
+ destination: args.destination,
302
+ destinationVisibility: args.destinationVisibility,
303
+ source: args.source,
304
+ sessionId: args.sessionId,
305
+ sliceId: args.sliceId,
306
+ allMessages: args.messages,
307
+ loadedSkillNames: args.loadedSkillNames,
308
+ logContext: args.logContext,
309
+ requester: args.requester,
310
+ surface: args.surface,
311
+ turnStartMessageIndex: args.turnStartMessageIndex
312
+ });
313
+ }
314
+ async function persistAuthPauseSessionRecord(args) {
315
+ const nextSliceId = args.currentSliceId + 1;
316
+ try {
317
+ const latestSessionRecord = await getAgentTurnSessionRecord(
318
+ args.conversationId,
319
+ args.sessionId
320
+ );
321
+ const piMessages = resumableBoundary(
322
+ args.messages,
323
+ latestSessionRecord?.piMessages
324
+ );
325
+ if (piMessages.length > 0 && !isContinuableBoundary(piMessages)) {
326
+ return void 0;
327
+ }
328
+ return await upsertAgentTurnSessionRecord({
329
+ ...args.channelName ?? latestSessionRecord?.channelName ? { channelName: args.channelName ?? latestSessionRecord?.channelName } : {},
330
+ conversationId: args.conversationId,
331
+ cumulativeDurationMs: addDurationMs(
332
+ latestSessionRecord?.cumulativeDurationMs,
333
+ args.currentDurationMs
334
+ ),
335
+ cumulativeUsage: addAgentTurnUsage(
336
+ latestSessionRecord?.cumulativeUsage,
337
+ args.currentUsage
338
+ ),
339
+ ...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
340
+ ...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
341
+ sessionId: args.sessionId,
342
+ sliceId: nextSliceId,
343
+ state: "awaiting_resume",
344
+ piMessages,
345
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
346
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
347
+ resumeReason: "auth",
348
+ resumedFromSliceId: args.currentSliceId,
349
+ errorMessage: args.errorMessage,
350
+ ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
351
+ ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {}
352
+ });
353
+ } catch (recordError) {
354
+ logSessionRecordError(
355
+ recordError,
356
+ "agent_turn_auth_resume_session_record_failed",
357
+ args,
358
+ {
359
+ "app.ai.resume_from_slice_id": args.currentSliceId,
360
+ "app.ai.resume_next_slice_id": nextSliceId
361
+ },
362
+ "Failed to persist auth session record before retry"
363
+ );
364
+ }
365
+ return void 0;
366
+ }
367
+ async function persistTimeoutSessionRecord(args) {
368
+ const nextSliceId = args.currentSliceId + 1;
369
+ try {
370
+ const latestSessionRecord = await getAgentTurnSessionRecord(
371
+ args.conversationId,
372
+ args.sessionId
373
+ );
374
+ const piMessages = resumableBoundary(
375
+ args.messages,
376
+ latestSessionRecord?.piMessages
377
+ );
378
+ if (piMessages.length === 0 || !isContinuableBoundary(piMessages)) {
379
+ return void 0;
380
+ }
381
+ const cumulativeDurationMs = addDurationMs(
382
+ latestSessionRecord?.cumulativeDurationMs,
383
+ args.currentDurationMs
384
+ );
385
+ const cumulativeUsage = addAgentTurnUsage(
386
+ latestSessionRecord?.cumulativeUsage,
387
+ args.currentUsage
388
+ );
389
+ if (nextSliceId > AGENT_CONTINUE_MAX_SLICES) {
390
+ return await upsertAgentTurnSessionRecord({
391
+ ...args.channelName ?? latestSessionRecord?.channelName ? {
392
+ channelName: args.channelName ?? latestSessionRecord?.channelName
393
+ } : {},
394
+ conversationId: args.conversationId,
395
+ cumulativeDurationMs,
396
+ cumulativeUsage,
397
+ ...args.destination ?? latestSessionRecord?.destination ? {
398
+ destination: args.destination ?? latestSessionRecord?.destination
399
+ } : {},
400
+ ...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
401
+ sessionId: args.sessionId,
402
+ sliceId: args.currentSliceId,
403
+ state: "failed",
404
+ piMessages,
405
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
406
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
407
+ resumeReason: "timeout",
408
+ resumedFromSliceId: latestSessionRecord?.resumedFromSliceId,
409
+ errorMessage: `Agent continuation exceeded slice limit (${AGENT_CONTINUE_MAX_SLICES})`,
410
+ ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
411
+ ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {}
412
+ });
413
+ }
414
+ return await upsertAgentTurnSessionRecord({
415
+ ...args.channelName ?? latestSessionRecord?.channelName ? { channelName: args.channelName ?? latestSessionRecord?.channelName } : {},
416
+ conversationId: args.conversationId,
417
+ cumulativeDurationMs,
418
+ cumulativeUsage,
419
+ ...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
420
+ ...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
421
+ sessionId: args.sessionId,
422
+ sliceId: nextSliceId,
423
+ state: "awaiting_resume",
424
+ piMessages,
425
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
426
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
427
+ resumeReason: "timeout",
428
+ resumedFromSliceId: args.currentSliceId,
429
+ errorMessage: args.errorMessage,
430
+ ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
431
+ ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {}
432
+ });
433
+ } catch (recordError) {
434
+ logSessionRecordError(
435
+ recordError,
436
+ "agent_continue_session_record_failed",
437
+ args,
438
+ {
439
+ "app.ai.resume_from_slice_id": args.currentSliceId,
440
+ "app.ai.resume_next_slice_id": nextSliceId
441
+ },
442
+ "Failed to persist session record before scheduling agent continuation"
443
+ );
444
+ return void 0;
445
+ }
446
+ }
447
+ async function persistYieldSessionRecord(args) {
448
+ try {
449
+ const latestSessionRecord = await getAgentTurnSessionRecord(
450
+ args.conversationId,
451
+ args.sessionId
452
+ );
453
+ const piMessages = resumableBoundary(
454
+ args.messages,
455
+ latestSessionRecord?.piMessages
456
+ );
457
+ if (piMessages.length === 0 || !isContinuableBoundary(piMessages)) {
458
+ return void 0;
459
+ }
460
+ return await upsertAgentTurnSessionRecord({
461
+ ...args.channelName ?? latestSessionRecord?.channelName ? { channelName: args.channelName ?? latestSessionRecord?.channelName } : {},
462
+ conversationId: args.conversationId,
463
+ cumulativeDurationMs: addDurationMs(
464
+ latestSessionRecord?.cumulativeDurationMs,
465
+ args.currentDurationMs
466
+ ),
467
+ cumulativeUsage: addAgentTurnUsage(
468
+ latestSessionRecord?.cumulativeUsage,
469
+ args.currentUsage
470
+ ),
471
+ ...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
472
+ ...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
473
+ sessionId: args.sessionId,
474
+ sliceId: args.currentSliceId,
475
+ state: "awaiting_resume",
476
+ piMessages,
477
+ ...args.surface ?? latestSessionRecord?.surface ? { surface: args.surface ?? latestSessionRecord?.surface } : {},
478
+ ...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
479
+ resumeReason: "yield",
480
+ resumedFromSliceId: latestSessionRecord?.resumedFromSliceId,
481
+ errorMessage: args.errorMessage,
482
+ ...args.requester ?? latestSessionRecord?.requester ? { requester: args.requester ?? latestSessionRecord?.requester } : {},
483
+ ...getActiveTraceId() ?? latestSessionRecord?.traceId ? { traceId: getActiveTraceId() ?? latestSessionRecord?.traceId } : {}
484
+ });
485
+ } catch (recordError) {
486
+ logSessionRecordError(
487
+ recordError,
488
+ "agent_turn_yield_session_record_failed",
489
+ args,
490
+ {
491
+ "app.ai.resume_slice_id": args.currentSliceId
492
+ },
493
+ "Failed to persist cooperative yield session record"
494
+ );
495
+ return void 0;
496
+ }
497
+ }
498
+
499
+ // src/chat/state/artifacts.ts
500
+ function coerceThreadArtifactsState(value) {
501
+ if (!value || typeof value !== "object") {
502
+ return {};
503
+ }
504
+ const raw = value;
505
+ const artifacts = raw.artifacts ?? {};
506
+ const listColumnMap = artifacts.listColumnMap ?? {};
507
+ const recentCanvases = [];
508
+ if (Array.isArray(artifacts.recentCanvases)) {
509
+ for (const entry of artifacts.recentCanvases) {
510
+ if (!entry || typeof entry !== "object") {
511
+ continue;
512
+ }
513
+ const candidate = entry;
514
+ if (typeof candidate.id !== "string" || candidate.id.trim().length === 0) {
515
+ continue;
516
+ }
517
+ recentCanvases.push({
518
+ id: candidate.id,
519
+ title: typeof candidate.title === "string" ? candidate.title : void 0,
520
+ url: typeof candidate.url === "string" ? candidate.url : void 0,
521
+ createdAt: typeof candidate.createdAt === "string" ? candidate.createdAt : void 0
522
+ });
523
+ }
524
+ }
525
+ return {
526
+ assistantContextChannelId: typeof artifacts.assistantContextChannelId === "string" ? artifacts.assistantContextChannelId : void 0,
527
+ assistantTitle: typeof artifacts.assistantTitle === "string" ? artifacts.assistantTitle : void 0,
528
+ assistantTitleSourceMessageId: typeof artifacts.assistantTitleSourceMessageId === "string" ? artifacts.assistantTitleSourceMessageId : void 0,
529
+ lastCanvasId: typeof artifacts.lastCanvasId === "string" ? artifacts.lastCanvasId : void 0,
530
+ lastCanvasUrl: typeof artifacts.lastCanvasUrl === "string" ? artifacts.lastCanvasUrl : void 0,
531
+ recentCanvases,
532
+ lastListId: typeof artifacts.lastListId === "string" ? artifacts.lastListId : void 0,
533
+ lastListUrl: typeof artifacts.lastListUrl === "string" ? artifacts.lastListUrl : void 0,
534
+ listColumnMap: {
535
+ titleColumnId: typeof listColumnMap.titleColumnId === "string" ? listColumnMap.titleColumnId : void 0,
536
+ completedColumnId: typeof listColumnMap.completedColumnId === "string" ? listColumnMap.completedColumnId : void 0,
537
+ assigneeColumnId: typeof listColumnMap.assigneeColumnId === "string" ? listColumnMap.assigneeColumnId : void 0,
538
+ dueDateColumnId: typeof listColumnMap.dueDateColumnId === "string" ? listColumnMap.dueDateColumnId : void 0
539
+ },
540
+ updatedAt: typeof artifacts.updatedAt === "string" ? artifacts.updatedAt : void 0
541
+ };
542
+ }
543
+ function buildArtifactStatePatch(patch) {
544
+ return {
545
+ artifacts: {
546
+ ...patch,
547
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
548
+ }
549
+ };
550
+ }
551
+
552
+ // src/chat/configuration/validation.ts
553
+ var CONFIG_KEY_RE = /^[a-z0-9]+(?:\.[a-z0-9-]+)+$/;
554
+ var SECRET_KEY_RE = /(?:^|[_.-])(token|secret|password|passphrase|api[-_]?key|private[-_]?key|credential|auth)(?:$|[_.-])/i;
555
+ var SECRET_VALUE_PATTERNS = [
556
+ /\bBearer\s+[A-Za-z0-9._-]{16,}\b/i,
557
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
558
+ /\b(?:ghp|ghs|github_pat)_[A-Za-z0-9_]{20,}\b/,
559
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/i,
560
+ /\bsk-[A-Za-z0-9]{20,}\b/,
561
+ /\bAIza[0-9A-Za-z\-_]{30,}\b/,
562
+ /\bAKIA[0-9A-Z]{16}\b/,
563
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/
564
+ ];
565
+ function validateConfigKey(key) {
566
+ const trimmed = key.trim();
567
+ if (!trimmed) {
568
+ return "Configuration key must not be empty";
569
+ }
570
+ if (!CONFIG_KEY_RE.test(trimmed)) {
571
+ return `Invalid configuration key "${key}"; expected dotted lowercase namespace (for example "provider.repo")`;
572
+ }
573
+ if (SECRET_KEY_RE.test(trimmed)) {
574
+ return `Configuration key "${key}" appears to be secret-related and is not allowed`;
575
+ }
576
+ return void 0;
577
+ }
578
+ function collectStringValues(value, output, depth = 0) {
579
+ if (depth > 5) {
580
+ return;
581
+ }
582
+ if (typeof value === "string") {
583
+ output.push(value);
584
+ return;
585
+ }
586
+ if (Array.isArray(value)) {
587
+ for (const item of value) {
588
+ collectStringValues(item, output, depth + 1);
589
+ }
590
+ return;
591
+ }
592
+ if (value && typeof value === "object") {
593
+ for (const [key, nested] of Object.entries(
594
+ value
595
+ )) {
596
+ output.push(key);
597
+ collectStringValues(nested, output, depth + 1);
598
+ }
599
+ }
600
+ }
601
+ function validateConfigValue(value) {
602
+ const stringValues = [];
603
+ collectStringValues(value, stringValues);
604
+ for (const text of stringValues) {
605
+ for (const pattern of SECRET_VALUE_PATTERNS) {
606
+ if (pattern.test(text)) {
607
+ return "Configuration value appears to contain secret material and is not allowed";
608
+ }
609
+ }
610
+ }
611
+ return void 0;
612
+ }
613
+
614
+ // src/chat/configuration/service.ts
615
+ function defaultState() {
616
+ return {
617
+ schemaVersion: 1,
618
+ entries: {}
619
+ };
620
+ }
621
+ function sanitizeEntry(value) {
622
+ if (!isRecord(value)) {
623
+ return void 0;
624
+ }
625
+ const key = toOptionalString(value.key);
626
+ if (!key) {
627
+ return void 0;
628
+ }
629
+ if (validateConfigKey(key)) {
630
+ return void 0;
631
+ }
632
+ const updatedAt = toOptionalString(value.updatedAt);
633
+ if (!updatedAt) {
634
+ return void 0;
635
+ }
636
+ if (value.scope !== "channel" && value.scope !== "conversation") {
637
+ return void 0;
638
+ }
639
+ const scope = "conversation";
640
+ return {
641
+ key,
642
+ value: value.value,
643
+ scope,
644
+ updatedAt,
645
+ updatedBy: toOptionalString(value.updatedBy),
646
+ source: toOptionalString(value.source),
647
+ expiresAt: toOptionalString(value.expiresAt)
648
+ };
649
+ }
650
+ function coerceState(raw) {
651
+ if (!isRecord(raw)) {
652
+ return defaultState();
653
+ }
654
+ const rawConfig = isRecord(raw.configuration) ? raw.configuration : {};
655
+ const rawEntries = isRecord(rawConfig.entries) ? rawConfig.entries : {};
656
+ const entries = {};
657
+ for (const [key, value] of Object.entries(rawEntries)) {
658
+ const entry = sanitizeEntry(value);
659
+ if (!entry) {
660
+ continue;
661
+ }
662
+ entries[key] = entry;
663
+ }
664
+ return {
665
+ schemaVersion: 1,
666
+ entries
667
+ };
668
+ }
669
+ function createChannelConfigurationService(storage) {
670
+ const getState = async () => {
671
+ const loaded = await storage.load();
672
+ return coerceState(loaded);
673
+ };
674
+ const saveState = async (state) => {
675
+ await storage.save({
676
+ schemaVersion: 1,
677
+ entries: state.entries
678
+ });
679
+ };
680
+ const get = async (key) => {
681
+ const normalizedKey = key.trim();
682
+ const state = await getState();
683
+ return state.entries[normalizedKey];
684
+ };
685
+ const set = async (input) => {
686
+ const normalizedKey = input.key.trim();
687
+ const keyError = validateConfigKey(normalizedKey);
688
+ if (keyError) {
689
+ throw new Error(keyError);
690
+ }
691
+ const valueError = validateConfigValue(input.value);
692
+ if (valueError) {
693
+ throw new Error(valueError);
694
+ }
695
+ const state = await getState();
696
+ const nextEntry = {
697
+ key: normalizedKey,
698
+ value: input.value,
699
+ scope: "conversation",
700
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
701
+ updatedBy: toOptionalString(input.updatedBy),
702
+ source: toOptionalString(input.source),
703
+ expiresAt: toOptionalString(input.expiresAt)
704
+ };
705
+ state.entries[normalizedKey] = nextEntry;
706
+ await saveState(state);
707
+ return nextEntry;
708
+ };
709
+ const unset = async (key) => {
710
+ const normalizedKey = key.trim();
711
+ const state = await getState();
712
+ if (!state.entries[normalizedKey]) {
713
+ return false;
714
+ }
715
+ delete state.entries[normalizedKey];
716
+ await saveState(state);
717
+ return true;
718
+ };
719
+ const list = async (options = {}) => {
720
+ const state = await getState();
721
+ const prefix = options.prefix?.trim();
722
+ return Object.values(state.entries).filter((entry) => prefix ? entry.key.startsWith(prefix) : true).sort((a, b) => a.key.localeCompare(b.key));
723
+ };
724
+ const resolve = async (key) => {
725
+ const entry = await get(key);
726
+ return entry?.value;
727
+ };
728
+ const resolveValues = async (options = {}) => {
729
+ const keys = Array.isArray(options.keys) ? options.keys.map((entry) => entry.trim()).filter((entry) => entry.length > 0) : void 0;
730
+ const entries = options.prefix ? await list({ prefix: options.prefix }) : await list({});
731
+ const filtered = keys ? entries.filter((entry) => keys.includes(entry.key)) : entries;
732
+ const resolved = {};
733
+ for (const entry of filtered) {
734
+ resolved[entry.key] = entry.value;
735
+ }
736
+ return resolved;
737
+ };
738
+ return {
739
+ get,
740
+ set,
741
+ unset,
742
+ list,
743
+ resolve,
744
+ resolveValues
745
+ };
746
+ }
747
+
748
+ // src/chat/runtime/thread-state.ts
749
+ function threadStateKey(threadId) {
750
+ return `thread-state:${threadId}`;
751
+ }
752
+ function channelStateKey(channelId) {
753
+ return `channel-state:${channelId}`;
754
+ }
755
+ function buildThreadStatePayload(patch) {
756
+ const payload = {};
757
+ if (patch.artifacts) {
758
+ Object.assign(payload, buildArtifactStatePatch(patch.artifacts));
759
+ }
760
+ if (patch.conversation) {
761
+ Object.assign(payload, buildConversationStatePatch(patch.conversation));
762
+ }
763
+ if (patch.sandboxId !== void 0) {
764
+ payload.app_sandbox_id = patch.sandboxId;
765
+ }
766
+ if (patch.sandboxDependencyProfileHash !== void 0) {
767
+ payload.app_sandbox_dependency_profile_hash = patch.sandboxDependencyProfileHash;
768
+ }
769
+ return payload;
770
+ }
771
+ function mergeArtifactsState(artifacts, patch) {
772
+ if (!patch) {
773
+ return artifacts;
774
+ }
775
+ return {
776
+ ...artifacts,
777
+ ...patch,
778
+ listColumnMap: {
779
+ ...artifacts.listColumnMap,
780
+ ...patch.listColumnMap
781
+ }
782
+ };
783
+ }
784
+ function getPersistedSandboxState(state) {
785
+ return {
786
+ sandboxId: toOptionalString(state.app_sandbox_id),
787
+ sandboxDependencyProfileHash: toOptionalString(
788
+ state.app_sandbox_dependency_profile_hash
789
+ )
790
+ };
791
+ }
792
+ async function persistThreadState(thread, patch) {
793
+ const payload = buildThreadStatePayload(patch);
794
+ if (Object.keys(payload).length === 0) {
795
+ return;
796
+ }
797
+ await thread.setState(payload);
798
+ }
799
+ async function getPersistedThreadState(threadId) {
800
+ const stateAdapter = getStateAdapter();
801
+ await stateAdapter.connect();
802
+ return await stateAdapter.get(
803
+ threadStateKey(threadId)
804
+ ) ?? {};
805
+ }
806
+ async function getPersistedChannelState(channelId) {
807
+ const stateAdapter = getStateAdapter();
808
+ await stateAdapter.connect();
809
+ return await stateAdapter.get(
810
+ channelStateKey(channelId)
811
+ ) ?? {};
812
+ }
813
+ async function persistThreadStateById(threadId, patch) {
814
+ const payload = buildThreadStatePayload(patch);
815
+ if (Object.keys(payload).length === 0) {
816
+ return;
817
+ }
818
+ const stateAdapter = getStateAdapter();
819
+ await stateAdapter.connect();
820
+ const key = threadStateKey(threadId);
821
+ const existing = await stateAdapter.get(key) ?? {};
822
+ await stateAdapter.set(
823
+ key,
824
+ { ...existing, ...payload },
825
+ JUNIOR_THREAD_STATE_TTL_MS
826
+ );
827
+ }
828
+ function getChannelConfigurationService(thread) {
829
+ const channel = thread.channel;
830
+ return createChannelConfigurationService({
831
+ load: async () => channel.state,
832
+ save: async (state) => {
833
+ await channel.setState({
834
+ configuration: state
835
+ });
836
+ }
837
+ });
838
+ }
839
+ function getChannelConfigurationServiceById(channelId) {
840
+ return createChannelConfigurationService({
841
+ load: async () => await getPersistedChannelState(channelId),
842
+ save: async (state) => {
843
+ const stateAdapter = getStateAdapter();
844
+ await stateAdapter.connect();
845
+ const key = channelStateKey(channelId);
846
+ const existing = await stateAdapter.get(key) ?? {};
847
+ await stateAdapter.set(
848
+ key,
849
+ { ...existing, configuration: state },
850
+ JUNIOR_THREAD_STATE_TTL_MS
851
+ );
852
+ }
853
+ });
854
+ }
855
+
856
+ // src/chat/services/pending-auth.ts
857
+ var AUTH_LINK_REUSE_WINDOW_MS = 10 * 60 * 1e3;
858
+ var NON_REQUEST_SKIPPED_REASON_PREFIXES = [
859
+ "directed_to_other_party:",
860
+ "side_conversation:"
861
+ ];
862
+ function isSkippedNonRequest(reason) {
863
+ return NON_REQUEST_SKIPPED_REASON_PREFIXES.some(
864
+ (prefix) => reason?.startsWith(prefix)
865
+ );
866
+ }
867
+ function canReusePendingAuthLink(args) {
868
+ const { pendingAuth } = args;
869
+ if (!pendingAuth) {
870
+ return false;
871
+ }
872
+ return pendingAuth.kind === args.kind && pendingAuth.provider === args.provider && pendingAuth.requesterId === args.requesterId && pendingAuth.scope === args.scope && pendingAuth.sessionId === args.sessionId && pendingAuth.linkSentAtMs + AUTH_LINK_REUSE_WINDOW_MS > (args.nowMs ?? Date.now());
873
+ }
874
+ function getConversationPendingAuth(args) {
875
+ const pendingAuth = args.conversation.processing.pendingAuth;
876
+ if (!pendingAuth) {
877
+ return void 0;
878
+ }
879
+ if (pendingAuth.kind !== args.kind || pendingAuth.provider !== args.provider || pendingAuth.requesterId !== args.requesterId || pendingAuth.scope !== args.scope) {
880
+ return void 0;
881
+ }
882
+ return pendingAuth;
883
+ }
884
+ function clearPendingAuth(conversation, sessionId) {
885
+ if (!conversation.processing.pendingAuth) {
886
+ return;
887
+ }
888
+ if (sessionId && conversation.processing.pendingAuth.sessionId !== sessionId) {
889
+ return;
890
+ }
891
+ conversation.processing.pendingAuth = void 0;
892
+ }
893
+ async function applyPendingAuthUpdate(args) {
894
+ const previousPendingAuth = args.conversation.processing.pendingAuth;
895
+ args.conversation.processing.pendingAuth = args.nextPendingAuth;
896
+ if (previousPendingAuth && previousPendingAuth.sessionId !== args.nextPendingAuth.sessionId && args.conversationId) {
897
+ await abandonAgentTurnSessionRecord({
898
+ conversationId: args.conversationId,
899
+ sessionId: previousPendingAuth.sessionId,
900
+ errorMessage: "Abandoned by a newer auth-blocked request in the same conversation."
901
+ });
902
+ }
903
+ }
904
+ function isPendingAuthLatestRequest(conversation, pendingAuth) {
905
+ for (let index = conversation.messages.length - 1; index >= 0; index -= 1) {
906
+ const message = conversation.messages[index];
907
+ if (message?.role !== "user") {
908
+ continue;
909
+ }
910
+ if (message.author?.isBot) {
911
+ continue;
912
+ }
913
+ if (isSkippedNonRequest(message.meta?.skippedReason)) {
914
+ continue;
915
+ }
916
+ return buildDeterministicTurnId(message.id) === pendingAuth.sessionId;
917
+ }
918
+ return false;
919
+ }
920
+
921
+ export {
922
+ buildDeterministicTurnId,
923
+ CooperativeTurnYieldError,
924
+ isCooperativeTurnYieldError,
925
+ TurnInputCommitLostError,
926
+ isTurnInputCommitLostError,
927
+ TurnInputDeferredError,
928
+ isTurnInputDeferredError,
929
+ startActiveTurn,
930
+ markTurnClosed,
931
+ markTurnCompleted,
932
+ markTurnFailed,
933
+ hasAgentTurnUsage,
934
+ addAgentTurnUsage,
935
+ loadTurnSessionRecord,
936
+ persistRunningSessionRecord,
937
+ persistCompletedSessionRecord,
938
+ completeDeliveredTurn,
939
+ persistAuthPauseSessionRecord,
940
+ persistTimeoutSessionRecord,
941
+ persistYieldSessionRecord,
942
+ canReusePendingAuthLink,
943
+ getConversationPendingAuth,
944
+ clearPendingAuth,
945
+ applyPendingAuthUpdate,
946
+ isPendingAuthLatestRequest,
947
+ coerceThreadArtifactsState,
948
+ mergeArtifactsState,
949
+ getPersistedSandboxState,
950
+ persistThreadState,
951
+ getPersistedThreadState,
952
+ persistThreadStateById,
953
+ getChannelConfigurationService,
954
+ getChannelConfigurationServiceById
955
+ };