@dexto/core 1.5.2 → 1.5.4
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/DextoAgent.cjs +296 -2
- package/dist/agent/DextoAgent.d.ts +114 -0
- package/dist/agent/DextoAgent.d.ts.map +1 -1
- package/dist/agent/DextoAgent.js +287 -2
- package/dist/agent/schemas.d.ts +93 -21
- package/dist/agent/schemas.d.ts.map +1 -1
- package/dist/approval/manager.cjs +16 -0
- package/dist/approval/manager.d.ts +10 -0
- package/dist/approval/manager.d.ts.map +1 -1
- package/dist/approval/manager.js +16 -0
- package/dist/approval/types.d.ts +11 -0
- package/dist/approval/types.d.ts.map +1 -1
- package/dist/context/compaction/overflow.cjs +6 -10
- package/dist/context/compaction/overflow.d.ts +14 -11
- package/dist/context/compaction/overflow.d.ts.map +1 -1
- package/dist/context/compaction/overflow.js +6 -10
- package/dist/context/compaction/providers/reactive-overflow-provider.cjs +15 -0
- package/dist/context/compaction/providers/reactive-overflow-provider.d.ts +15 -0
- package/dist/context/compaction/providers/reactive-overflow-provider.d.ts.map +1 -1
- package/dist/context/compaction/providers/reactive-overflow-provider.js +15 -0
- package/dist/context/compaction/schemas.cjs +22 -2
- package/dist/context/compaction/schemas.d.ts +45 -0
- package/dist/context/compaction/schemas.d.ts.map +1 -1
- package/dist/context/compaction/schemas.js +22 -2
- package/dist/context/compaction/strategies/reactive-overflow.cjs +166 -26
- package/dist/context/compaction/strategies/reactive-overflow.d.ts +21 -0
- package/dist/context/compaction/strategies/reactive-overflow.d.ts.map +1 -1
- package/dist/context/compaction/strategies/reactive-overflow.js +166 -26
- package/dist/context/manager.cjs +278 -31
- package/dist/context/manager.d.ts +192 -5
- package/dist/context/manager.d.ts.map +1 -1
- package/dist/context/manager.js +285 -32
- package/dist/context/types.d.ts +6 -0
- package/dist/context/types.d.ts.map +1 -1
- package/dist/context/utils.cjs +77 -11
- package/dist/context/utils.d.ts +86 -8
- package/dist/context/utils.d.ts.map +1 -1
- package/dist/context/utils.js +71 -11
- package/dist/events/index.cjs +7 -1
- package/dist/events/index.d.ts +58 -7
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +7 -1
- package/dist/filesystem/filesystem-service.cjs +18 -15
- package/dist/filesystem/filesystem-service.d.ts +3 -3
- package/dist/filesystem/filesystem-service.d.ts.map +1 -1
- package/dist/filesystem/filesystem-service.js +18 -15
- package/dist/filesystem/path-validator.cjs +16 -7
- package/dist/filesystem/path-validator.d.ts +10 -3
- package/dist/filesystem/path-validator.d.ts.map +1 -1
- package/dist/filesystem/path-validator.js +16 -7
- package/dist/filesystem/types.d.ts +4 -0
- package/dist/filesystem/types.d.ts.map +1 -1
- package/dist/llm/executor/stream-processor.cjs +19 -1
- package/dist/llm/executor/stream-processor.d.ts +3 -0
- package/dist/llm/executor/stream-processor.d.ts.map +1 -1
- package/dist/llm/executor/stream-processor.js +19 -1
- package/dist/llm/executor/turn-executor.cjs +219 -30
- package/dist/llm/executor/turn-executor.d.ts +62 -10
- package/dist/llm/executor/turn-executor.d.ts.map +1 -1
- package/dist/llm/executor/turn-executor.js +219 -30
- package/dist/llm/executor/types.d.ts +28 -0
- package/dist/llm/executor/types.d.ts.map +1 -1
- package/dist/llm/formatters/vercel.cjs +36 -28
- package/dist/llm/formatters/vercel.d.ts.map +1 -1
- package/dist/llm/formatters/vercel.js +36 -28
- package/dist/llm/services/factory.cjs +3 -2
- package/dist/llm/services/factory.d.ts +3 -1
- package/dist/llm/services/factory.d.ts.map +1 -1
- package/dist/llm/services/factory.js +3 -2
- package/dist/llm/services/vercel.cjs +34 -6
- package/dist/llm/services/vercel.d.ts +23 -3
- package/dist/llm/services/vercel.d.ts.map +1 -1
- package/dist/llm/services/vercel.js +34 -6
- package/dist/logger/v2/schemas.cjs +4 -0
- package/dist/logger/v2/schemas.d.ts +16 -0
- package/dist/logger/v2/schemas.d.ts.map +1 -1
- package/dist/logger/v2/schemas.js +4 -0
- package/dist/logger/v2/transport-factory.cjs +4 -1
- package/dist/logger/v2/transport-factory.d.ts.map +1 -1
- package/dist/logger/v2/transport-factory.js +4 -1
- package/dist/logger/v2/transports/silent-transport.cjs +33 -0
- package/dist/logger/v2/transports/silent-transport.d.ts +15 -0
- package/dist/logger/v2/transports/silent-transport.d.ts.map +1 -0
- package/dist/logger/v2/transports/silent-transport.js +10 -0
- package/dist/session/chat-session.cjs +20 -11
- package/dist/session/chat-session.d.ts +9 -4
- package/dist/session/chat-session.d.ts.map +1 -1
- package/dist/session/chat-session.js +20 -11
- package/dist/session/compaction-service.cjs +139 -0
- package/dist/session/compaction-service.d.ts +81 -0
- package/dist/session/compaction-service.d.ts.map +1 -0
- package/dist/session/compaction-service.js +106 -0
- package/dist/session/session-manager.cjs +146 -0
- package/dist/session/session-manager.d.ts +50 -0
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +146 -0
- package/dist/session/title-generator.cjs +2 -2
- package/dist/session/title-generator.js +2 -2
- package/dist/systemPrompt/in-built-prompts.cjs +36 -0
- package/dist/systemPrompt/in-built-prompts.d.ts +18 -1
- package/dist/systemPrompt/in-built-prompts.d.ts.map +1 -1
- package/dist/systemPrompt/in-built-prompts.js +25 -0
- package/dist/systemPrompt/manager.cjs +22 -0
- package/dist/systemPrompt/manager.d.ts +10 -0
- package/dist/systemPrompt/manager.d.ts.map +1 -1
- package/dist/systemPrompt/manager.js +22 -0
- package/dist/systemPrompt/registry.cjs +2 -1
- package/dist/systemPrompt/registry.d.ts +1 -1
- package/dist/systemPrompt/registry.d.ts.map +1 -1
- package/dist/systemPrompt/registry.js +2 -1
- package/dist/systemPrompt/schemas.cjs +7 -0
- package/dist/systemPrompt/schemas.d.ts +13 -13
- package/dist/systemPrompt/schemas.d.ts.map +1 -1
- package/dist/systemPrompt/schemas.js +7 -0
- package/dist/tools/error-codes.cjs +1 -0
- package/dist/tools/error-codes.d.ts +1 -0
- package/dist/tools/error-codes.d.ts.map +1 -1
- package/dist/tools/error-codes.js +1 -0
- package/dist/tools/errors.cjs +17 -0
- package/dist/tools/errors.d.ts +9 -0
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +17 -0
- package/dist/tools/internal-tools/provider.cjs +3 -2
- package/dist/tools/internal-tools/provider.d.ts +1 -1
- package/dist/tools/internal-tools/provider.d.ts.map +1 -1
- package/dist/tools/internal-tools/provider.js +3 -2
- package/dist/tools/tool-manager.cjs +77 -4
- package/dist/tools/tool-manager.d.ts +18 -0
- package/dist/tools/tool-manager.d.ts.map +1 -1
- package/dist/tools/tool-manager.js +78 -5
- package/dist/tools/types.d.ts +5 -3
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/utils/index.cjs +3 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/package.json +1 -1
package/dist/agent/DextoAgent.js
CHANGED
|
@@ -398,7 +398,10 @@ Either:
|
|
|
398
398
|
llmConfig.model
|
|
399
399
|
);
|
|
400
400
|
}
|
|
401
|
-
const
|
|
401
|
+
const responseEvents = events.filter(
|
|
402
|
+
(e) => e.name === "llm:response"
|
|
403
|
+
);
|
|
404
|
+
const responseEvent = responseEvents[responseEvents.length - 1];
|
|
402
405
|
if (!responseEvent || responseEvent.name !== "llm:response") {
|
|
403
406
|
const llmConfig = this.stateManager.getLLMConfig(sessionId);
|
|
404
407
|
throw LLMError.generationFailed(
|
|
@@ -582,6 +585,30 @@ Either:
|
|
|
582
585
|
signal: cleanupSignal
|
|
583
586
|
});
|
|
584
587
|
listeners.push({ event: "tool:running", listener: toolRunningListener });
|
|
588
|
+
const contextCompactingListener = (data) => {
|
|
589
|
+
if (data.sessionId !== sessionId) return;
|
|
590
|
+
eventQueue.push({ name: "context:compacting", ...data });
|
|
591
|
+
};
|
|
592
|
+
this.agentEventBus.on("context:compacting", contextCompactingListener, {
|
|
593
|
+
signal: cleanupSignal
|
|
594
|
+
});
|
|
595
|
+
listeners.push({ event: "context:compacting", listener: contextCompactingListener });
|
|
596
|
+
const contextCompactedListener = (data) => {
|
|
597
|
+
if (data.sessionId !== sessionId) return;
|
|
598
|
+
eventQueue.push({ name: "context:compacted", ...data });
|
|
599
|
+
};
|
|
600
|
+
this.agentEventBus.on("context:compacted", contextCompactedListener, {
|
|
601
|
+
signal: cleanupSignal
|
|
602
|
+
});
|
|
603
|
+
listeners.push({ event: "context:compacted", listener: contextCompactedListener });
|
|
604
|
+
const sessionContinuedListener = (data) => {
|
|
605
|
+
if (data.previousSessionId !== sessionId) return;
|
|
606
|
+
eventQueue.push({ name: "session:continued", ...data });
|
|
607
|
+
};
|
|
608
|
+
this.agentEventBus.on("session:continued", sessionContinuedListener, {
|
|
609
|
+
signal: cleanupSignal
|
|
610
|
+
});
|
|
611
|
+
listeners.push({ event: "session:continued", listener: sessionContinuedListener });
|
|
585
612
|
const messageQueuedListener = (data) => {
|
|
586
613
|
if (data.sessionId !== sessionId) return;
|
|
587
614
|
eventQueue.push({ name: "message:queued", ...data });
|
|
@@ -598,6 +625,14 @@ Either:
|
|
|
598
625
|
signal: cleanupSignal
|
|
599
626
|
});
|
|
600
627
|
listeners.push({ event: "message:dequeued", listener: messageDequeuedListener });
|
|
628
|
+
const serviceEventListener = (data) => {
|
|
629
|
+
if (data.sessionId !== sessionId) return;
|
|
630
|
+
eventQueue.push({ name: "service:event", ...data });
|
|
631
|
+
};
|
|
632
|
+
this.agentEventBus.on("service:event", serviceEventListener, {
|
|
633
|
+
signal: cleanupSignal
|
|
634
|
+
});
|
|
635
|
+
listeners.push({ event: "service:event", listener: serviceEventListener });
|
|
601
636
|
const runCompleteListener = (data) => {
|
|
602
637
|
if (data.sessionId !== sessionId) return;
|
|
603
638
|
eventQueue.push({ name: "run:complete", ...data });
|
|
@@ -733,12 +768,18 @@ Either:
|
|
|
733
768
|
contentParts = [{ type: "text", text: textContent }];
|
|
734
769
|
}
|
|
735
770
|
const session = await this.sessionManager.getSession(sessionId) || await this.sessionManager.createSession(sessionId);
|
|
736
|
-
await session.stream(
|
|
771
|
+
const streamResult = await session.stream(
|
|
772
|
+
contentParts,
|
|
773
|
+
signal ? { signal } : void 0
|
|
774
|
+
);
|
|
737
775
|
this.sessionManager.incrementMessageCount(session.id).catch(
|
|
738
776
|
(error) => this.logger.warn(
|
|
739
777
|
`Failed to increment message count: ${error instanceof Error ? error.message : String(error)}`
|
|
740
778
|
)
|
|
741
779
|
);
|
|
780
|
+
if (streamResult.didCompact && streamResult.compaction) {
|
|
781
|
+
await this.handleSessionContinuation(session, streamResult.compaction);
|
|
782
|
+
}
|
|
742
783
|
} catch (err) {
|
|
743
784
|
const error = err instanceof DextoRuntimeError || err instanceof DextoValidationError ? err : err instanceof Error ? err : AgentError.streamFailed(String(err));
|
|
744
785
|
completed = true;
|
|
@@ -1112,6 +1153,173 @@ Either:
|
|
|
1112
1153
|
sessionId
|
|
1113
1154
|
});
|
|
1114
1155
|
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Manually compact the context using session-native compaction.
|
|
1158
|
+
*
|
|
1159
|
+
* Session-native compaction creates a NEW session with the summary as initial context,
|
|
1160
|
+
* providing clean session isolation while maintaining traceability via linking.
|
|
1161
|
+
*
|
|
1162
|
+
* The old session is marked as compacted with `continuedTo` pointing to the new session,
|
|
1163
|
+
* and the new session has `continuedFrom` pointing back to the old session.
|
|
1164
|
+
*
|
|
1165
|
+
* @param sessionId Session ID of the session to compact (required)
|
|
1166
|
+
* @returns Compaction result with new session info, or null if compaction was skipped
|
|
1167
|
+
*/
|
|
1168
|
+
async compactContext(sessionId) {
|
|
1169
|
+
this.ensureStarted();
|
|
1170
|
+
if (!sessionId || typeof sessionId !== "string") {
|
|
1171
|
+
throw AgentError.apiValidationError(
|
|
1172
|
+
"sessionId is required and must be a non-empty string"
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
const session = await this.sessionManager.getSession(sessionId);
|
|
1176
|
+
if (!session) {
|
|
1177
|
+
throw SessionError.notFound(sessionId);
|
|
1178
|
+
}
|
|
1179
|
+
const llmService = session.getLLMService();
|
|
1180
|
+
const compactionStrategy = llmService.getCompactionStrategy();
|
|
1181
|
+
if (!compactionStrategy) {
|
|
1182
|
+
this.logger.warn(
|
|
1183
|
+
`Compaction strategy not configured for session ${sessionId} - skipping manual compaction`
|
|
1184
|
+
);
|
|
1185
|
+
return null;
|
|
1186
|
+
}
|
|
1187
|
+
const { SessionCompactionService } = await import("../session/compaction-service.js");
|
|
1188
|
+
const compactionService = new SessionCompactionService(
|
|
1189
|
+
this.sessionManager,
|
|
1190
|
+
compactionStrategy,
|
|
1191
|
+
this.logger
|
|
1192
|
+
);
|
|
1193
|
+
const compactionResult = await compactionService.compact(session, {
|
|
1194
|
+
reason: "manual",
|
|
1195
|
+
eventBus: this.agentEventBus
|
|
1196
|
+
});
|
|
1197
|
+
if (!compactionResult) {
|
|
1198
|
+
this.logger.debug(`Compaction skipped for session ${sessionId} - nothing to compact`);
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
this.logger.info(
|
|
1202
|
+
`Session-native compaction complete: ${sessionId} \u2192 ${compactionResult.newSessionId}, ${compactionResult.originalMessages} messages \u2192 ~${compactionResult.summaryTokens} token summary`
|
|
1203
|
+
);
|
|
1204
|
+
return {
|
|
1205
|
+
previousSessionId: compactionResult.previousSessionId,
|
|
1206
|
+
newSessionId: compactionResult.newSessionId,
|
|
1207
|
+
summaryTokens: compactionResult.summaryTokens,
|
|
1208
|
+
originalMessages: compactionResult.originalMessages
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Get the chain of linked sessions (ancestors and descendants) for a session.
|
|
1213
|
+
* Useful for displaying session history and understanding compaction lineage.
|
|
1214
|
+
*
|
|
1215
|
+
* @param sessionId Any session ID in the chain
|
|
1216
|
+
* @returns Array of session data in the chain, ordered chronologically (oldest first)
|
|
1217
|
+
*/
|
|
1218
|
+
async getSessionLineage(sessionId) {
|
|
1219
|
+
this.ensureStarted();
|
|
1220
|
+
if (!sessionId || typeof sessionId !== "string") {
|
|
1221
|
+
throw AgentError.apiValidationError(
|
|
1222
|
+
"sessionId is required and must be a non-empty string"
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
const chain = await this.sessionManager.getSessionChain(sessionId);
|
|
1226
|
+
if (chain.length === 0) {
|
|
1227
|
+
throw SessionError.notFound(sessionId);
|
|
1228
|
+
}
|
|
1229
|
+
const currentIndex = chain.findIndex((s) => s.id === sessionId);
|
|
1230
|
+
if (currentIndex < 0) {
|
|
1231
|
+
throw SessionError.notFound(sessionId);
|
|
1232
|
+
}
|
|
1233
|
+
return {
|
|
1234
|
+
chain: chain.map((s) => {
|
|
1235
|
+
const item = {
|
|
1236
|
+
id: s.id,
|
|
1237
|
+
createdAt: s.createdAt
|
|
1238
|
+
};
|
|
1239
|
+
if (s.continuedFrom !== void 0) {
|
|
1240
|
+
item.continuedFrom = s.continuedFrom;
|
|
1241
|
+
}
|
|
1242
|
+
if (s.continuedTo !== void 0) {
|
|
1243
|
+
item.continuedTo = s.continuedTo;
|
|
1244
|
+
}
|
|
1245
|
+
if (s.compactedAt !== void 0) {
|
|
1246
|
+
item.compactedAt = s.compactedAt;
|
|
1247
|
+
}
|
|
1248
|
+
return item;
|
|
1249
|
+
}),
|
|
1250
|
+
currentIndex
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Get context usage statistics for a session.
|
|
1255
|
+
* Useful for monitoring context window usage and compaction status.
|
|
1256
|
+
*
|
|
1257
|
+
* @param sessionId Session ID (required)
|
|
1258
|
+
* @returns Context statistics including token estimates and message counts
|
|
1259
|
+
*/
|
|
1260
|
+
async getContextStats(sessionId) {
|
|
1261
|
+
this.ensureStarted();
|
|
1262
|
+
if (!sessionId || typeof sessionId !== "string") {
|
|
1263
|
+
throw AgentError.apiValidationError(
|
|
1264
|
+
"sessionId is required and must be a non-empty string"
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
const session = await this.sessionManager.getSession(sessionId);
|
|
1268
|
+
if (!session) {
|
|
1269
|
+
throw SessionError.notFound(sessionId);
|
|
1270
|
+
}
|
|
1271
|
+
const contextManager = session.getContextManager();
|
|
1272
|
+
const contributorContext = { mcpManager: this.mcpManager };
|
|
1273
|
+
const llmService = session.getLLMService();
|
|
1274
|
+
const tools = await llmService.getAllTools();
|
|
1275
|
+
const tokenEstimate = await contextManager.getContextTokenEstimate(
|
|
1276
|
+
contributorContext,
|
|
1277
|
+
tools
|
|
1278
|
+
);
|
|
1279
|
+
const history = await contextManager.getHistory();
|
|
1280
|
+
const runtimeConfig = this.stateManager.getRuntimeConfig(sessionId);
|
|
1281
|
+
const compactionConfig = runtimeConfig.compaction;
|
|
1282
|
+
const modelContextWindow = contextManager.getMaxInputTokens();
|
|
1283
|
+
let maxContextTokens = modelContextWindow;
|
|
1284
|
+
if (compactionConfig?.maxContextTokens !== void 0) {
|
|
1285
|
+
maxContextTokens = Math.min(maxContextTokens, compactionConfig.maxContextTokens);
|
|
1286
|
+
}
|
|
1287
|
+
const thresholdPercent = compactionConfig?.thresholdPercent ?? 0.9;
|
|
1288
|
+
if (thresholdPercent < 1) {
|
|
1289
|
+
maxContextTokens = Math.floor(maxContextTokens * thresholdPercent);
|
|
1290
|
+
}
|
|
1291
|
+
const hasSummary = history.some(
|
|
1292
|
+
(msg) => msg.metadata?.isSummary === true || msg.metadata?.isSessionSummary === true
|
|
1293
|
+
);
|
|
1294
|
+
const llmConfig = runtimeConfig.llm;
|
|
1295
|
+
const { getModelDisplayName } = await import("../llm/registry.js");
|
|
1296
|
+
const modelDisplayName = getModelDisplayName(llmConfig.model, llmConfig.provider);
|
|
1297
|
+
const estimatedTokens = tokenEstimate.estimated;
|
|
1298
|
+
const compactionCount = await this.sessionManager.getCompactionCount(sessionId);
|
|
1299
|
+
return {
|
|
1300
|
+
estimatedTokens,
|
|
1301
|
+
actualTokens: tokenEstimate.actual,
|
|
1302
|
+
maxContextTokens,
|
|
1303
|
+
modelContextWindow,
|
|
1304
|
+
thresholdPercent,
|
|
1305
|
+
usagePercent: maxContextTokens > 0 ? Math.round(estimatedTokens / maxContextTokens * 100) : 0,
|
|
1306
|
+
messageCount: tokenEstimate.stats.originalMessageCount,
|
|
1307
|
+
filteredMessageCount: tokenEstimate.stats.filteredMessageCount,
|
|
1308
|
+
prunedToolCount: tokenEstimate.stats.prunedToolCount,
|
|
1309
|
+
hasSummary,
|
|
1310
|
+
compactionCount,
|
|
1311
|
+
model: llmConfig.model,
|
|
1312
|
+
modelDisplayName,
|
|
1313
|
+
breakdown: {
|
|
1314
|
+
systemPrompt: tokenEstimate.breakdown.systemPrompt,
|
|
1315
|
+
tools: tokenEstimate.breakdown.tools,
|
|
1316
|
+
messages: tokenEstimate.breakdown.messages
|
|
1317
|
+
},
|
|
1318
|
+
...tokenEstimate.calculationBasis && {
|
|
1319
|
+
calculationBasis: tokenEstimate.calculationBasis
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1115
1323
|
// ============= LLM MANAGEMENT =============
|
|
1116
1324
|
/**
|
|
1117
1325
|
* Gets the current LLM configuration with all defaults applied.
|
|
@@ -1187,6 +1395,83 @@ Either:
|
|
|
1187
1395
|
}
|
|
1188
1396
|
return validatedConfig;
|
|
1189
1397
|
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Handles session-native continuation after compaction.
|
|
1400
|
+
*
|
|
1401
|
+
* When context compaction occurs, this method:
|
|
1402
|
+
* 1. Receives compaction data directly (summary text + preserved messages)
|
|
1403
|
+
* 2. Creates a new continuation session
|
|
1404
|
+
* 3. Adds the summary as the first message in the new session
|
|
1405
|
+
* 4. Adds preserved messages to the new session
|
|
1406
|
+
* 5. Links the old and new sessions for traceability
|
|
1407
|
+
* 6. Emits session:continued event for UI to handle session switch
|
|
1408
|
+
*
|
|
1409
|
+
* IMPORTANT: The original session is NOT modified. The summary was never added to it.
|
|
1410
|
+
* This is the clean session-native compaction approach where:
|
|
1411
|
+
* - Original session: UNCHANGED (full history preserved)
|
|
1412
|
+
* - New session: [summary, ...preservedMessages]
|
|
1413
|
+
*
|
|
1414
|
+
* @param currentSession The session that triggered compaction
|
|
1415
|
+
* @param compactionData The compaction data with summary text and preserved messages
|
|
1416
|
+
*/
|
|
1417
|
+
async handleSessionContinuation(currentSession, compactionData) {
|
|
1418
|
+
const currentSessionId = currentSession.id;
|
|
1419
|
+
try {
|
|
1420
|
+
const { summaryText, preservedMessages, summarizedCount } = compactionData;
|
|
1421
|
+
if (!summaryText) {
|
|
1422
|
+
this.logger.warn(
|
|
1423
|
+
`Session continuation skipped: empty summary text for session ${currentSessionId}`
|
|
1424
|
+
);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
const { sessionId: newSessionId, session: newSession } = await this.sessionManager.createContinuationSession(currentSessionId);
|
|
1428
|
+
const sessionSummaryMessage = {
|
|
1429
|
+
role: "assistant",
|
|
1430
|
+
content: [{ type: "text", text: summaryText }],
|
|
1431
|
+
timestamp: Date.now(),
|
|
1432
|
+
metadata: {
|
|
1433
|
+
isSessionSummary: true,
|
|
1434
|
+
continuedFrom: currentSessionId,
|
|
1435
|
+
summarizedAt: Date.now(),
|
|
1436
|
+
originalMessageCount: summarizedCount,
|
|
1437
|
+
originalFirstTimestamp: compactionData.originalFirstTimestamp,
|
|
1438
|
+
originalLastTimestamp: compactionData.originalLastTimestamp
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
const newContextManager = newSession.getContextManager();
|
|
1442
|
+
await newContextManager.addMessage(sessionSummaryMessage);
|
|
1443
|
+
for (const msg of preservedMessages) {
|
|
1444
|
+
await newContextManager.addMessage(msg);
|
|
1445
|
+
}
|
|
1446
|
+
await this.sessionManager.markSessionCompacted(currentSessionId, newSessionId);
|
|
1447
|
+
const { estimateMessagesTokens } = await import("../context/utils.js");
|
|
1448
|
+
const summaryTokens = estimateMessagesTokens([sessionSummaryMessage]);
|
|
1449
|
+
const totalOriginalMessages = summarizedCount + preservedMessages.length;
|
|
1450
|
+
const newSessionLLMConfig = this.stateManager.getRuntimeConfig(newSessionId).llm;
|
|
1451
|
+
const { getModelDisplayName } = await import("../llm/registry.js");
|
|
1452
|
+
const modelDisplayName = getModelDisplayName(
|
|
1453
|
+
newSessionLLMConfig.model,
|
|
1454
|
+
newSessionLLMConfig.provider
|
|
1455
|
+
);
|
|
1456
|
+
this.logger.info(
|
|
1457
|
+
`Session continuation: ${currentSessionId} \u2192 ${newSessionId} (${totalOriginalMessages} messages \u2192 summary + ${preservedMessages.length} preserved)`
|
|
1458
|
+
);
|
|
1459
|
+
this.agentEventBus.emit("session:continued", {
|
|
1460
|
+
previousSessionId: currentSessionId,
|
|
1461
|
+
newSessionId,
|
|
1462
|
+
summaryTokens,
|
|
1463
|
+
originalMessages: totalOriginalMessages,
|
|
1464
|
+
reason: "overflow",
|
|
1465
|
+
sessionId: newSessionId,
|
|
1466
|
+
model: newSessionLLMConfig.model,
|
|
1467
|
+
modelDisplayName
|
|
1468
|
+
});
|
|
1469
|
+
} catch (error) {
|
|
1470
|
+
this.logger.error(
|
|
1471
|
+
`Failed to handle session continuation for ${currentSessionId}: ${error instanceof Error ? error.message : String(error)}`
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1190
1475
|
/**
|
|
1191
1476
|
* Performs the actual LLM switch with a validated configuration.
|
|
1192
1477
|
* This is a helper method that handles state management and session switching.
|