@dexto/core 1.5.3 → 1.5.5

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 (143) hide show
  1. package/dist/agent/DextoAgent.cjs +190 -1
  2. package/dist/agent/DextoAgent.d.ts +71 -0
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +181 -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 +168 -26
  20. package/dist/context/compaction/strategies/reactive-overflow.d.ts +22 -0
  21. package/dist/context/compaction/strategies/reactive-overflow.d.ts.map +1 -1
  22. package/dist/context/compaction/strategies/reactive-overflow.js +168 -26
  23. package/dist/context/compaction/types.d.ts +13 -1
  24. package/dist/context/compaction/types.d.ts.map +1 -1
  25. package/dist/context/manager.cjs +278 -31
  26. package/dist/context/manager.d.ts +192 -5
  27. package/dist/context/manager.d.ts.map +1 -1
  28. package/dist/context/manager.js +285 -32
  29. package/dist/context/types.d.ts +6 -0
  30. package/dist/context/types.d.ts.map +1 -1
  31. package/dist/context/utils.cjs +77 -11
  32. package/dist/context/utils.d.ts +86 -8
  33. package/dist/context/utils.d.ts.map +1 -1
  34. package/dist/context/utils.js +71 -11
  35. package/dist/errors/types.cjs +0 -2
  36. package/dist/errors/types.d.ts +1 -5
  37. package/dist/errors/types.d.ts.map +1 -1
  38. package/dist/errors/types.js +0 -2
  39. package/dist/events/index.cjs +2 -0
  40. package/dist/events/index.d.ts +21 -6
  41. package/dist/events/index.d.ts.map +1 -1
  42. package/dist/events/index.js +2 -0
  43. package/dist/llm/executor/stream-processor.cjs +104 -28
  44. package/dist/llm/executor/stream-processor.d.ts +7 -0
  45. package/dist/llm/executor/stream-processor.d.ts.map +1 -1
  46. package/dist/llm/executor/stream-processor.js +104 -28
  47. package/dist/llm/executor/turn-executor.cjs +147 -30
  48. package/dist/llm/executor/turn-executor.d.ts +28 -10
  49. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  50. package/dist/llm/executor/turn-executor.js +147 -30
  51. package/dist/llm/formatters/vercel.cjs +36 -28
  52. package/dist/llm/formatters/vercel.d.ts.map +1 -1
  53. package/dist/llm/formatters/vercel.js +36 -28
  54. package/dist/llm/services/factory.cjs +3 -2
  55. package/dist/llm/services/factory.d.ts +3 -1
  56. package/dist/llm/services/factory.d.ts.map +1 -1
  57. package/dist/llm/services/factory.js +3 -2
  58. package/dist/llm/services/vercel.cjs +31 -6
  59. package/dist/llm/services/vercel.d.ts +18 -3
  60. package/dist/llm/services/vercel.d.ts.map +1 -1
  61. package/dist/llm/services/vercel.js +31 -6
  62. package/dist/session/chat-session.cjs +29 -13
  63. package/dist/session/chat-session.d.ts +6 -4
  64. package/dist/session/chat-session.d.ts.map +1 -1
  65. package/dist/session/chat-session.js +29 -13
  66. package/dist/session/session-manager.cjs +11 -0
  67. package/dist/session/session-manager.d.ts +7 -0
  68. package/dist/session/session-manager.d.ts.map +1 -1
  69. package/dist/session/session-manager.js +11 -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/telemetry/telemetry.cjs +12 -5
  89. package/dist/telemetry/telemetry.d.ts.map +1 -1
  90. package/dist/telemetry/telemetry.js +12 -5
  91. package/dist/utils/index.cjs +3 -1
  92. package/dist/utils/index.d.ts +1 -0
  93. package/dist/utils/index.d.ts.map +1 -1
  94. package/dist/utils/index.js +1 -0
  95. package/package.json +15 -5
  96. package/dist/filesystem/error-codes.cjs +0 -53
  97. package/dist/filesystem/error-codes.d.ts +0 -31
  98. package/dist/filesystem/error-codes.d.ts.map +0 -1
  99. package/dist/filesystem/error-codes.js +0 -30
  100. package/dist/filesystem/errors.cjs +0 -303
  101. package/dist/filesystem/errors.d.ts +0 -109
  102. package/dist/filesystem/errors.d.ts.map +0 -1
  103. package/dist/filesystem/errors.js +0 -280
  104. package/dist/filesystem/filesystem-service.cjs +0 -534
  105. package/dist/filesystem/filesystem-service.d.ts +0 -97
  106. package/dist/filesystem/filesystem-service.d.ts.map +0 -1
  107. package/dist/filesystem/filesystem-service.js +0 -501
  108. package/dist/filesystem/index.cjs +0 -37
  109. package/dist/filesystem/index.d.ts +0 -11
  110. package/dist/filesystem/index.d.ts.map +0 -1
  111. package/dist/filesystem/index.js +0 -11
  112. package/dist/filesystem/path-validator.cjs +0 -250
  113. package/dist/filesystem/path-validator.d.ts +0 -103
  114. package/dist/filesystem/path-validator.d.ts.map +0 -1
  115. package/dist/filesystem/path-validator.js +0 -217
  116. package/dist/filesystem/types.cjs +0 -16
  117. package/dist/filesystem/types.d.ts +0 -175
  118. package/dist/filesystem/types.d.ts.map +0 -1
  119. package/dist/filesystem/types.js +0 -0
  120. package/dist/process/command-validator.cjs +0 -554
  121. package/dist/process/command-validator.d.ts +0 -49
  122. package/dist/process/command-validator.d.ts.map +0 -1
  123. package/dist/process/command-validator.js +0 -531
  124. package/dist/process/error-codes.cjs +0 -47
  125. package/dist/process/error-codes.d.ts +0 -25
  126. package/dist/process/error-codes.d.ts.map +0 -1
  127. package/dist/process/error-codes.js +0 -24
  128. package/dist/process/errors.cjs +0 -244
  129. package/dist/process/errors.d.ts +0 -87
  130. package/dist/process/errors.d.ts.map +0 -1
  131. package/dist/process/errors.js +0 -221
  132. package/dist/process/index.cjs +0 -37
  133. package/dist/process/index.d.ts +0 -11
  134. package/dist/process/index.d.ts.map +0 -1
  135. package/dist/process/index.js +0 -11
  136. package/dist/process/process-service.cjs +0 -497
  137. package/dist/process/process-service.d.ts +0 -69
  138. package/dist/process/process-service.d.ts.map +0 -1
  139. package/dist/process/process-service.js +0 -464
  140. package/dist/process/types.cjs +0 -16
  141. package/dist/process/types.d.ts +0 -107
  142. package/dist/process/types.d.ts.map +0 -1
  143. package/dist/process/types.js +0 -0
@@ -23,7 +23,7 @@ import { ReactiveOverflowStrategy } from "../../context/compaction/strategies/re
23
23
  const toolSupportCache = /* @__PURE__ */ new Map();
24
24
  const LOCAL_PROVIDERS = ["ollama", "local"];
25
25
  class TurnExecutor {
26
- constructor(model, toolManager, contextManager, eventBus, resourceManager, sessionId, config, llmContext, logger, messageQueue, modelLimits, externalSignal, compactionStrategy) {
26
+ constructor(model, toolManager, contextManager, eventBus, resourceManager, sessionId, config, llmContext, logger, messageQueue, modelLimits, externalSignal, compactionStrategy, compactionThresholdPercent = 1) {
27
27
  this.model = model;
28
28
  this.toolManager = toolManager;
29
29
  this.contextManager = contextManager;
@@ -35,6 +35,7 @@ class TurnExecutor {
35
35
  this.messageQueue = messageQueue;
36
36
  this.modelLimits = modelLimits;
37
37
  this.externalSignal = externalSignal;
38
+ this.compactionThresholdPercent = compactionThresholdPercent;
38
39
  this.logger = logger.createChild(DextoLogComponent.EXECUTOR);
39
40
  this.stepAbortController = new AbortController();
40
41
  if (compactionStrategy !== void 0) {
@@ -57,11 +58,13 @@ class TurnExecutor {
57
58
  approvalMetadata = /* @__PURE__ */ new Map();
58
59
  /**
59
60
  * Get StreamProcessor config from TurnExecutor state.
61
+ * @param estimatedInputTokens Optional estimated input tokens for analytics
60
62
  */
61
- getStreamProcessorConfig() {
63
+ getStreamProcessorConfig(estimatedInputTokens) {
62
64
  return {
63
65
  provider: this.llmContext.provider,
64
- model: this.llmContext.model
66
+ model: this.llmContext.model,
67
+ ...estimatedInputTokens !== void 0 && { estimatedInputTokens }
65
68
  };
66
69
  }
67
70
  /**
@@ -117,13 +120,41 @@ class TurnExecutor {
117
120
  if (coalesced) {
118
121
  await this.injectQueuedMessages(coalesced);
119
122
  }
120
- if (lastStepTokens && this.checkAndHandleOverflow(lastStepTokens)) {
121
- await this.compress(lastStepTokens.inputTokens ?? 0);
122
- }
123
- const prepared = await this.contextManager.getFormattedMessagesWithCompression(
123
+ await this.pruneOldToolOutputs();
124
+ let prepared = await this.contextManager.getFormattedMessagesForLLM(
124
125
  contributorContext,
125
126
  this.llmContext
126
127
  );
128
+ const toolDefinitions = supportsTools ? await this.toolManager.getAllTools() : {};
129
+ let estimatedTokens = await this.contextManager.getEstimatedNextInputTokens(
130
+ prepared.systemPrompt,
131
+ prepared.preparedHistory,
132
+ toolDefinitions
133
+ );
134
+ if (this.shouldCompact(estimatedTokens)) {
135
+ this.logger.debug(
136
+ `Pre-check: estimated ${estimatedTokens} tokens exceeds threshold, compacting`
137
+ );
138
+ const didCompact = await this.compactContext(
139
+ estimatedTokens,
140
+ contributorContext,
141
+ toolDefinitions
142
+ );
143
+ if (didCompact) {
144
+ prepared = await this.contextManager.getFormattedMessagesForLLM(
145
+ contributorContext,
146
+ this.llmContext
147
+ );
148
+ estimatedTokens = await this.contextManager.getEstimatedNextInputTokens(
149
+ prepared.systemPrompt,
150
+ prepared.preparedHistory,
151
+ toolDefinitions
152
+ );
153
+ this.logger.debug(
154
+ `Post-compaction: recomputed estimate is ${estimatedTokens} tokens`
155
+ );
156
+ }
157
+ }
127
158
  this.logger.debug(`Step ${stepCount}: Starting`);
128
159
  const tools = supportsTools ? await this.createTools() : {};
129
160
  const streamProcessor = new StreamProcessor(
@@ -131,7 +162,7 @@ class TurnExecutor {
131
162
  this.eventBus,
132
163
  this.resourceManager,
133
164
  this.stepAbortController.signal,
134
- this.getStreamProcessorConfig(),
165
+ this.getStreamProcessorConfig(estimatedTokens),
135
166
  this.logger,
136
167
  streaming,
137
168
  this.approvalMetadata
@@ -170,6 +201,35 @@ class TurnExecutor {
170
201
  this.logger.debug(
171
202
  `Step ${stepCount}: Finished with reason="${result.finishReason}", tokens=${JSON.stringify(result.usage)}`
172
203
  );
204
+ if (result.finishReason === "cancelled") {
205
+ this.logger.info(
206
+ `Context estimation (cancelled): keeping last known actuals, partial response (${result.text.length} chars) will be estimated`
207
+ );
208
+ } else if (result.usage?.inputTokens !== void 0) {
209
+ const contextInputTokens2 = this.getContextInputTokens(result.usage);
210
+ const actualInputTokens = contextInputTokens2 ?? result.usage.inputTokens;
211
+ const diff = estimatedTokens - actualInputTokens;
212
+ const diffPercent = actualInputTokens > 0 ? (diff / actualInputTokens * 100).toFixed(1) : "0.0";
213
+ this.logger.info(
214
+ `Context estimation accuracy: estimated=${estimatedTokens}, actual=${actualInputTokens}, error=${diff} (${diffPercent}%)`
215
+ );
216
+ this.contextManager.setLastActualInputTokens(actualInputTokens);
217
+ if (result.usage?.outputTokens !== void 0) {
218
+ this.contextManager.setLastActualOutputTokens(result.usage.outputTokens);
219
+ }
220
+ await this.contextManager.recordLastCallMessageCount();
221
+ }
222
+ const contextInputTokens = result.usage ? this.getContextInputTokens(result.usage) : null;
223
+ if (contextInputTokens && this.shouldCompactFromActual(contextInputTokens)) {
224
+ this.logger.debug(
225
+ `Post-response: actual ${contextInputTokens} tokens exceeds threshold, compacting`
226
+ );
227
+ await this.compactContext(
228
+ contextInputTokens,
229
+ contributorContext,
230
+ toolDefinitions
231
+ );
232
+ }
173
233
  if (result.finishReason !== "tool-calls") {
174
234
  const queuedOnTerminate = this.messageQueue.dequeueAll();
175
235
  if (queuedOnTerminate) {
@@ -193,7 +253,6 @@ class TurnExecutor {
193
253
  lastFinishReason = "max-steps";
194
254
  break;
195
255
  }
196
- await this.pruneOldToolOutputs();
197
256
  }
198
257
  } catch (error) {
199
258
  const mappedError = this.mapProviderError(error);
@@ -521,7 +580,7 @@ class TurnExecutor {
521
580
  /**
522
581
  * Prunes old tool outputs by marking them with compactedAt timestamp.
523
582
  * Does NOT modify content - transformation happens at format time in
524
- * ContextManager.getFormattedMessagesWithCompression().
583
+ * ContextManager.prepareHistory().
525
584
  *
526
585
  * Algorithm:
527
586
  * 1. Go backwards through history (most recent first)
@@ -590,54 +649,108 @@ class TurnExecutor {
590
649
  this.messageQueue.clear();
591
650
  }
592
651
  /**
593
- * Check if context has overflowed based on actual token usage from API.
652
+ * Check if context should be compacted based on estimated token count.
653
+ * Uses the threshold percentage from compaction config to trigger earlier (e.g., at 90%).
654
+ *
655
+ * @param estimatedTokens Estimated token count from the current context
656
+ * @returns true if compaction is needed before making the LLM call
594
657
  */
595
- checkAndHandleOverflow(tokens) {
658
+ shouldCompact(estimatedTokens) {
596
659
  if (!this.modelLimits || !this.compactionStrategy) {
597
660
  return false;
598
661
  }
599
- return isOverflow(tokens, this.modelLimits);
662
+ return isOverflow(
663
+ { inputTokens: estimatedTokens },
664
+ this.modelLimits,
665
+ this.compactionThresholdPercent
666
+ );
600
667
  }
601
668
  /**
602
- * Compress context using ReactiveOverflowStrategy.
669
+ * Check if context should be compacted based on actual token count from API response.
670
+ * This is a post-response check using real token counts rather than estimates.
603
671
  *
604
- * Generates a summary of older messages and adds it to history.
605
- * The actual token reduction happens at read-time via filterCompacted()
606
- * in getFormattedMessagesWithCompression().
672
+ * @param actualTokens Actual input token count from the API response
673
+ * @returns true if compaction is needed
674
+ */
675
+ shouldCompactFromActual(actualTokens) {
676
+ if (!this.modelLimits || !this.compactionStrategy) {
677
+ return false;
678
+ }
679
+ return isOverflow(
680
+ { inputTokens: actualTokens },
681
+ this.modelLimits,
682
+ this.compactionThresholdPercent
683
+ );
684
+ }
685
+ /**
686
+ * Compact context by generating a summary and adding it to the same session.
687
+ *
688
+ * The summary message is added to the conversation history with `isSummary: true` metadata.
689
+ * When the context is loaded via getFormattedMessagesForLLM(), filterCompacted() will
690
+ * exclude all messages before the summary, effectively compacting the context.
607
691
  *
608
- * @param originalTokens The actual input token count from API that triggered overflow
692
+ * @param originalTokens The estimated input token count that triggered overflow
693
+ * @param contributorContext Context for system prompt contributors (needed for accurate token estimation)
694
+ * @param tools Tool definitions (needed for accurate token estimation)
695
+ * @returns true if compaction occurred, false if skipped
609
696
  */
610
- async compress(originalTokens) {
697
+ async compactContext(originalTokens, contributorContext, tools) {
611
698
  if (!this.compactionStrategy) {
612
- return;
699
+ return false;
613
700
  }
614
701
  this.logger.info(
615
- `Context overflow detected (${originalTokens} tokens), running compression`
702
+ `Context overflow detected (${originalTokens} tokens), checking if compression is possible`
616
703
  );
617
704
  const history = await this.contextManager.getHistory();
705
+ const { filterCompacted } = await import("../../context/utils.js");
706
+ const originalFiltered = filterCompacted(history);
707
+ const originalMessages = originalFiltered.length;
708
+ if (history.length < 4) {
709
+ this.logger.debug("Compaction skipped: history too short to summarize");
710
+ return false;
711
+ }
712
+ this.eventBus.emit("context:compacting", {
713
+ estimatedTokens: originalTokens
714
+ });
618
715
  const summaryMessages = await this.compactionStrategy.compact(history);
619
716
  if (summaryMessages.length === 0) {
620
- this.logger.debug("Compaction returned no summary (history too short)");
621
- return;
717
+ this.logger.debug(
718
+ "Compaction skipped: strategy returned no summary (likely already compacted or nothing to summarize)"
719
+ );
720
+ this.eventBus.emit("context:compacted", {
721
+ originalTokens,
722
+ compactedTokens: originalTokens,
723
+ // No change
724
+ originalMessages,
725
+ compactedMessages: originalMessages,
726
+ // No change
727
+ strategy: this.compactionStrategy.name,
728
+ reason: "overflow"
729
+ });
730
+ return false;
622
731
  }
623
732
  for (const summary of summaryMessages) {
624
733
  await this.contextManager.addMessage(summary);
625
734
  }
626
- const { filterCompacted, estimateMessagesTokens } = await import("../../context/utils.js");
627
- const updatedHistory = await this.contextManager.getHistory();
628
- const filteredHistory = filterCompacted(updatedHistory);
629
- const compactedTokens = estimateMessagesTokens(filteredHistory);
735
+ this.contextManager.resetActualTokenTracking();
736
+ const afterEstimate = await this.contextManager.getContextTokenEstimate(
737
+ contributorContext,
738
+ tools
739
+ );
740
+ const compactedTokens = afterEstimate.estimated;
741
+ const compactedMessages = afterEstimate.stats.filteredMessageCount;
630
742
  this.eventBus.emit("context:compacted", {
631
743
  originalTokens,
632
744
  compactedTokens,
633
- originalMessages: history.length,
634
- compactedMessages: filteredHistory.length,
745
+ originalMessages,
746
+ compactedMessages,
635
747
  strategy: this.compactionStrategy.name,
636
748
  reason: "overflow"
637
749
  });
638
750
  this.logger.info(
639
- `Compaction complete: ${originalTokens} \u2192 ~${compactedTokens} tokens (${history.length} \u2192 ${filteredHistory.length} messages after filtering)`
751
+ `Compaction complete: ${originalTokens} \u2192 ~${compactedTokens} tokens (${originalMessages} \u2192 ${compactedMessages} messages after filtering)`
640
752
  );
753
+ return true;
641
754
  }
642
755
  /**
643
756
  * Set telemetry span attributes for token usage.
@@ -660,6 +773,10 @@ class TurnExecutor {
660
773
  activeSpan.setAttribute("gen_ai.usage.reasoning_tokens", usage.reasoningTokens);
661
774
  }
662
775
  }
776
+ getContextInputTokens(usage) {
777
+ if (usage.inputTokens === void 0) return null;
778
+ return usage.inputTokens + (usage.cacheReadTokens ?? 0) + (usage.cacheWriteTokens ?? 0);
779
+ }
663
780
  /**
664
781
  * Map provider errors to DextoRuntimeError.
665
782
  */
@@ -166,16 +166,26 @@ class VercelMessageFormatter {
166
166
  formatSystemPrompt() {
167
167
  return null;
168
168
  }
169
- // Helper to format Assistant messages (with optional tool calls)
169
+ // Helper to format Assistant messages (with optional tool calls and reasoning)
170
170
  formatAssistantMessage(msg) {
171
- if (msg.toolCalls && msg.toolCalls.length > 0) {
172
- const contentParts = [];
173
- if (Array.isArray(msg.content)) {
174
- const combined = msg.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
175
- if (combined) {
176
- contentParts.push({ type: "text", text: combined });
177
- }
171
+ const contentParts = [];
172
+ if (msg.reasoning) {
173
+ const reasoningPart = {
174
+ type: "reasoning",
175
+ text: msg.reasoning,
176
+ ...msg.reasoningMetadata && { providerOptions: msg.reasoningMetadata }
177
+ };
178
+ contentParts.push(reasoningPart);
179
+ }
180
+ if (Array.isArray(msg.content)) {
181
+ const combined = msg.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
182
+ if (combined) {
183
+ contentParts.push({ type: "text", text: combined });
178
184
  }
185
+ } else if (typeof msg.content === "string") {
186
+ contentParts.push({ type: "text", text: msg.content });
187
+ }
188
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
179
189
  for (const toolCall of msg.toolCalls) {
180
190
  const rawArgs = toolCall.function.arguments;
181
191
  let parsed = {};
@@ -202,28 +212,26 @@ class VercelMessageFormatter {
202
212
  }
203
213
  contentParts.push(toolCallPart);
204
214
  }
205
- const firstToolCall = msg.toolCalls?.[0];
206
- if (firstToolCall) {
207
- const argString = (() => {
208
- const raw = firstToolCall.function.arguments;
209
- if (typeof raw === "string") return raw;
210
- try {
211
- return JSON.stringify(raw ?? {});
212
- } catch {
213
- return "{}";
214
- }
215
- })();
216
- return {
217
- content: contentParts,
218
- function_call: {
219
- name: firstToolCall.function.name,
220
- arguments: argString
221
- }
222
- };
223
- }
215
+ const firstToolCall = msg.toolCalls[0];
216
+ const argString = (() => {
217
+ const raw = firstToolCall.function.arguments;
218
+ if (typeof raw === "string") return raw;
219
+ try {
220
+ return JSON.stringify(raw ?? {});
221
+ } catch {
222
+ return "{}";
223
+ }
224
+ })();
225
+ return {
226
+ content: contentParts,
227
+ function_call: {
228
+ name: firstToolCall.function.name,
229
+ arguments: argString
230
+ }
231
+ };
224
232
  }
225
233
  return {
226
- content: typeof msg.content === "string" ? [{ type: "text", text: msg.content }] : msg.content === null ? [] : msg.content
234
+ content: contentParts.length > 0 ? contentParts : []
227
235
  };
228
236
  }
229
237
  // Helper to format Tool result messages
@@ -1 +1 @@
1
- {"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../../src/llm/formatters/vercel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAiD,MAAM,IAAI,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAiC,MAAM,wBAAwB,CAAC;AAE7F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAmB7D;;;;;;;;;;GAUG;AACH,qBAAa,sBAAsB;IAC/B,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,EAAE,YAAY;IAGhC;;;;;;OAMG;IACH,MAAM,CACF,OAAO,EAAE,QAAQ,CAAC,eAAe,EAAE,CAAC,EACpC,OAAO,EAAE,UAAU,EACnB,YAAY,EAAE,MAAM,GAAG,IAAI,GAC5B,YAAY,EAAE;IAsJjB;;;;;;OAMG;IACH,kBAAkB,IAAI,IAAI;IAK1B,OAAO,CAAC,sBAAsB;IA8E9B,OAAO,CAAC,iBAAiB;CAoE5B"}
1
+ {"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../../src/llm/formatters/vercel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAiD,MAAM,IAAI,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAiC,MAAM,wBAAwB,CAAC;AAE7F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAmB7D;;;;;;;;;;GAUG;AACH,qBAAa,sBAAsB;IAC/B,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,EAAE,YAAY;IAGhC;;;;;;OAMG;IACH,MAAM,CACF,OAAO,EAAE,QAAQ,CAAC,eAAe,EAAE,CAAC,EACpC,OAAO,EAAE,UAAU,EACnB,YAAY,EAAE,MAAM,GAAG,IAAI,GAC5B,YAAY,EAAE;IAsJjB;;;;;;OAMG;IACH,kBAAkB,IAAI,IAAI;IAK1B,OAAO,CAAC,sBAAsB;IA0F9B,OAAO,CAAC,iBAAiB;CAoE5B"}
@@ -144,16 +144,26 @@ class VercelMessageFormatter {
144
144
  formatSystemPrompt() {
145
145
  return null;
146
146
  }
147
- // Helper to format Assistant messages (with optional tool calls)
147
+ // Helper to format Assistant messages (with optional tool calls and reasoning)
148
148
  formatAssistantMessage(msg) {
149
- if (msg.toolCalls && msg.toolCalls.length > 0) {
150
- const contentParts = [];
151
- if (Array.isArray(msg.content)) {
152
- const combined = msg.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
153
- if (combined) {
154
- contentParts.push({ type: "text", text: combined });
155
- }
149
+ const contentParts = [];
150
+ if (msg.reasoning) {
151
+ const reasoningPart = {
152
+ type: "reasoning",
153
+ text: msg.reasoning,
154
+ ...msg.reasoningMetadata && { providerOptions: msg.reasoningMetadata }
155
+ };
156
+ contentParts.push(reasoningPart);
157
+ }
158
+ if (Array.isArray(msg.content)) {
159
+ const combined = msg.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
160
+ if (combined) {
161
+ contentParts.push({ type: "text", text: combined });
156
162
  }
163
+ } else if (typeof msg.content === "string") {
164
+ contentParts.push({ type: "text", text: msg.content });
165
+ }
166
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
157
167
  for (const toolCall of msg.toolCalls) {
158
168
  const rawArgs = toolCall.function.arguments;
159
169
  let parsed = {};
@@ -180,28 +190,26 @@ class VercelMessageFormatter {
180
190
  }
181
191
  contentParts.push(toolCallPart);
182
192
  }
183
- const firstToolCall = msg.toolCalls?.[0];
184
- if (firstToolCall) {
185
- const argString = (() => {
186
- const raw = firstToolCall.function.arguments;
187
- if (typeof raw === "string") return raw;
188
- try {
189
- return JSON.stringify(raw ?? {});
190
- } catch {
191
- return "{}";
192
- }
193
- })();
194
- return {
195
- content: contentParts,
196
- function_call: {
197
- name: firstToolCall.function.name,
198
- arguments: argString
199
- }
200
- };
201
- }
193
+ const firstToolCall = msg.toolCalls[0];
194
+ const argString = (() => {
195
+ const raw = firstToolCall.function.arguments;
196
+ if (typeof raw === "string") return raw;
197
+ try {
198
+ return JSON.stringify(raw ?? {});
199
+ } catch {
200
+ return "{}";
201
+ }
202
+ })();
203
+ return {
204
+ content: contentParts,
205
+ function_call: {
206
+ name: firstToolCall.function.name,
207
+ arguments: argString
208
+ }
209
+ };
202
210
  }
203
211
  return {
204
- content: typeof msg.content === "string" ? [{ type: "text", text: msg.content }] : msg.content === null ? [] : msg.content
212
+ content: contentParts.length > 0 ? contentParts : []
205
213
  };
206
214
  }
207
215
  // Helper to format Tool result messages
@@ -139,7 +139,7 @@ function getOpenAICompatibleBaseURL(llmConfig) {
139
139
  }
140
140
  return "";
141
141
  }
142
- function createLLMService(config, toolManager, systemPromptManager, historyProvider, sessionEventBus, sessionId, resourceManager, logger, compactionStrategy) {
142
+ function createLLMService(config, toolManager, systemPromptManager, historyProvider, sessionEventBus, sessionId, resourceManager, logger, compactionStrategy, compactionConfig) {
143
143
  const model = createVercelModel(config);
144
144
  return new import_vercel.VercelLLMService(
145
145
  toolManager,
@@ -151,7 +151,8 @@ function createLLMService(config, toolManager, systemPromptManager, historyProvi
151
151
  sessionId,
152
152
  resourceManager,
153
153
  logger,
154
- compactionStrategy
154
+ compactionStrategy,
155
+ compactionConfig
155
156
  );
156
157
  }
157
158
  // Annotate the CommonJS export names for ESM import in node:
@@ -6,6 +6,7 @@ import { SessionEventBus } from '../../events/index.js';
6
6
  import type { IConversationHistoryProvider } from '../../session/history/types.js';
7
7
  import type { SystemPromptManager } from '../../systemPrompt/manager.js';
8
8
  import type { IDextoLogger } from '../../logger/v2/types.js';
9
+ import type { CompactionConfigInput } from '../../context/compaction/schemas.js';
9
10
  export declare function createVercelModel(llmConfig: ValidatedLLMConfig): LanguageModel;
10
11
  /**
11
12
  * Create an LLM service instance using the Vercel AI SDK.
@@ -20,7 +21,8 @@ export declare function createVercelModel(llmConfig: ValidatedLLMConfig): Langua
20
21
  * @param resourceManager Resource manager for blob storage and resource access
21
22
  * @param logger Logger instance for dependency injection
22
23
  * @param compactionStrategy Optional compaction strategy for context management
24
+ * @param compactionConfig Optional compaction configuration for thresholds
23
25
  * @returns VercelLLMService instance
24
26
  */
25
- export declare function createLLMService(config: ValidatedLLMConfig, toolManager: ToolManager, systemPromptManager: SystemPromptManager, historyProvider: IConversationHistoryProvider, sessionEventBus: SessionEventBus, sessionId: string, resourceManager: import('../../resources/index.js').ResourceManager, logger: IDextoLogger, compactionStrategy?: import('../../context/compaction/types.js').ICompactionStrategy | null): VercelLLMService;
27
+ export declare function createLLMService(config: ValidatedLLMConfig, toolManager: ToolManager, systemPromptManager: SystemPromptManager, historyProvider: IConversationHistoryProvider, sessionEventBus: SessionEventBus, sessionId: string, resourceManager: import('../../resources/index.js').ResourceManager, logger: IDextoLogger, compactionStrategy?: import('../../context/compaction/types.js').ICompactionStrategy | null, compactionConfig?: CompactionConfigInput): VercelLLMService;
26
28
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/llm/services/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAUnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI7D,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,aAAa,CAoJ9E;AAoBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC5B,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,mBAAmB,EACxC,eAAe,EAAE,4BAA4B,EAC7C,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,OAAO,0BAA0B,EAAE,eAAe,EACnE,MAAM,EAAE,YAAY,EACpB,kBAAkB,CAAC,EAAE,OAAO,mCAAmC,EAAE,mBAAmB,GAAG,IAAI,GAC5F,gBAAgB,CAelB"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/llm/services/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAUnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAEjF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,kBAAkB,GAAG,aAAa,CAoJ9E;AAoBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC5B,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,mBAAmB,EACxC,eAAe,EAAE,4BAA4B,EAC7C,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,OAAO,0BAA0B,EAAE,eAAe,EACnE,MAAM,EAAE,YAAY,EACpB,kBAAkB,CAAC,EAAE,OAAO,mCAAmC,EAAE,mBAAmB,GAAG,IAAI,EAC3F,gBAAgB,CAAC,EAAE,qBAAqB,GACzC,gBAAgB,CAgBlB"}
@@ -116,7 +116,7 @@ function getOpenAICompatibleBaseURL(llmConfig) {
116
116
  }
117
117
  return "";
118
118
  }
119
- function createLLMService(config, toolManager, systemPromptManager, historyProvider, sessionEventBus, sessionId, resourceManager, logger, compactionStrategy) {
119
+ function createLLMService(config, toolManager, systemPromptManager, historyProvider, sessionEventBus, sessionId, resourceManager, logger, compactionStrategy, compactionConfig) {
120
120
  const model = createVercelModel(config);
121
121
  return new VercelLLMService(
122
122
  toolManager,
@@ -128,7 +128,8 @@ function createLLMService(config, toolManager, systemPromptManager, historyProvi
128
128
  sessionId,
129
129
  resourceManager,
130
130
  logger,
131
- compactionStrategy
131
+ compactionStrategy,
132
+ compactionConfig
132
133
  );
133
134
  }
134
135
  export {
@@ -92,13 +92,15 @@ class VercelLLMService {
92
92
  resourceManager;
93
93
  messageQueue;
94
94
  compactionStrategy;
95
+ modelLimits;
96
+ compactionThresholdPercent;
95
97
  /**
96
98
  * Helper to extract model ID from LanguageModel union type (string | LanguageModelV2)
97
99
  */
98
100
  getModelId() {
99
101
  return typeof this.model === "string" ? this.model : this.model.modelId;
100
102
  }
101
- constructor(toolManager, model, systemPromptManager, historyProvider, sessionEventBus, config, sessionId, resourceManager, logger, compactionStrategy) {
103
+ constructor(toolManager, model, systemPromptManager, historyProvider, sessionEventBus, config, sessionId, resourceManager, logger, compactionStrategy, compactionConfig) {
102
104
  this.logger = logger.createChild(import_types2.DextoLogComponent.LLM);
103
105
  this.model = model;
104
106
  this.config = config;
@@ -107,9 +109,20 @@ class VercelLLMService {
107
109
  this.sessionId = sessionId;
108
110
  this.resourceManager = resourceManager;
109
111
  this.compactionStrategy = compactionStrategy ?? null;
112
+ this.compactionThresholdPercent = compactionConfig?.thresholdPercent ?? 0.9;
110
113
  this.messageQueue = new import_message_queue.MessageQueueService(this.sessionEventBus, this.logger);
111
114
  const formatter = new import_vercel.VercelMessageFormatter(this.logger);
112
115
  const maxInputTokens = (0, import_registry.getEffectiveMaxInputTokens)(config, this.logger);
116
+ let effectiveContextWindow = maxInputTokens;
117
+ if (compactionConfig?.maxContextTokens !== void 0) {
118
+ effectiveContextWindow = Math.min(maxInputTokens, compactionConfig.maxContextTokens);
119
+ this.logger.debug(
120
+ `Compaction: Using maxContextTokens override: ${compactionConfig.maxContextTokens} (model max: ${maxInputTokens})`
121
+ );
122
+ }
123
+ this.modelLimits = {
124
+ contextWindow: effectiveContextWindow
125
+ };
113
126
  this.contextManager = new import_manager.ContextManager(
114
127
  config,
115
128
  formatter,
@@ -149,19 +162,23 @@ class VercelLLMService {
149
162
  { provider: this.config.provider, model: this.getModelId() },
150
163
  this.logger,
151
164
  this.messageQueue,
152
- void 0,
153
- // modelLimits - TurnExecutor will use defaults
165
+ this.modelLimits,
154
166
  externalSignal,
155
- this.compactionStrategy
167
+ this.compactionStrategy,
168
+ this.compactionThresholdPercent
156
169
  );
157
170
  }
171
+ /**
172
+ * Result from streaming a response.
173
+ */
174
+ static StreamResult;
158
175
  /**
159
176
  * Stream a response for the given content.
160
177
  * Primary method for running conversations with multi-image support.
161
178
  *
162
179
  * @param content - String or ContentPart[] (text, images, files)
163
180
  * @param options - { signal?: AbortSignal }
164
- * @returns The assistant's text response
181
+ * @returns Object with text response
165
182
  */
166
183
  async stream(content, options) {
167
184
  const activeSpan = import_api.trace.getActiveSpan();
@@ -191,7 +208,9 @@ class VercelLLMService {
191
208
  const executor = this.createTurnExecutor(options?.signal);
192
209
  const contributorContext = { mcpManager: this.toolManager.getMcpManager() };
193
210
  const result = await executor.execute(contributorContext, true);
194
- return result.text ?? "";
211
+ return {
212
+ text: result.text ?? ""
213
+ };
195
214
  });
196
215
  }
197
216
  /**
@@ -236,6 +255,12 @@ class VercelLLMService {
236
255
  getMessageQueue() {
237
256
  return this.messageQueue;
238
257
  }
258
+ /**
259
+ * Get the compaction strategy for external access (e.g., session-native compaction)
260
+ */
261
+ getCompactionStrategy() {
262
+ return this.compactionStrategy;
263
+ }
239
264
  }
240
265
  _init = __decoratorStart(null);
241
266
  VercelLLMService = __decorateElement(_init, 0, "VercelLLMService", _VercelLLMService_decorators, VercelLLMService);