@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.
- package/dist/agent/DextoAgent.cjs +284 -1
- package/dist/agent/DextoAgent.d.ts +114 -0
- package/dist/agent/DextoAgent.d.ts.map +1 -1
- package/dist/agent/DextoAgent.js +275 -1
- package/dist/agent/schemas.d.ts +51 -21
- package/dist/agent/schemas.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 +4 -0
- package/dist/events/index.d.ts +41 -7
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +4 -0
- 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/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/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
|
@@ -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) {
|
|
@@ -55,13 +56,32 @@ class TurnExecutor {
|
|
|
55
56
|
* Used to pass approval info from tool execution to result persistence.
|
|
56
57
|
*/
|
|
57
58
|
approvalMetadata = /* @__PURE__ */ new Map();
|
|
59
|
+
/**
|
|
60
|
+
* Tracks whether compaction occurred during this turn.
|
|
61
|
+
* Used to signal to the caller that session continuation may be needed.
|
|
62
|
+
*/
|
|
63
|
+
compactionOccurred = false;
|
|
64
|
+
/**
|
|
65
|
+
* Compaction data captured during this turn.
|
|
66
|
+
* Contains summary text and preserved messages for session continuation.
|
|
67
|
+
* This data is passed up the call chain (NOT persisted to original session).
|
|
68
|
+
*/
|
|
69
|
+
compactionData = null;
|
|
70
|
+
/**
|
|
71
|
+
* Virtual context for remaining iterations after compaction.
|
|
72
|
+
* When set, the main loop uses this instead of calling getFormattedMessagesForLLM().
|
|
73
|
+
* This provides reduced context to the LLM without persisting to the original session.
|
|
74
|
+
*/
|
|
75
|
+
virtualContext = null;
|
|
58
76
|
/**
|
|
59
77
|
* Get StreamProcessor config from TurnExecutor state.
|
|
78
|
+
* @param estimatedInputTokens Optional estimated input tokens for analytics
|
|
60
79
|
*/
|
|
61
|
-
getStreamProcessorConfig() {
|
|
80
|
+
getStreamProcessorConfig(estimatedInputTokens) {
|
|
62
81
|
return {
|
|
63
82
|
provider: this.llmContext.provider,
|
|
64
|
-
model: this.llmContext.model
|
|
83
|
+
model: this.llmContext.model,
|
|
84
|
+
...estimatedInputTokens !== void 0 && { estimatedInputTokens }
|
|
65
85
|
};
|
|
66
86
|
}
|
|
67
87
|
/**
|
|
@@ -117,13 +137,34 @@ class TurnExecutor {
|
|
|
117
137
|
if (coalesced) {
|
|
118
138
|
await this.injectQueuedMessages(coalesced);
|
|
119
139
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
const prepared = await this.contextManager.getFormattedMessagesWithCompression(
|
|
140
|
+
await this.pruneOldToolOutputs();
|
|
141
|
+
let prepared = this.virtualContext ? await this.buildMessagesFromVirtualContext(contributorContext) : await this.contextManager.getFormattedMessagesForLLM(
|
|
124
142
|
contributorContext,
|
|
125
143
|
this.llmContext
|
|
126
144
|
);
|
|
145
|
+
const toolDefinitions = supportsTools ? await this.toolManager.getAllTools() : {};
|
|
146
|
+
let estimatedTokens = await this.contextManager.getEstimatedNextInputTokens(
|
|
147
|
+
prepared.systemPrompt,
|
|
148
|
+
prepared.preparedHistory,
|
|
149
|
+
toolDefinitions
|
|
150
|
+
);
|
|
151
|
+
if (this.shouldCompact(estimatedTokens)) {
|
|
152
|
+
this.logger.debug(
|
|
153
|
+
`Pre-check: estimated ${estimatedTokens} tokens exceeds threshold, compacting`
|
|
154
|
+
);
|
|
155
|
+
await this.compactToVirtualContext(estimatedTokens);
|
|
156
|
+
if (this.virtualContext) {
|
|
157
|
+
prepared = await this.buildMessagesFromVirtualContext(contributorContext);
|
|
158
|
+
estimatedTokens = await this.contextManager.getEstimatedNextInputTokens(
|
|
159
|
+
prepared.systemPrompt,
|
|
160
|
+
prepared.preparedHistory,
|
|
161
|
+
toolDefinitions
|
|
162
|
+
);
|
|
163
|
+
this.logger.debug(
|
|
164
|
+
`Post-compaction: recomputed estimate is ${estimatedTokens} tokens`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
127
168
|
this.logger.debug(`Step ${stepCount}: Starting`);
|
|
128
169
|
const tools = supportsTools ? await this.createTools() : {};
|
|
129
170
|
const streamProcessor = new StreamProcessor(
|
|
@@ -131,7 +172,7 @@ class TurnExecutor {
|
|
|
131
172
|
this.eventBus,
|
|
132
173
|
this.resourceManager,
|
|
133
174
|
this.stepAbortController.signal,
|
|
134
|
-
this.getStreamProcessorConfig(),
|
|
175
|
+
this.getStreamProcessorConfig(estimatedTokens),
|
|
135
176
|
this.logger,
|
|
136
177
|
streaming,
|
|
137
178
|
this.approvalMetadata
|
|
@@ -170,6 +211,28 @@ class TurnExecutor {
|
|
|
170
211
|
this.logger.debug(
|
|
171
212
|
`Step ${stepCount}: Finished with reason="${result.finishReason}", tokens=${JSON.stringify(result.usage)}`
|
|
172
213
|
);
|
|
214
|
+
if (result.finishReason === "cancelled") {
|
|
215
|
+
this.logger.info(
|
|
216
|
+
`Context estimation (cancelled): keeping last known actuals, partial response (${result.text.length} chars) will be estimated`
|
|
217
|
+
);
|
|
218
|
+
} else if (result.usage?.inputTokens !== void 0) {
|
|
219
|
+
const diff = estimatedTokens - result.usage.inputTokens;
|
|
220
|
+
const diffPercent = result.usage.inputTokens > 0 ? (diff / result.usage.inputTokens * 100).toFixed(1) : "0.0";
|
|
221
|
+
this.logger.info(
|
|
222
|
+
`Context estimation accuracy: estimated=${estimatedTokens}, actual=${result.usage.inputTokens}, error=${diff} (${diffPercent}%)`
|
|
223
|
+
);
|
|
224
|
+
this.contextManager.setLastActualInputTokens(result.usage.inputTokens);
|
|
225
|
+
if (result.usage?.outputTokens !== void 0) {
|
|
226
|
+
this.contextManager.setLastActualOutputTokens(result.usage.outputTokens);
|
|
227
|
+
}
|
|
228
|
+
await this.contextManager.recordLastCallMessageCount();
|
|
229
|
+
}
|
|
230
|
+
if (!this.virtualContext && result.usage?.inputTokens && this.shouldCompactFromActual(result.usage.inputTokens)) {
|
|
231
|
+
this.logger.debug(
|
|
232
|
+
`Post-response: actual ${result.usage.inputTokens} tokens exceeds threshold, compacting`
|
|
233
|
+
);
|
|
234
|
+
await this.compactToVirtualContext(result.usage.inputTokens);
|
|
235
|
+
}
|
|
173
236
|
if (result.finishReason !== "tool-calls") {
|
|
174
237
|
const queuedOnTerminate = this.messageQueue.dequeueAll();
|
|
175
238
|
if (queuedOnTerminate) {
|
|
@@ -193,7 +256,6 @@ class TurnExecutor {
|
|
|
193
256
|
lastFinishReason = "max-steps";
|
|
194
257
|
break;
|
|
195
258
|
}
|
|
196
|
-
await this.pruneOldToolOutputs();
|
|
197
259
|
}
|
|
198
260
|
} catch (error) {
|
|
199
261
|
const mappedError = this.mapProviderError(error);
|
|
@@ -223,7 +285,14 @@ class TurnExecutor {
|
|
|
223
285
|
text: lastText,
|
|
224
286
|
stepCount,
|
|
225
287
|
usage: lastStepTokens,
|
|
226
|
-
finishReason: lastFinishReason
|
|
288
|
+
finishReason: lastFinishReason,
|
|
289
|
+
// Signal to caller that compaction occurred during this turn
|
|
290
|
+
// Caller can use this to trigger session-native continuation
|
|
291
|
+
didCompact: this.compactionOccurred,
|
|
292
|
+
// Pass compaction data up the chain (NOT persisted to original session)
|
|
293
|
+
// Caller uses this to create the continuation session with summary
|
|
294
|
+
// Use spread to conditionally include only when data exists (exactOptionalPropertyTypes)
|
|
295
|
+
...this.compactionData && { compaction: this.compactionData }
|
|
227
296
|
};
|
|
228
297
|
} catch (_2) {
|
|
229
298
|
var _error = _2, _hasError = true;
|
|
@@ -521,7 +590,7 @@ class TurnExecutor {
|
|
|
521
590
|
/**
|
|
522
591
|
* Prunes old tool outputs by marking them with compactedAt timestamp.
|
|
523
592
|
* Does NOT modify content - transformation happens at format time in
|
|
524
|
-
* ContextManager.
|
|
593
|
+
* ContextManager.prepareHistory().
|
|
525
594
|
*
|
|
526
595
|
* Algorithm:
|
|
527
596
|
* 1. Go backwards through history (most recent first)
|
|
@@ -590,55 +659,175 @@ class TurnExecutor {
|
|
|
590
659
|
this.messageQueue.clear();
|
|
591
660
|
}
|
|
592
661
|
/**
|
|
593
|
-
* Check if context
|
|
662
|
+
* Check if context should be compacted based on estimated token count.
|
|
663
|
+
* Uses the threshold percentage from compaction config to trigger earlier (e.g., at 90%).
|
|
664
|
+
*
|
|
665
|
+
* @param estimatedTokens Estimated token count from the current context
|
|
666
|
+
* @returns true if compaction is needed before making the LLM call
|
|
594
667
|
*/
|
|
595
|
-
|
|
668
|
+
shouldCompact(estimatedTokens) {
|
|
596
669
|
if (!this.modelLimits || !this.compactionStrategy) {
|
|
597
670
|
return false;
|
|
598
671
|
}
|
|
599
|
-
return isOverflow(
|
|
672
|
+
return isOverflow(
|
|
673
|
+
{ inputTokens: estimatedTokens },
|
|
674
|
+
this.modelLimits,
|
|
675
|
+
this.compactionThresholdPercent
|
|
676
|
+
);
|
|
600
677
|
}
|
|
601
678
|
/**
|
|
602
|
-
*
|
|
679
|
+
* Check if context should be compacted based on actual token count from API response.
|
|
680
|
+
* This is a post-response check using real token counts rather than estimates.
|
|
603
681
|
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
|
|
682
|
+
* @param actualTokens Actual input token count from the API response
|
|
683
|
+
* @returns true if compaction is needed
|
|
684
|
+
*/
|
|
685
|
+
shouldCompactFromActual(actualTokens) {
|
|
686
|
+
if (!this.modelLimits || !this.compactionStrategy) {
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
return isOverflow(
|
|
690
|
+
{ inputTokens: actualTokens },
|
|
691
|
+
this.modelLimits,
|
|
692
|
+
this.compactionThresholdPercent
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Compact context using ReactiveOverflowStrategy WITHOUT persisting to original session.
|
|
697
|
+
*
|
|
698
|
+
* Key design: Creates a virtual context (summary + preserved messages) that will be used
|
|
699
|
+
* for the remaining iterations of this turn. The compaction data is passed up the call chain
|
|
700
|
+
* so the caller can create a continuation session with the summary.
|
|
607
701
|
*
|
|
608
|
-
*
|
|
702
|
+
* The original session remains UNTOUCHED - no messages are added or modified.
|
|
703
|
+
*
|
|
704
|
+
* @param originalTokens The estimated input token count that triggered overflow
|
|
609
705
|
*/
|
|
610
|
-
async
|
|
706
|
+
async compactToVirtualContext(originalTokens) {
|
|
611
707
|
if (!this.compactionStrategy) {
|
|
612
708
|
return;
|
|
613
709
|
}
|
|
614
710
|
this.logger.info(
|
|
615
|
-
`Context overflow detected (${originalTokens} tokens),
|
|
711
|
+
`Context overflow detected (${originalTokens} tokens), checking if compression is possible`
|
|
616
712
|
);
|
|
617
713
|
const history = await this.contextManager.getHistory();
|
|
714
|
+
if (history.length < 4) {
|
|
715
|
+
this.logger.debug("Compaction skipped: history too short to summarize");
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
this.eventBus.emit("context:compacting", {
|
|
719
|
+
estimatedTokens: originalTokens
|
|
720
|
+
});
|
|
618
721
|
const summaryMessages = await this.compactionStrategy.compact(history);
|
|
619
722
|
if (summaryMessages.length === 0) {
|
|
620
|
-
this.logger.debug(
|
|
723
|
+
this.logger.debug(
|
|
724
|
+
"Compaction skipped: strategy returned no summary (likely already compacted or nothing to summarize)"
|
|
725
|
+
);
|
|
726
|
+
this.eventBus.emit("context:compacted", {
|
|
727
|
+
originalTokens,
|
|
728
|
+
compactedTokens: originalTokens,
|
|
729
|
+
// No change
|
|
730
|
+
originalMessages: history.length,
|
|
731
|
+
compactedMessages: history.length,
|
|
732
|
+
// No change
|
|
733
|
+
strategy: this.compactionStrategy.name,
|
|
734
|
+
reason: "overflow"
|
|
735
|
+
});
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const summaryMessage = summaryMessages[0];
|
|
739
|
+
if (!summaryMessage) {
|
|
740
|
+
this.logger.warn("Compaction returned empty summary message array");
|
|
621
741
|
return;
|
|
622
742
|
}
|
|
623
|
-
|
|
624
|
-
|
|
743
|
+
const summaryText = this.extractSummaryText(summaryMessage);
|
|
744
|
+
const summarizedCount = summaryMessage.metadata?.originalMessageCount ?? 0;
|
|
745
|
+
let existingSummaryIndex = -1;
|
|
746
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
747
|
+
const msg = history[i];
|
|
748
|
+
if (msg?.metadata?.isSummary === true || msg?.metadata?.isSessionSummary === true) {
|
|
749
|
+
existingSummaryIndex = i;
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
625
752
|
}
|
|
626
|
-
const
|
|
627
|
-
const
|
|
628
|
-
const
|
|
629
|
-
const
|
|
753
|
+
const baseIndex = existingSummaryIndex >= 0 ? existingSummaryIndex + 1 : 0;
|
|
754
|
+
const preservedMessages = history.slice(baseIndex + summarizedCount);
|
|
755
|
+
const firstTimestamp = summaryMessage.metadata?.originalFirstTimestamp;
|
|
756
|
+
const lastTimestamp = summaryMessage.metadata?.originalLastTimestamp;
|
|
757
|
+
this.compactionData = {
|
|
758
|
+
summaryText,
|
|
759
|
+
preservedMessages: [...preservedMessages],
|
|
760
|
+
// Copy to avoid mutation
|
|
761
|
+
summarizedCount,
|
|
762
|
+
...firstTimestamp !== void 0 && { originalFirstTimestamp: firstTimestamp },
|
|
763
|
+
...lastTimestamp !== void 0 && { originalLastTimestamp: lastTimestamp }
|
|
764
|
+
};
|
|
765
|
+
this.virtualContext = {
|
|
766
|
+
summaryMessage,
|
|
767
|
+
preservedMessages: [...preservedMessages]
|
|
768
|
+
};
|
|
769
|
+
this.compactionOccurred = true;
|
|
770
|
+
this.contextManager.resetActualTokenTracking();
|
|
771
|
+
const { estimateMessagesTokens: estimateTokens } = await import("../../context/utils.js");
|
|
772
|
+
const virtualMessages = [summaryMessage, ...preservedMessages];
|
|
773
|
+
const compactedTokens = estimateTokens(virtualMessages);
|
|
630
774
|
this.eventBus.emit("context:compacted", {
|
|
631
775
|
originalTokens,
|
|
632
776
|
compactedTokens,
|
|
633
777
|
originalMessages: history.length,
|
|
634
|
-
compactedMessages:
|
|
778
|
+
compactedMessages: virtualMessages.length,
|
|
635
779
|
strategy: this.compactionStrategy.name,
|
|
636
780
|
reason: "overflow"
|
|
637
781
|
});
|
|
638
782
|
this.logger.info(
|
|
639
|
-
`Compaction complete: ${originalTokens} \u2192 ~${compactedTokens} tokens (${history.length} \u2192 ${
|
|
783
|
+
`Compaction complete (virtual context): ${originalTokens} \u2192 ~${compactedTokens} tokens (${history.length} \u2192 ${virtualMessages.length} messages). Original session unchanged - summary will be passed to continuation session.`
|
|
640
784
|
);
|
|
641
785
|
}
|
|
786
|
+
/**
|
|
787
|
+
* Extract the summary text from a summary message.
|
|
788
|
+
*/
|
|
789
|
+
extractSummaryText(summaryMessage) {
|
|
790
|
+
if (typeof summaryMessage.content === "string") {
|
|
791
|
+
return summaryMessage.content;
|
|
792
|
+
}
|
|
793
|
+
if (Array.isArray(summaryMessage.content)) {
|
|
794
|
+
return summaryMessage.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
795
|
+
}
|
|
796
|
+
return "";
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Build formatted messages from virtual context (after compaction).
|
|
800
|
+
*
|
|
801
|
+
* This creates LLM-ready messages using:
|
|
802
|
+
* - System prompt (same as normal flow)
|
|
803
|
+
* - Summary message (as first message)
|
|
804
|
+
* - Preserved messages (formatted for LLM)
|
|
805
|
+
*
|
|
806
|
+
* Uses the same formatting pipeline as getFormattedMessagesForLLM()
|
|
807
|
+
* but with our virtual history instead of the stored history.
|
|
808
|
+
*
|
|
809
|
+
* @param contributorContext Context for system prompt contributors
|
|
810
|
+
* @returns Formatted messages ready for LLM call, matching getFormattedMessagesForLLM return type
|
|
811
|
+
*/
|
|
812
|
+
async buildMessagesFromVirtualContext(contributorContext) {
|
|
813
|
+
if (!this.virtualContext) {
|
|
814
|
+
throw new Error("buildMessagesFromVirtualContext called without virtual context");
|
|
815
|
+
}
|
|
816
|
+
const { summaryMessage, preservedMessages } = this.virtualContext;
|
|
817
|
+
const systemPrompt = await this.contextManager.getSystemPrompt(contributorContext);
|
|
818
|
+
const virtualHistory = [summaryMessage, ...preservedMessages];
|
|
819
|
+
const formattedMessages = await this.contextManager.getFormattedMessages(
|
|
820
|
+
contributorContext,
|
|
821
|
+
this.llmContext,
|
|
822
|
+
systemPrompt,
|
|
823
|
+
virtualHistory
|
|
824
|
+
);
|
|
825
|
+
return {
|
|
826
|
+
formattedMessages,
|
|
827
|
+
systemPrompt,
|
|
828
|
+
preparedHistory: virtualHistory
|
|
829
|
+
};
|
|
830
|
+
}
|
|
642
831
|
/**
|
|
643
832
|
* Set telemetry span attributes for token usage.
|
|
644
833
|
*/
|
|
@@ -1,5 +1,23 @@
|
|
|
1
|
+
import type { InternalMessage } from '../../context/types.js';
|
|
1
2
|
import { TokenUsage } from '../types.js';
|
|
2
3
|
import { LLMFinishReason } from '../../events/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Data captured during context compaction for session-native continuation.
|
|
6
|
+
* This is passed through the call chain so the new session can be created
|
|
7
|
+
* with the summary and preserved messages.
|
|
8
|
+
*/
|
|
9
|
+
export interface CompactionData {
|
|
10
|
+
/** The generated summary text */
|
|
11
|
+
summaryText: string;
|
|
12
|
+
/** Messages preserved (not summarized) - typically last N turns */
|
|
13
|
+
preservedMessages: InternalMessage[];
|
|
14
|
+
/** Number of messages that were summarized */
|
|
15
|
+
summarizedCount: number;
|
|
16
|
+
/** Timestamp of first summarized message */
|
|
17
|
+
originalFirstTimestamp?: number;
|
|
18
|
+
/** Timestamp of last summarized message */
|
|
19
|
+
originalLastTimestamp?: number;
|
|
20
|
+
}
|
|
3
21
|
export interface ExecutorResult {
|
|
4
22
|
/**
|
|
5
23
|
* The accumulated text from assistant responses.
|
|
@@ -13,6 +31,16 @@ export interface ExecutorResult {
|
|
|
13
31
|
usage: TokenUsage | null;
|
|
14
32
|
/** Reason the execution finished */
|
|
15
33
|
finishReason: LLMFinishReason;
|
|
34
|
+
/**
|
|
35
|
+
* Set to true if context compaction occurred during this turn.
|
|
36
|
+
* Caller can use this to trigger session-native continuation (create new session).
|
|
37
|
+
*/
|
|
38
|
+
didCompact: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Compaction data when didCompact is true.
|
|
41
|
+
* Contains the summary text and preserved messages for creating the continuation session.
|
|
42
|
+
*/
|
|
43
|
+
compaction?: CompactionData;
|
|
16
44
|
}
|
|
17
45
|
export interface StreamProcessorResult {
|
|
18
46
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/llm/executor/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,cAAc;IAC3B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,oCAAoC;IACpC,YAAY,EAAE,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/llm/executor/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC3B,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,8CAA8C;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,2CAA2C;IAC3C,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC3B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,oCAAoC;IACpC,YAAY,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,eAAe,CAAC;IAC9B,KAAK,EAAE,UAAU,CAAC;CACrB"}
|
|
@@ -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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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:
|
|
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;
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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:
|
|
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;
|
|
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 {
|