@dexto/core 1.5.3 → 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.
Files changed (92) hide show
  1. package/dist/agent/DextoAgent.cjs +284 -1
  2. package/dist/agent/DextoAgent.d.ts +114 -0
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +275 -1
  5. package/dist/agent/schemas.d.ts +51 -21
  6. package/dist/agent/schemas.d.ts.map +1 -1
  7. package/dist/context/compaction/overflow.cjs +6 -10
  8. package/dist/context/compaction/overflow.d.ts +14 -11
  9. package/dist/context/compaction/overflow.d.ts.map +1 -1
  10. package/dist/context/compaction/overflow.js +6 -10
  11. package/dist/context/compaction/providers/reactive-overflow-provider.cjs +15 -0
  12. package/dist/context/compaction/providers/reactive-overflow-provider.d.ts +15 -0
  13. package/dist/context/compaction/providers/reactive-overflow-provider.d.ts.map +1 -1
  14. package/dist/context/compaction/providers/reactive-overflow-provider.js +15 -0
  15. package/dist/context/compaction/schemas.cjs +22 -2
  16. package/dist/context/compaction/schemas.d.ts +45 -0
  17. package/dist/context/compaction/schemas.d.ts.map +1 -1
  18. package/dist/context/compaction/schemas.js +22 -2
  19. package/dist/context/compaction/strategies/reactive-overflow.cjs +166 -26
  20. package/dist/context/compaction/strategies/reactive-overflow.d.ts +21 -0
  21. package/dist/context/compaction/strategies/reactive-overflow.d.ts.map +1 -1
  22. package/dist/context/compaction/strategies/reactive-overflow.js +166 -26
  23. package/dist/context/manager.cjs +278 -31
  24. package/dist/context/manager.d.ts +192 -5
  25. package/dist/context/manager.d.ts.map +1 -1
  26. package/dist/context/manager.js +285 -32
  27. package/dist/context/types.d.ts +6 -0
  28. package/dist/context/types.d.ts.map +1 -1
  29. package/dist/context/utils.cjs +77 -11
  30. package/dist/context/utils.d.ts +86 -8
  31. package/dist/context/utils.d.ts.map +1 -1
  32. package/dist/context/utils.js +71 -11
  33. package/dist/events/index.cjs +4 -0
  34. package/dist/events/index.d.ts +41 -7
  35. package/dist/events/index.d.ts.map +1 -1
  36. package/dist/events/index.js +4 -0
  37. package/dist/llm/executor/stream-processor.cjs +19 -1
  38. package/dist/llm/executor/stream-processor.d.ts +3 -0
  39. package/dist/llm/executor/stream-processor.d.ts.map +1 -1
  40. package/dist/llm/executor/stream-processor.js +19 -1
  41. package/dist/llm/executor/turn-executor.cjs +219 -30
  42. package/dist/llm/executor/turn-executor.d.ts +62 -10
  43. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  44. package/dist/llm/executor/turn-executor.js +219 -30
  45. package/dist/llm/executor/types.d.ts +28 -0
  46. package/dist/llm/executor/types.d.ts.map +1 -1
  47. package/dist/llm/formatters/vercel.cjs +36 -28
  48. package/dist/llm/formatters/vercel.d.ts.map +1 -1
  49. package/dist/llm/formatters/vercel.js +36 -28
  50. package/dist/llm/services/factory.cjs +3 -2
  51. package/dist/llm/services/factory.d.ts +3 -1
  52. package/dist/llm/services/factory.d.ts.map +1 -1
  53. package/dist/llm/services/factory.js +3 -2
  54. package/dist/llm/services/vercel.cjs +34 -6
  55. package/dist/llm/services/vercel.d.ts +23 -3
  56. package/dist/llm/services/vercel.d.ts.map +1 -1
  57. package/dist/llm/services/vercel.js +34 -6
  58. package/dist/session/chat-session.cjs +20 -11
  59. package/dist/session/chat-session.d.ts +9 -4
  60. package/dist/session/chat-session.d.ts.map +1 -1
  61. package/dist/session/chat-session.js +20 -11
  62. package/dist/session/compaction-service.cjs +139 -0
  63. package/dist/session/compaction-service.d.ts +81 -0
  64. package/dist/session/compaction-service.d.ts.map +1 -0
  65. package/dist/session/compaction-service.js +106 -0
  66. package/dist/session/session-manager.cjs +146 -0
  67. package/dist/session/session-manager.d.ts +50 -0
  68. package/dist/session/session-manager.d.ts.map +1 -1
  69. package/dist/session/session-manager.js +146 -0
  70. package/dist/session/title-generator.cjs +2 -2
  71. package/dist/session/title-generator.js +2 -2
  72. package/dist/systemPrompt/in-built-prompts.cjs +36 -0
  73. package/dist/systemPrompt/in-built-prompts.d.ts +18 -1
  74. package/dist/systemPrompt/in-built-prompts.d.ts.map +1 -1
  75. package/dist/systemPrompt/in-built-prompts.js +25 -0
  76. package/dist/systemPrompt/manager.cjs +22 -0
  77. package/dist/systemPrompt/manager.d.ts +10 -0
  78. package/dist/systemPrompt/manager.d.ts.map +1 -1
  79. package/dist/systemPrompt/manager.js +22 -0
  80. package/dist/systemPrompt/registry.cjs +2 -1
  81. package/dist/systemPrompt/registry.d.ts +1 -1
  82. package/dist/systemPrompt/registry.d.ts.map +1 -1
  83. package/dist/systemPrompt/registry.js +2 -1
  84. package/dist/systemPrompt/schemas.cjs +7 -0
  85. package/dist/systemPrompt/schemas.d.ts +13 -13
  86. package/dist/systemPrompt/schemas.d.ts.map +1 -1
  87. package/dist/systemPrompt/schemas.js +7 -0
  88. package/dist/utils/index.cjs +3 -1
  89. package/dist/utils/index.d.ts +1 -0
  90. package/dist/utils/index.d.ts.map +1 -1
  91. package/dist/utils/index.js +1 -0
  92. package/package.json +1 -1
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Session Compaction Service
3
+ *
4
+ * Handles session-native compaction where compacting a session creates a new
5
+ * continuation session with the summary as initial context. This provides
6
+ * clean session isolation with linking for traceability.
7
+ *
8
+ * ## Architecture
9
+ *
10
+ * Session A (compacted) --continuedTo--> Session B (active)
11
+ * ^ |
12
+ * +--------continuedFrom-----------------+
13
+ *
14
+ * When compaction triggers:
15
+ * 1. Generate summary of old messages via compaction strategy
16
+ * 2. Create new session with summary as first message (isSessionSummary marker)
17
+ * 3. Mark old session as compacted (continuedTo, compactedAt)
18
+ * 4. Emit session:continued event
19
+ * 5. Return new session for caller to switch to
20
+ */
21
+ import type { ICompactionStrategy } from '../context/compaction/types.js';
22
+ import type { IDextoLogger } from '../logger/v2/types.js';
23
+ import type { SessionManager } from './session-manager.js';
24
+ import type { ChatSession } from './chat-session.js';
25
+ import type { InternalMessage } from '../context/types.js';
26
+ import type { AgentEventBus } from '../events/index.js';
27
+ /**
28
+ * Result returned when compaction creates a new continuation session.
29
+ */
30
+ export interface CompactionResult {
31
+ /** The session that was compacted */
32
+ previousSessionId: string;
33
+ /** The new session created for continuation */
34
+ newSessionId: string;
35
+ /** The ChatSession instance for the new session */
36
+ newSession: ChatSession;
37
+ /** The summary message added to the new session */
38
+ summary: InternalMessage;
39
+ /** Estimated tokens in the summary */
40
+ summaryTokens: number;
41
+ /** Number of messages that were summarized */
42
+ originalMessages: number;
43
+ }
44
+ /**
45
+ * Options for performing compaction.
46
+ */
47
+ export interface CompactOptions {
48
+ /** Why the compaction was triggered */
49
+ reason: 'overflow' | 'manual';
50
+ /** Optional AgentEventBus to emit session:continued event */
51
+ eventBus?: AgentEventBus;
52
+ }
53
+ /**
54
+ * Service for performing session-native compaction.
55
+ *
56
+ * Instead of adding a summary message to the same session and filtering at read-time,
57
+ * this service creates a new session with the summary as the first message.
58
+ * This provides cleaner session isolation while maintaining traceability via linking.
59
+ */
60
+ export declare class SessionCompactionService {
61
+ private readonly sessionManager;
62
+ private readonly compactionStrategy;
63
+ private readonly logger;
64
+ constructor(sessionManager: SessionManager, compactionStrategy: ICompactionStrategy, logger: IDextoLogger);
65
+ /**
66
+ * Perform session-native compaction.
67
+ *
68
+ * This creates a new continuation session with the summary as initial context,
69
+ * then marks the old session as compacted.
70
+ *
71
+ * @param currentSession The session to compact
72
+ * @param options Compaction options
73
+ * @returns CompactionResult with new session, or null if compaction not needed/possible
74
+ */
75
+ compact(currentSession: ChatSession, options: CompactOptions): Promise<CompactionResult | null>;
76
+ /**
77
+ * Extract text content from message content.
78
+ */
79
+ private extractTextContent;
80
+ }
81
+ //# sourceMappingURL=compaction-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compaction-service.d.ts","sourceRoot":"","sources":["../../src/session/compaction-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,UAAU,EAAE,WAAW,CAAC;IACxB,mDAAmD;IACnD,OAAO,EAAE,eAAe,CAAC;IACzB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,uCAAuC;IACvC,MAAM,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAJvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAGjB,cAAc,EAAE,cAAc,EAC9B,kBAAkB,EAAE,mBAAmB,EACxD,MAAM,EAAE,YAAY;IAKxB;;;;;;;;;OASG;IACG,OAAO,CACT,cAAc,EAAE,WAAW,EAC3B,OAAO,EAAE,cAAc,GACxB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IA6GnC;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAS7B"}
@@ -0,0 +1,106 @@
1
+ import "../chunk-PTJYTZNU.js";
2
+ import { DextoLogComponent } from "../logger/v2/types.js";
3
+ import { estimateMessagesTokens } from "../context/utils.js";
4
+ class SessionCompactionService {
5
+ constructor(sessionManager, compactionStrategy, logger) {
6
+ this.sessionManager = sessionManager;
7
+ this.compactionStrategy = compactionStrategy;
8
+ this.logger = logger.createChild(DextoLogComponent.SESSION);
9
+ }
10
+ logger;
11
+ /**
12
+ * Perform session-native compaction.
13
+ *
14
+ * This creates a new continuation session with the summary as initial context,
15
+ * then marks the old session as compacted.
16
+ *
17
+ * @param currentSession The session to compact
18
+ * @param options Compaction options
19
+ * @returns CompactionResult with new session, or null if compaction not needed/possible
20
+ */
21
+ async compact(currentSession, options) {
22
+ const { reason, eventBus } = options;
23
+ const currentSessionId = currentSession.id;
24
+ this.logger.info(
25
+ `SessionCompactionService: Starting compaction for session ${currentSessionId} (reason: ${reason})`
26
+ );
27
+ const history = await currentSession.getHistory();
28
+ if (history.length <= 2) {
29
+ this.logger.debug("SessionCompactionService: History too short for compaction");
30
+ return null;
31
+ }
32
+ const summaryMessages = await this.compactionStrategy.compact(history);
33
+ if (summaryMessages.length === 0) {
34
+ this.logger.debug("SessionCompactionService: Strategy returned no summary");
35
+ return null;
36
+ }
37
+ const strategySummary = summaryMessages[0];
38
+ if (!strategySummary || !strategySummary.content) {
39
+ return null;
40
+ }
41
+ const summaryText = this.extractTextContent(strategySummary.content);
42
+ if (!summaryText.trim()) {
43
+ this.logger.debug("SessionCompactionService: Empty summary text; skipping compaction");
44
+ return null;
45
+ }
46
+ const summaryMessage = {
47
+ role: "assistant",
48
+ content: [{ type: "text", text: summaryText }],
49
+ timestamp: Date.now(),
50
+ metadata: {
51
+ isSessionSummary: true,
52
+ // New marker for session-native compaction
53
+ continuedFrom: currentSessionId,
54
+ summarizedAt: Date.now(),
55
+ originalMessageCount: history.length,
56
+ originalFirstTimestamp: history[0]?.timestamp,
57
+ originalLastTimestamp: history[history.length - 1]?.timestamp
58
+ }
59
+ };
60
+ const summaryTokens = estimateMessagesTokens([summaryMessage]);
61
+ const { sessionId: newSessionId, session: newSession } = await this.sessionManager.createContinuationSession(currentSessionId);
62
+ const contextManager = newSession.getContextManager();
63
+ await contextManager.addMessage(summaryMessage);
64
+ await this.sessionManager.markSessionCompacted(currentSessionId, newSessionId);
65
+ this.logger.info(
66
+ `SessionCompactionService: Compaction complete. ${currentSessionId} \u2192 ${newSessionId}, ${history.length} messages \u2192 summary (~${summaryTokens} tokens)`
67
+ );
68
+ if (eventBus) {
69
+ const llmConfig = newSession.getLLMService().getConfig();
70
+ const modelId = typeof llmConfig.model === "string" ? llmConfig.model : llmConfig.model.modelId;
71
+ const { getModelDisplayName } = await import("../llm/registry.js");
72
+ const modelDisplayName = getModelDisplayName(modelId, llmConfig.provider);
73
+ eventBus.emit("session:continued", {
74
+ previousSessionId: currentSessionId,
75
+ newSessionId,
76
+ summaryTokens,
77
+ originalMessages: history.length,
78
+ reason,
79
+ sessionId: newSessionId,
80
+ // For consistency with other streaming events
81
+ model: modelId,
82
+ modelDisplayName
83
+ });
84
+ }
85
+ return {
86
+ previousSessionId: currentSessionId,
87
+ newSessionId,
88
+ newSession,
89
+ summary: summaryMessage,
90
+ summaryTokens,
91
+ originalMessages: history.length
92
+ };
93
+ }
94
+ /**
95
+ * Extract text content from message content.
96
+ */
97
+ extractTextContent(content) {
98
+ if (typeof content === "string") {
99
+ return content;
100
+ }
101
+ return content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
102
+ }
103
+ }
104
+ export {
105
+ SessionCompactionService
106
+ };
@@ -516,6 +516,152 @@ class SessionManager {
516
516
  sessionTTL: this.sessionTTL
517
517
  };
518
518
  }
519
+ /**
520
+ * Get the raw session data for a session ID.
521
+ * This is used for accessing continuation fields and other metadata.
522
+ *
523
+ * @param sessionId The session ID
524
+ * @returns Session data if found, undefined otherwise
525
+ */
526
+ async getSessionData(sessionId) {
527
+ await this.ensureInitialized();
528
+ const sessionKey = `session:${sessionId}`;
529
+ return await this.services.storageManager.getDatabase().get(sessionKey);
530
+ }
531
+ /**
532
+ * Creates a continuation session from a compacted session.
533
+ * The new session will have the summary as its first message.
534
+ *
535
+ * @param fromSessionId The session being compacted
536
+ * @returns The new session ID and ChatSession
537
+ */
538
+ async createContinuationSession(fromSessionId) {
539
+ await this.ensureInitialized();
540
+ const fromSessionData = await this.getSessionData(fromSessionId);
541
+ if (!fromSessionData) {
542
+ throw import_errors.SessionError.notFound(fromSessionId);
543
+ }
544
+ const activeSessionKeys = await this.services.storageManager.getDatabase().list("session:");
545
+ if (activeSessionKeys.length >= this.maxSessions) {
546
+ throw import_errors.SessionError.maxSessionsExceeded(activeSessionKeys.length, this.maxSessions);
547
+ }
548
+ const newSessionId = (0, import_crypto.randomUUID)();
549
+ const originalLLMConfig = this.services.stateManager.getRuntimeConfig(fromSessionId).llm;
550
+ this.services.stateManager.updateLLM(originalLLMConfig, newSessionId);
551
+ const parentCompactionCount = fromSessionData.compactionCount ?? 0;
552
+ const newSessionData = {
553
+ id: newSessionId,
554
+ createdAt: Date.now(),
555
+ lastActivity: Date.now(),
556
+ messageCount: 0,
557
+ continuedFrom: fromSessionId,
558
+ compactionCount: parentCompactionCount + 1,
559
+ ...fromSessionData.userId !== void 0 && { userId: fromSessionData.userId },
560
+ ...fromSessionData.metadata && {
561
+ metadata: {
562
+ ...fromSessionData.metadata,
563
+ title: fromSessionData.metadata?.title
564
+ // Preserve title
565
+ }
566
+ }
567
+ };
568
+ const sessionKey = `session:${newSessionId}`;
569
+ try {
570
+ await this.services.storageManager.getDatabase().set(sessionKey, newSessionData);
571
+ await this.services.storageManager.getCache().set(sessionKey, newSessionData, this.sessionTTL / 1e3);
572
+ } catch (error) {
573
+ this.services.stateManager.clearSessionOverride(newSessionId);
574
+ throw error;
575
+ }
576
+ const session = new import_chat_session.ChatSession(
577
+ { ...this.services, sessionManager: this },
578
+ newSessionId,
579
+ this.logger
580
+ );
581
+ try {
582
+ await session.init();
583
+ } catch (error) {
584
+ session.dispose();
585
+ await this.services.storageManager.getDatabase().delete(sessionKey);
586
+ await this.services.storageManager.getCache().delete(sessionKey);
587
+ this.services.stateManager.clearSessionOverride(newSessionId);
588
+ throw error;
589
+ }
590
+ this.sessions.set(newSessionId, session);
591
+ this.logger.info(
592
+ `Created continuation session ${newSessionId} from compacted session ${fromSessionId}`
593
+ );
594
+ return { sessionId: newSessionId, session };
595
+ }
596
+ /**
597
+ * Marks a session as compacted and links it to its continuation session.
598
+ *
599
+ * @param sessionId The session being compacted
600
+ * @param continuedToId The new session created from compaction
601
+ */
602
+ async markSessionCompacted(sessionId, continuedToId) {
603
+ await this.ensureInitialized();
604
+ const sessionKey = `session:${sessionId}`;
605
+ const sessionData = await this.services.storageManager.getDatabase().get(sessionKey);
606
+ if (!sessionData) {
607
+ throw import_errors.SessionError.notFound(sessionId);
608
+ }
609
+ sessionData.continuedTo = continuedToId;
610
+ sessionData.compactedAt = Date.now();
611
+ sessionData.lastActivity = Date.now();
612
+ await this.services.storageManager.getDatabase().set(sessionKey, sessionData);
613
+ await this.services.storageManager.getCache().set(sessionKey, sessionData, this.sessionTTL / 1e3);
614
+ this.logger.debug(`Marked session ${sessionId} as compacted \u2192 ${continuedToId}`);
615
+ }
616
+ /**
617
+ * Gets the compaction count for a session.
618
+ * Returns 0 if the session has never been compacted.
619
+ *
620
+ * @param sessionId The session ID
621
+ * @returns Number of times this session chain has been compacted
622
+ */
623
+ async getCompactionCount(sessionId) {
624
+ const sessionData = await this.getSessionData(sessionId);
625
+ return sessionData?.compactionCount ?? 0;
626
+ }
627
+ /**
628
+ * Gets the chain of linked sessions (ancestors and descendants).
629
+ * Returns sessions in chronological order (oldest first).
630
+ *
631
+ * @param sessionId Any session ID in the chain
632
+ * @returns Array of session data in the chain, ordered chronologically
633
+ */
634
+ async getSessionChain(sessionId) {
635
+ await this.ensureInitialized();
636
+ const chain = [];
637
+ const visited = /* @__PURE__ */ new Set();
638
+ let currentData = await this.getSessionData(sessionId);
639
+ if (!currentData) {
640
+ return [];
641
+ }
642
+ while (currentData?.continuedFrom && !visited.has(currentData.continuedFrom)) {
643
+ visited.add(currentData.id);
644
+ const parent = await this.getSessionData(currentData.continuedFrom);
645
+ if (!parent) {
646
+ break;
647
+ }
648
+ currentData = parent;
649
+ }
650
+ if (currentData && !visited.has(currentData.id)) {
651
+ visited.add(currentData.id);
652
+ }
653
+ visited.clear();
654
+ while (currentData && !visited.has(currentData.id)) {
655
+ visited.add(currentData.id);
656
+ chain.push(currentData);
657
+ if (currentData.continuedTo) {
658
+ currentData = await this.getSessionData(currentData.continuedTo);
659
+ } else {
660
+ break;
661
+ }
662
+ }
663
+ return chain;
664
+ }
519
665
  /**
520
666
  * Cleanup all sessions and resources.
521
667
  * This should be called when shutting down the application.
@@ -34,6 +34,14 @@ export interface SessionData {
34
34
  metadata?: Record<string, any>;
35
35
  tokenUsage?: SessionTokenUsage;
36
36
  estimatedCost?: number;
37
+ /** Parent session that was compacted to create this session */
38
+ continuedFrom?: string;
39
+ /** Child session created when this session was compacted */
40
+ continuedTo?: string;
41
+ /** Timestamp when this session was compacted (created a continuation) */
42
+ compactedAt?: number;
43
+ /** Number of times this session chain has been compacted (inherited + 1 on each compaction) */
44
+ compactionCount?: number;
37
45
  }
38
46
  /**
39
47
  * Manages multiple chat sessions within a Dexto agent.
@@ -204,6 +212,48 @@ export declare class SessionManager {
204
212
  maxSessions: number;
205
213
  sessionTTL: number;
206
214
  }>;
215
+ /**
216
+ * Get the raw session data for a session ID.
217
+ * This is used for accessing continuation fields and other metadata.
218
+ *
219
+ * @param sessionId The session ID
220
+ * @returns Session data if found, undefined otherwise
221
+ */
222
+ getSessionData(sessionId: string): Promise<SessionData | undefined>;
223
+ /**
224
+ * Creates a continuation session from a compacted session.
225
+ * The new session will have the summary as its first message.
226
+ *
227
+ * @param fromSessionId The session being compacted
228
+ * @returns The new session ID and ChatSession
229
+ */
230
+ createContinuationSession(fromSessionId: string): Promise<{
231
+ sessionId: string;
232
+ session: ChatSession;
233
+ }>;
234
+ /**
235
+ * Marks a session as compacted and links it to its continuation session.
236
+ *
237
+ * @param sessionId The session being compacted
238
+ * @param continuedToId The new session created from compaction
239
+ */
240
+ markSessionCompacted(sessionId: string, continuedToId: string): Promise<void>;
241
+ /**
242
+ * Gets the compaction count for a session.
243
+ * Returns 0 if the session has never been compacted.
244
+ *
245
+ * @param sessionId The session ID
246
+ * @returns Number of times this session chain has been compacted
247
+ */
248
+ getCompactionCount(sessionId: string): Promise<number>;
249
+ /**
250
+ * Gets the chain of linked sessions (ancestors and descendants).
251
+ * Returns sessions in chronological order (oldest first).
252
+ *
253
+ * @param sessionId Any session ID in the chain
254
+ * @returns Array of session data in the chain, ordered chronologically
255
+ */
256
+ getSessionChain(sessionId: string): Promise<SessionData[]>;
207
257
  /**
208
258
  * Cleanup all sessions and resources.
209
259
  * This should be called when shutting down the application.
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -494,6 +494,152 @@ class SessionManager {
494
494
  sessionTTL: this.sessionTTL
495
495
  };
496
496
  }
497
+ /**
498
+ * Get the raw session data for a session ID.
499
+ * This is used for accessing continuation fields and other metadata.
500
+ *
501
+ * @param sessionId The session ID
502
+ * @returns Session data if found, undefined otherwise
503
+ */
504
+ async getSessionData(sessionId) {
505
+ await this.ensureInitialized();
506
+ const sessionKey = `session:${sessionId}`;
507
+ return await this.services.storageManager.getDatabase().get(sessionKey);
508
+ }
509
+ /**
510
+ * Creates a continuation session from a compacted session.
511
+ * The new session will have the summary as its first message.
512
+ *
513
+ * @param fromSessionId The session being compacted
514
+ * @returns The new session ID and ChatSession
515
+ */
516
+ async createContinuationSession(fromSessionId) {
517
+ await this.ensureInitialized();
518
+ const fromSessionData = await this.getSessionData(fromSessionId);
519
+ if (!fromSessionData) {
520
+ throw SessionError.notFound(fromSessionId);
521
+ }
522
+ const activeSessionKeys = await this.services.storageManager.getDatabase().list("session:");
523
+ if (activeSessionKeys.length >= this.maxSessions) {
524
+ throw SessionError.maxSessionsExceeded(activeSessionKeys.length, this.maxSessions);
525
+ }
526
+ const newSessionId = randomUUID();
527
+ const originalLLMConfig = this.services.stateManager.getRuntimeConfig(fromSessionId).llm;
528
+ this.services.stateManager.updateLLM(originalLLMConfig, newSessionId);
529
+ const parentCompactionCount = fromSessionData.compactionCount ?? 0;
530
+ const newSessionData = {
531
+ id: newSessionId,
532
+ createdAt: Date.now(),
533
+ lastActivity: Date.now(),
534
+ messageCount: 0,
535
+ continuedFrom: fromSessionId,
536
+ compactionCount: parentCompactionCount + 1,
537
+ ...fromSessionData.userId !== void 0 && { userId: fromSessionData.userId },
538
+ ...fromSessionData.metadata && {
539
+ metadata: {
540
+ ...fromSessionData.metadata,
541
+ title: fromSessionData.metadata?.title
542
+ // Preserve title
543
+ }
544
+ }
545
+ };
546
+ const sessionKey = `session:${newSessionId}`;
547
+ try {
548
+ await this.services.storageManager.getDatabase().set(sessionKey, newSessionData);
549
+ await this.services.storageManager.getCache().set(sessionKey, newSessionData, this.sessionTTL / 1e3);
550
+ } catch (error) {
551
+ this.services.stateManager.clearSessionOverride(newSessionId);
552
+ throw error;
553
+ }
554
+ const session = new ChatSession(
555
+ { ...this.services, sessionManager: this },
556
+ newSessionId,
557
+ this.logger
558
+ );
559
+ try {
560
+ await session.init();
561
+ } catch (error) {
562
+ session.dispose();
563
+ await this.services.storageManager.getDatabase().delete(sessionKey);
564
+ await this.services.storageManager.getCache().delete(sessionKey);
565
+ this.services.stateManager.clearSessionOverride(newSessionId);
566
+ throw error;
567
+ }
568
+ this.sessions.set(newSessionId, session);
569
+ this.logger.info(
570
+ `Created continuation session ${newSessionId} from compacted session ${fromSessionId}`
571
+ );
572
+ return { sessionId: newSessionId, session };
573
+ }
574
+ /**
575
+ * Marks a session as compacted and links it to its continuation session.
576
+ *
577
+ * @param sessionId The session being compacted
578
+ * @param continuedToId The new session created from compaction
579
+ */
580
+ async markSessionCompacted(sessionId, continuedToId) {
581
+ await this.ensureInitialized();
582
+ const sessionKey = `session:${sessionId}`;
583
+ const sessionData = await this.services.storageManager.getDatabase().get(sessionKey);
584
+ if (!sessionData) {
585
+ throw SessionError.notFound(sessionId);
586
+ }
587
+ sessionData.continuedTo = continuedToId;
588
+ sessionData.compactedAt = Date.now();
589
+ sessionData.lastActivity = Date.now();
590
+ await this.services.storageManager.getDatabase().set(sessionKey, sessionData);
591
+ await this.services.storageManager.getCache().set(sessionKey, sessionData, this.sessionTTL / 1e3);
592
+ this.logger.debug(`Marked session ${sessionId} as compacted \u2192 ${continuedToId}`);
593
+ }
594
+ /**
595
+ * Gets the compaction count for a session.
596
+ * Returns 0 if the session has never been compacted.
597
+ *
598
+ * @param sessionId The session ID
599
+ * @returns Number of times this session chain has been compacted
600
+ */
601
+ async getCompactionCount(sessionId) {
602
+ const sessionData = await this.getSessionData(sessionId);
603
+ return sessionData?.compactionCount ?? 0;
604
+ }
605
+ /**
606
+ * Gets the chain of linked sessions (ancestors and descendants).
607
+ * Returns sessions in chronological order (oldest first).
608
+ *
609
+ * @param sessionId Any session ID in the chain
610
+ * @returns Array of session data in the chain, ordered chronologically
611
+ */
612
+ async getSessionChain(sessionId) {
613
+ await this.ensureInitialized();
614
+ const chain = [];
615
+ const visited = /* @__PURE__ */ new Set();
616
+ let currentData = await this.getSessionData(sessionId);
617
+ if (!currentData) {
618
+ return [];
619
+ }
620
+ while (currentData?.continuedFrom && !visited.has(currentData.continuedFrom)) {
621
+ visited.add(currentData.id);
622
+ const parent = await this.getSessionData(currentData.continuedFrom);
623
+ if (!parent) {
624
+ break;
625
+ }
626
+ currentData = parent;
627
+ }
628
+ if (currentData && !visited.has(currentData.id)) {
629
+ visited.add(currentData.id);
630
+ }
631
+ visited.clear();
632
+ while (currentData && !visited.has(currentData.id)) {
633
+ visited.add(currentData.id);
634
+ chain.push(currentData);
635
+ if (currentData.continuedTo) {
636
+ currentData = await this.getSessionData(currentData.continuedTo);
637
+ } else {
638
+ break;
639
+ }
640
+ }
641
+ return chain;
642
+ }
497
643
  /**
498
644
  * Cleanup all sessions and resources.
499
645
  * This should be called when shutting down the application.
@@ -52,11 +52,11 @@ async function generateSessionTitle(config, toolManager, systemPromptManager, re
52
52
  "Message:",
53
53
  sanitizeUserText(userText, 512)
54
54
  ].join("\n");
55
- const result = await tempService.stream(
55
+ const streamResult = await tempService.stream(
56
56
  instruction,
57
57
  controller ? { signal: controller.signal } : void 0
58
58
  );
59
- const processed = postProcessTitle(result);
59
+ const processed = postProcessTitle(streamResult.text);
60
60
  if (!processed) {
61
61
  return { error: "LLM returned empty title" };
62
62
  }
@@ -29,11 +29,11 @@ async function generateSessionTitle(config, toolManager, systemPromptManager, re
29
29
  "Message:",
30
30
  sanitizeUserText(userText, 512)
31
31
  ].join("\n");
32
- const result = await tempService.stream(
32
+ const streamResult = await tempService.stream(
33
33
  instruction,
34
34
  controller ? { signal: controller.signal } : void 0
35
35
  );
36
- const processed = postProcessTitle(result);
36
+ const processed = postProcessTitle(streamResult.text);
37
37
  if (!processed) {
38
38
  return { error: "LLM returned empty title" };
39
39
  }
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,10 +17,19 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var in_built_prompts_exports = {};
20
30
  __export(in_built_prompts_exports, {
21
31
  getCurrentDate: () => getCurrentDate,
32
+ getEnvironmentInfo: () => getEnvironmentInfo,
22
33
  getResourceData: () => getResourceData
23
34
  });
24
35
  module.exports = __toCommonJS(in_built_prompts_exports);
@@ -26,6 +37,30 @@ async function getCurrentDate(_context) {
26
37
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
27
38
  return `<date>Current date: ${date}</date>`;
28
39
  }
40
+ async function getEnvironmentInfo(_context) {
41
+ if (typeof process === "undefined" || !process.cwd) {
42
+ return "<environment>Environment info not available in browser context</environment>";
43
+ }
44
+ try {
45
+ const [{ existsSync }, { platform }, { join }] = await Promise.all([
46
+ import("fs"),
47
+ import("os"),
48
+ import("path")
49
+ ]);
50
+ const cwd = process.cwd();
51
+ const os = platform();
52
+ const isGitRepo = existsSync(join(cwd, ".git"));
53
+ const shell = process.env.SHELL || (os === "win32" ? "cmd.exe" : "/bin/sh");
54
+ return `<environment>
55
+ <cwd>${cwd}</cwd>
56
+ <platform>${os}</platform>
57
+ <is_git_repo>${isGitRepo}</is_git_repo>
58
+ <shell>${shell}</shell>
59
+ </environment>`;
60
+ } catch {
61
+ return "<environment>Environment info not available</environment>";
62
+ }
63
+ }
29
64
  async function getResourceData(context) {
30
65
  const resources = await context.mcpManager.listAllResources();
31
66
  if (!resources || resources.length === 0) {
@@ -58,5 +93,6 @@ ${parts.join("\n")}
58
93
  // Annotate the CommonJS export names for ESM import in node:
59
94
  0 && (module.exports = {
60
95
  getCurrentDate,
96
+ getEnvironmentInfo,
61
97
  getResourceData
62
98
  });