feat: allow model selection in compaction modal
Nicolas Leão committed
Mar 26, 2026 at 16:01 UTC
32eb5f8fba528b0725229f7c9e882d41e074b00f
5 files changed
+357
-157
plugins/_chat_compaction/api/compact_chat.py
+7
-7
@@ -33,12 +33,12 @@ class CompactChat(ApiHandler):
33
return {"ok": True, "stats": stats}
34
35
elif action == "compact":
36
- from helpers.plugins import get_plugin_config
37
- agent = context.agent0
38
- plugin_config = get_plugin_config("_chat_compaction", agent=agent) or {}
39
- use_chat_model = plugin_config.get("use_chat_model", True)
36
+ use_chat_model = input.get("use_chat_model", True)
37
+ preset_name = input.get("preset_name") or None
38
41
- context.run_task(_run_compaction_task, context, use_chat_model)
39
+ context.run_task(
40
+ _run_compaction_task, context, use_chat_model, preset_name
41
+ )
42
43
return {"ok": True, "message": "Compaction started"}
44
@@ -46,10 +46,10 @@ class CompactChat(ApiHandler):
46
return Response(f"Unknown action: {action}", 400)
47
48
49
-async def _run_compaction_task(context, use_chat_model: bool):
49
+async def _run_compaction_task(context, use_chat_model: bool, preset_name: str | None):
50
"""Wrapper to run compaction and handle errors."""
51
try:
52
- await run_compaction(context, use_chat_model)
52
+ await run_compaction(context, use_chat_model, preset_name)
53
except Exception as e:
54
context.log.log(
55
type="error",
plugins/_chat_compaction/extensions/webui/chat-input-bottom-actions-start/compact-button.html
+110
-13
@@ -58,15 +58,35 @@
58
<span class="cmpct-stat-label">Tokens</span>
59
<span class="cmpct-stat-value" x-text="$store.compactStore?.stats?.token_count?.toLocaleString()"></span>
60
</div>
61
- <div class="cmpct-stat">
62
- <span class="cmpct-stat-label">Model</span>
63
- <span class="cmpct-stat-value" x-text="$store.compactStore?.stats?.model_name"></span>
61
+ </div>
62
+
63
+ <!-- Model selection -->
64
+ <div class="cmpct-model-section">
65
+ <div class="cmpct-model-label">Model</div>
66
+
67
+ <div class="cmpct-model-controls">
68
+ <select class="cmpct-select"
69
+ x-model="$store.compactStore.selectedPresetName">
70
+ <option value="">Current</option>
71
+ <template x-for="preset in $store.compactStore.presets" :key="preset.name">
72
+ <option :value="preset.name" x-text="preset.name"></option>
73
+ </template>
74
+ </select>
75
+
76
+ <div class="cmpct-toggle">
77
+ <button :class="{ active: $store.compactStore.useChatModel }"
78
+ @click="$store.compactStore.useChatModel = true">Chat</button>
79
+ <button :class="{ active: !$store.compactStore.useChatModel }"
80
+ @click="$store.compactStore.useChatModel = false">Utility</button>
81
+ </div>
82
</div>
83
+
84
+ <div class="cmpct-model-name" x-text="$store.compactStore.selectedModelDisplay"></div>
85
</div>
86
67
- <div class="cmpct-warning">
68
- <span class="material-symbols-outlined">warning</span>
69
- <span>This action cannot be undone. The original conversation will be replaced with a summary.</span>
87
+ <div class="cmpct-info">
88
+ <span class="material-symbols-outlined">check_circle</span>
89
+ <span>The context will be replaced with a compacted summary. The original conversation will be backed up.</span>
90
</div>
91
</div>
92
</template>
@@ -115,7 +135,7 @@
135
border-radius: 12px;
136
box-shadow: 0 4px 23px rgba(0, 0, 0, 0.3);
137
width: 90%;
118
- max-width: 420px;
138
+ max-width: 560px;
139
overflow: hidden;
140
}
141
@@ -160,7 +180,7 @@
180
181
.cmpct-stats {
182
display: grid;
163
- grid-template-columns: repeat(3, 1fr);
183
+ grid-template-columns: repeat(2, 1fr);
184
gap: 12px;
185
margin-bottom: 16px;
186
}
@@ -188,19 +208,96 @@
208
color: var(--color-text, #e5e5e5);
209
}
210
191
- .cmpct-warning {
211
+ /* Model selection section */
212
+ .cmpct-model-section {
213
+ margin-bottom: 16px;
214
+ }
215
+
216
+ .cmpct-model-label {
217
+ font-size: 0.7rem;
218
+ color: var(--color-text-secondary, #999);
219
+ text-transform: uppercase;
220
+ letter-spacing: 0.05em;
221
+ margin-bottom: 8px;
222
+ }
223
+
224
+ .cmpct-model-controls {
225
+ display: flex;
226
+ gap: 8px;
227
+ margin-bottom: 6px;
228
+ }
229
+
230
+ .cmpct-select {
231
+ flex: 1;
232
+ min-width: 0;
233
+ padding: 6px 10px;
234
+ border-radius: 6px;
235
+ border: 1px solid var(--color-border, #333);
236
+ background: var(--color-background-muted, #252525);
237
+ color: var(--color-text, #e5e5e5);
238
+ font-size: 0.85rem;
239
+ cursor: pointer;
240
+ }
241
+
242
+ .cmpct-select:focus {
243
+ outline: none;
244
+ border-color: var(--color-primary, #3b82f6);
245
+ }
246
+
247
+ .cmpct-toggle {
248
+ display: flex;
249
+ border-radius: 6px;
250
+ border: 1px solid var(--color-border, #333);
251
+ overflow: hidden;
252
+ flex-shrink: 0;
253
+ }
254
+
255
+ .cmpct-toggle button {
256
+ padding: 6px 14px;
257
+ border: none;
258
+ background: var(--color-background-muted, #252525);
259
+ color: var(--color-text-secondary, #999);
260
+ font-size: 0.8rem;
261
+ font-weight: 500;
262
+ cursor: pointer;
263
+ transition: all 0.15s;
264
+ }
265
+
266
+ .cmpct-toggle button:first-child {
267
+ border-right: 1px solid var(--color-border, #333);
268
+ }
269
+
270
+ .cmpct-toggle button.active {
271
+ background: var(--color-primary, #3b82f6);
272
+ color: white;
273
+ }
274
+
275
+ .cmpct-toggle button:hover:not(.active) {
276
+ background: var(--color-background-hover, #444);
277
+ }
278
+
279
+ .cmpct-model-name {
280
+ font-size: 0.85rem;
281
+ color: var(--color-text, #e5e5e5);
282
+ opacity: 0.7;
283
+ white-space: nowrap;
284
+ overflow: hidden;
285
+ text-overflow: ellipsis;
286
+ }
287
+
288
+ .cmpct-info {
289
display: flex;
290
align-items: flex-start;
291
gap: 8px;
292
padding: 10px 12px;
196
- background: rgba(245, 158, 11, 0.1);
197
- border: 1px solid rgba(245, 158, 11, 0.3);
293
+ background: rgba(34, 197, 94, 0.1);
294
+ border: 1px solid rgba(34, 197, 94, 0.25);
295
border-radius: 8px;
199
- color: #f59e0b;
296
+ color: #4ade80;
297
font-size: 0.8rem;
298
}
299
203
- .cmpct-warning .material-symbols-outlined {
300
+ .cmpct-info .material-symbols-outlined {
301
font-size: 1.1rem;
302
flex-shrink: 0;
303
}
plugins/_chat_compaction/helpers/compactor.py
+95
-125
@@ -1,13 +1,11 @@
1
"""Core compaction logic for the compaction plugin."""
2
-import asyncio
2
import os
3
from datetime import datetime
5
-from typing import Callable
4
5
+import models as models_module
6
from agent import Agent
8
-from helpers import files, history, tokens
7
+from helpers import tokens
8
from helpers.history import History, output_text
10
-from helpers.log import Log
9
from helpers.persist_chat import (
10
export_json_chat,
11
get_chat_folder_path,
@@ -15,7 +13,14 @@ from helpers.persist_chat import (
13
remove_msg_files,
14
)
15
from helpers.state_monitor_integration import mark_dirty_all
18
-from plugins._model_config.helpers.model_config import get_chat_model_config
16
+from plugins._model_config.helpers.model_config import (
17
+ get_chat_model_config,
18
+ get_utility_model_config,
19
+ get_preset_by_name,
20
+ build_model_config,
21
+ build_chat_model,
22
+ build_utility_model,
23
+)
24
25
26
def _save_pre_compaction_backup(context, full_text: str) -> dict[str, str]:
@@ -40,7 +45,36 @@ def _save_pre_compaction_backup(context, full_text: str) -> dict[str, str]:
45
return {"json": json_path, "txt": txt_path}
46
47
43
-async def run_compaction(context, use_chat_model: bool = True) -> None:
48
+def _build_model(use_chat_model: bool, preset_name: str | None, agent):
49
+ """Build the LLM model for compaction based on user selection.
50
+
51
+ If preset_name is given, builds from that preset's config.
52
+ Otherwise falls back to the agent's currently configured model.
53
+ """
54
+ if preset_name:
55
+ preset = get_preset_by_name(preset_name)
56
+ if preset:
57
+ model_key = "chat" if use_chat_model else "utility"
58
+ cfg = preset.get(model_key, {})
59
+ if cfg.get("provider") or cfg.get("name"):
60
+ mc = build_model_config(cfg, models_module.ModelType.CHAT)
61
+ return cfg, models_module.get_chat_model(
62
+ mc.provider, mc.name, model_config=mc, **mc.build_kwargs()
63
+ )
64
+
65
+ if use_chat_model:
66
+ cfg = get_chat_model_config(agent)
67
+ return cfg, build_chat_model(agent)
68
+ else:
69
+ cfg = get_utility_model_config(agent)
70
+ return cfg, build_utility_model(agent)
71
+
72
+
73
+async def run_compaction(
74
+ context,
75
+ use_chat_model: bool = True,
76
+ preset_name: str | None = None,
77
+) -> None:
78
"""
79
Compact the chat history into a single summarized message.
80
@@ -66,17 +100,11 @@ async def run_compaction(context, use_chat_model: bool = True) -> None:
100
if not full_text.strip():
101
raise ValueError("No conversation content to compact")
102
69
- # Step 2: Estimate tokens and get model config
103
+ # Step 2: Estimate tokens, resolve model, and compute context budget
104
token_count = tokens.approximate_tokens(full_text)
71
-
72
- model_config = get_chat_model_config() if use_chat_model else None
73
- if model_config is None:
74
- # Fallback: use default context length
75
- ctx_length = 128000
76
- else:
77
- ctx_length = int(model_config.get("ctx_length", 128000))
78
-
79
- # Leave some buffer for the prompt and response
105
+
106
+ resolved_cfg, model = _build_model(use_chat_model, preset_name, agent)
107
+ ctx_length = int(resolved_cfg.get("ctx_length", 128000)) if resolved_cfg else 128000
108
max_input_tokens = int(ctx_length * 0.7)
109
110
# Step 3: Create progress log item (count user-visible messages only)
@@ -91,12 +119,11 @@ async def run_compaction(context, use_chat_model: bool = True) -> None:
119
# Step 4: Handle large histories by chunking if necessary
120
if token_count > max_input_tokens:
121
summary = await _compact_large_history(
94
- agent, full_text, token_count, max_input_tokens, log_item, use_chat_model
122
+ agent, full_text, token_count, max_input_tokens, log_item, model
123
)
124
else:
97
- # Single-pass compaction
125
summary = await _compact_single_pass(
99
- agent, full_text, log_item, use_chat_model
126
+ agent, full_text, log_item, model
127
)
128
129
if not summary or not summary.strip():
@@ -149,130 +176,69 @@ async def run_compaction(context, use_chat_model: bool = True) -> None:
176
raise
177
178
152
-async def _compact_single_pass(
153
- agent,
154
- full_text: str,
155
- log_item,
156
- use_chat_model: bool
157
-) -> str:
158
- """Compact history in a single LLM call."""
159
-
179
+async def _compact_single_pass(agent, full_text: str, log_item, model) -> str:
180
+ """Compact history in a single LLM call using the provided model."""
181
system_prompt = agent.read_prompt("compact.sys.md")
182
user_prompt = agent.read_prompt("compact.msg.md", conversation=full_text)
162
-
163
- if use_chat_model:
164
- from langchain_core.messages import HumanMessage, SystemMessage
165
- messages = [
166
- SystemMessage(content=system_prompt),
167
- HumanMessage(content=user_prompt)
168
- ]
169
-
170
- async def chat_stream_cb(chunk: str, total: str):
171
- if chunk:
172
- log_item.stream(content=chunk)
173
-
174
- summary, _ = await agent.call_chat_model(
175
- messages=messages,
176
- response_callback=chat_stream_cb,
177
- )
178
- else:
179
- async def util_stream_cb(chunk: str):
180
- if chunk:
181
- log_item.stream(content=chunk)
182
-
183
- summary = await agent.call_utility_model(
184
- system=system_prompt,
185
- message=user_prompt,
186
- callback=util_stream_cb,
187
- )
188
-
183
+
184
+ async def stream_cb(chunk: str, total: str):
185
+ if chunk:
186
+ log_item.stream(content=chunk)
187
+
188
+ summary, _ = await model.unified_call(
189
+ system_message=system_prompt,
190
+ user_message=user_prompt,
191
+ response_callback=stream_cb,
192
+ )
193
return summary
194
195
196
async def _compact_large_history(
193
- agent,
194
- full_text: str,
195
- token_count: int,
196
- max_input_tokens: int,
197
- log_item,
198
- use_chat_model: bool
197
+ agent, full_text: str, token_count: int, max_input_tokens: int, log_item, model
198
) -> str:
200
- """
201
- Handle large histories by splitting into chunks and summarizing iteratively.
202
- """
199
+ """Handle large histories by splitting into chunks and summarizing iteratively."""
200
log_item.update(
201
content=f"History is large (~{token_count} tokens). Splitting into chunks...",
202
)
206
-
207
- # Split conversation into roughly equal halves
203
+
204
lines = full_text.split('\n')
205
mid = len(lines) // 2
210
-
211
- chunks = [
212
- '\n'.join(lines[:mid]),
213
- '\n'.join(lines[mid:])
214
- ]
215
-
206
+ chunks = ['\n'.join(lines[:mid]), '\n'.join(lines[mid:])]
207
+
208
summaries = []
209
for i, chunk in enumerate(chunks, 1):
218
- log_item.update(
219
- content=f"Summarizing part {i}/{len(chunks)}...",
220
- )
221
-
210
+ log_item.update(content=f"Summarizing part {i}/{len(chunks)}...")
211
+
212
system_prompt = agent.read_prompt("compact.sys.md")
213
user_prompt = agent.read_prompt("compact.msg.md", conversation=chunk)
224
-
225
- if use_chat_model:
226
- from langchain_core.messages import HumanMessage, SystemMessage
227
- messages = [
228
- SystemMessage(content=system_prompt),
229
- HumanMessage(content=user_prompt)
230
- ]
231
- chunk_summary, _ = await agent.call_chat_model(
232
- messages=messages,
233
- response_callback=None, # No streaming for chunks
234
- )
235
- else:
236
- chunk_summary = await agent.call_utility_model(
237
- system=system_prompt,
238
- message=user_prompt,
239
- callback=None,
240
- )
241
-
214
+
215
+ chunk_summary, _ = await model.unified_call(
216
+ system_message=system_prompt,
217
+ user_message=user_prompt,
218
+ )
219
summaries.append(chunk_summary)
243
-
244
- # Combine summaries
220
+
221
combined = "\n\n---\n\n".join(summaries)
246
-
247
- log_item.update(
248
- content="Creating final summary from parts...",
249
- )
250
-
251
- # Final compaction of combined summaries
222
+ log_item.update(content="Creating final summary from parts...")
223
+
224
final_prompt = agent.read_prompt("compact.sys.md")
225
final_user = agent.read_prompt(
254
- "compact.msg.md",
255
- conversation=f"This is a multi-part conversation. Here are summaries of each part:\n\n{combined}"
226
+ "compact.msg.md",
227
+ conversation=f"This is a multi-part conversation. Here are summaries of each part:\n\n{combined}",
228
+ )
229
+
230
+ async def stream_cb(chunk: str, total: str):
231
+ if chunk:
232
+ log_item.stream(content=chunk)
233
+
234
+ final_summary, _ = await model.unified_call(
235
+ system_message=final_prompt,
236
+ user_message=final_user,
237
+ response_callback=stream_cb,
238
)
257
-
258
- if use_chat_model:
259
- from langchain_core.messages import HumanMessage, SystemMessage
260
- messages = [
261
- SystemMessage(content=final_prompt),
262
- HumanMessage(content=final_user)
263
- ]
264
- final_summary, _ = await agent.call_chat_model(
265
- messages=messages,
266
- response_callback=lambda chunk, total: log_item.stream(content=chunk),
267
- )
268
- else:
269
- final_summary = await agent.call_utility_model(
270
- system=final_prompt,
271
- message=final_user,
272
- callback=lambda chunk: log_item.stream(content=chunk),
273
- )
274
-
239
return final_summary
240
+
241
+
242
async def get_compaction_stats(context) -> dict:
243
"""
244
Get statistics about the current chat for the confirmation modal.
@@ -296,12 +262,16 @@ async def get_compaction_stats(context) -> dict:
262
full_text = output_text(history_output, ai_label="assistant", human_label="user")
263
token_count = tokens.approximate_tokens(full_text) if full_text else 0
264
299
- # Get model name
300
- model_config = get_chat_model_config()
301
- model_name = model_config.get("name", "Default Model") if model_config else "Utility Model"
265
+ # Get model names for both chat and utility
266
+ chat_cfg = get_chat_model_config(agent)
267
+ utility_cfg = get_utility_model_config(agent)
268
+ chat_model_name = chat_cfg.get("name", "Default") if chat_cfg else "Default"
269
+ utility_model_name = utility_cfg.get("name", "Default") if utility_cfg else "Default"
270
271
return {
272
"message_count": message_count,
273
"token_count": token_count,
306
- "model_name": model_name,
274
+ "model_name": chat_model_name,
275
+ "chat_model_name": chat_model_name,
276
+ "utility_model_name": utility_model_name,
277
}
plugins/_chat_compaction/webui/compact-modal.html
+109
-5
@@ -29,10 +29,36 @@
29
<span class="stat-label">Tokens</span>
30
<span class="stat-value" x-text="$store.compactStore?.stats?.token_count?.toLocaleString()"></span>
31
</div>
32
- <div class="stat-item">
33
- <span class="stat-label">Model</span>
34
- <span class="stat-value" x-text="$store.compactStore?.stats?.model_name"></span>
32
+ </div>
33
+
34
+ <!-- Model selection -->
35
+ <div class="model-section">
36
+ <div class="model-section-label">Model</div>
37
+
38
+ <div class="model-controls">
39
+ <!-- Preset dropdown -->
40
+ <select class="compact-select"
41
+ x-model="$store.compactStore.selectedPresetName">
42
+ <option value="">Current</option>
43
+ <template x-for="preset in $store.compactStore.presets" :key="preset.name">
44
+ <option :value="preset.name" x-text="preset.name"></option>
45
+ </template>
46
+ </select>
47
+
48
+ <!-- Chat / Utility toggle -->
49
+ <div class="model-type-toggle">
50
+ <button :class="{ active: $store.compactStore.useChatModel }"
51
+ @click="$store.compactStore.useChatModel = true">
52
+ Chat
53
+ </button>
54
+ <button :class="{ active: !$store.compactStore.useChatModel }"
55
+ @click="$store.compactStore.useChatModel = false">
56
+ Utility
57
+ </button>
58
+ </div>
59
</div>
60
+
61
+ <div class="model-name" x-text="$store.compactStore.selectedModelDisplay"></div>
62
</div>
63
64
<div class="stats-warning">
@@ -88,7 +114,7 @@
114
border-radius: var(--border-radius-md);
115
box-shadow: var(--shadow-lg);
116
width: 90%;
91
- max-width: 500px;
117
+ max-width: 640px;
118
max-height: 90vh;
119
overflow-y: auto;
120
}
@@ -133,7 +159,7 @@
159
160
.stats-grid {
161
display: grid;
136
- grid-template-columns: repeat(3, 1fr);
162
+ grid-template-columns: repeat(2, 1fr);
163
gap: var(--spacing-md);
164
margin-bottom: var(--spacing-lg);
165
}
@@ -160,6 +186,84 @@
186
font-weight: 600;
187
color: var(--color-text);
188
}
189
+
190
+ /* ── Model selection ── */
191
+ .model-section {
192
+ margin-bottom: var(--spacing-lg);
193
+ }
194
+
195
+ .model-section-label {
196
+ font-size: 0.75rem;
197
+ color: var(--color-text-secondary);
198
+ text-transform: uppercase;
199
+ letter-spacing: 0.05em;
200
+ margin-bottom: var(--spacing-sm);
201
+ }
202
+
203
+ .model-controls {
204
+ display: flex;
205
+ gap: var(--spacing-sm);
206
+ margin-bottom: var(--spacing-sm);
207
+ }
208
+
209
+ .compact-select {
210
+ flex: 1;
211
+ min-width: 0;
212
+ padding: 6px 10px;
213
+ border-radius: var(--border-radius-md);
214
+ border: 1px solid var(--color-border);
215
+ background: var(--color-background-muted);
216
+ color: var(--color-text);
217
+ font-size: 0.85rem;
218
+ cursor: pointer;
219
+ appearance: auto;
220
+ }
221
+
222
+ .compact-select:focus {
223
+ outline: none;
224
+ border-color: var(--color-primary, #3b82f6);
225
+ }
226
+
227
+ .model-type-toggle {
228
+ display: flex;
229
+ border-radius: var(--border-radius-md);
230
+ border: 1px solid var(--color-border);
231
+ overflow: hidden;
232
+ flex-shrink: 0;
233
+ }
234
+
235
+ .model-type-toggle button {
236
+ padding: 6px 14px;
237
+ border: none;
238
+ background: var(--color-background-muted);
239
+ color: var(--color-text-secondary);
240
+ font-size: 0.8rem;
241
+ font-weight: 500;
242
+ cursor: pointer;
243
+ transition: all 0.15s;
244
+ }
245
+
246
+ .model-type-toggle button:not(:last-child) {
247
+ border-right: 1px solid var(--color-border);
248
+ }
249
+
250
+ .model-type-toggle button.active {
251
+ background: var(--color-primary, #3b82f6);
252
+ color: white;
253
+ }
254
+
255
+ .model-type-toggle button:hover:not(.active) {
256
+ background: var(--color-background-hover);
257
+ }
258
+
259
+ .model-name {
260
+ font-size: 0.85rem;
261
+ color: var(--color-text);
262
+ opacity: 0.7;
263
+ white-space: nowrap;
264
+ overflow: hidden;
265
+ text-overflow: ellipsis;
266
+ }
267
268
.stats-warning {
269
display: flex;
plugins/_chat_compaction/webui/compact-store.js
+36
-7
@@ -9,6 +9,24 @@ export const store = createStore("compactStore", {
9
compacting: false,
10
stats: null,
11
showModal: false,
12
+ presets: [],
13
+ selectedPresetName: "",
14
+ useChatModel: true,
15
+
16
+ get selectedModelDisplay() {
17
+ if (this.selectedPresetName) {
18
+ const preset = this.presets.find(
19
+ (p) => p.name === this.selectedPresetName
20
+ );
21
+ if (preset) {
22
+ const cfg = this.useChatModel ? preset.chat : preset.utility;
23
+ if (cfg?.name) return cfg.name;
24
+ }
25
+ }
26
+ return this.useChatModel
27
+ ? this.stats?.chat_model_name || "Chat Model"
28
+ : this.stats?.utility_model_name || "Utility Model";
29
+ },
30
31
async fetchStats() {
32
try {
@@ -18,16 +36,22 @@ export const store = createStore("compactStore", {
36
return;
37
}
38
21
- const res = await callJsonApi("/plugins/_chat_compaction/compact_chat", {
22
- context: ctxid,
23
- action: "stats",
24
- });
39
+ const [statsRes, presetsRes] = await Promise.all([
40
+ callJsonApi("/plugins/_chat_compaction/compact_chat", {
41
+ context: ctxid,
42
+ action: "stats",
43
+ }),
44
+ callJsonApi("/plugins/_model_config/model_presets", {
45
+ action: "get",
46
+ }),
47
+ ]);
48
26
- if (!res?.ok) {
27
- throw new Error(res?.message || "Failed to fetch stats");
49
+ if (!statsRes?.ok) {
50
+ throw new Error(statsRes?.message || "Failed to fetch stats");
51
}
52
30
- this.stats = res.stats;
53
+ this.stats = statsRes.stats;
54
+ this.presets = presetsRes?.ok ? presetsRes.presets || [] : [];
55
this.showModal = true;
56
} catch (e) {
57
toastFrontendError(e.message, "Compaction");
@@ -45,6 +69,8 @@ export const store = createStore("compactStore", {
69
const res = await callJsonApi("/plugins/_chat_compaction/compact_chat", {
70
context: ctxid,
71
action: "compact",
72
+ use_chat_model: this.useChatModel,
73
+ preset_name: this.selectedPresetName || null,
74
});
75
76
if (!res?.ok) {
@@ -63,5 +89,8 @@ export const store = createStore("compactStore", {
89
closeModal() {
90
this.showModal = false;
91
this.stats = null;
92
+ this.presets = [];
93
+ this.selectedPresetName = "";
94
+ this.useChatModel = true;
95
},
96
});