@exreve/exk 1.0.75 → 1.0.77

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.
@@ -56,7 +56,7 @@ const symlinkAsync = promisify(fsSymlink);
56
56
  // AI config - loaded from server after registration, stored in ~/.talk-to-code/ai-config.json
57
57
  // (Do not read ANTHROPIC_* / CLAUDE_MODEL from the host environment — only this file + code default model.)
58
58
  const AI_CONFIG_PATH = path.join(os.homedir(), '.talk-to-code', 'ai-config.json');
59
- const DEFAULT_AI_MODEL = 'glm-5.1';
59
+ const DEFAULT_AI_MODEL = 'glm-5.2';
60
60
  /** TTL cache for ai-config.json reads to avoid hitting disk on every call */
61
61
  let _aiConfigCache = null;
62
62
  const AI_CONFIG_TTL_MS = 5_000;
@@ -66,12 +66,12 @@ const PROVIDERS = {
66
66
  zai: {
67
67
  apiKey: process.env.ZHIPU_API_KEY || '',
68
68
  baseUrl: process.env.CLI_AI_BASE_URL || 'https://api.z.ai/api/anthropic',
69
- models: ['glm-5.1', 'glm-4.7', 'glm-4.5-air'],
69
+ models: ['glm-5.2'],
70
70
  },
71
71
  minimax: {
72
72
  apiKey: '',
73
73
  baseUrl: 'https://api.minimax.io/anthropic',
74
- models: ['MiniMax-M2.7', 'MiniMax-M2.7-highspeed'],
74
+ models: ['MiniMax-M3'],
75
75
  },
76
76
  openrouter: {
77
77
  apiKey: '',
@@ -588,23 +588,43 @@ export class AgentSessionManager {
588
588
  finalPrompt = `${skillContent}\n\n${effectivePrompt}`;
589
589
  }
590
590
  }
591
- // Inject DB history if context was lost in a previous prompt (resume failed)
591
+ // Inject compacted summary or raw DB history if context was lost
592
592
  if (session.contextLost) {
593
- console.log(`[agentSession] Context was lost previously, fetching DB history for session ${sessionId}`);
594
- try {
595
- const history = await this.fetchSessionHistory(sessionId);
596
- if (history.length > 0) {
597
- const historyPrefix = this.formatHistoryForPrompt(history);
598
- finalPrompt = historyPrefix + finalPrompt;
599
- console.log(`[agentSession] Injected ${history.length} history entries into prompt for session ${sessionId}`);
593
+ if (session.compactionSummary) {
594
+ // Use AI-generated summary from compaction
595
+ console.log(`[agentSession] Injecting AI compaction summary for session ${sessionId}`);
596
+ const summaryPrefix = [
597
+ '[Compacted Session Context]',
598
+ 'The following is an AI-generated summary of the previous conversation in this session.',
599
+ 'Use it as context to continue where you left off.',
600
+ '',
601
+ session.compactionSummary,
602
+ '',
603
+ '[End of Compacted Context]',
604
+ '',
605
+ '',
606
+ ].join('\n');
607
+ finalPrompt = summaryPrefix + finalPrompt;
608
+ session.compactionSummary = undefined; // Only inject once
609
+ }
610
+ else {
611
+ // Fallback: inject raw DB history
612
+ console.log(`[agentSession] No compaction summary, fetching DB history for session ${sessionId}`);
613
+ try {
614
+ const history = await this.fetchSessionHistory(sessionId);
615
+ if (history.length > 0) {
616
+ const historyPrefix = this.formatHistoryForPrompt(history);
617
+ finalPrompt = historyPrefix + finalPrompt;
618
+ console.log(`[agentSession] Injected ${history.length} history entries into prompt for session ${sessionId}`);
619
+ }
620
+ else {
621
+ console.log(`[agentSession] No DB history available for session ${sessionId}`);
622
+ }
600
623
  }
601
- else {
602
- console.log(`[agentSession] No DB history available for session ${sessionId}`);
624
+ catch (err) {
625
+ console.error(`[agentSession] Failed to fetch/format history:`, err);
603
626
  }
604
627
  }
605
- catch (err) {
606
- console.error(`[agentSession] Failed to fetch/format history:`, err);
607
- }
608
628
  session.contextLost = false; // Reset after injection attempt
609
629
  }
610
630
  // Add user message to history
@@ -719,13 +739,13 @@ export class AgentSessionManager {
719
739
  resumeSessionId = session.sdkSessionId;
720
740
  }
721
741
  }
722
- // Enable auto-compaction: trigger when context reaches ~150k (of 200k), keep default target
742
+ // Enable auto-compaction: trigger when context reaches ~800k (of 1M), keep default target
723
743
  if (effectiveSettings) {
724
744
  effectiveSettings.autoCompactEnabled = true;
725
- effectiveSettings.autoCompactWindow = 150000;
745
+ effectiveSettings.autoCompactWindow = 800000;
726
746
  }
727
747
  else {
728
- effectiveSettings = { autoCompactEnabled: true, autoCompactWindow: 150000 };
748
+ effectiveSettings = { autoCompactEnabled: true, autoCompactWindow: 800000 };
729
749
  }
730
750
  // Build backend config
731
751
  const backendConfig = {
@@ -1088,23 +1108,127 @@ export class AgentSessionManager {
1088
1108
  }
1089
1109
  }
1090
1110
  /**
1091
- * Compact session context — proactively clear SDK session and inject
1092
- * a summary on the next prompt. Prevents hitting the hard context
1093
- * window limit.
1111
+ * AI-powered session compaction.
1112
+ *
1113
+ * 1. Fetches full conversation history from the backend DB
1114
+ * 2. Writes it to a temp file
1115
+ * 3. Spawns a real prompt asking the model to summarize the conversation
1116
+ * 4. Captures the model's summary
1117
+ * 5. Clears the SDK session and stores the summary for injection on next prompt
1118
+ *
1119
+ * Returns true if the compaction prompt was queued successfully.
1120
+ * The `onCompactionComplete` callback fires when the model finishes summarizing.
1094
1121
  */
1095
- compactSession(sessionId) {
1122
+ async compactSession(sessionId, projectPath, onOutput, onCompactionComplete) {
1096
1123
  const session = this.sessions.get(sessionId);
1097
1124
  if (!session)
1098
1125
  return false;
1099
1126
  // Don't compact while a prompt is actively running
1100
1127
  if (session.isProcessingQueue && session.activeBackendStream)
1101
1128
  return false;
1102
- const prevSdkSessionId = session.sdkSessionId;
1103
- session.sdkSessionId = undefined;
1104
- session.contextLost = true;
1105
- session.messages = [];
1106
- deleteSessionState(sessionId);
1107
- console.log(`[AgentSessionManager] Session compacted: ${sessionId} (was ${prevSdkSessionId ?? 'empty'})`);
1129
+ // 1. Fetch conversation history from DB
1130
+ const history = await this.fetchSessionHistory(sessionId);
1131
+ if (history.length === 0) {
1132
+ console.log(`[AgentSessionManager] No history to compact for session ${sessionId}`);
1133
+ // Still allow compaction even without history — just clears context
1134
+ session.sdkSessionId = undefined;
1135
+ session.contextLost = true;
1136
+ session.messages = [];
1137
+ deleteSessionState(sessionId);
1138
+ onCompactionComplete?.(true, 'Session context cleared (no history available)');
1139
+ return true;
1140
+ }
1141
+ console.log(`[AgentSessionManager] Starting AI compaction for session ${sessionId} with ${history.length} history entries`);
1142
+ // 2. Build the conversation text
1143
+ const conversationLines = [];
1144
+ for (const entry of history) {
1145
+ const content = typeof entry.content === 'string' ? entry.content : JSON.stringify(entry.content);
1146
+ conversationLines.push(`=== ${entry.role.toUpperCase()} ===\n${content}`);
1147
+ }
1148
+ const conversationText = conversationLines.join('\n\n');
1149
+ // 3. Write conversation to a temp file
1150
+ const attachmentDir = path.join(os.tmpdir(), 'talk-to-code', 'compaction', sessionId);
1151
+ mkdirSync(attachmentDir, { recursive: true });
1152
+ const conversationFilePath = path.join(attachmentDir, 'conversation.md');
1153
+ writeFileSync(conversationFilePath, conversationText, 'utf-8');
1154
+ // 4. Build the compaction prompt
1155
+ const compactionPrompt = [
1156
+ 'You are performing a CONTEXT COMPACTION for an ongoing coding session.',
1157
+ '',
1158
+ 'Read the full conversation history in the attached file `conversation.md`.',
1159
+ '',
1160
+ 'Your task: Create a comprehensive summary that captures:',
1161
+ '1. What the user is working on (project, goals, current task)',
1162
+ '2. All decisions made and their reasoning',
1163
+ '3. The current state of the codebase (what was changed, added, removed)',
1164
+ '4. Any open issues, bugs, or TODOs discussed',
1165
+ '5. Important technical details (file paths, configurations, API designs)',
1166
+ '6. The last thing the user was doing or about to do',
1167
+ '',
1168
+ 'Be thorough but concise. Include specific file paths, code snippets, and technical details.',
1169
+ 'This summary will be the ONLY context carried forward — everything else is lost.',
1170
+ '',
1171
+ 'Format the summary as a structured document with clear sections.',
1172
+ 'Write the summary directly — no preamble or meta-commentary.',
1173
+ ].join('\n');
1174
+ // 5. Create a synthetic attachment for the conversation file
1175
+ const attachment = {
1176
+ filename: 'conversation.md',
1177
+ mimeType: 'text/markdown',
1178
+ content: Buffer.from(conversationText).toString('base64'),
1179
+ };
1180
+ // 6. Spawn a compaction prompt through the normal pipeline
1181
+ const compactionPromptId = `compact-${sessionId}-${Date.now()}`;
1182
+ let summaryParts = [];
1183
+ await this.sendPrompt(sessionId, compactionPrompt, [], {
1184
+ sessionId,
1185
+ projectPath,
1186
+ promptId: compactionPromptId,
1187
+ model: session.model,
1188
+ attachments: [attachment],
1189
+ onOutput: (output) => {
1190
+ // Forward to caller for UI display (shows compacting progress)
1191
+ onOutput?.(output);
1192
+ // Capture assistant text for the summary
1193
+ if (output.type === 'assistant' && output.data) {
1194
+ const d = output.data;
1195
+ const text = typeof output.data === 'string'
1196
+ ? output.data
1197
+ : (d?.content?.[0]?.text || d?.text || '');
1198
+ if (text)
1199
+ summaryParts.push(text);
1200
+ }
1201
+ },
1202
+ onError: (error) => {
1203
+ console.error(`[AgentSessionManager] Compaction prompt error: ${error}`);
1204
+ onCompactionComplete?.(false, `Compaction failed: ${error}`);
1205
+ },
1206
+ onComplete: (exitCode) => {
1207
+ const summary = summaryParts.join('\n').trim();
1208
+ if (summary && exitCode === 0) {
1209
+ // Store summary and clear old context
1210
+ session.compactionSummary = summary;
1211
+ session.sdkSessionId = undefined;
1212
+ session.contextLost = true;
1213
+ session.messages = [];
1214
+ deleteSessionState(sessionId);
1215
+ console.log(`[AgentSessionManager] AI compaction complete for session ${sessionId} (${summary.length} chars summary)`);
1216
+ onCompactionComplete?.(true, 'Session context compacted with AI summary');
1217
+ }
1218
+ else {
1219
+ // Compaction prompt failed — fall back to simple clear
1220
+ session.sdkSessionId = undefined;
1221
+ session.contextLost = true;
1222
+ session.messages = [];
1223
+ deleteSessionState(sessionId);
1224
+ console.warn(`[AgentSessionManager] Compaction prompt failed (exit=${exitCode}), falling back to simple clear`);
1225
+ onCompactionComplete?.(true, 'Session context cleared (compaction prompt did not produce summary)');
1226
+ }
1227
+ },
1228
+ onStatusUpdate: () => {
1229
+ // Status updates from the compaction prompt — ignore
1230
+ },
1231
+ });
1108
1232
  return true;
1109
1233
  }
1110
1234
  /**
@@ -262,7 +262,7 @@ async function runSdkBenchmark(provider) {
262
262
  // ── Main ────────────────────────────────────────────────────────────
263
263
  async function main() {
264
264
  console.log(`\n${BOLD}╔══════════════════════════════════════════════════════════════════════╗${RESET}`);
265
- console.log(`${BOLD}║ SDK Benchmark: MiniMax M2.7-highspeed vs Cerebras zai-glm-4.7 ║${RESET}`);
265
+ console.log(`${BOLD}║ SDK Benchmark: MiniMax M3 vs Cerebras zai-glm-4.7 ║${RESET}`);
266
266
  console.log(`${BOLD}║ Task: Generate a complete HTML real estate page ║${RESET}`);
267
267
  console.log(`${BOLD}╚══════════════════════════════════════════════════════════════════════╝${RESET}\n`);
268
268
  const config = loadConfig();
@@ -278,8 +278,8 @@ async function main() {
278
278
  const providers = [];
279
279
  if (minimaxKey) {
280
280
  providers.push({
281
- name: 'MiniMax M2.7-highspeed',
282
- model: 'MiniMax-M2.7-highspeed',
281
+ name: 'MiniMax M3',
282
+ model: 'MiniMax-M3',
283
283
  apiKey: minimaxKey,
284
284
  baseUrl: 'https://api.minimax.io/anthropic',
285
285
  needsProxy: false,
@@ -188,6 +188,8 @@ export class ClaudeBackend {
188
188
  settingSources: ['project'],
189
189
  permissionMode: 'bypassPermissions',
190
190
  allowDangerouslySkipPermissions: true,
191
+ // Enable 1M token context window (GLM-5.2 supports 1M context via z.ai)
192
+ betas: ['context-1m-2025-08-07'],
191
193
  mcpServers: { 'claude-voice-modules': mcpServer },
192
194
  ...(pathToClaudeCodeExecutable ? { pathToClaudeCodeExecutable } : {}),
193
195
  spawnClaudeCodeProcess: (spawnOptions) => {
@@ -250,26 +250,58 @@ export function registerSessionHandlers(socket, foreground, activeSessions, getS
250
250
  callback?.({ success: false, message: 'Missing sessionId' });
251
251
  return;
252
252
  }
253
+ const sessionInfo = activeSessions.get(sessionId);
254
+ if (!sessionInfo) {
255
+ callback?.({ success: false, message: 'Session not found' });
256
+ return;
257
+ }
253
258
  if (foreground) {
254
259
  console.log(`[CLI] Compacting session: ${sessionId}`);
255
260
  }
256
- const compacted = agentSessionManager.compactSession(sessionId);
257
- if (compacted) {
261
+ // Respond immediately — compaction runs in the background
262
+ callback?.({ success: true, message: 'Compaction started' });
263
+ const compacted = await agentSessionManager.compactSession(sessionId, sessionInfo.projectPath, (output) => {
264
+ // Forward compaction prompt output to the backend for UI display
265
+ const compactPromptId = `compact-${sessionId}`;
266
+ getSocket().emit('prompt:output', {
267
+ sessionId,
268
+ promptId: compactPromptId,
269
+ type: output.type,
270
+ data: output.data,
271
+ timestamp: output.timestamp,
272
+ metadata: { ...output.metadata, isCompaction: true },
273
+ });
274
+ }, (success, message) => {
275
+ // Compaction finished — notify UI
258
276
  getSocket().emit('session:compacted', {
259
277
  sessionId,
260
278
  timestamp: Date.now(),
279
+ success,
280
+ message,
281
+ });
282
+ if (foreground) {
283
+ console.log(`[CLI] Compaction ${success ? 'complete' : 'failed'}: ${message}`);
284
+ }
285
+ });
286
+ if (!compacted) {
287
+ getSocket().emit('session:compacted', {
288
+ sessionId,
289
+ timestamp: Date.now(),
290
+ success: false,
291
+ message: 'Session not found or prompt is running',
261
292
  });
262
- callback?.({ success: true, message: 'Session context compacted' });
263
- }
264
- else {
265
- callback?.({ success: false, message: 'Session not found or prompt is running' });
266
293
  }
267
294
  }
268
295
  catch (error) {
269
296
  if (foreground) {
270
297
  console.error(`✗ Error compacting session: ${error.message}`);
271
298
  }
272
- callback?.({ success: false, message: error.message });
299
+ getSocket().emit('session:compacted', {
300
+ sessionId: data.sessionId,
301
+ timestamp: Date.now(),
302
+ success: false,
303
+ message: error.message,
304
+ });
273
305
  }
274
306
  });
275
307
  socket.on('emergency:stop', async (data, callback) => {
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exreve/exk",
3
- "version": "1.0.75",
3
+ "version": "1.0.77",
4
4
  "description": "exk - Control Claude CLI with voice and programmable interfaces",
5
5
  "type": "module",
6
6
  "bin": {