@sentry/junior 0.108.0 → 0.110.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.
- package/dist/{agent-hooks-NU5HK3PS.js → agent-hooks-ELT4ODFF.js} +12 -13
- package/dist/api/conversations/access.d.ts +9 -0
- package/dist/api/conversations/aggregate.d.ts +12 -1
- package/dist/api/conversations/archive.d.ts +3 -5
- package/dist/api/conversations/detail.d.ts +156 -7
- package/dist/api/conversations/events.d.ts +2 -2
- package/dist/api/conversations/list.d.ts +57 -6
- package/dist/api/conversations/projection.d.ts +6 -7
- package/dist/api/conversations/reporting.d.ts +10 -4
- package/dist/api/conversations/routes.d.ts +2 -1
- package/dist/api/conversations/shared.d.ts +1 -1
- package/dist/api/conversations/stats.d.ts +37 -6
- package/dist/api/conversations/stats.query.d.ts +1 -1
- package/dist/api/conversations/usage.d.ts +9 -0
- package/dist/api/http.d.ts +7 -0
- package/dist/api/locations/detail.d.ts +102 -6
- package/dist/api/locations/list.d.ts +43 -5
- package/dist/api/locations/query.d.ts +4 -2
- package/dist/api/locations/routes.d.ts +2 -1
- package/dist/api/people/list.d.ts +28 -6
- package/dist/api/people/list.query.d.ts +1 -1
- package/dist/api/people/profile.d.ts +96 -7
- package/dist/api/people/profile.query.d.ts +4 -2
- package/dist/api/people/routes.d.ts +2 -1
- package/dist/api/people/shared.d.ts +1219 -2
- package/dist/api/route.d.ts +18 -4
- package/dist/api/schema/common.d.ts +6 -0
- package/dist/api/{conversations/schema.d.ts → schema/conversation.d.ts} +88 -9
- package/dist/api/{locations/schema.d.ts → schema/location.d.ts} +5 -0
- package/dist/api/{people/schema.d.ts → schema/person.d.ts} +37 -45
- package/dist/api/schema.d.ts +8 -22
- package/dist/api/schema.js +10 -2
- package/dist/api.d.ts +5 -1
- package/dist/api.js +838 -369
- package/dist/app.d.ts +1 -0
- package/dist/app.js +1564 -486
- package/dist/catalog-runtime-4GI22PXK.js +16 -0
- package/dist/chat/agent/resume.d.ts +11 -12
- package/dist/chat/conversations/history.d.ts +3 -0
- package/dist/chat/conversations/sql/privacy.d.ts +3 -15
- package/dist/chat/conversations/sql/store.d.ts +0 -7
- package/dist/chat/log-context.d.ts +40 -0
- package/dist/chat/logging.d.ts +3 -26
- package/dist/chat/pi/messages.d.ts +2 -2
- package/dist/chat/pi/sql-model-usage.d.ts +4 -1
- package/dist/chat/runtime/slack-resume.d.ts +2 -2
- package/dist/chat/services/auth-pause.d.ts +4 -0
- package/dist/chat/services/context-compaction.d.ts +1 -0
- package/dist/chat/services/turn-session-record.d.ts +0 -2
- package/dist/chat/slack/reply.d.ts +7 -19
- package/dist/chat/state/conversation.d.ts +1 -0
- package/dist/chat/task-execution/queue-signing.d.ts +10 -8
- package/dist/chat/task-execution/queue.d.ts +9 -7
- package/dist/chat/task-execution/slack-work.d.ts +6 -6
- package/dist/{chunk-UD6THJ2I.js → chunk-2T7TIEXI.js} +197 -12
- package/dist/{chunk-CEA3A3UA.js → chunk-2ZTTXTSZ.js} +24 -1
- package/dist/{chunk-XKB7LGIW.js → chunk-3S7YYHBI.js} +3 -139
- package/dist/chunk-3TV7OEHL.js +10 -0
- package/dist/{chunk-A5CO2EHL.js → chunk-3UBQI73J.js} +11 -15
- package/dist/{chunk-7FBGKXPE.js → chunk-42WRQLJ6.js} +10 -33
- package/dist/{chunk-TE4QHJH4.js → chunk-4QU44P7Q.js} +135 -595
- package/dist/{chunk-RT5BUHR5.js → chunk-6Y5L4BOM.js} +3 -5
- package/dist/{chunk-VIXFG2VC.js → chunk-C4MZ3GP5.js} +1 -2
- package/dist/{chunk-3RGQLX2F.js → chunk-C5XAFTHY.js} +1011 -29
- package/dist/{chunk-PUAMO4PI.js → chunk-FPK7XY3F.js} +139 -99
- package/dist/{chunk-H3QYZL7K.js → chunk-GK47NBDE.js} +28 -3
- package/dist/{chunk-O24R4DCK.js → chunk-IYKPU7H6.js} +94 -56
- package/dist/chunk-JQFJO5WH.js +477 -0
- package/dist/{chunk-VH6KWKG2.js → chunk-L5XQPJ7T.js} +3 -3
- package/dist/{chunk-2XXEKR44.js → chunk-MIAKQNYX.js} +43 -31
- package/dist/{chunk-KPMPQ6AA.js → chunk-RHHRKSPI.js} +249 -223
- package/dist/{chunk-YT72TOEK.js → chunk-SBOBTS27.js} +2 -2
- package/dist/{chunk-B5I5LMSP.js → chunk-W6RJZG7F.js} +5 -7
- package/dist/chunk-W75ZPAGG.js +44 -0
- package/dist/{chunk-SS67LUOK.js → chunk-WNOVRQ67.js} +6 -7
- package/dist/{chunk-YIPD3L6L.js → chunk-Y3H2DN6F.js} +8 -10
- package/dist/{chunk-DY7TRYB5.js → chunk-Y5FK3CNG.js} +1 -1
- package/dist/chunk-ZKIOWEFL.js +125 -0
- package/dist/cli/chat.js +23 -24
- package/dist/cli/check.js +9 -7
- package/dist/cli/plugins.js +16 -17
- package/dist/cli/snapshot-warmup.js +11 -10
- package/dist/cli/upgrade.js +314 -3505
- package/dist/db/db.d.ts +1 -1
- package/dist/db/schema/conversations.d.ts +17 -0
- package/dist/db/schema.d.ts +17 -0
- package/dist/{db-AMRBAT5D.js → db-Y6W6CWWW.js} +8 -7
- package/dist/instrumentation.js +4 -3
- package/dist/nitro.js +4 -4
- package/dist/reporting-schema.d.ts +46 -0
- package/dist/{runner-TQH5GAJ4.js → runner-BBFV5GLR.js} +17 -21
- package/dist/{skills-ITNHBARB.js → skills-AR4AF32L.js} +8 -6
- package/dist/{validation-AGQ46ZGV.js → validation-FBIEPTC2.js} +8 -6
- package/dist/version.d.ts +2 -0
- package/dist/version.js +7 -0
- package/migrations/0006_drop_legacy_conversation_messages.sql +1 -0
- package/migrations/0007_thick_sugar_man.sql +23 -0
- package/migrations/README.md +12 -9
- package/migrations/meta/0006_snapshot.json +948 -0
- package/migrations/meta/0007_snapshot.json +1013 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +9 -5
- package/dist/catalog-runtime-FOFNPR3P.js +0 -14
- package/dist/chunk-AHJR2IFF.js +0 -115
- package/dist/chunk-B7PUBQQM.js +0 -53
- package/dist/chunk-G3E7SCME.js +0 -28
- package/dist/chunk-J3B3FPP2.js +0 -1061
- package/dist/chunk-OB42YVAE.js +0 -16
- package/dist/chunk-TWINAEZQ.js +0 -1283
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
buildConversationStatePatch,
|
|
5
|
-
getAgentTurnSessionRecord,
|
|
6
|
-
getAgentTurnSessionRecordForResume,
|
|
7
|
-
upsertAgentTurnSessionRecord
|
|
8
|
-
} from "./chunk-J3B3FPP2.js";
|
|
9
|
-
import {
|
|
10
|
-
addAgentTurnUsage
|
|
2
|
+
addAgentTurnUsage,
|
|
3
|
+
agentTurnUsageSchema
|
|
11
4
|
} from "./chunk-MU6HHZEN.js";
|
|
12
5
|
import {
|
|
13
6
|
getStateAdapter
|
|
14
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GK47NBDE.js";
|
|
15
8
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
contextProvenance,
|
|
10
|
+
createSqlConversationEventStore,
|
|
11
|
+
getConversationEventStore,
|
|
12
|
+
getConversationStore,
|
|
13
|
+
getSqlExecutor,
|
|
14
|
+
instructionActors,
|
|
15
|
+
instructionProvenanceFor,
|
|
16
|
+
sanitizePostgresJson,
|
|
17
|
+
withConversationEventLock
|
|
18
|
+
} from "./chunk-4QU44P7Q.js";
|
|
18
19
|
import {
|
|
19
20
|
sleep
|
|
20
21
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -23,22 +24,343 @@ import {
|
|
|
23
24
|
escapeXml,
|
|
24
25
|
getPiMessageRole,
|
|
25
26
|
resolveGatewayModel,
|
|
27
|
+
retainRuntimeTurnContext,
|
|
26
28
|
standardModelId,
|
|
29
|
+
stripRuntimeTurnContext,
|
|
27
30
|
trimTrailingAssistantMessages
|
|
28
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-WNOVRQ67.js";
|
|
32
|
+
import {
|
|
33
|
+
toStoredSlackActor
|
|
34
|
+
} from "./chunk-C4MZ3GP5.js";
|
|
29
35
|
import {
|
|
30
36
|
getActiveTraceId,
|
|
31
37
|
logException,
|
|
32
38
|
logWarn,
|
|
33
39
|
setSpanAttributes
|
|
34
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-IYKPU7H6.js";
|
|
35
41
|
import {
|
|
36
42
|
isRecord,
|
|
43
|
+
parseSlackMessageTs,
|
|
44
|
+
toOptionalNumber,
|
|
37
45
|
toOptionalString
|
|
38
|
-
} from "./chunk-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} from "
|
|
46
|
+
} from "./chunk-42WRQLJ6.js";
|
|
47
|
+
|
|
48
|
+
// src/chat/conversations/projection.ts
|
|
49
|
+
import { isDeepStrictEqual } from "util";
|
|
50
|
+
|
|
51
|
+
// src/chat/pi/messages.ts
|
|
52
|
+
import { z } from "zod";
|
|
53
|
+
var piMessageSchema = z.object({
|
|
54
|
+
role: z.string()
|
|
55
|
+
}).passthrough().transform((value) => value);
|
|
56
|
+
var piContentMessageSchema = z.object({
|
|
57
|
+
content: z.array(z.unknown()),
|
|
58
|
+
role: z.string().min(1)
|
|
59
|
+
}).passthrough().transform((value) => value);
|
|
60
|
+
|
|
61
|
+
// src/chat/pi/conversation-events.ts
|
|
62
|
+
function authorizationObservationMessage(data, createdAtMs) {
|
|
63
|
+
const label = data.kind === "mcp" ? "MCP authorization" : "Authorization";
|
|
64
|
+
return piMessageSchema.parse({
|
|
65
|
+
role: "user",
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: `${label} completed for provider "${data.provider}". Continue the blocked request and retry the provider operation if needed.`
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
timestamp: createdAtMs
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function messageEventProvenance(data) {
|
|
76
|
+
return data.provenance ?? contextProvenance;
|
|
77
|
+
}
|
|
78
|
+
function durableMessages(message) {
|
|
79
|
+
return stripRuntimeTurnContext([piMessageSchema.parse(message)]);
|
|
80
|
+
}
|
|
81
|
+
function projectConversationEvents(events, options) {
|
|
82
|
+
const messages = [];
|
|
83
|
+
const provenance = [];
|
|
84
|
+
const seqs = [];
|
|
85
|
+
let modelProfile = "standard";
|
|
86
|
+
let modelId;
|
|
87
|
+
for (const event of events) {
|
|
88
|
+
if (options?.maxSeq !== void 0 && event.seq > options.maxSeq) break;
|
|
89
|
+
if (event.data.type === "unknown") {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Unsupported conversation event "${event.data.originalType}" at seq ${event.seq} (schema version ${event.schemaVersion})`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (event.data.type === "compaction" || event.data.type === "handoff" || event.data.type === "rollback") {
|
|
95
|
+
modelProfile = event.data.modelProfile;
|
|
96
|
+
modelId = event.data.modelId;
|
|
97
|
+
for (const replacement of event.data.replacementHistory) {
|
|
98
|
+
for (const message of durableMessages(replacement.message)) {
|
|
99
|
+
messages.push(message);
|
|
100
|
+
provenance.push(replacement.provenance ?? contextProvenance);
|
|
101
|
+
seqs.push(replacement.sourceEventSeq ?? event.seq);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (event.data.type === "agent_step") {
|
|
107
|
+
for (const message of durableMessages(event.data.message)) {
|
|
108
|
+
messages.push(message);
|
|
109
|
+
provenance.push(messageEventProvenance(event.data));
|
|
110
|
+
seqs.push(event.seq);
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (event.data.type === "authorization_completed") {
|
|
115
|
+
messages.push(
|
|
116
|
+
authorizationObservationMessage(event.data, event.createdAtMs)
|
|
117
|
+
);
|
|
118
|
+
provenance.push(contextProvenance);
|
|
119
|
+
seqs.push(event.seq);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { messages, provenance, seqs, modelProfile, modelId };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/chat/conversations/projection.ts
|
|
126
|
+
function connectedMcpProvidersFromEvents(events) {
|
|
127
|
+
const providers = /* @__PURE__ */ new Set();
|
|
128
|
+
for (const event of events) {
|
|
129
|
+
if (event.data.type === "mcp_provider_connected") {
|
|
130
|
+
providers.add(event.data.provider);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return [...providers].sort((left, right) => left.localeCompare(right));
|
|
134
|
+
}
|
|
135
|
+
function isUserMessage(message) {
|
|
136
|
+
return message.role === "user";
|
|
137
|
+
}
|
|
138
|
+
function countMatchingPrefix(left, right) {
|
|
139
|
+
const limit = Math.min(left.length, right.length);
|
|
140
|
+
for (let index = 0; index < limit; index += 1) {
|
|
141
|
+
if (!isDeepStrictEqual(left[index], right[index])) {
|
|
142
|
+
return index;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return limit;
|
|
146
|
+
}
|
|
147
|
+
function normalizeDurableMessage(message) {
|
|
148
|
+
return piMessageSchema.parse(
|
|
149
|
+
JSON.parse(JSON.stringify(sanitizePostgresJson(message)))
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
function resolveCommitProvenance(args) {
|
|
153
|
+
if (args.explicitProvenance) {
|
|
154
|
+
if (args.explicitProvenance.length !== args.nextMessages.length) {
|
|
155
|
+
throw new Error("commit provenance must align one-to-one with messages");
|
|
156
|
+
}
|
|
157
|
+
return args.explicitProvenance;
|
|
158
|
+
}
|
|
159
|
+
const matchingPrefix = args.matchingPrefix;
|
|
160
|
+
const provenance = args.nextMessages.map(
|
|
161
|
+
(_, index) => index < matchingPrefix ? args.existing.provenance[index] ?? contextProvenance : contextProvenance
|
|
162
|
+
);
|
|
163
|
+
if (args.newMessageProvenance) {
|
|
164
|
+
for (let index = args.nextMessages.length - 1; index >= matchingPrefix; index -= 1) {
|
|
165
|
+
if (isUserMessage(args.nextMessages[index])) {
|
|
166
|
+
provenance[index] = args.newMessageProvenance;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (args.trailingMessageProvenance) {
|
|
172
|
+
if (args.trailingMessageProvenance.length > provenance.length) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
"trailing commit provenance cannot exceed committed messages"
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
const newMessageCount = args.nextMessages.length - matchingPrefix;
|
|
178
|
+
if (args.trailingMessageProvenance.length > newMessageCount) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
"trailing commit provenance must align to newly committed messages"
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const start = provenance.length - args.trailingMessageProvenance.length;
|
|
184
|
+
args.trailingMessageProvenance.forEach((entry, offset) => {
|
|
185
|
+
provenance[start + offset] = entry;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return provenance;
|
|
189
|
+
}
|
|
190
|
+
async function loadProjection(args) {
|
|
191
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
192
|
+
args.conversationId
|
|
193
|
+
);
|
|
194
|
+
return projectConversationEvents(events).messages;
|
|
195
|
+
}
|
|
196
|
+
async function loadConversationProjection(args) {
|
|
197
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
198
|
+
args.conversationId
|
|
199
|
+
);
|
|
200
|
+
return projectConversationEvents(events);
|
|
201
|
+
}
|
|
202
|
+
async function openConversationProjection(args) {
|
|
203
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
204
|
+
args.conversationId
|
|
205
|
+
);
|
|
206
|
+
return projectConversationEvents(events);
|
|
207
|
+
}
|
|
208
|
+
async function loadTurnProjection(args) {
|
|
209
|
+
const eventStore = getConversationEventStore();
|
|
210
|
+
if (args.committedSeq < 0) {
|
|
211
|
+
return projectConversationEvents(
|
|
212
|
+
await eventStore.loadCurrentHistory(args.conversationId)
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
const historyEvents = await eventStore.loadHistoryContaining(
|
|
216
|
+
args.conversationId,
|
|
217
|
+
args.committedSeq,
|
|
218
|
+
args.includeTail ? void 0 : args.committedSeq
|
|
219
|
+
);
|
|
220
|
+
if (!historyEvents) {
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
return projectConversationEvents(historyEvents);
|
|
224
|
+
}
|
|
225
|
+
async function loadConnectedMcpProviders(args) {
|
|
226
|
+
const events = await getConversationEventStore().loadCurrentHistory(
|
|
227
|
+
args.conversationId
|
|
228
|
+
);
|
|
229
|
+
return connectedMcpProvidersFromEvents(events);
|
|
230
|
+
}
|
|
231
|
+
function messageTimestamp(message) {
|
|
232
|
+
const timestamp = message.timestamp;
|
|
233
|
+
return typeof timestamp === "number" ? timestamp : Date.now();
|
|
234
|
+
}
|
|
235
|
+
async function commitMessages(args) {
|
|
236
|
+
const executor = args.executor ?? getSqlExecutor();
|
|
237
|
+
return await withConversationEventLock(
|
|
238
|
+
executor,
|
|
239
|
+
args.conversationId,
|
|
240
|
+
async () => executor.transaction(
|
|
241
|
+
async () => await commitMessagesLocked(args, executor)
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
async function commitMessagesLocked(args, executor) {
|
|
246
|
+
const eventStore = createSqlConversationEventStore(executor);
|
|
247
|
+
const currentEvents = await eventStore.loadCurrentHistory(
|
|
248
|
+
args.conversationId
|
|
249
|
+
);
|
|
250
|
+
const current = projectConversationEvents(currentEvents);
|
|
251
|
+
const nextLocalMessages = stripRuntimeTurnContext(args.messages).map(
|
|
252
|
+
normalizeDurableMessage
|
|
253
|
+
);
|
|
254
|
+
const matchingPrefix = countMatchingPrefix(
|
|
255
|
+
current.messages,
|
|
256
|
+
nextLocalMessages
|
|
257
|
+
);
|
|
258
|
+
const nextLocalProvenance = resolveCommitProvenance({
|
|
259
|
+
existing: current,
|
|
260
|
+
nextMessages: nextLocalMessages,
|
|
261
|
+
matchingPrefix,
|
|
262
|
+
...args.provenance ? { explicitProvenance: args.provenance } : {},
|
|
263
|
+
...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {},
|
|
264
|
+
...args.newMessageProvenance ? { newMessageProvenance: args.newMessageProvenance } : {}
|
|
265
|
+
});
|
|
266
|
+
if (matchingPrefix === current.messages.length) {
|
|
267
|
+
const newMessages = nextLocalMessages.slice(matchingPrefix);
|
|
268
|
+
await eventStore.append(
|
|
269
|
+
args.conversationId,
|
|
270
|
+
newMessages.map((message, index) => ({
|
|
271
|
+
data: {
|
|
272
|
+
type: "agent_step",
|
|
273
|
+
message,
|
|
274
|
+
provenance: nextLocalProvenance[matchingPrefix + index]
|
|
275
|
+
},
|
|
276
|
+
createdAtMs: messageTimestamp(message)
|
|
277
|
+
}))
|
|
278
|
+
);
|
|
279
|
+
} else {
|
|
280
|
+
throw new Error(
|
|
281
|
+
`Agent history for ${args.conversationId} changed before its committed boundary`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
const committedEvents = await eventStore.loadCurrentHistory(
|
|
285
|
+
args.conversationId
|
|
286
|
+
);
|
|
287
|
+
const committed = projectConversationEvents(committedEvents);
|
|
288
|
+
return {
|
|
289
|
+
committedSeq: committedEvents.at(-1)?.seq ?? -1,
|
|
290
|
+
historyVersion: committedEvents.at(-1)?.historyVersion ?? 0,
|
|
291
|
+
messageSeqs: committed.seqs,
|
|
292
|
+
messages: nextLocalMessages,
|
|
293
|
+
provenance: nextLocalProvenance
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async function recordMcpProviderConnected(args) {
|
|
297
|
+
const eventStore = getConversationEventStore();
|
|
298
|
+
const events = await eventStore.loadCurrentHistory(args.conversationId);
|
|
299
|
+
if (connectedMcpProvidersFromEvents(events).includes(args.provider)) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
await eventStore.append(args.conversationId, [
|
|
303
|
+
{
|
|
304
|
+
data: { type: "mcp_provider_connected", provider: args.provider },
|
|
305
|
+
createdAtMs: Date.now()
|
|
306
|
+
}
|
|
307
|
+
]);
|
|
308
|
+
}
|
|
309
|
+
async function recordAuthorizationRequested(args) {
|
|
310
|
+
const eventStore = getConversationEventStore();
|
|
311
|
+
const events = await eventStore.loadCurrentHistory(args.conversationId);
|
|
312
|
+
if (events.some(
|
|
313
|
+
(event) => event.data.type === "authorization_requested" && event.data.authorizationId === args.authorizationId
|
|
314
|
+
)) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
await eventStore.append(args.conversationId, [
|
|
318
|
+
{
|
|
319
|
+
data: {
|
|
320
|
+
type: "authorization_requested",
|
|
321
|
+
kind: args.kind,
|
|
322
|
+
provider: args.provider,
|
|
323
|
+
actorId: args.actorId,
|
|
324
|
+
authorizationId: args.authorizationId,
|
|
325
|
+
delivery: args.delivery
|
|
326
|
+
},
|
|
327
|
+
createdAtMs: Date.now()
|
|
328
|
+
}
|
|
329
|
+
]);
|
|
330
|
+
}
|
|
331
|
+
async function recordAuthorizationCompleted(args) {
|
|
332
|
+
const eventStore = getConversationEventStore();
|
|
333
|
+
const events = await eventStore.loadCurrentHistory(args.conversationId);
|
|
334
|
+
if (events.some(
|
|
335
|
+
(event) => event.data.type === "authorization_completed" && event.data.authorizationId === args.authorizationId
|
|
336
|
+
)) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
await eventStore.append(args.conversationId, [
|
|
340
|
+
{
|
|
341
|
+
data: {
|
|
342
|
+
type: "authorization_completed",
|
|
343
|
+
kind: args.kind,
|
|
344
|
+
provider: args.provider,
|
|
345
|
+
actorId: args.actorId,
|
|
346
|
+
authorizationId: args.authorizationId
|
|
347
|
+
},
|
|
348
|
+
createdAtMs: Date.now()
|
|
349
|
+
}
|
|
350
|
+
]);
|
|
351
|
+
}
|
|
352
|
+
async function recordToolExecutionStarted(args) {
|
|
353
|
+
await getConversationEventStore().append(args.conversationId, [
|
|
354
|
+
{
|
|
355
|
+
data: {
|
|
356
|
+
type: "tool_execution_started",
|
|
357
|
+
toolCallId: args.toolCallId,
|
|
358
|
+
toolName: args.toolName
|
|
359
|
+
},
|
|
360
|
+
createdAtMs: args.createdAtMs ?? Date.now()
|
|
361
|
+
}
|
|
362
|
+
]);
|
|
363
|
+
}
|
|
42
364
|
|
|
43
365
|
// src/chat/state/turn-id.ts
|
|
44
366
|
function buildDeterministicTurnId(messageId) {
|
|
@@ -145,6 +467,531 @@ async function persistWithRetry(persist) {
|
|
|
145
467
|
throw lastError;
|
|
146
468
|
}
|
|
147
469
|
|
|
470
|
+
// src/chat/state/turn-session.ts
|
|
471
|
+
import { THREAD_STATE_TTL_MS } from "chat";
|
|
472
|
+
import {
|
|
473
|
+
actorSchema,
|
|
474
|
+
destinationSchema,
|
|
475
|
+
sourceSchema
|
|
476
|
+
} from "@sentry/junior-plugin-api";
|
|
477
|
+
import { z as z2 } from "zod";
|
|
478
|
+
|
|
479
|
+
// src/chat/state/turn-session-keys.ts
|
|
480
|
+
var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
|
|
481
|
+
function agentTurnSessionKey(conversationId, sessionId) {
|
|
482
|
+
return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
|
|
483
|
+
}
|
|
484
|
+
function agentTurnSessionConversationIndexKey(conversationId) {
|
|
485
|
+
return `${AGENT_TURN_SESSION_PREFIX}:conversation:${conversationId}:index`;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/chat/state/turn-session.ts
|
|
489
|
+
var AGENT_TURN_SESSION_INDEX_KEY = `${AGENT_TURN_SESSION_PREFIX}:index`;
|
|
490
|
+
var AGENT_TURN_SESSION_INDEX_MAX_LENGTH = 5e3;
|
|
491
|
+
var AGENT_TURN_SESSION_TTL_MS = THREAD_STATE_TTL_MS;
|
|
492
|
+
var agentTurnSessionStatusSchema = z2.enum([
|
|
493
|
+
"running",
|
|
494
|
+
"awaiting_resume",
|
|
495
|
+
"completed",
|
|
496
|
+
"failed",
|
|
497
|
+
"abandoned"
|
|
498
|
+
]);
|
|
499
|
+
var agentTurnSurfaceSchema = z2.enum([
|
|
500
|
+
"slack",
|
|
501
|
+
"api",
|
|
502
|
+
"scheduler",
|
|
503
|
+
"internal"
|
|
504
|
+
]);
|
|
505
|
+
var agentTurnResumeReasonSchema = z2.enum([
|
|
506
|
+
"timeout",
|
|
507
|
+
"auth",
|
|
508
|
+
"yield",
|
|
509
|
+
"retry"
|
|
510
|
+
]);
|
|
511
|
+
var nonNegativeNumberSchema = z2.number().finite().nonnegative();
|
|
512
|
+
var seqCursorSchema = z2.number().int().min(-1);
|
|
513
|
+
var agentTurnSessionSummarySchema = z2.object({
|
|
514
|
+
channelName: z2.string().min(1).optional(),
|
|
515
|
+
version: z2.number().int().nonnegative(),
|
|
516
|
+
conversationId: z2.string().min(1),
|
|
517
|
+
cumulativeDurationMs: nonNegativeNumberSchema,
|
|
518
|
+
cumulativeUsage: agentTurnUsageSchema.optional(),
|
|
519
|
+
destination: destinationSchema.optional(),
|
|
520
|
+
source: sourceSchema.optional(),
|
|
521
|
+
lastProgressAtMs: nonNegativeNumberSchema,
|
|
522
|
+
loadedSkillNames: z2.array(z2.string()).optional(),
|
|
523
|
+
modelId: z2.string().min(1).optional(),
|
|
524
|
+
reasoningLevel: z2.string().min(1).optional(),
|
|
525
|
+
actor: actorSchema.optional(),
|
|
526
|
+
resumeReason: agentTurnResumeReasonSchema.optional(),
|
|
527
|
+
resumedFromSliceId: z2.number().int().nonnegative().optional(),
|
|
528
|
+
sessionId: z2.string().min(1),
|
|
529
|
+
sliceId: z2.number().int().nonnegative(),
|
|
530
|
+
startedAtMs: nonNegativeNumberSchema,
|
|
531
|
+
state: agentTurnSessionStatusSchema,
|
|
532
|
+
surface: agentTurnSurfaceSchema.optional(),
|
|
533
|
+
traceId: z2.string().optional(),
|
|
534
|
+
updatedAtMs: nonNegativeNumberSchema
|
|
535
|
+
}).strict();
|
|
536
|
+
var storedAgentTurnSessionRecordSchema = agentTurnSessionSummarySchema.extend({
|
|
537
|
+
actors: z2.array(actorSchema).optional(),
|
|
538
|
+
committedSeq: seqCursorSchema,
|
|
539
|
+
historyVersion: z2.number().int().nonnegative().optional(),
|
|
540
|
+
errorMessage: z2.string().optional(),
|
|
541
|
+
turnStartSeq: seqCursorSchema.optional(),
|
|
542
|
+
runtimeContext: z2.array(piMessageSchema).optional()
|
|
543
|
+
}).strict();
|
|
544
|
+
function conversationExecutionFromSummary(summary) {
|
|
545
|
+
const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
|
|
546
|
+
return {
|
|
547
|
+
status,
|
|
548
|
+
runId: summary.sessionId,
|
|
549
|
+
updatedAtMs: summary.updatedAtMs
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function sessionLogActor(actor) {
|
|
553
|
+
return actor?.platform === "slack" ? toStoredSlackActor(actor) : void 0;
|
|
554
|
+
}
|
|
555
|
+
function parseAgentTurnSessionRecord(value) {
|
|
556
|
+
return storedAgentTurnSessionRecordSchema.parse(value);
|
|
557
|
+
}
|
|
558
|
+
function parseAgentTurnSessionSummary(value) {
|
|
559
|
+
return agentTurnSessionSummarySchema.parse(value);
|
|
560
|
+
}
|
|
561
|
+
async function appendAgentTurnSessionSummary(summary, ttlMs) {
|
|
562
|
+
const stateAdapter = getStateAdapter();
|
|
563
|
+
await Promise.all([
|
|
564
|
+
stateAdapter.appendToList(AGENT_TURN_SESSION_INDEX_KEY, summary, {
|
|
565
|
+
maxLength: AGENT_TURN_SESSION_INDEX_MAX_LENGTH,
|
|
566
|
+
ttlMs
|
|
567
|
+
}),
|
|
568
|
+
stateAdapter.appendToList(
|
|
569
|
+
agentTurnSessionConversationIndexKey(summary.conversationId),
|
|
570
|
+
summary,
|
|
571
|
+
{ ttlMs }
|
|
572
|
+
)
|
|
573
|
+
]);
|
|
574
|
+
}
|
|
575
|
+
async function recordConversationActivityMetadata(args) {
|
|
576
|
+
const conversationStore = args.conversationStore ?? getConversationStore();
|
|
577
|
+
const source = args.summary.destination?.platform === "local" ? "local" : args.summary.surface;
|
|
578
|
+
await conversationStore.recordActivity({
|
|
579
|
+
activityAtMs: args.summary.updatedAtMs,
|
|
580
|
+
channelName: args.summary.channelName,
|
|
581
|
+
conversationId: args.summary.conversationId,
|
|
582
|
+
destination: args.summary.destination,
|
|
583
|
+
nowMs: args.nowMs,
|
|
584
|
+
actor: sessionLogActor(args.summary.actor),
|
|
585
|
+
source,
|
|
586
|
+
visibility: args.destinationVisibility
|
|
587
|
+
});
|
|
588
|
+
await conversationStore.recordExecution({
|
|
589
|
+
channelName: args.summary.channelName,
|
|
590
|
+
conversationId: args.summary.conversationId,
|
|
591
|
+
createdAtMs: args.summary.startedAtMs,
|
|
592
|
+
destination: args.summary.destination,
|
|
593
|
+
execution: conversationExecutionFromSummary(args.summary),
|
|
594
|
+
lastActivityAtMs: args.summary.updatedAtMs,
|
|
595
|
+
metrics: {
|
|
596
|
+
durationMs: args.summary.cumulativeDurationMs,
|
|
597
|
+
...args.summary.cumulativeUsage ? { usage: args.summary.cumulativeUsage } : {}
|
|
598
|
+
},
|
|
599
|
+
actor: sessionLogActor(args.summary.actor),
|
|
600
|
+
source,
|
|
601
|
+
updatedAtMs: args.nowMs,
|
|
602
|
+
visibility: args.destinationVisibility
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
function materializeAgentTurnSessionRecord(stored, piProjection, turnStartMessageIndex, restoreVolatileContext = true) {
|
|
606
|
+
const piMessages = restoreVolatileContext && (stored.state === "running" || stored.state === "awaiting_resume") ? restoreRuntimeContext(piProjection.messages, stored.runtimeContext) : piProjection.messages;
|
|
607
|
+
return {
|
|
608
|
+
version: stored.version,
|
|
609
|
+
...stored.channelName ? { channelName: stored.channelName } : {},
|
|
610
|
+
conversationId: stored.conversationId,
|
|
611
|
+
sessionId: stored.sessionId,
|
|
612
|
+
sliceId: stored.sliceId,
|
|
613
|
+
state: stored.state,
|
|
614
|
+
startedAtMs: stored.startedAtMs,
|
|
615
|
+
lastProgressAtMs: stored.lastProgressAtMs,
|
|
616
|
+
updatedAtMs: stored.updatedAtMs,
|
|
617
|
+
piMessages,
|
|
618
|
+
piMessageProvenance: piProjection.provenance,
|
|
619
|
+
actors: stored.actors ?? instructionActors(piProjection.provenance),
|
|
620
|
+
cumulativeDurationMs: stored.cumulativeDurationMs,
|
|
621
|
+
...stored.destination ? { destination: stored.destination } : {},
|
|
622
|
+
...stored.source ? { source: stored.source } : {},
|
|
623
|
+
...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
|
|
624
|
+
...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
|
|
625
|
+
...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
|
|
626
|
+
...stored.loadedSkillNames ? { loadedSkillNames: stored.loadedSkillNames } : {},
|
|
627
|
+
...stored.modelId ? { modelId: stored.modelId } : {},
|
|
628
|
+
...stored.reasoningLevel ? { reasoningLevel: stored.reasoningLevel } : {},
|
|
629
|
+
...stored.actor ? { actor: stored.actor } : {},
|
|
630
|
+
...stored.resumedFromSliceId !== void 0 ? { resumedFromSliceId: stored.resumedFromSliceId } : {},
|
|
631
|
+
...stored.surface ? { surface: stored.surface } : {},
|
|
632
|
+
...stored.traceId ? { traceId: stored.traceId } : {},
|
|
633
|
+
...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function restoreRuntimeContext(messages, runtimeContext) {
|
|
637
|
+
if (!runtimeContext || runtimeContext.length === 0) return messages;
|
|
638
|
+
const restored = [...messages];
|
|
639
|
+
for (const runtimeMessage of runtimeContext) {
|
|
640
|
+
const runtime = runtimeMessage;
|
|
641
|
+
const targetIndex = restored.findIndex((message) => {
|
|
642
|
+
const candidate = message;
|
|
643
|
+
return candidate.role === "user" && candidate.timestamp === runtime.timestamp;
|
|
644
|
+
});
|
|
645
|
+
if (targetIndex < 0) {
|
|
646
|
+
restored.push(runtimeMessage);
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
const target = restored[targetIndex];
|
|
650
|
+
restored[targetIndex] = {
|
|
651
|
+
...restored[targetIndex],
|
|
652
|
+
content: [
|
|
653
|
+
...Array.isArray(runtime.content) ? runtime.content : [],
|
|
654
|
+
...Array.isArray(target.content) ? target.content : []
|
|
655
|
+
]
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
return restored;
|
|
659
|
+
}
|
|
660
|
+
async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
|
|
661
|
+
const stateAdapter = getStateAdapter();
|
|
662
|
+
await stateAdapter.connect();
|
|
663
|
+
const value = await stateAdapter.get(
|
|
664
|
+
agentTurnSessionKey(conversationId, sessionId)
|
|
665
|
+
);
|
|
666
|
+
return value == null ? void 0 : parseAgentTurnSessionRecord(value);
|
|
667
|
+
}
|
|
668
|
+
async function materializeStoredAgentTurnSessionRecord(conversationId, sessionId, followCurrentReplacement) {
|
|
669
|
+
const parsed = await getStoredAgentTurnSessionRecord(
|
|
670
|
+
conversationId,
|
|
671
|
+
sessionId
|
|
672
|
+
);
|
|
673
|
+
if (!parsed) {
|
|
674
|
+
return void 0;
|
|
675
|
+
}
|
|
676
|
+
const pinnedProjection = await loadTurnProjection({
|
|
677
|
+
conversationId,
|
|
678
|
+
committedSeq: parsed.committedSeq,
|
|
679
|
+
// Unfinished records include the current-epoch tail so parked input
|
|
680
|
+
// appended after the last safe boundary stays model-visible on resume.
|
|
681
|
+
includeTail: parsed.state === "running" || parsed.state === "awaiting_resume"
|
|
682
|
+
});
|
|
683
|
+
if (!pinnedProjection) {
|
|
684
|
+
return void 0;
|
|
685
|
+
}
|
|
686
|
+
const currentHistory = await getConversationEventStore().loadCurrentHistory(conversationId);
|
|
687
|
+
const currentHistoryVersion = currentHistory.at(-1)?.historyVersion ?? parsed.historyVersion ?? 0;
|
|
688
|
+
const followsReplacement = followCurrentReplacement && (parsed.state === "running" || parsed.state === "awaiting_resume") && parsed.historyVersion !== void 0 && parsed.historyVersion !== currentHistoryVersion;
|
|
689
|
+
const piProjection = followsReplacement ? projectConversationEvents(currentHistory) : pinnedProjection;
|
|
690
|
+
const turnStartMessageIndex = followsReplacement ? 0 : parsed.turnStartSeq === void 0 ? void 0 : piProjection.seqs.filter((seq) => seq <= parsed.turnStartSeq).length;
|
|
691
|
+
return materializeAgentTurnSessionRecord(
|
|
692
|
+
parsed,
|
|
693
|
+
piProjection,
|
|
694
|
+
turnStartMessageIndex,
|
|
695
|
+
!followsReplacement && (parsed.historyVersion === void 0 || parsed.historyVersion === currentHistoryVersion)
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
async function getAgentTurnSessionRecord(conversationId, sessionId) {
|
|
699
|
+
return await materializeStoredAgentTurnSessionRecord(
|
|
700
|
+
conversationId,
|
|
701
|
+
sessionId,
|
|
702
|
+
false
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
async function getAgentTurnSessionRecordForResume(conversationId, sessionId) {
|
|
706
|
+
return await materializeStoredAgentTurnSessionRecord(
|
|
707
|
+
conversationId,
|
|
708
|
+
sessionId,
|
|
709
|
+
true
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
function buildStoredRecord(args) {
|
|
713
|
+
const nowMs = Date.now();
|
|
714
|
+
return {
|
|
715
|
+
version: (args.previousVersion ?? 0) + 1,
|
|
716
|
+
...args.channelName ? { channelName: args.channelName } : {},
|
|
717
|
+
conversationId: args.conversationId,
|
|
718
|
+
sessionId: args.sessionId,
|
|
719
|
+
sliceId: args.sliceId,
|
|
720
|
+
state: args.state,
|
|
721
|
+
startedAtMs: args.startedAtMs ?? nowMs,
|
|
722
|
+
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
723
|
+
updatedAtMs: nowMs,
|
|
724
|
+
committedSeq: args.committedSeq,
|
|
725
|
+
...args.historyVersion !== void 0 ? { historyVersion: args.historyVersion } : {},
|
|
726
|
+
...args.turnStartSeq !== void 0 ? { turnStartSeq: args.turnStartSeq } : {},
|
|
727
|
+
...args.runtimeContext && args.runtimeContext.length > 0 ? { runtimeContext: args.runtimeContext } : {},
|
|
728
|
+
cumulativeDurationMs: args.cumulativeDurationMs,
|
|
729
|
+
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
730
|
+
...args.destination ? { destination: args.destination } : {},
|
|
731
|
+
...args.source ? { source: args.source } : {},
|
|
732
|
+
...args.actor ? { actor: args.actor } : {},
|
|
733
|
+
...args.actors ? { actors: args.actors } : {},
|
|
734
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
735
|
+
...args.modelId ? { modelId: args.modelId } : {},
|
|
736
|
+
...args.reasoningLevel ? { reasoningLevel: args.reasoningLevel } : {},
|
|
737
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
738
|
+
...args.errorMessage ? { errorMessage: args.errorMessage } : {},
|
|
739
|
+
...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
|
|
740
|
+
...args.surface ? { surface: args.surface } : {},
|
|
741
|
+
...args.traceId ? { traceId: args.traceId } : {}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
async function setStoredRecord(args) {
|
|
745
|
+
const stateAdapter = getStateAdapter();
|
|
746
|
+
await stateAdapter.connect();
|
|
747
|
+
await recordConversationActivityMetadata({
|
|
748
|
+
conversationStore: args.conversationStore,
|
|
749
|
+
destinationVisibility: args.destinationVisibility,
|
|
750
|
+
nowMs: Date.now(),
|
|
751
|
+
summary: args.record
|
|
752
|
+
});
|
|
753
|
+
await stateAdapter.set(
|
|
754
|
+
agentTurnSessionKey(args.record.conversationId, args.record.sessionId),
|
|
755
|
+
args.record,
|
|
756
|
+
args.ttlMs
|
|
757
|
+
);
|
|
758
|
+
const {
|
|
759
|
+
actors: _actors,
|
|
760
|
+
committedSeq: _committedSeq,
|
|
761
|
+
historyVersion: _historyVersion,
|
|
762
|
+
errorMessage: _errorMessage,
|
|
763
|
+
turnStartSeq: _turnStartSeq,
|
|
764
|
+
runtimeContext: _runtimeContext,
|
|
765
|
+
...summary
|
|
766
|
+
} = args.record;
|
|
767
|
+
await appendAgentTurnSessionSummary(summary, args.ttlMs);
|
|
768
|
+
return materializeAgentTurnSessionRecord(
|
|
769
|
+
args.record,
|
|
770
|
+
{
|
|
771
|
+
messages: [...args.piMessages],
|
|
772
|
+
provenance: [...args.piMessageProvenance]
|
|
773
|
+
},
|
|
774
|
+
args.turnStartMessageIndex
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
async function updateAgentTurnSessionState(args) {
|
|
778
|
+
const parsed = await getStoredAgentTurnSessionRecord(
|
|
779
|
+
args.existing.conversationId,
|
|
780
|
+
args.existing.sessionId
|
|
781
|
+
);
|
|
782
|
+
if (!parsed || parsed.version !== args.existing.version) {
|
|
783
|
+
return void 0;
|
|
784
|
+
}
|
|
785
|
+
return await setStoredRecord({
|
|
786
|
+
piMessages: args.existing.piMessages,
|
|
787
|
+
piMessageProvenance: args.existing.piMessageProvenance,
|
|
788
|
+
ttlMs: AGENT_TURN_SESSION_TTL_MS,
|
|
789
|
+
...args.existing.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.existing.turnStartMessageIndex } : {},
|
|
790
|
+
record: buildStoredRecord({
|
|
791
|
+
conversationId: args.existing.conversationId,
|
|
792
|
+
sessionId: args.existing.sessionId,
|
|
793
|
+
sliceId: args.existing.sliceId,
|
|
794
|
+
state: args.state,
|
|
795
|
+
committedSeq: parsed.committedSeq,
|
|
796
|
+
...parsed.historyVersion !== void 0 ? { historyVersion: parsed.historyVersion } : {},
|
|
797
|
+
...parsed.turnStartSeq !== void 0 ? { turnStartSeq: parsed.turnStartSeq } : {},
|
|
798
|
+
...parsed.runtimeContext ? { runtimeContext: parsed.runtimeContext } : {},
|
|
799
|
+
...parsed.channelName ? { channelName: parsed.channelName } : {},
|
|
800
|
+
startedAtMs: parsed.startedAtMs,
|
|
801
|
+
lastProgressAtMs: parsed.lastProgressAtMs,
|
|
802
|
+
previousVersion: parsed.version,
|
|
803
|
+
cumulativeDurationMs: args.existing.cumulativeDurationMs,
|
|
804
|
+
...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
|
|
805
|
+
...args.existing.destination ? { destination: args.existing.destination } : {},
|
|
806
|
+
...args.existing.source ? { source: args.existing.source } : {},
|
|
807
|
+
...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
|
|
808
|
+
...args.existing.modelId ? { modelId: args.existing.modelId } : {},
|
|
809
|
+
...args.existing.reasoningLevel ? { reasoningLevel: args.existing.reasoningLevel } : {},
|
|
810
|
+
...args.existing.actor ? { actor: args.existing.actor } : {},
|
|
811
|
+
actors: args.existing.actors,
|
|
812
|
+
...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
|
|
813
|
+
...args.existing.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.existing.resumedFromSliceId } : {},
|
|
814
|
+
...args.existing.surface ? { surface: args.existing.surface } : {},
|
|
815
|
+
...args.existing.traceId ? { traceId: args.existing.traceId } : {},
|
|
816
|
+
...args.errorMessage ?? args.existing.errorMessage ? { errorMessage: args.errorMessage ?? args.existing.errorMessage } : {}
|
|
817
|
+
})
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
async function upsertAgentTurnSessionRecord(args) {
|
|
821
|
+
const existingRecord = await getStoredAgentTurnSessionRecord(
|
|
822
|
+
args.conversationId,
|
|
823
|
+
args.sessionId
|
|
824
|
+
);
|
|
825
|
+
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
826
|
+
const instructionActor = args.actor ?? existingRecord?.actor;
|
|
827
|
+
const commit = await commitMessages({
|
|
828
|
+
conversationId: args.conversationId,
|
|
829
|
+
messages: args.piMessages,
|
|
830
|
+
...instructionActor ? { newMessageProvenance: instructionProvenanceFor(instructionActor) } : {},
|
|
831
|
+
...args.trailingMessageProvenance ? { trailingMessageProvenance: args.trailingMessageProvenance } : {}
|
|
832
|
+
});
|
|
833
|
+
const durableTurnStartMessageIndex = args.turnStartMessageIndex === void 0 ? void 0 : stripRuntimeTurnContext(
|
|
834
|
+
args.piMessages.slice(0, args.turnStartMessageIndex)
|
|
835
|
+
).length;
|
|
836
|
+
const runtimeContext = retainRuntimeTurnContext(args.piMessages);
|
|
837
|
+
const retainedRuntimeContext = runtimeContext.length > 0 ? runtimeContext : existingRecord?.historyVersion === commit.historyVersion ? existingRecord.runtimeContext : void 0;
|
|
838
|
+
const turnStartSeq = durableTurnStartMessageIndex === void 0 ? existingRecord?.turnStartSeq : durableTurnStartMessageIndex <= 0 ? -1 : commit.messageSeqs[durableTurnStartMessageIndex - 1] ?? commit.committedSeq;
|
|
839
|
+
const turnStartMessageIndex = durableTurnStartMessageIndex ?? (turnStartSeq === void 0 ? void 0 : commit.messageSeqs.filter((seq) => seq <= turnStartSeq).length);
|
|
840
|
+
return await setStoredRecord({
|
|
841
|
+
conversationStore: args.conversationStore,
|
|
842
|
+
destinationVisibility: args.destinationVisibility,
|
|
843
|
+
piMessages: commit.messages,
|
|
844
|
+
piMessageProvenance: commit.provenance,
|
|
845
|
+
ttlMs,
|
|
846
|
+
...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {},
|
|
847
|
+
record: buildStoredRecord({
|
|
848
|
+
...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
|
|
849
|
+
conversationId: args.conversationId,
|
|
850
|
+
sessionId: args.sessionId,
|
|
851
|
+
sliceId: args.sliceId,
|
|
852
|
+
state: args.state,
|
|
853
|
+
...existingRecord?.startedAtMs !== void 0 ? { startedAtMs: existingRecord.startedAtMs } : {},
|
|
854
|
+
...args.lastProgressAtMs !== void 0 ? { lastProgressAtMs: args.lastProgressAtMs } : {},
|
|
855
|
+
committedSeq: commit.committedSeq,
|
|
856
|
+
historyVersion: commit.historyVersion,
|
|
857
|
+
...turnStartSeq !== void 0 ? { turnStartSeq } : {},
|
|
858
|
+
...retainedRuntimeContext ? { runtimeContext: retainedRuntimeContext } : {},
|
|
859
|
+
previousVersion: existingRecord?.version,
|
|
860
|
+
cumulativeDurationMs: args.cumulativeDurationMs ?? existingRecord?.cumulativeDurationMs ?? 0,
|
|
861
|
+
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
862
|
+
...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
|
|
863
|
+
...args.source ?? existingRecord?.source ? { source: args.source ?? existingRecord?.source } : {},
|
|
864
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
865
|
+
modelId: args.modelId,
|
|
866
|
+
...args.reasoningLevel ?? existingRecord?.reasoningLevel ? {
|
|
867
|
+
reasoningLevel: args.reasoningLevel ?? existingRecord?.reasoningLevel
|
|
868
|
+
} : {},
|
|
869
|
+
...args.actor ?? existingRecord?.actor ? { actor: args.actor ?? existingRecord?.actor } : {},
|
|
870
|
+
actors: instructionActors([
|
|
871
|
+
...(existingRecord?.actors ?? []).map(instructionProvenanceFor),
|
|
872
|
+
...(args.actors ?? []).map(instructionProvenanceFor),
|
|
873
|
+
...commit.provenance
|
|
874
|
+
]),
|
|
875
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
876
|
+
...args.errorMessage ? { errorMessage: args.errorMessage } : {},
|
|
877
|
+
...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
|
|
878
|
+
...args.surface ?? existingRecord?.surface ? { surface: args.surface ?? existingRecord?.surface } : {},
|
|
879
|
+
...args.traceId ?? existingRecord?.traceId ? { traceId: args.traceId ?? existingRecord?.traceId } : {}
|
|
880
|
+
})
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
async function recordAgentTurnSessionSummary(args) {
|
|
884
|
+
const existing = await getStoredAgentTurnSessionRecord(
|
|
885
|
+
args.conversationId,
|
|
886
|
+
args.sessionId
|
|
887
|
+
);
|
|
888
|
+
const nowMs = Date.now();
|
|
889
|
+
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
890
|
+
const summary = {
|
|
891
|
+
version: existing?.version ?? 0,
|
|
892
|
+
...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
|
|
893
|
+
conversationId: args.conversationId,
|
|
894
|
+
sessionId: args.sessionId,
|
|
895
|
+
sliceId: args.sliceId,
|
|
896
|
+
startedAtMs: existing?.startedAtMs ?? args.startedAtMs ?? nowMs,
|
|
897
|
+
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
898
|
+
state: args.state,
|
|
899
|
+
updatedAtMs: nowMs,
|
|
900
|
+
cumulativeDurationMs: args.cumulativeDurationMs ?? existing?.cumulativeDurationMs ?? 0,
|
|
901
|
+
...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
|
|
902
|
+
...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
|
|
903
|
+
...args.source ?? existing?.source ? { source: args.source ?? existing?.source } : {},
|
|
904
|
+
...args.actor ?? existing?.actor ? { actor: args.actor ?? existing?.actor } : {},
|
|
905
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : existing?.loadedSkillNames ? { loadedSkillNames: existing.loadedSkillNames } : {},
|
|
906
|
+
...args.modelId ?? existing?.modelId ? { modelId: args.modelId ?? existing?.modelId } : {},
|
|
907
|
+
...args.reasoningLevel ?? existing?.reasoningLevel ? { reasoningLevel: args.reasoningLevel ?? existing?.reasoningLevel } : {},
|
|
908
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
909
|
+
...args.surface ?? existing?.surface ? { surface: args.surface ?? existing?.surface } : {},
|
|
910
|
+
...args.traceId ?? existing?.traceId ? { traceId: args.traceId ?? existing?.traceId } : {}
|
|
911
|
+
};
|
|
912
|
+
await recordConversationActivityMetadata({
|
|
913
|
+
conversationStore: args.conversationStore,
|
|
914
|
+
destinationVisibility: args.destinationVisibility,
|
|
915
|
+
nowMs,
|
|
916
|
+
summary
|
|
917
|
+
});
|
|
918
|
+
await appendAgentTurnSessionSummary(summary, ttlMs);
|
|
919
|
+
}
|
|
920
|
+
async function readAgentTurnSessionSummariesFromIndex(key, stateAdapter) {
|
|
921
|
+
await stateAdapter.connect();
|
|
922
|
+
const values = await stateAdapter.getList(key);
|
|
923
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
924
|
+
for (const value of [...values].reverse()) {
|
|
925
|
+
let summary;
|
|
926
|
+
try {
|
|
927
|
+
summary = parseAgentTurnSessionSummary(value);
|
|
928
|
+
} catch (error) {
|
|
929
|
+
logWarn(
|
|
930
|
+
"agent_turn_session_summary_parse_failed",
|
|
931
|
+
{},
|
|
932
|
+
{
|
|
933
|
+
"app.state.key": key,
|
|
934
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
935
|
+
},
|
|
936
|
+
"Skipping an invalid turn-session summary index entry"
|
|
937
|
+
);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
const summaryKey = `${summary.conversationId}:${summary.sessionId}`;
|
|
941
|
+
if (!summaries.has(summaryKey)) {
|
|
942
|
+
summaries.set(summaryKey, summary);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return [...summaries.values()].sort(
|
|
946
|
+
(left, right) => right.updatedAtMs - left.updatedAtMs
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
async function listAgentTurnSessionSummariesForConversation(conversationId) {
|
|
950
|
+
const stateAdapter = getStateAdapter();
|
|
951
|
+
const summaries = await listBoundedAgentTurnSessionSummariesForConversation(conversationId);
|
|
952
|
+
if (summaries.length > 0) {
|
|
953
|
+
return summaries;
|
|
954
|
+
}
|
|
955
|
+
return (await readAgentTurnSessionSummariesFromIndex(
|
|
956
|
+
AGENT_TURN_SESSION_INDEX_KEY,
|
|
957
|
+
stateAdapter
|
|
958
|
+
)).filter((summary) => summary.conversationId === conversationId);
|
|
959
|
+
}
|
|
960
|
+
async function listBoundedAgentTurnSessionSummariesForConversation(conversationId) {
|
|
961
|
+
return readAgentTurnSessionSummariesFromIndex(
|
|
962
|
+
agentTurnSessionConversationIndexKey(conversationId),
|
|
963
|
+
getStateAdapter()
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
async function abandonAgentTurnSessionRecord(args) {
|
|
967
|
+
const existing = await getAgentTurnSessionRecord(
|
|
968
|
+
args.conversationId,
|
|
969
|
+
args.sessionId
|
|
970
|
+
);
|
|
971
|
+
if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned") {
|
|
972
|
+
return void 0;
|
|
973
|
+
}
|
|
974
|
+
return await updateAgentTurnSessionState({
|
|
975
|
+
existing,
|
|
976
|
+
state: "abandoned",
|
|
977
|
+
errorMessage: args.errorMessage ?? existing.errorMessage
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
async function failAgentTurnSessionRecord(args) {
|
|
981
|
+
const existing = await getAgentTurnSessionRecord(
|
|
982
|
+
args.conversationId,
|
|
983
|
+
args.sessionId
|
|
984
|
+
);
|
|
985
|
+
if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned" || existing.version !== args.expectedVersion) {
|
|
986
|
+
return void 0;
|
|
987
|
+
}
|
|
988
|
+
return await updateAgentTurnSessionState({
|
|
989
|
+
existing,
|
|
990
|
+
state: "failed",
|
|
991
|
+
errorMessage: args.errorMessage ?? existing.errorMessage
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
|
|
148
995
|
// src/chat/services/turn-limit.ts
|
|
149
996
|
var TurnSliceLimitExceededError = class extends Error {
|
|
150
997
|
constructor(maxSlices) {
|
|
@@ -162,9 +1009,9 @@ function logSessionRecordError(error, eventName, args, attributes, message) {
|
|
|
162
1009
|
error,
|
|
163
1010
|
eventName,
|
|
164
1011
|
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
1012
|
+
messageConversationId: args.logContext.threadId,
|
|
1013
|
+
userId: args.logContext.actorId,
|
|
1014
|
+
destinationName: args.logContext.channelId,
|
|
168
1015
|
runId: args.logContext.runId,
|
|
169
1016
|
assistantUserName: args.logContext.assistantUserName,
|
|
170
1017
|
modelId: args.modelId
|
|
@@ -319,7 +1166,6 @@ async function completeDeliveredTurn(args) {
|
|
|
319
1166
|
sliceId: args.sliceId,
|
|
320
1167
|
allMessages: args.messages,
|
|
321
1168
|
loadedSkillNames: args.loadedSkillNames,
|
|
322
|
-
logContext: args.logContext,
|
|
323
1169
|
modelId: args.modelId,
|
|
324
1170
|
actor: args.actor,
|
|
325
1171
|
reasoningLevel: args.reasoningLevel,
|
|
@@ -530,6 +1376,122 @@ async function persistYieldSessionRecord(args) {
|
|
|
530
1376
|
}
|
|
531
1377
|
}
|
|
532
1378
|
|
|
1379
|
+
// src/chat/state/conversation.ts
|
|
1380
|
+
function defaultConversationState() {
|
|
1381
|
+
const nowMs = Date.now();
|
|
1382
|
+
return {
|
|
1383
|
+
schemaVersion: 1,
|
|
1384
|
+
messages: [],
|
|
1385
|
+
compactions: [],
|
|
1386
|
+
backfill: {},
|
|
1387
|
+
processing: {},
|
|
1388
|
+
stats: {
|
|
1389
|
+
estimatedContextTokens: 0,
|
|
1390
|
+
totalMessageCount: 0,
|
|
1391
|
+
compactedMessageCount: 0,
|
|
1392
|
+
updatedAtMs: nowMs
|
|
1393
|
+
},
|
|
1394
|
+
vision: {
|
|
1395
|
+
byFileId: {}
|
|
1396
|
+
}
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
function coercePendingAuthState(value) {
|
|
1400
|
+
if (!isRecord(value)) {
|
|
1401
|
+
return void 0;
|
|
1402
|
+
}
|
|
1403
|
+
const kind = value.kind;
|
|
1404
|
+
const provider = toOptionalString(value.provider);
|
|
1405
|
+
const actorId = toOptionalString(value.actorId);
|
|
1406
|
+
const authSessionId = toOptionalString(value.authSessionId);
|
|
1407
|
+
const scope = toOptionalString(value.scope);
|
|
1408
|
+
const sessionId = toOptionalString(value.sessionId);
|
|
1409
|
+
const linkSentAtMs = toOptionalNumber(value.linkSentAtMs);
|
|
1410
|
+
if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || kind === "mcp" && !authSessionId || !sessionId || typeof linkSentAtMs !== "number") {
|
|
1411
|
+
return void 0;
|
|
1412
|
+
}
|
|
1413
|
+
const base = {
|
|
1414
|
+
provider,
|
|
1415
|
+
actorId,
|
|
1416
|
+
...scope ? { scope } : {},
|
|
1417
|
+
sessionId,
|
|
1418
|
+
linkSentAtMs
|
|
1419
|
+
};
|
|
1420
|
+
return kind === "mcp" ? { ...base, authSessionId, kind } : { ...base, kind };
|
|
1421
|
+
}
|
|
1422
|
+
function coerceThreadConversationState(value) {
|
|
1423
|
+
if (!isRecord(value)) {
|
|
1424
|
+
return defaultConversationState();
|
|
1425
|
+
}
|
|
1426
|
+
const root = value;
|
|
1427
|
+
const rawConversation = isRecord(root.conversation) ? root.conversation : {};
|
|
1428
|
+
const base = defaultConversationState();
|
|
1429
|
+
const messages = [];
|
|
1430
|
+
const compactions = [];
|
|
1431
|
+
const rawBackfill = isRecord(rawConversation.backfill) ? rawConversation.backfill : {};
|
|
1432
|
+
const backfill = {
|
|
1433
|
+
completedAtMs: toOptionalNumber(rawBackfill.completedAtMs),
|
|
1434
|
+
source: rawBackfill.source === "recent_messages" || rawBackfill.source === "thread_fetch" ? rawBackfill.source : void 0
|
|
1435
|
+
};
|
|
1436
|
+
const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
|
|
1437
|
+
const processing = {
|
|
1438
|
+
activeTurnId: toOptionalString(rawProcessing.activeTurnId),
|
|
1439
|
+
lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs),
|
|
1440
|
+
pendingAuth: coercePendingAuthState(rawProcessing.pendingAuth)
|
|
1441
|
+
};
|
|
1442
|
+
const rawStats = isRecord(rawConversation.stats) ? rawConversation.stats : {};
|
|
1443
|
+
const stats = {
|
|
1444
|
+
estimatedContextTokens: toOptionalNumber(rawStats.estimatedContextTokens) ?? base.stats.estimatedContextTokens,
|
|
1445
|
+
totalMessageCount: toOptionalNumber(rawStats.totalMessageCount) ?? messages.length,
|
|
1446
|
+
compactedMessageCount: toOptionalNumber(rawStats.compactedMessageCount) ?? 0,
|
|
1447
|
+
updatedAtMs: toOptionalNumber(rawStats.updatedAtMs) ?? base.stats.updatedAtMs
|
|
1448
|
+
};
|
|
1449
|
+
const rawVision = isRecord(rawConversation.vision) ? rawConversation.vision : {};
|
|
1450
|
+
const rawVisionByFileId = isRecord(rawVision.byFileId) ? rawVision.byFileId : {};
|
|
1451
|
+
const byFileId = {};
|
|
1452
|
+
for (const [fileId, value2] of Object.entries(rawVisionByFileId)) {
|
|
1453
|
+
if (typeof fileId !== "string" || fileId.trim().length === 0) continue;
|
|
1454
|
+
if (!isRecord(value2)) continue;
|
|
1455
|
+
const summary = toOptionalString(value2.summary);
|
|
1456
|
+
const analyzedAtMs = toOptionalNumber(value2.analyzedAtMs);
|
|
1457
|
+
if (!summary || !analyzedAtMs) continue;
|
|
1458
|
+
byFileId[fileId] = {
|
|
1459
|
+
summary,
|
|
1460
|
+
analyzedAtMs
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
return {
|
|
1464
|
+
schemaVersion: 1,
|
|
1465
|
+
messages,
|
|
1466
|
+
compactions,
|
|
1467
|
+
backfill,
|
|
1468
|
+
processing,
|
|
1469
|
+
stats,
|
|
1470
|
+
vision: {
|
|
1471
|
+
backfillCompletedAtMs: toOptionalNumber(rawVision.backfillCompletedAtMs),
|
|
1472
|
+
byFileId
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
function buildConversationStatePatch(conversation) {
|
|
1477
|
+
const {
|
|
1478
|
+
compactions: _compactions,
|
|
1479
|
+
messages: _messages,
|
|
1480
|
+
...scratch
|
|
1481
|
+
} = conversation;
|
|
1482
|
+
return {
|
|
1483
|
+
conversation: {
|
|
1484
|
+
...scratch,
|
|
1485
|
+
schemaVersion: 1,
|
|
1486
|
+
stats: {
|
|
1487
|
+
...conversation.stats,
|
|
1488
|
+
totalMessageCount: conversation.messages.length,
|
|
1489
|
+
updatedAtMs: Date.now()
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
|
|
533
1495
|
// src/chat/services/context-budget.ts
|
|
534
1496
|
var COMPACTION_TRIGGER_INPUT_RATIO = 0.75;
|
|
535
1497
|
var COMPACTION_OUTPUT_RESERVE_RATIO = 0.25;
|
|
@@ -804,9 +1766,9 @@ async function summarizeConversationChunk(messages, conversation, context, deps)
|
|
|
804
1766
|
logWarn(
|
|
805
1767
|
"conversation_compaction_summary_failed",
|
|
806
1768
|
{
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1769
|
+
messageConversationId: context.threadId,
|
|
1770
|
+
userId: context.actorId,
|
|
1771
|
+
destinationName: context.channelId,
|
|
810
1772
|
runId: context.runId,
|
|
811
1773
|
assistantUserName: botConfig.userName,
|
|
812
1774
|
modelId: botConfig.fastModelId
|
|
@@ -923,10 +1885,10 @@ function getConversationMessageSlackTs(message) {
|
|
|
923
1885
|
|
|
924
1886
|
// src/chat/conversations/messages.ts
|
|
925
1887
|
import { createHash } from "crypto";
|
|
926
|
-
import { isDeepStrictEqual as
|
|
1888
|
+
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
927
1889
|
|
|
928
1890
|
// src/chat/conversations/message-summaries.ts
|
|
929
|
-
import { isDeepStrictEqual } from "util";
|
|
1891
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
930
1892
|
function projectConversationMessageSummaries(events) {
|
|
931
1893
|
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
932
1894
|
const data = events[index]?.data;
|
|
@@ -940,7 +1902,7 @@ async function persistConversationMessageSummaries(args) {
|
|
|
940
1902
|
const eventStore = getConversationEventStore();
|
|
941
1903
|
const history = await eventStore.loadMessageHistory(args.conversationId);
|
|
942
1904
|
const existing = history.compaction ? projectConversationMessageSummaries([history.compaction]) : [];
|
|
943
|
-
if (
|
|
1905
|
+
if (isDeepStrictEqual2(existing, args.conversation.compactions)) {
|
|
944
1906
|
return;
|
|
945
1907
|
}
|
|
946
1908
|
const liveMessageIds = new Set(
|
|
@@ -1078,7 +2040,7 @@ async function persistConversationMessages(args) {
|
|
|
1078
2040
|
const events = args.conversation.messages.flatMap((message) => {
|
|
1079
2041
|
const stored = toStoredConversationMessage(message);
|
|
1080
2042
|
const existing = existingMessages.get(stored.messageId);
|
|
1081
|
-
const changed = existing !== void 0 && !
|
|
2043
|
+
const changed = existing !== void 0 && !isDeepStrictEqual3(toStoredConversationMessage(existing), stored);
|
|
1082
2044
|
const messageEvent = existing ? changed ? [
|
|
1083
2045
|
{
|
|
1084
2046
|
idempotencyKey: `message:${stored.messageId}:update:${messageStateKey(stored)}`,
|
|
@@ -1372,6 +2334,9 @@ function createChannelConfigurationService(storage) {
|
|
|
1372
2334
|
};
|
|
1373
2335
|
}
|
|
1374
2336
|
|
|
2337
|
+
// src/chat/state/ttl.ts
|
|
2338
|
+
var JUNIOR_THREAD_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2339
|
+
|
|
1375
2340
|
// src/chat/runtime/thread-state.ts
|
|
1376
2341
|
function threadStateKey(threadId) {
|
|
1377
2342
|
return `thread-state:${threadId}`;
|
|
@@ -1565,6 +2530,15 @@ function isPendingAuthLatestRequest(conversation, pendingAuth) {
|
|
|
1565
2530
|
}
|
|
1566
2531
|
|
|
1567
2532
|
export {
|
|
2533
|
+
loadProjection,
|
|
2534
|
+
loadConversationProjection,
|
|
2535
|
+
openConversationProjection,
|
|
2536
|
+
loadConnectedMcpProviders,
|
|
2537
|
+
commitMessages,
|
|
2538
|
+
recordMcpProviderConnected,
|
|
2539
|
+
recordAuthorizationRequested,
|
|
2540
|
+
recordAuthorizationCompleted,
|
|
2541
|
+
recordToolExecutionStarted,
|
|
1568
2542
|
buildDeterministicTurnId,
|
|
1569
2543
|
buildDeterministicAssistantMessageId,
|
|
1570
2544
|
ConversationTurnBoundaryError,
|
|
@@ -1579,6 +2553,12 @@ export {
|
|
|
1579
2553
|
markTurnClosed,
|
|
1580
2554
|
markTurnCompleted,
|
|
1581
2555
|
markTurnFailed,
|
|
2556
|
+
getAgentTurnSessionRecord,
|
|
2557
|
+
getAgentTurnSessionRecordForResume,
|
|
2558
|
+
recordAgentTurnSessionSummary,
|
|
2559
|
+
listAgentTurnSessionSummariesForConversation,
|
|
2560
|
+
abandonAgentTurnSessionRecord,
|
|
2561
|
+
failAgentTurnSessionRecord,
|
|
1582
2562
|
persistWithRetry,
|
|
1583
2563
|
TurnSliceLimitExceededError,
|
|
1584
2564
|
buildTurnLimitResponse,
|
|
@@ -1590,11 +2570,13 @@ export {
|
|
|
1590
2570
|
persistContinuationSessionRecord,
|
|
1591
2571
|
persistYieldSessionRecord,
|
|
1592
2572
|
getInterruptionMarker,
|
|
2573
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
1593
2574
|
canReusePendingAuthLink,
|
|
1594
2575
|
getConversationPendingAuth,
|
|
1595
2576
|
clearPendingAuth,
|
|
1596
2577
|
abandonReplacedPendingAuth,
|
|
1597
2578
|
isPendingAuthLatestRequest,
|
|
2579
|
+
coerceThreadConversationState,
|
|
1598
2580
|
persistConversationMessageSummaries,
|
|
1599
2581
|
estimateTextTokens,
|
|
1600
2582
|
getAgentContextCompactionTriggerTokens,
|