snow-ai 0.6.32 → 0.6.33

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/bundle/cli.mjs CHANGED
@@ -81929,6 +81929,7 @@ var init_en = __esm({
81929
81929
  description: "This checkpoint has",
81930
81930
  filesCount: "{count} file(s) will be rolled back",
81931
81931
  filesCountWithSelection: "{count} file(s) will be rolled back ({selected}/{total} selected)",
81932
+ notebookCount: "{count} notebook(s) will also be rolled back",
81932
81933
  question: "Do you want to rollback the files as well?",
81933
81934
  yesRollbackFiles: "Yes, rollback files and conversation",
81934
81935
  noConversationOnly: "No, rollback conversation only",
@@ -83179,6 +83180,7 @@ var init_zh = __esm({
83179
83180
  description: "\u6B64\u68C0\u67E5\u70B9\u5305\u542B",
83180
83181
  filesCount: "{count} \u4E2A\u6587\u4EF6\u5C06\u88AB\u56DE\u6EDA",
83181
83182
  filesCountWithSelection: "{count} \u4E2A\u6587\u4EF6\u5C06\u88AB\u56DE\u6EDA ({selected}/{total} \u5DF2\u9009\u62E9)",
83183
+ notebookCount: "{count} \u6761\u5907\u5FD8\u5F55\u4E5F\u5C06\u88AB\u56DE\u6EDA",
83182
83184
  question: "\u662F\u5426\u540C\u65F6\u56DE\u6EDA\u6587\u4EF6\uFF1F",
83183
83185
  yesRollbackFiles: "\u662F\uFF0C\u56DE\u6EDA\u6587\u4EF6\u548C\u5BF9\u8BDD",
83184
83186
  noConversationOnly: "\u5426\uFF0C\u4EC5\u56DE\u6EDA\u5BF9\u8BDD",
@@ -84428,6 +84430,7 @@ var init_zh_TW = __esm({
84428
84430
  description: "\u6B64\u6AA2\u67E5\u9EDE\u5305\u542B",
84429
84431
  filesCount: "{count} \u500B\u6A94\u6848\u5C07\u88AB\u56DE\u6EFE",
84430
84432
  filesCountWithSelection: "{count} \u500B\u6A94\u6848\u5C07\u88AB\u56DE\u6EFE ({selected}/{total} \u5DF2\u9078\u64C7)",
84433
+ notebookCount: "{count} \u689D\u5099\u5FD8\u9304\u4E5F\u5C07\u88AB\u56DE\u6EFE",
84431
84434
  question: "\u662F\u5426\u540C\u6642\u56DE\u6EFE\u6A94\u6848\uFF1F",
84432
84435
  yesRollbackFiles: "\u662F\uFF0C\u56DE\u6EFE\u6A94\u6848\u548C\u5C0D\u8A71",
84433
84436
  noConversationOnly: "\u5426\uFF0C\u50C5\u56DE\u6EFE\u5C0D\u8A71",
@@ -352053,6 +352056,16 @@ function getNotebooksByFile(filePath) {
352053
352056
  const data = readNotebookData();
352054
352057
  return data[normalizedPath] || [];
352055
352058
  }
352059
+ function findNotebookById(notebookId) {
352060
+ const data = readNotebookData();
352061
+ for (const [, entries] of Object.entries(data)) {
352062
+ const entry = entries.find((e) => e.id === notebookId);
352063
+ if (entry) {
352064
+ return { ...entry };
352065
+ }
352066
+ }
352067
+ return null;
352068
+ }
352056
352069
  function updateNotebook(notebookId, newNote) {
352057
352070
  const data = readNotebookData();
352058
352071
  let updatedEntry = null;
@@ -352087,6 +352100,141 @@ function deleteNotebook(notebookId) {
352087
352100
  }
352088
352101
  return found;
352089
352102
  }
352103
+ function getNotebookSnapshotFilePath() {
352104
+ const projectRoot = process.cwd();
352105
+ const projectName = path16.basename(projectRoot);
352106
+ const notebookDir = getNotebookDir();
352107
+ return path16.join(notebookDir, `${projectName}_snapshots.json`);
352108
+ }
352109
+ function readNotebookSnapshotData() {
352110
+ const filePath = getNotebookSnapshotFilePath();
352111
+ if (!fs16.existsSync(filePath)) {
352112
+ return {};
352113
+ }
352114
+ try {
352115
+ const content = fs16.readFileSync(filePath, "utf-8");
352116
+ return JSON.parse(content);
352117
+ } catch {
352118
+ return {};
352119
+ }
352120
+ }
352121
+ function saveNotebookSnapshotData(data) {
352122
+ const filePath = getNotebookSnapshotFilePath();
352123
+ try {
352124
+ fs16.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
352125
+ } catch (error) {
352126
+ console.error("Failed to save notebook snapshot data:", error);
352127
+ }
352128
+ }
352129
+ function appendNotebookOperation(sessionId, messageIndex, operation) {
352130
+ const data = readNotebookSnapshotData();
352131
+ const key = `${sessionId}:${messageIndex}`;
352132
+ if (!data[key]) {
352133
+ data[key] = [];
352134
+ }
352135
+ data[key].push(operation);
352136
+ saveNotebookSnapshotData(data);
352137
+ }
352138
+ function recordNotebookAddition(sessionId, messageIndex, notebookId) {
352139
+ appendNotebookOperation(sessionId, messageIndex, {
352140
+ op: "add",
352141
+ notebookId
352142
+ });
352143
+ }
352144
+ function recordNotebookUpdate(sessionId, messageIndex, notebookId, previousNote) {
352145
+ appendNotebookOperation(sessionId, messageIndex, {
352146
+ op: "update",
352147
+ notebookId,
352148
+ previousNote
352149
+ });
352150
+ }
352151
+ function recordNotebookDeletion(sessionId, messageIndex, entry) {
352152
+ appendNotebookOperation(sessionId, messageIndex, {
352153
+ op: "delete",
352154
+ entry
352155
+ });
352156
+ }
352157
+ function getNotebookOpsToRollback(sessionId, targetMessageIndex) {
352158
+ const data = readNotebookSnapshotData();
352159
+ const ops = [];
352160
+ for (const [key, operations] of Object.entries(data)) {
352161
+ if (!key.startsWith(`${sessionId}:`))
352162
+ continue;
352163
+ const msgIndex = parseInt(key.split(":")[1] || "", 10);
352164
+ if (!isNaN(msgIndex) && msgIndex >= targetMessageIndex) {
352165
+ ops.push(...operations);
352166
+ }
352167
+ }
352168
+ return ops;
352169
+ }
352170
+ function getNotebookRollbackCount(sessionId, targetMessageIndex) {
352171
+ return getNotebookOpsToRollback(sessionId, targetMessageIndex).length;
352172
+ }
352173
+ function rollbackNotebooks(sessionId, targetMessageIndex) {
352174
+ const ops = getNotebookOpsToRollback(sessionId, targetMessageIndex);
352175
+ let rolledBackCount = 0;
352176
+ for (let i = ops.length - 1; i >= 0; i--) {
352177
+ const op2 = ops[i];
352178
+ if (!op2)
352179
+ continue;
352180
+ try {
352181
+ switch (op2.op) {
352182
+ case "add":
352183
+ deleteNotebook(op2.notebookId);
352184
+ rolledBackCount++;
352185
+ break;
352186
+ case "update":
352187
+ updateNotebook(op2.notebookId, op2.previousNote);
352188
+ rolledBackCount++;
352189
+ break;
352190
+ case "delete": {
352191
+ const data = readNotebookData();
352192
+ const fp = op2.entry.filePath;
352193
+ if (!data[fp]) {
352194
+ data[fp] = [];
352195
+ }
352196
+ data[fp].unshift(op2.entry);
352197
+ saveNotebookData(data);
352198
+ rolledBackCount++;
352199
+ break;
352200
+ }
352201
+ }
352202
+ } catch (error) {
352203
+ console.error(`Failed to rollback notebook operation:`, error);
352204
+ }
352205
+ }
352206
+ deleteNotebookSnapshotsFromIndex(sessionId, targetMessageIndex);
352207
+ return rolledBackCount;
352208
+ }
352209
+ function deleteNotebookSnapshotsFromIndex(sessionId, targetMessageIndex) {
352210
+ const data = readNotebookSnapshotData();
352211
+ let changed = false;
352212
+ for (const key of Object.keys(data)) {
352213
+ if (!key.startsWith(`${sessionId}:`))
352214
+ continue;
352215
+ const msgIndex = parseInt(key.split(":")[1] || "", 10);
352216
+ if (!isNaN(msgIndex) && msgIndex >= targetMessageIndex) {
352217
+ delete data[key];
352218
+ changed = true;
352219
+ }
352220
+ }
352221
+ if (changed) {
352222
+ saveNotebookSnapshotData(data);
352223
+ }
352224
+ }
352225
+ function clearAllNotebookSnapshots(sessionId) {
352226
+ const data = readNotebookSnapshotData();
352227
+ let changed = false;
352228
+ for (const key of Object.keys(data)) {
352229
+ if (key.startsWith(`${sessionId}:`)) {
352230
+ delete data[key];
352231
+ changed = true;
352232
+ }
352233
+ }
352234
+ if (changed) {
352235
+ saveNotebookSnapshotData(data);
352236
+ }
352237
+ }
352090
352238
  var MAX_ENTRIES_PER_FILE;
352091
352239
  var init_notebookManager = __esm({
352092
352240
  "dist/utils/core/notebookManager.js"() {
@@ -361462,7 +361610,7 @@ var require_lib12 = __commonJS({
361462
361610
  module2.exports._canonicalizeEncoding = function(encoding) {
361463
361611
  return ("" + encoding).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "");
361464
361612
  };
361465
- module2.exports.getEncoder = function getEncoder(encoding, options3) {
361613
+ module2.exports.getEncoder = function getEncoder2(encoding, options3) {
361466
361614
  var codec = module2.exports.getCodec(encoding);
361467
361615
  var encoder = new codec.encoder(options3, codec);
361468
361616
  if (codec.bomAware && options3 && options3.addBOM) {
@@ -438009,11 +438157,11 @@ var init_compactAgent = __esm({
438009
438157
  let chunkCount = 0;
438010
438158
  let encoder;
438011
438159
  try {
438012
- const { encoding_for_model: encoding_for_model2 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
438013
- encoder = encoding_for_model2("gpt-5");
438160
+ const { encoding_for_model: encoding_for_model3 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
438161
+ encoder = encoding_for_model3("gpt-5");
438014
438162
  } catch (e) {
438015
- const { encoding_for_model: encoding_for_model2 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
438016
- encoder = encoding_for_model2("gpt-5");
438163
+ const { encoding_for_model: encoding_for_model3 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
438164
+ encoder = encoding_for_model3("gpt-5");
438017
438165
  }
438018
438166
  try {
438019
438167
  for await (const chunk2 of streamGenerator) {
@@ -443046,6 +443194,13 @@ async function executeNotebookTool(toolName, args2) {
443046
443194
  };
443047
443195
  }
443048
443196
  const entry = addNotebook(filePath, note);
443197
+ try {
443198
+ const context2 = getConversationContext();
443199
+ if (context2) {
443200
+ recordNotebookAddition(context2.sessionId, context2.messageIndex, entry.id);
443201
+ }
443202
+ } catch {
443203
+ }
443049
443204
  return {
443050
443205
  content: [
443051
443206
  {
@@ -443113,6 +443268,8 @@ async function executeNotebookTool(toolName, args2) {
443113
443268
  isError: true
443114
443269
  };
443115
443270
  }
443271
+ const previousEntry = findNotebookById(notebookId);
443272
+ const previousNote = previousEntry == null ? void 0 : previousEntry.note;
443116
443273
  const updatedEntry = updateNotebook(notebookId, note);
443117
443274
  if (!updatedEntry) {
443118
443275
  return {
@@ -443128,6 +443285,13 @@ async function executeNotebookTool(toolName, args2) {
443128
443285
  isError: true
443129
443286
  };
443130
443287
  }
443288
+ try {
443289
+ const context2 = getConversationContext();
443290
+ if (context2 && previousNote !== void 0) {
443291
+ recordNotebookUpdate(context2.sessionId, context2.messageIndex, notebookId, previousNote);
443292
+ }
443293
+ } catch {
443294
+ }
443131
443295
  return {
443132
443296
  content: [
443133
443297
  {
@@ -443159,6 +443323,7 @@ async function executeNotebookTool(toolName, args2) {
443159
443323
  isError: true
443160
443324
  };
443161
443325
  }
443326
+ const entryToDelete = findNotebookById(notebookId);
443162
443327
  const deleted = deleteNotebook(notebookId);
443163
443328
  if (!deleted) {
443164
443329
  return {
@@ -443174,6 +443339,13 @@ async function executeNotebookTool(toolName, args2) {
443174
443339
  isError: true
443175
443340
  };
443176
443341
  }
443342
+ try {
443343
+ const context2 = getConversationContext();
443344
+ if (context2 && entryToDelete) {
443345
+ recordNotebookDeletion(context2.sessionId, context2.messageIndex, entryToDelete);
443346
+ }
443347
+ } catch {
443348
+ }
443177
443349
  return {
443178
443350
  content: [
443179
443351
  {
@@ -443247,6 +443419,7 @@ var init_notebook = __esm({
443247
443419
  "dist/mcp/notebook.js"() {
443248
443420
  "use strict";
443249
443421
  init_notebookManager();
443422
+ init_conversationContext();
443250
443423
  mcpTools8 = [
443251
443424
  {
443252
443425
  name: "notebook-add",
@@ -444803,6 +444976,368 @@ var init_yoloPermissionChecker = __esm({
444803
444976
  }
444804
444977
  });
444805
444978
 
444979
+ // dist/utils/core/subAgentContextCompressor.js
444980
+ function getEncoder() {
444981
+ if (!_encoder) {
444982
+ try {
444983
+ _encoder = (0, import_tiktoken.encoding_for_model)("gpt-4o");
444984
+ } catch {
444985
+ _encoder = (0, import_tiktoken.encoding_for_model)("gpt-3.5-turbo");
444986
+ }
444987
+ }
444988
+ return _encoder;
444989
+ }
444990
+ function countMessagesTokens(messages) {
444991
+ var _a21, _b14;
444992
+ try {
444993
+ const encoder = getEncoder();
444994
+ let total = 0;
444995
+ for (const msg of messages) {
444996
+ if (msg.content) {
444997
+ total += encoder.encode(msg.content).length;
444998
+ }
444999
+ if (msg.tool_calls) {
445000
+ for (const tc of msg.tool_calls) {
445001
+ if ((_a21 = tc.function) == null ? void 0 : _a21.arguments) {
445002
+ total += encoder.encode(tc.function.arguments).length;
445003
+ }
445004
+ if ((_b14 = tc.function) == null ? void 0 : _b14.name) {
445005
+ total += encoder.encode(tc.function.name).length;
445006
+ }
445007
+ }
445008
+ }
445009
+ total += 4;
445010
+ }
445011
+ return total;
445012
+ } catch (error) {
445013
+ console.error("[SubAgentCompressor] tiktoken counting failed:", error);
445014
+ const totalChars = messages.reduce((sum, m) => {
445015
+ var _a22;
445016
+ return sum + (((_a22 = m.content) == null ? void 0 : _a22.length) || 0);
445017
+ }, 0);
445018
+ return Math.round(totalChars / 4);
445019
+ }
445020
+ }
445021
+ function getContextPercentage(totalTokens, maxContextTokens) {
445022
+ if (!maxContextTokens || maxContextTokens <= 0)
445023
+ return 0;
445024
+ return Math.min(100, totalTokens / maxContextTokens * 100);
445025
+ }
445026
+ function shouldCompressSubAgentContext(totalTokens, maxContextTokens) {
445027
+ return getContextPercentage(totalTokens, maxContextTokens) >= COMPRESS_THRESHOLD;
445028
+ }
445029
+ function getAdaptiveKeepRounds(percentage) {
445030
+ if (percentage >= 95)
445031
+ return 1;
445032
+ if (percentage >= 85)
445033
+ return 2;
445034
+ return DEFAULT_KEEP_RECENT_ROUNDS;
445035
+ }
445036
+ function findRecentRoundsStartIndex(messages, keepRounds) {
445037
+ var _a21, _b14, _c6, _d4;
445038
+ let roundCount = 0;
445039
+ let i = messages.length - 1;
445040
+ while (i >= 0 && roundCount < keepRounds) {
445041
+ const msg = messages[i];
445042
+ if ((msg == null ? void 0 : msg.role) === "tool") {
445043
+ while (i >= 0 && ((_a21 = messages[i]) == null ? void 0 : _a21.role) === "tool") {
445044
+ i--;
445045
+ }
445046
+ if (i >= 0 && ((_b14 = messages[i]) == null ? void 0 : _b14.role) === "assistant" && ((_d4 = (_c6 = messages[i]) == null ? void 0 : _c6.tool_calls) == null ? void 0 : _d4.length)) {
445047
+ roundCount++;
445048
+ i--;
445049
+ }
445050
+ } else {
445051
+ i--;
445052
+ }
445053
+ }
445054
+ return Math.max(0, i + 1);
445055
+ }
445056
+ function formatMessageForTranscript(msg) {
445057
+ var _a21, _b14;
445058
+ if (msg.role === "tool") {
445059
+ return null;
445060
+ }
445061
+ if (msg.role === "system") {
445062
+ return null;
445063
+ }
445064
+ const parts = [];
445065
+ const roleLabel = msg.role === "user" ? "[User]" : "[Assistant]";
445066
+ if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0) {
445067
+ if (msg.content) {
445068
+ parts.push(`${roleLabel}
445069
+ ${msg.content}`);
445070
+ } else {
445071
+ parts.push(roleLabel);
445072
+ }
445073
+ for (const tc of msg.tool_calls) {
445074
+ const funcName = ((_a21 = tc.function) == null ? void 0 : _a21.name) || "unknown";
445075
+ const args2 = ((_b14 = tc.function) == null ? void 0 : _b14.arguments) || "{}";
445076
+ const truncatedArgs = args2.length > 500 ? args2.substring(0, 500) + "..." : args2;
445077
+ parts.push(` -> Tool Call: ${funcName}(${truncatedArgs})`);
445078
+ }
445079
+ return parts.join("\n");
445080
+ }
445081
+ if (msg.content) {
445082
+ parts.push(`${roleLabel}
445083
+ ${msg.content}`);
445084
+ }
445085
+ return parts.length > 0 ? parts.join("\n") : null;
445086
+ }
445087
+ function prepareMessagesForAICompression(conversationMessages) {
445088
+ const messages = [];
445089
+ messages.push({
445090
+ role: "system",
445091
+ content: "You are a technical summarization assistant. Your job is to compress a tool-using AI agent's conversation history into a concise but complete handover document."
445092
+ });
445093
+ const transcriptParts = [];
445094
+ for (const msg of conversationMessages) {
445095
+ const formatted = formatMessageForTranscript(msg);
445096
+ if (formatted) {
445097
+ transcriptParts.push(formatted);
445098
+ }
445099
+ }
445100
+ const transcript = transcriptParts.join("\n\n---\n\n");
445101
+ messages.push({
445102
+ role: "user",
445103
+ content: `## Sub-Agent Conversation History to Compress
445104
+
445105
+ ${transcript}`
445106
+ });
445107
+ messages.push({
445108
+ role: "user",
445109
+ content: SUB_AGENT_COMPRESSION_PROMPT
445110
+ });
445111
+ return messages;
445112
+ }
445113
+ async function aiSummaryCompress(messages, keepRounds, config3) {
445114
+ const preserveStartIndex = findRecentRoundsStartIndex(messages, keepRounds);
445115
+ if (preserveStartIndex === 0) {
445116
+ return messages;
445117
+ }
445118
+ const messagesToCompress = messages.slice(0, preserveStartIndex);
445119
+ const preservedMessages = messages.slice(preserveStartIndex);
445120
+ const compressionMessages = prepareMessagesForAICompression(messagesToCompress);
445121
+ let summary = "";
445122
+ try {
445123
+ switch (config3.requestMethod) {
445124
+ case "gemini": {
445125
+ for await (const chunk2 of createStreamingGeminiCompletion({
445126
+ model: config3.model,
445127
+ messages: compressionMessages,
445128
+ configProfile: config3.configProfile
445129
+ })) {
445130
+ if (chunk2.type === "content" && chunk2.content) {
445131
+ summary += chunk2.content;
445132
+ }
445133
+ }
445134
+ break;
445135
+ }
445136
+ case "anthropic": {
445137
+ for await (const chunk2 of createStreamingAnthropicCompletion({
445138
+ model: config3.model,
445139
+ messages: compressionMessages,
445140
+ max_tokens: config3.maxTokens || 4096,
445141
+ disableThinking: true,
445142
+ configProfile: config3.configProfile
445143
+ })) {
445144
+ if (chunk2.type === "content" && chunk2.content) {
445145
+ summary += chunk2.content;
445146
+ }
445147
+ }
445148
+ break;
445149
+ }
445150
+ case "responses": {
445151
+ for await (const chunk2 of createStreamingResponse({
445152
+ model: config3.model,
445153
+ messages: compressionMessages,
445154
+ configProfile: config3.configProfile
445155
+ })) {
445156
+ if (chunk2.type === "content" && chunk2.content) {
445157
+ summary += chunk2.content;
445158
+ }
445159
+ }
445160
+ break;
445161
+ }
445162
+ case "chat":
445163
+ default: {
445164
+ for await (const chunk2 of createStreamingChatCompletion({
445165
+ model: config3.model,
445166
+ messages: compressionMessages,
445167
+ stream: true,
445168
+ configProfile: config3.configProfile
445169
+ })) {
445170
+ if (chunk2.type === "content" && chunk2.content) {
445171
+ summary += chunk2.content;
445172
+ }
445173
+ }
445174
+ break;
445175
+ }
445176
+ }
445177
+ } catch (error) {
445178
+ console.error("[SubAgentCompressor] AI compression failed:", error);
445179
+ return messages;
445180
+ }
445181
+ if (!summary) {
445182
+ console.warn("[SubAgentCompressor] AI compression returned empty summary");
445183
+ return messages;
445184
+ }
445185
+ const newMessages = [
445186
+ {
445187
+ role: "user",
445188
+ content: `## Previous Context (Auto-Compressed Summary)
445189
+
445190
+ ${summary}
445191
+
445192
+ ---
445193
+
445194
+ *The above is a compressed summary of earlier conversation. Continue the task based on this context and the recent tool interactions below.*`
445195
+ },
445196
+ ...preservedMessages
445197
+ ];
445198
+ return newMessages;
445199
+ }
445200
+ function truncateToolResults(messages, keepRounds) {
445201
+ if (messages.length === 0)
445202
+ return [];
445203
+ const preserveStartIndex = findRecentRoundsStartIndex(messages, keepRounds);
445204
+ const result2 = [];
445205
+ const MIN_TRUNCATION_LENGTH = 500;
445206
+ const MAX_PRESERVED_CHARS = 2e3;
445207
+ for (let i = 0; i < messages.length; i++) {
445208
+ const msg = messages[i];
445209
+ if (!msg)
445210
+ continue;
445211
+ const findToolName = () => {
445212
+ for (let j = i - 1; j >= 0; j--) {
445213
+ const prev = messages[j];
445214
+ if ((prev == null ? void 0 : prev.role) === "assistant" && prev.tool_calls) {
445215
+ const match2 = prev.tool_calls.find((tc) => tc.id === msg.tool_call_id);
445216
+ if (match2)
445217
+ return match2.function.name;
445218
+ }
445219
+ if ((prev == null ? void 0 : prev.role) !== "tool")
445220
+ break;
445221
+ }
445222
+ return "unknown";
445223
+ };
445224
+ if (i < preserveStartIndex) {
445225
+ if (msg.role === "tool" && msg.content && msg.content.length > MIN_TRUNCATION_LENGTH) {
445226
+ result2.push({
445227
+ ...msg,
445228
+ content: `[Tool result truncated: ${findToolName()}, original ${msg.content.length} chars]`
445229
+ });
445230
+ } else {
445231
+ result2.push(msg);
445232
+ }
445233
+ continue;
445234
+ }
445235
+ if (msg.role === "tool" && msg.content && msg.content.length > MAX_PRESERVED_CHARS) {
445236
+ const toolName = findToolName();
445237
+ const keepStart = Math.floor(MAX_PRESERVED_CHARS * 0.6);
445238
+ const keepEnd = Math.floor(MAX_PRESERVED_CHARS * 0.3);
445239
+ const truncated = msg.content.length - keepStart - keepEnd;
445240
+ result2.push({
445241
+ ...msg,
445242
+ content: msg.content.substring(0, keepStart) + `
445243
+
445244
+ [... ${truncated} chars truncated from ${toolName} result ...]
445245
+
445246
+ ` + msg.content.substring(msg.content.length - keepEnd)
445247
+ });
445248
+ } else {
445249
+ result2.push(msg);
445250
+ }
445251
+ }
445252
+ return result2;
445253
+ }
445254
+ async function compressSubAgentContext(messages, totalTokens, maxContextTokens, config3) {
445255
+ const percentage = getContextPercentage(totalTokens, maxContextTokens);
445256
+ if (percentage < COMPRESS_THRESHOLD) {
445257
+ return {
445258
+ compressed: false,
445259
+ messages
445260
+ };
445261
+ }
445262
+ const keepRounds = getAdaptiveKeepRounds(percentage);
445263
+ const compressedMessages = await aiSummaryCompress(messages, keepRounds, config3);
445264
+ if (compressedMessages !== messages) {
445265
+ const afterTokens2 = countMessagesTokens(compressedMessages);
445266
+ return {
445267
+ compressed: true,
445268
+ messages: compressedMessages,
445269
+ beforeTokens: totalTokens,
445270
+ afterTokensEstimate: afterTokens2
445271
+ };
445272
+ }
445273
+ console.warn(`[SubAgentCompressor] AI compression ineffective, falling back to truncation`);
445274
+ const truncatedMessages = truncateToolResults(messages, keepRounds);
445275
+ const afterTokens = countMessagesTokens(truncatedMessages);
445276
+ if (afterTokens < totalTokens) {
445277
+ return {
445278
+ compressed: true,
445279
+ messages: truncatedMessages,
445280
+ beforeTokens: totalTokens,
445281
+ afterTokensEstimate: afterTokens
445282
+ };
445283
+ }
445284
+ return {
445285
+ compressed: false,
445286
+ messages
445287
+ };
445288
+ }
445289
+ var import_tiktoken, COMPRESS_THRESHOLD, DEFAULT_KEEP_RECENT_ROUNDS, SUB_AGENT_COMPRESSION_PROMPT, _encoder;
445290
+ var init_subAgentContextCompressor = __esm({
445291
+ "dist/utils/core/subAgentContextCompressor.js"() {
445292
+ "use strict";
445293
+ import_tiktoken = __toESM(require_tiktoken(), 1);
445294
+ init_chat();
445295
+ init_responses();
445296
+ init_gemini();
445297
+ init_anthropic();
445298
+ COMPRESS_THRESHOLD = 80;
445299
+ DEFAULT_KEEP_RECENT_ROUNDS = 3;
445300
+ SUB_AGENT_COMPRESSION_PROMPT = `**TASK: Create a concise handover document from the sub-agent conversation history above.**
445301
+
445302
+ You are creating a technical handover document for a tool-using AI agent. Extract and preserve all critical information with rigorous detail.
445303
+
445304
+ **OUTPUT FORMAT:**
445305
+
445306
+ ## Task Objective
445307
+ - What the agent was asked to do
445308
+ - Current completion status
445309
+
445310
+ ## Key Findings
445311
+ - Important information discovered via tool calls
445312
+ - **EXACT** file paths, function names, code identifiers
445313
+ - Search results, code patterns, architecture details
445314
+
445315
+ ## Actions Taken
445316
+ - Files read/modified (with exact paths)
445317
+ - Commands executed and their outcomes
445318
+ - Tools used and their results (key details only)
445319
+
445320
+ ## Work In Progress
445321
+ - Incomplete tasks with specific reasons
445322
+ - Planned next steps (concrete, actionable)
445323
+ - Known issues and blockers
445324
+
445325
+ ## Critical Reference Data
445326
+ - Important values, IDs, error messages (exact wording)
445327
+ - User requirements and constraints
445328
+ - Edge cases and special handling
445329
+
445330
+ **QUALITY REQUIREMENTS:**
445331
+ 1. Preserve EXACT technical terms \u2014 never paraphrase code/file names
445332
+ 2. Include FULL context \u2014 paths, versions, configurations
445333
+ 3. NO vague summaries \u2014 provide actionable, specific details
445334
+ 4. Use markdown code blocks for code snippets
445335
+
445336
+ **EXECUTE NOW \u2014 Output the handover document immediately.**`;
445337
+ _encoder = null;
445338
+ }
445339
+ });
445340
+
444806
445341
  // dist/utils/execution/runningSubAgentTracker.js
444807
445342
  var runningSubAgentTracker_exports = {};
444808
445343
  __export(runningSubAgentTracker_exports, {
@@ -444838,6 +445373,24 @@ var init_runningSubAgentTracker = __esm({
444838
445373
  writable: true,
444839
445374
  value: /* @__PURE__ */ new Map()
444840
445375
  });
445376
+ Object.defineProperty(this, "interAgentQueues", {
445377
+ enumerable: true,
445378
+ configurable: true,
445379
+ writable: true,
445380
+ value: /* @__PURE__ */ new Map()
445381
+ });
445382
+ Object.defineProperty(this, "spawnedResults", {
445383
+ enumerable: true,
445384
+ configurable: true,
445385
+ writable: true,
445386
+ value: []
445387
+ });
445388
+ Object.defineProperty(this, "interAgentListeners", {
445389
+ enumerable: true,
445390
+ configurable: true,
445391
+ writable: true,
445392
+ value: /* @__PURE__ */ new Set()
445393
+ });
444841
445394
  }
444842
445395
  /**
444843
445396
  * Register a running sub-agent
@@ -444845,6 +445398,7 @@ var init_runningSubAgentTracker = __esm({
444845
445398
  register(agent) {
444846
445399
  this.agents.set(agent.instanceId, agent);
444847
445400
  this.messageQueues.set(agent.instanceId, []);
445401
+ this.interAgentQueues.set(agent.instanceId, []);
444848
445402
  this.rebuildSnapshot();
444849
445403
  this.notifyListeners();
444850
445404
  }
@@ -444854,6 +445408,7 @@ var init_runningSubAgentTracker = __esm({
444854
445408
  unregister(instanceId) {
444855
445409
  if (this.agents.delete(instanceId)) {
444856
445410
  this.messageQueues.delete(instanceId);
445411
+ this.interAgentQueues.delete(instanceId);
444857
445412
  this.rebuildSnapshot();
444858
445413
  this.notifyListeners();
444859
445414
  }
@@ -444878,6 +445433,68 @@ var init_runningSubAgentTracker = __esm({
444878
445433
  isRunning(instanceId) {
444879
445434
  return this.agents.has(instanceId);
444880
445435
  }
445436
+ /**
445437
+ * Check if there are any spawned sub-agents still running.
445438
+ * Spawned agents have instanceIds starting with "spawn-".
445439
+ */
445440
+ hasRunningSpawnedAgents() {
445441
+ for (const instanceId of this.agents.keys()) {
445442
+ if (instanceId.startsWith("spawn-")) {
445443
+ return true;
445444
+ }
445445
+ }
445446
+ return false;
445447
+ }
445448
+ /**
445449
+ * Wait for all spawned agents to complete, with a timeout.
445450
+ * Resolves when all spawned agents finish or the timeout is reached.
445451
+ * @param timeoutMs Maximum time to wait in milliseconds (default: 5 minutes)
445452
+ * @param abortSignal Optional abort signal to cancel waiting early
445453
+ * @returns true if all spawned agents completed, false if timed out or aborted
445454
+ */
445455
+ waitForSpawnedAgents(timeoutMs = 3e5, abortSignal) {
445456
+ return new Promise((resolve12) => {
445457
+ if (!this.hasRunningSpawnedAgents()) {
445458
+ resolve12(true);
445459
+ return;
445460
+ }
445461
+ const startTime = Date.now();
445462
+ let unsubscribe;
445463
+ const checkDone = () => {
445464
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
445465
+ cleanup();
445466
+ resolve12(false);
445467
+ return;
445468
+ }
445469
+ if (!this.hasRunningSpawnedAgents()) {
445470
+ cleanup();
445471
+ resolve12(true);
445472
+ return;
445473
+ }
445474
+ if (Date.now() - startTime > timeoutMs) {
445475
+ cleanup();
445476
+ resolve12(false);
445477
+ return;
445478
+ }
445479
+ };
445480
+ const cleanup = () => {
445481
+ if (unsubscribe) {
445482
+ unsubscribe();
445483
+ unsubscribe = void 0;
445484
+ }
445485
+ };
445486
+ unsubscribe = this.subscribe(() => {
445487
+ checkDone();
445488
+ });
445489
+ if (abortSignal) {
445490
+ abortSignal.addEventListener("abort", () => {
445491
+ cleanup();
445492
+ resolve12(false);
445493
+ }, { once: true });
445494
+ }
445495
+ checkDone();
445496
+ });
445497
+ }
444881
445498
  // ── Message queue for injecting user messages into running sub-agents ──
444882
445499
  /**
444883
445500
  * Enqueue a user message for a running sub-agent.
@@ -444906,6 +445523,120 @@ var init_runningSubAgentTracker = __esm({
444906
445523
  queue.length = 0;
444907
445524
  return messages;
444908
445525
  }
445526
+ // ── Inter-agent messaging ──────────────────────────────────────────────
445527
+ /**
445528
+ * Send a message from one sub-agent to another.
445529
+ * The message is queued for the target and also triggers a listener notification
445530
+ * so that the UI can display the inter-agent communication.
445531
+ * Returns true if the target agent is running and the message was enqueued.
445532
+ */
445533
+ sendInterAgentMessage(fromInstanceId, targetInstanceId, content) {
445534
+ const queue = this.interAgentQueues.get(targetInstanceId);
445535
+ if (!queue) {
445536
+ return false;
445537
+ }
445538
+ const fromAgent = this.agents.get(fromInstanceId);
445539
+ if (!fromAgent) {
445540
+ return false;
445541
+ }
445542
+ const message = {
445543
+ fromInstanceId,
445544
+ fromAgentId: fromAgent.agentId,
445545
+ fromAgentName: fromAgent.agentName,
445546
+ content,
445547
+ sentAt: /* @__PURE__ */ new Date()
445548
+ };
445549
+ queue.push(message);
445550
+ this.notifyInterAgentListeners(fromAgent, targetInstanceId, message);
445551
+ return true;
445552
+ }
445553
+ /**
445554
+ * Dequeue all pending inter-agent messages for a sub-agent instance.
445555
+ * Called by the sub-agent executor at the top of each while-loop iteration.
445556
+ */
445557
+ dequeueInterAgentMessages(instanceId) {
445558
+ const queue = this.interAgentQueues.get(instanceId);
445559
+ if (!queue || queue.length === 0) {
445560
+ return [];
445561
+ }
445562
+ const messages = [...queue];
445563
+ queue.length = 0;
445564
+ return messages;
445565
+ }
445566
+ /**
445567
+ * Find a running sub-agent instance by agentId (type).
445568
+ * If multiple instances of the same type are running, returns the first match.
445569
+ * Use this to resolve agentId -> instanceId for inter-agent messaging.
445570
+ */
445571
+ findInstanceByAgentId(agentId) {
445572
+ for (const agent of this.agents.values()) {
445573
+ if (agent.agentId === agentId) {
445574
+ return agent;
445575
+ }
445576
+ }
445577
+ return void 0;
445578
+ }
445579
+ /**
445580
+ * Find all running sub-agent instances by agentId (type).
445581
+ */
445582
+ findAllInstancesByAgentId(agentId) {
445583
+ const result2 = [];
445584
+ for (const agent of this.agents.values()) {
445585
+ if (agent.agentId === agentId) {
445586
+ result2.push(agent);
445587
+ }
445588
+ }
445589
+ return result2;
445590
+ }
445591
+ onInterAgentMessage(listener) {
445592
+ this.interAgentListeners.add(listener);
445593
+ return () => {
445594
+ this.interAgentListeners.delete(listener);
445595
+ };
445596
+ }
445597
+ notifyInterAgentListeners(fromAgent, targetInstanceId, message) {
445598
+ const targetAgent = this.agents.get(targetInstanceId);
445599
+ if (!targetAgent)
445600
+ return;
445601
+ for (const listener of this.interAgentListeners) {
445602
+ try {
445603
+ listener({
445604
+ from: fromAgent,
445605
+ to: targetAgent,
445606
+ message
445607
+ });
445608
+ } catch {
445609
+ }
445610
+ }
445611
+ }
445612
+ // ── Spawned agent result storage ──────────────────────────────────────
445613
+ /**
445614
+ * Store the result of a sub-agent that was spawned by another sub-agent.
445615
+ * The main conversation flow drains these between tool execution rounds.
445616
+ */
445617
+ storeSpawnedResult(result2) {
445618
+ this.spawnedResults.push(result2);
445619
+ this.notifyListeners();
445620
+ }
445621
+ /**
445622
+ * Drain all completed spawned agent results.
445623
+ * Called by the main conversation flow to inject results as context.
445624
+ * Returns an empty array if no results are pending.
445625
+ */
445626
+ drainSpawnedResults() {
445627
+ if (this.spawnedResults.length === 0) {
445628
+ return [];
445629
+ }
445630
+ const results = [...this.spawnedResults];
445631
+ this.spawnedResults.length = 0;
445632
+ return results;
445633
+ }
445634
+ /**
445635
+ * Check if there are any pending spawned agent results.
445636
+ */
445637
+ hasSpawnedResults() {
445638
+ return this.spawnedResults.length > 0;
445639
+ }
444909
445640
  /**
444910
445641
  * Subscribe to changes in the running agents list.
444911
445642
  * Returns an unsubscribe function.
@@ -444920,9 +445651,11 @@ var init_runningSubAgentTracker = __esm({
444920
445651
  * Clear all running agents (useful for cleanup)
444921
445652
  */
444922
445653
  clear() {
444923
- if (this.agents.size > 0) {
445654
+ if (this.agents.size > 0 || this.spawnedResults.length > 0) {
444924
445655
  this.agents.clear();
444925
445656
  this.messageQueues.clear();
445657
+ this.interAgentQueues.clear();
445658
+ this.spawnedResults.length = 0;
444926
445659
  this.rebuildSnapshot();
444927
445660
  this.notifyListeners();
444928
445661
  }
@@ -444944,7 +445677,8 @@ var init_runningSubAgentTracker = __esm({
444944
445677
  });
444945
445678
 
444946
445679
  // dist/utils/execution/subAgentExecutor.js
444947
- async function executeSubAgent(agentId, prompt, onMessage, abortSignal, requestToolConfirmation, isToolAutoApproved, yoloMode, addToAlwaysApproved, requestUserQuestion, instanceId) {
445680
+ async function executeSubAgent(agentId, prompt, onMessage, abortSignal, requestToolConfirmation, isToolAutoApproved, yoloMode, addToAlwaysApproved, requestUserQuestion, instanceId, spawnDepth = 0) {
445681
+ var _a21, _b14, _c6;
444948
445682
  try {
444949
445683
  let agent;
444950
445684
  if (agentId === "agent_explore" || agentId === "agent_plan" || agentId === "agent_general" || agentId === "agent_analyze" || agentId === "agent_debug") {
@@ -445853,12 +446587,117 @@ Inserted log points:
445853
446587
  error: `Sub-agent "${agent.name}" has no valid tools configured`
445854
446588
  };
445855
446589
  }
446590
+ const { runningSubAgentTracker: runningSubAgentTracker2 } = await Promise.resolve().then(() => (init_runningSubAgentTracker(), runningSubAgentTracker_exports));
446591
+ const sendMessageTool = {
446592
+ type: "function",
446593
+ function: {
446594
+ name: "send_message_to_agent",
446595
+ description: "Send a message to another running sub-agent. Use this to share information, findings, or coordinate work with other agents that are executing in parallel. The message will be injected into the target agent's context. IMPORTANT: Use query_agents_status first to check if the target agent is still running before sending.",
446596
+ parameters: {
446597
+ type: "object",
446598
+ properties: {
446599
+ target_agent_id: {
446600
+ type: "string",
446601
+ description: 'The agent ID (type) of the target sub-agent (e.g., "agent_explore", "agent_general"). If multiple instances of the same type are running, the message is sent to the first found instance.'
446602
+ },
446603
+ target_instance_id: {
446604
+ type: "string",
446605
+ description: "(Optional) The specific instance ID of the target sub-agent. Use this for precise targeting when multiple instances of the same agent type are running."
446606
+ },
446607
+ message: {
446608
+ type: "string",
446609
+ description: "The message content to send to the target agent. Be clear and specific about what information you are sharing or what action you are requesting."
446610
+ }
446611
+ },
446612
+ required: ["message"]
446613
+ }
446614
+ }
446615
+ };
446616
+ const queryAgentsStatusTool = {
446617
+ type: "function",
446618
+ function: {
446619
+ name: "query_agents_status",
446620
+ description: "Query the current status of all running sub-agents. Returns a list of currently active agents with their IDs, names, prompts, and how long they have been running. Use this to check if a target agent is still running before sending it a message, or to discover new agents that have started.",
446621
+ parameters: {
446622
+ type: "object",
446623
+ properties: {},
446624
+ required: []
446625
+ }
446626
+ }
446627
+ };
446628
+ const spawnSubAgentTool = {
446629
+ type: "function",
446630
+ function: {
446631
+ name: "spawn_sub_agent",
446632
+ description: `Spawn a NEW sub-agent of a DIFFERENT type to get specialized help. The spawned agent runs in parallel and results are reported back automatically.
446633
+
446634
+ **WHEN TO USE** \u2014 Only spawn when you genuinely need a different agent's specialization:
446635
+ - You are an Explore Agent and need code modifications \u2192 spawn agent_general
446636
+ - You are a General Purpose Agent and need deep code analysis \u2192 spawn agent_explore
446637
+ - You need a detailed implementation plan \u2192 spawn agent_plan
446638
+ - You need requirement clarification with user \u2192 spawn agent_analyze
446639
+
446640
+ **WHEN NOT TO USE** \u2014 Do NOT spawn to offload YOUR OWN work:
446641
+ - NEVER spawn an agent of the same type as yourself to delegate your task \u2014 that is lazy and wasteful
446642
+ - NEVER spawn an agent just to "break work into pieces" if you can do it yourself
446643
+ - NEVER spawn when you are simply stuck \u2014 try harder or ask the user instead
446644
+ - If you can complete the task with your own tools, DO IT YOURSELF
446645
+
446646
+ Available agent types: agent_explore (code exploration, read-only), agent_plan (planning, read-only), agent_general (full access, code modification), agent_analyze (requirement analysis), agent_debug (debug logging).`,
446647
+ parameters: {
446648
+ type: "object",
446649
+ properties: {
446650
+ agent_id: {
446651
+ type: "string",
446652
+ description: 'The agent type to spawn. Must be a DIFFERENT type from yourself unless you have a very strong justification. (e.g., "agent_explore", "agent_plan", "agent_general", "agent_analyze", "agent_debug", or a user-defined agent ID).'
446653
+ },
446654
+ prompt: {
446655
+ type: "string",
446656
+ description: "CRITICAL: The task prompt for the spawned agent. Must include COMPLETE context since the spawned agent has NO access to your conversation history. Include all relevant file paths, findings, constraints, and requirements."
446657
+ }
446658
+ },
446659
+ required: ["agent_id", "prompt"]
446660
+ }
446661
+ }
446662
+ };
446663
+ allowedTools.push(sendMessageTool, queryAgentsStatusTool);
446664
+ if (spawnDepth < MAX_SPAWN_DEPTH) {
446665
+ allowedTools.push(spawnSubAgentTool);
446666
+ }
446667
+ const otherAgents = runningSubAgentTracker2.getRunningAgents().filter((a) => a.instanceId !== instanceId);
446668
+ const canSpawn = spawnDepth < MAX_SPAWN_DEPTH;
446669
+ let otherAgentsContext = "";
446670
+ if (otherAgents.length > 0) {
446671
+ const agentList = otherAgents.map((a) => `- ${a.agentName} (id: ${a.agentId}, instance: ${a.instanceId}): "${a.prompt ? a.prompt.substring(0, 120) : "N/A"}"`).join("\n");
446672
+ const spawnHint = canSpawn ? ", or `spawn_sub_agent` to request a DIFFERENT type of agent for specialized help" : "";
446673
+ const spawnAdvice = canSpawn ? "\n\n**Spawn rules**: Only spawn agents of a DIFFERENT type for work you CANNOT do with your own tools. Complete your own task first \u2014 do NOT delegate it." : "";
446674
+ otherAgentsContext = `
446675
+
446676
+ ## Currently Running Peer Agents
446677
+ The following sub-agents are running in parallel with you. You can use \`query_agents_status\` to get real-time status, \`send_message_to_agent\` to communicate${spawnHint}.
446678
+
446679
+ ${agentList}
446680
+
446681
+ If you discover information useful to another agent, proactively share it.${spawnAdvice}`;
446682
+ } else {
446683
+ const spawnToolLine = canSpawn ? "\n- `spawn_sub_agent`: Spawn a DIFFERENT type of agent for specialized help (do NOT spawn your own type to offload work)" : "";
446684
+ const spawnUsage = canSpawn ? '\n\n**Spawn rules**: Only use `spawn_sub_agent` when you genuinely need a different agent\'s specialization (e.g., you are read-only but need code changes). NEVER spawn to delegate your own task or to "parallelize" work you should do yourself.' : "";
446685
+ otherAgentsContext = `
446686
+
446687
+ ## Agent Collaboration Tools
446688
+ You have access to these collaboration tools:
446689
+ - \`query_agents_status\`: Check which sub-agents are currently running
446690
+ - \`send_message_to_agent\`: Send a message to a running peer agent (check status first!)${spawnToolLine}${spawnUsage}`;
446691
+ }
445856
446692
  let finalPrompt = prompt;
445857
446693
  if (agent.role) {
445858
446694
  finalPrompt = `${prompt}
445859
446695
 
445860
446696
  ${agent.role}`;
445861
446697
  }
446698
+ if (otherAgentsContext) {
446699
+ finalPrompt = `${finalPrompt}${otherAgentsContext}`;
446700
+ }
445862
446701
  const messages = [
445863
446702
  {
445864
446703
  role: "user",
@@ -445869,7 +446708,9 @@ ${agent.role}`;
445869
446708
  let hasError = false;
445870
446709
  let errorMessage = "";
445871
446710
  let totalUsage;
446711
+ let latestTotalTokens = 0;
445872
446712
  const collectedInjectedMessages = [];
446713
+ const spawnedChildInstanceIds = /* @__PURE__ */ new Set();
445873
446714
  const sessionApprovedTools = /* @__PURE__ */ new Set();
445874
446715
  while (true) {
445875
446716
  if (abortSignal == null ? void 0 : abortSignal.aborted) {
@@ -445890,7 +446731,6 @@ ${agent.role}`;
445890
446731
  };
445891
446732
  }
445892
446733
  if (instanceId) {
445893
- const { runningSubAgentTracker: runningSubAgentTracker2 } = await Promise.resolve().then(() => (init_runningSubAgentTracker(), runningSubAgentTracker_exports));
445894
446734
  const injectedMessages = runningSubAgentTracker2.dequeueMessages(instanceId);
445895
446735
  for (const injectedMsg of injectedMessages) {
445896
446736
  collectedInjectedMessages.push(injectedMsg);
@@ -445911,6 +446751,27 @@ ${injectedMsg}`
445911
446751
  });
445912
446752
  }
445913
446753
  }
446754
+ const interAgentMessages = runningSubAgentTracker2.dequeueInterAgentMessages(instanceId);
446755
+ for (const iaMsg of interAgentMessages) {
446756
+ messages.push({
446757
+ role: "user",
446758
+ content: `[Inter-agent message from ${iaMsg.fromAgentName} (${iaMsg.fromAgentId})]
446759
+ ${iaMsg.content}`
446760
+ });
446761
+ if (onMessage) {
446762
+ onMessage({
446763
+ type: "sub_agent_message",
446764
+ agentId: agent.id,
446765
+ agentName: agent.name,
446766
+ message: {
446767
+ type: "inter_agent_received",
446768
+ fromAgentId: iaMsg.fromAgentId,
446769
+ fromAgentName: iaMsg.fromAgentName,
446770
+ content: iaMsg.content
446771
+ }
446772
+ });
446773
+ }
446774
+ }
445914
446775
  }
445915
446776
  const currentSession = sessionManager.getCurrentSession();
445916
446777
  let config3;
@@ -445981,6 +446842,7 @@ ${injectedMsg}`
445981
446842
  }
445982
446843
  if (event.type === "usage" && event.usage) {
445983
446844
  const eventUsage = event.usage;
446845
+ latestTotalTokens = eventUsage.total_tokens || (eventUsage.prompt_tokens || 0) + (eventUsage.completion_tokens || 0);
445984
446846
  if (!totalUsage) {
445985
446847
  totalUsage = {
445986
446848
  inputTokens: eventUsage.prompt_tokens || 0,
@@ -445998,6 +446860,20 @@ ${injectedMsg}`
445998
446860
  totalUsage.cacheReadInputTokens = (totalUsage.cacheReadInputTokens || 0) + eventUsage.cache_read_input_tokens;
445999
446861
  }
446000
446862
  }
446863
+ if (onMessage && config3.maxContextTokens && latestTotalTokens > 0) {
446864
+ const ctxPct = getContextPercentage(latestTotalTokens, config3.maxContextTokens);
446865
+ onMessage({
446866
+ type: "sub_agent_message",
446867
+ agentId: agent.id,
446868
+ agentName: agent.name,
446869
+ message: {
446870
+ type: "context_usage",
446871
+ percentage: Math.max(1, Math.round(ctxPct)),
446872
+ inputTokens: latestTotalTokens,
446873
+ maxTokens: config3.maxContextTokens
446874
+ }
446875
+ });
446876
+ }
446001
446877
  }
446002
446878
  if (event.type === "content" && event.content) {
446003
446879
  currentContent += event.content;
@@ -446041,7 +446917,129 @@ ${injectedMsg}`
446041
446917
  messages.push(assistantMessage);
446042
446918
  finalResponse = currentContent;
446043
446919
  }
446920
+ if (latestTotalTokens === 0 && config3.maxContextTokens) {
446921
+ latestTotalTokens = countMessagesTokens(messages);
446922
+ if (onMessage && latestTotalTokens > 0) {
446923
+ const ctxPct = getContextPercentage(latestTotalTokens, config3.maxContextTokens);
446924
+ onMessage({
446925
+ type: "sub_agent_message",
446926
+ agentId: agent.id,
446927
+ agentName: agent.name,
446928
+ message: {
446929
+ type: "context_usage",
446930
+ percentage: Math.max(1, Math.round(ctxPct)),
446931
+ inputTokens: latestTotalTokens,
446932
+ maxTokens: config3.maxContextTokens
446933
+ }
446934
+ });
446935
+ }
446936
+ }
446937
+ let justCompressed = false;
446938
+ if (latestTotalTokens > 0 && config3.maxContextTokens) {
446939
+ if (shouldCompressSubAgentContext(latestTotalTokens, config3.maxContextTokens)) {
446940
+ const ctxPercentage = getContextPercentage(latestTotalTokens, config3.maxContextTokens);
446941
+ if (onMessage) {
446942
+ onMessage({
446943
+ type: "sub_agent_message",
446944
+ agentId: agent.id,
446945
+ agentName: agent.name,
446946
+ message: {
446947
+ type: "context_compressing",
446948
+ percentage: Math.round(ctxPercentage)
446949
+ }
446950
+ });
446951
+ }
446952
+ try {
446953
+ const compressionResult = await compressSubAgentContext(messages, latestTotalTokens, config3.maxContextTokens, {
446954
+ model,
446955
+ requestMethod: config3.requestMethod,
446956
+ maxTokens: config3.maxTokens,
446957
+ configProfile: agent.configProfile
446958
+ });
446959
+ if (compressionResult.compressed) {
446960
+ messages.length = 0;
446961
+ messages.push(...compressionResult.messages);
446962
+ justCompressed = true;
446963
+ if (compressionResult.afterTokensEstimate) {
446964
+ latestTotalTokens = compressionResult.afterTokensEstimate;
446965
+ }
446966
+ if (onMessage) {
446967
+ onMessage({
446968
+ type: "sub_agent_message",
446969
+ agentId: agent.id,
446970
+ agentName: agent.name,
446971
+ message: {
446972
+ type: "context_compressed",
446973
+ beforeTokens: compressionResult.beforeTokens,
446974
+ afterTokensEstimate: compressionResult.afterTokensEstimate
446975
+ }
446976
+ });
446977
+ }
446978
+ console.log(`[SubAgent:${agent.name}] Context compressed: ${compressionResult.beforeTokens} \u2192 ~${compressionResult.afterTokensEstimate} tokens`);
446979
+ }
446980
+ } catch (compressError) {
446981
+ console.error(`[SubAgent:${agent.name}] Context compression failed:`, compressError);
446982
+ }
446983
+ }
446984
+ }
446985
+ if (justCompressed && toolCalls.length === 0) {
446986
+ while (messages.length > 0 && ((_a21 = messages[messages.length - 1]) == null ? void 0 : _a21.role) === "assistant") {
446987
+ messages.pop();
446988
+ }
446989
+ messages.push({
446990
+ role: "user",
446991
+ content: "[System] Your context has been auto-compressed to free up space. Your task is NOT finished. Continue working based on the compressed context above. Pick up where you left off."
446992
+ });
446993
+ continue;
446994
+ }
446044
446995
  if (toolCalls.length === 0) {
446996
+ const runningChildren = Array.from(spawnedChildInstanceIds).filter((id) => runningSubAgentTracker2.isRunning(id));
446997
+ if (runningChildren.length > 0 || runningSubAgentTracker2.hasSpawnedResults()) {
446998
+ if (runningChildren.length > 0) {
446999
+ await runningSubAgentTracker2.waitForSpawnedAgents(
447000
+ 3e5,
447001
+ // 5 min timeout
447002
+ abortSignal
447003
+ );
447004
+ }
447005
+ const spawnedResults = runningSubAgentTracker2.drainSpawnedResults();
447006
+ if (spawnedResults.length > 0) {
447007
+ for (const sr of spawnedResults) {
447008
+ const statusIcon = sr.success ? "\u2713" : "\u2717";
447009
+ const resultSummary = sr.success ? sr.result.length > 800 ? sr.result.substring(0, 800) + "..." : sr.result : sr.error || "Unknown error";
447010
+ messages.push({
447011
+ role: "user",
447012
+ content: `[Spawned Sub-Agent Result] ${statusIcon} ${sr.agentName} (${sr.agentId})
447013
+ Prompt: ${sr.prompt}
447014
+ Result: ${resultSummary}`
447015
+ });
447016
+ if (onMessage) {
447017
+ onMessage({
447018
+ type: "sub_agent_message",
447019
+ agentId: agent.id,
447020
+ agentName: agent.name,
447021
+ message: {
447022
+ type: "spawned_agent_completed",
447023
+ spawnedAgentId: sr.agentId,
447024
+ spawnedAgentName: sr.agentName,
447025
+ success: sr.success
447026
+ }
447027
+ });
447028
+ }
447029
+ }
447030
+ if (onMessage) {
447031
+ onMessage({
447032
+ type: "sub_agent_message",
447033
+ agentId: agent.id,
447034
+ agentName: agent.name,
447035
+ message: {
447036
+ type: "done"
447037
+ }
447038
+ });
447039
+ }
447040
+ continue;
447041
+ }
447042
+ }
446045
447043
  try {
446046
447044
  const hookResult = await unifiedHooksExecutor.executeHooks("onSubAgentComplete", {
446047
447045
  agentId: agent.id,
@@ -446095,6 +447093,238 @@ ${injectedMsg}`
446095
447093
  }
446096
447094
  break;
446097
447095
  }
447096
+ const sendMsgTools = toolCalls.filter((tc) => tc.function.name === "send_message_to_agent");
447097
+ if (sendMsgTools.length > 0 && instanceId) {
447098
+ for (const sendMsgTool of sendMsgTools) {
447099
+ let targetAgentId;
447100
+ let targetInstanceId;
447101
+ let msgContent = "";
447102
+ try {
447103
+ const args2 = JSON.parse(sendMsgTool.function.arguments);
447104
+ targetAgentId = args2.target_agent_id;
447105
+ targetInstanceId = args2.target_instance_id;
447106
+ msgContent = args2.message || "";
447107
+ } catch (error) {
447108
+ console.error("Failed to parse send_message_to_agent arguments:", error);
447109
+ }
447110
+ let success = false;
447111
+ let resultText = "";
447112
+ if (!msgContent) {
447113
+ resultText = "Error: message content is empty";
447114
+ } else if (targetInstanceId) {
447115
+ success = runningSubAgentTracker2.sendInterAgentMessage(instanceId, targetInstanceId, msgContent);
447116
+ if (success) {
447117
+ const targetAgent = runningSubAgentTracker2.getRunningAgents().find((a) => a.instanceId === targetInstanceId);
447118
+ resultText = `Message sent to ${(targetAgent == null ? void 0 : targetAgent.agentName) || targetInstanceId}`;
447119
+ } else {
447120
+ resultText = `Error: Target agent instance "${targetInstanceId}" is not running`;
447121
+ }
447122
+ } else if (targetAgentId) {
447123
+ const targetAgent = runningSubAgentTracker2.findInstanceByAgentId(targetAgentId);
447124
+ if (targetAgent && targetAgent.instanceId !== instanceId) {
447125
+ success = runningSubAgentTracker2.sendInterAgentMessage(instanceId, targetAgent.instanceId, msgContent);
447126
+ if (success) {
447127
+ resultText = `Message sent to ${targetAgent.agentName} (instance: ${targetAgent.instanceId})`;
447128
+ } else {
447129
+ resultText = `Error: Failed to send message to ${targetAgentId}`;
447130
+ }
447131
+ } else if (targetAgent && targetAgent.instanceId === instanceId) {
447132
+ resultText = "Error: Cannot send a message to yourself";
447133
+ } else {
447134
+ resultText = `Error: No running agent found with ID "${targetAgentId}"`;
447135
+ }
447136
+ } else {
447137
+ resultText = "Error: Either target_agent_id or target_instance_id must be provided";
447138
+ }
447139
+ const toolResultMessage = {
447140
+ role: "tool",
447141
+ tool_call_id: sendMsgTool.id,
447142
+ content: JSON.stringify({ success, result: resultText })
447143
+ };
447144
+ messages.push(toolResultMessage);
447145
+ if (onMessage) {
447146
+ onMessage({
447147
+ type: "sub_agent_message",
447148
+ agentId: agent.id,
447149
+ agentName: agent.name,
447150
+ message: {
447151
+ type: "inter_agent_sent",
447152
+ targetAgentId: targetAgentId || targetInstanceId || "unknown",
447153
+ targetAgentName: (targetInstanceId ? (_b14 = runningSubAgentTracker2.getRunningAgents().find((a) => a.instanceId === targetInstanceId)) == null ? void 0 : _b14.agentName : targetAgentId ? (_c6 = runningSubAgentTracker2.findInstanceByAgentId(targetAgentId)) == null ? void 0 : _c6.agentName : void 0) || targetAgentId || "unknown",
447154
+ content: msgContent,
447155
+ success
447156
+ }
447157
+ });
447158
+ }
447159
+ }
447160
+ toolCalls = toolCalls.filter((tc) => tc.function.name !== "send_message_to_agent");
447161
+ if (toolCalls.length === 0) {
447162
+ continue;
447163
+ }
447164
+ }
447165
+ const queryStatusTools = toolCalls.filter((tc) => tc.function.name === "query_agents_status");
447166
+ if (queryStatusTools.length > 0) {
447167
+ for (const queryTool of queryStatusTools) {
447168
+ const allAgents = runningSubAgentTracker2.getRunningAgents();
447169
+ const statusList = allAgents.map((a) => ({
447170
+ instanceId: a.instanceId,
447171
+ agentId: a.agentId,
447172
+ agentName: a.agentName,
447173
+ prompt: a.prompt ? a.prompt.substring(0, 150) : "N/A",
447174
+ runningFor: `${Math.floor((Date.now() - a.startedAt.getTime()) / 1e3)}s`,
447175
+ isSelf: a.instanceId === instanceId
447176
+ }));
447177
+ const toolResultMessage = {
447178
+ role: "tool",
447179
+ tool_call_id: queryTool.id,
447180
+ content: JSON.stringify({
447181
+ totalRunning: allAgents.length,
447182
+ agents: statusList
447183
+ })
447184
+ };
447185
+ messages.push(toolResultMessage);
447186
+ }
447187
+ toolCalls = toolCalls.filter((tc) => tc.function.name !== "query_agents_status");
447188
+ if (toolCalls.length === 0) {
447189
+ continue;
447190
+ }
447191
+ }
447192
+ const spawnTools = toolCalls.filter((tc) => tc.function.name === "spawn_sub_agent");
447193
+ if (spawnTools.length > 0 && instanceId) {
447194
+ for (const spawnTool of spawnTools) {
447195
+ let spawnAgentId = "";
447196
+ let spawnPrompt = "";
447197
+ try {
447198
+ const args2 = JSON.parse(spawnTool.function.arguments);
447199
+ spawnAgentId = args2.agent_id || "";
447200
+ spawnPrompt = args2.prompt || "";
447201
+ } catch (error) {
447202
+ console.error("Failed to parse spawn_sub_agent arguments:", error);
447203
+ }
447204
+ if (!spawnAgentId || !spawnPrompt) {
447205
+ const toolResultMessage2 = {
447206
+ role: "tool",
447207
+ tool_call_id: spawnTool.id,
447208
+ content: JSON.stringify({
447209
+ success: false,
447210
+ error: "Both agent_id and prompt are required"
447211
+ })
447212
+ };
447213
+ messages.push(toolResultMessage2);
447214
+ continue;
447215
+ }
447216
+ if (spawnAgentId === agent.id) {
447217
+ const toolResultMessage2 = {
447218
+ role: "tool",
447219
+ tool_call_id: spawnTool.id,
447220
+ content: JSON.stringify({
447221
+ success: false,
447222
+ error: `REJECTED: You (${agent.name}) attempted to spawn another "${spawnAgentId}" which is the SAME type as yourself. This is not allowed because it wastes resources and delegates work you should complete yourself. If you need help from a DIFFERENT specialization, spawn a different agent type. If the task is within your capabilities, do it yourself.`
447223
+ })
447224
+ };
447225
+ messages.push(toolResultMessage2);
447226
+ continue;
447227
+ }
447228
+ let spawnAgentName = spawnAgentId;
447229
+ try {
447230
+ const agentConfig = getSubAgent(spawnAgentId);
447231
+ if (agentConfig) {
447232
+ spawnAgentName = agentConfig.name;
447233
+ }
447234
+ } catch {
447235
+ const builtinNames = {
447236
+ agent_explore: "Explore Agent",
447237
+ agent_plan: "Plan Agent",
447238
+ agent_general: "General Purpose Agent",
447239
+ agent_analyze: "Requirement Analysis Agent",
447240
+ agent_debug: "Debug Assistant"
447241
+ };
447242
+ spawnAgentName = builtinNames[spawnAgentId] || spawnAgentId;
447243
+ }
447244
+ const spawnInstanceId = `spawn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
447245
+ const spawnerInfo = {
447246
+ instanceId,
447247
+ agentId: agent.id,
447248
+ agentName: agent.name
447249
+ };
447250
+ spawnedChildInstanceIds.add(spawnInstanceId);
447251
+ runningSubAgentTracker2.register({
447252
+ instanceId: spawnInstanceId,
447253
+ agentId: spawnAgentId,
447254
+ agentName: spawnAgentName,
447255
+ prompt: spawnPrompt,
447256
+ startedAt: /* @__PURE__ */ new Date()
447257
+ });
447258
+ executeSubAgent(
447259
+ spawnAgentId,
447260
+ spawnPrompt,
447261
+ onMessage,
447262
+ // Same UI callback — spawned agent's messages are visible
447263
+ abortSignal,
447264
+ // Same abort signal — ESC stops everything
447265
+ requestToolConfirmation,
447266
+ isToolAutoApproved,
447267
+ yoloMode,
447268
+ addToAlwaysApproved,
447269
+ requestUserQuestion,
447270
+ spawnInstanceId,
447271
+ spawnDepth + 1
447272
+ ).then((result2) => {
447273
+ runningSubAgentTracker2.storeSpawnedResult({
447274
+ instanceId: spawnInstanceId,
447275
+ agentId: spawnAgentId,
447276
+ agentName: spawnAgentName,
447277
+ prompt: spawnPrompt.length > 200 ? spawnPrompt.substring(0, 200) + "..." : spawnPrompt,
447278
+ success: result2.success,
447279
+ result: result2.result,
447280
+ error: result2.error,
447281
+ completedAt: /* @__PURE__ */ new Date(),
447282
+ spawnedBy: spawnerInfo
447283
+ });
447284
+ }).catch((error) => {
447285
+ runningSubAgentTracker2.storeSpawnedResult({
447286
+ instanceId: spawnInstanceId,
447287
+ agentId: spawnAgentId,
447288
+ agentName: spawnAgentName,
447289
+ prompt: spawnPrompt.length > 200 ? spawnPrompt.substring(0, 200) + "..." : spawnPrompt,
447290
+ success: false,
447291
+ result: "",
447292
+ error: error instanceof Error ? error.message : "Unknown error",
447293
+ completedAt: /* @__PURE__ */ new Date(),
447294
+ spawnedBy: spawnerInfo
447295
+ });
447296
+ }).finally(() => {
447297
+ runningSubAgentTracker2.unregister(spawnInstanceId);
447298
+ });
447299
+ if (onMessage) {
447300
+ onMessage({
447301
+ type: "sub_agent_message",
447302
+ agentId: agent.id,
447303
+ agentName: agent.name,
447304
+ message: {
447305
+ type: "agent_spawned",
447306
+ spawnedAgentId: spawnAgentId,
447307
+ spawnedAgentName: spawnAgentName,
447308
+ spawnedInstanceId: spawnInstanceId,
447309
+ spawnedPrompt: spawnPrompt
447310
+ }
447311
+ });
447312
+ }
447313
+ const toolResultMessage = {
447314
+ role: "tool",
447315
+ tool_call_id: spawnTool.id,
447316
+ content: JSON.stringify({
447317
+ success: true,
447318
+ result: `Agent "${spawnAgentName}" (${spawnAgentId}) has been spawned and is now running in the background with instance ID "${spawnInstanceId}". Its results will be automatically reported to the main workflow when it completes.`
447319
+ })
447320
+ };
447321
+ messages.push(toolResultMessage);
447322
+ }
447323
+ toolCalls = toolCalls.filter((tc) => tc.function.name !== "spawn_sub_agent");
447324
+ if (toolCalls.length === 0) {
447325
+ continue;
447326
+ }
447327
+ }
446098
447328
  const askUserTool = toolCalls.find((tc) => tc.function.name.startsWith("askuser-"));
446099
447329
  if (askUserTool && requestUserQuestion) {
446100
447330
  let question = "Please select an option:";
@@ -446291,6 +447521,7 @@ ${injectedMsg}`
446291
447521
  };
446292
447522
  }
446293
447523
  }
447524
+ var MAX_SPAWN_DEPTH;
446294
447525
  var init_subAgentExecutor = __esm({
446295
447526
  "dist/utils/execution/subAgentExecutor.js"() {
446296
447527
  "use strict";
@@ -446304,6 +447535,8 @@ var init_subAgentExecutor = __esm({
446304
447535
  init_sessionManager();
446305
447536
  init_unifiedHooksExecutor();
446306
447537
  init_yoloPermissionChecker();
447538
+ init_subAgentContextCompressor();
447539
+ MAX_SPAWN_DEPTH = 1;
446307
447540
  }
446308
447541
  });
446309
447542
 
@@ -453611,6 +454844,12 @@ var init_LSPClient = __esm({
453611
454844
  writable: true,
453612
454845
  value: false
453613
454846
  });
454847
+ Object.defineProperty(this, "isProcessAlive", {
454848
+ enumerable: true,
454849
+ configurable: true,
454850
+ writable: true,
454851
+ value: false
454852
+ });
453614
454853
  Object.defineProperty(this, "openDocuments", {
453615
454854
  enumerable: true,
453616
454855
  configurable: true,
@@ -453661,6 +454900,7 @@ var init_LSPClient = __esm({
453661
454900
  }
453662
454901
  }
453663
454902
  async start() {
454903
+ var _a21;
453664
454904
  if (this.isInitialized) {
453665
454905
  return;
453666
454906
  }
@@ -453683,17 +454923,34 @@ var init_LSPClient = __esm({
453683
454923
  stdio: ["pipe", "pipe", "pipe"],
453684
454924
  cwd: this.config.rootPath
453685
454925
  });
454926
+ this.isProcessAlive = true;
454927
+ this.process.on("exit", () => {
454928
+ this.isProcessAlive = false;
454929
+ });
454930
+ this.process.on("error", () => {
454931
+ this.isProcessAlive = false;
454932
+ });
454933
+ (_a21 = this.process.stdin) == null ? void 0 : _a21.on("error", () => {
454934
+ this.isProcessAlive = false;
454935
+ });
453686
454936
  processManager.register(this.process);
453687
454937
  this.connection = (0, import_node.createMessageConnection)(new import_node.StreamMessageReader(this.process.stdout), new import_node.StreamMessageWriter(this.process.stdin));
454938
+ this.connection.onError(([error]) => {
454939
+ console.debug("LSP connection error:", (error == null ? void 0 : error.message) || error);
454940
+ });
454941
+ this.connection.onClose(() => {
454942
+ this.isInitialized = false;
454943
+ this.isProcessAlive = false;
454944
+ });
453688
454945
  this.connection.onRequest("window/workDoneProgress/create", () => null);
453689
454946
  this.connection.onRequest("client/registerCapability", () => null);
453690
454947
  this.connection.onRequest("workspace/configuration", () => []);
453691
454948
  this.connection.onNotification("window/logMessage", (params) => {
453692
- var _a21;
454949
+ var _a22;
453693
454950
  const message = typeof (params == null ? void 0 : params.message) === "string" ? params.message : "";
453694
454951
  if (!this.csharpSolutionLoaded && message.includes("Finished loading solution")) {
453695
454952
  this.csharpSolutionLoaded = true;
453696
- (_a21 = this.resolveCsharpSolutionLoad) == null ? void 0 : _a21.call(this);
454953
+ (_a22 = this.resolveCsharpSolutionLoad) == null ? void 0 : _a22.call(this);
453697
454954
  }
453698
454955
  });
453699
454956
  this.connection.onNotification("window/showMessage", (_params) => {
@@ -453765,11 +455022,23 @@ var init_LSPClient = __esm({
453765
455022
  return;
453766
455023
  }
453767
455024
  try {
453768
- for (const uri of this.openDocuments) {
453769
- await this.closeDocument(uri);
455025
+ if (this.isProcessAlive) {
455026
+ for (const uri of [...this.openDocuments]) {
455027
+ try {
455028
+ await this.closeDocument(uri);
455029
+ } catch {
455030
+ break;
455031
+ }
455032
+ }
455033
+ try {
455034
+ await this.connection.sendRequest("shutdown", null);
455035
+ } catch {
455036
+ }
455037
+ try {
455038
+ await this.connection.sendNotification("exit", null);
455039
+ } catch {
455040
+ }
453770
455041
  }
453771
- await this.connection.sendRequest("shutdown", null);
453772
- await this.connection.sendNotification("exit", null);
453773
455042
  } catch (error) {
453774
455043
  console.debug("Error during LSP shutdown:", error);
453775
455044
  } finally {
@@ -453778,14 +455047,21 @@ var init_LSPClient = __esm({
453778
455047
  }
453779
455048
  async cleanup() {
453780
455049
  if (this.connection) {
453781
- this.connection.dispose();
455050
+ try {
455051
+ this.connection.dispose();
455052
+ } catch {
455053
+ }
453782
455054
  this.connection = void 0;
453783
455055
  }
453784
455056
  if (this.process) {
453785
- this.process.kill();
455057
+ try {
455058
+ this.process.kill();
455059
+ } catch {
455060
+ }
453786
455061
  this.process = void 0;
453787
455062
  }
453788
455063
  this.isInitialized = false;
455064
+ this.isProcessAlive = false;
453789
455065
  this.openDocuments.clear();
453790
455066
  this.documentVersions.clear();
453791
455067
  }
@@ -453942,7 +455218,7 @@ var init_LSPClient = __esm({
453942
455218
  return this.capabilities;
453943
455219
  }
453944
455220
  isReady() {
453945
- return this.isInitialized;
455221
+ return this.isInitialized && this.isProcessAlive;
453946
455222
  }
453947
455223
  };
453948
455224
  }
@@ -454190,6 +455466,11 @@ var init_LSPManager = __esm({
454190
455466
  if (client.isReady()) {
454191
455467
  return client;
454192
455468
  }
455469
+ try {
455470
+ await client.shutdown();
455471
+ } catch {
455472
+ }
455473
+ this.clients.delete(language);
454193
455474
  }
454194
455475
  const config3 = LSPServerRegistry.getConfig(language);
454195
455476
  if (!config3) {
@@ -454653,8 +455934,8 @@ async function validateTokenLimit(content, maxTokens) {
454653
455934
  contentStr = String(contentWithoutImages);
454654
455935
  }
454655
455936
  try {
454656
- const { encoding_for_model: encoding_for_model2 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
454657
- const encoder = encoding_for_model2("gpt-4o");
455937
+ const { encoding_for_model: encoding_for_model3 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
455938
+ const encoder = encoding_for_model3("gpt-4o");
454658
455939
  try {
454659
455940
  const tokens2 = encoder.encode(contentStr);
454660
455941
  const tokenCount = tokens2.length;
@@ -454687,8 +455968,8 @@ Tip: Consider breaking down the operation into smaller chunks or filtering the d
454687
455968
  }
454688
455969
  async function truncateToTokenLimit(content, maxTokens) {
454689
455970
  try {
454690
- const { encoding_for_model: encoding_for_model2 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
454691
- const encoder = encoding_for_model2("gpt-4o");
455971
+ const { encoding_for_model: encoding_for_model3 } = await Promise.resolve().then(() => __toESM(require_tiktoken(), 1));
455972
+ const encoder = encoding_for_model3("gpt-4o");
454692
455973
  try {
454693
455974
  const tokens2 = encoder.encode(content);
454694
455975
  if (tokens2.length <= maxTokens) {
@@ -455804,19 +457085,48 @@ ${combinedOutput}`);
455804
457085
  result2 = await wrapToolResultWithTokenLimit2(result2, toolName);
455805
457086
  return result2;
455806
457087
  }
457088
+ function isConnectionError(error) {
457089
+ if (error instanceof Error) {
457090
+ const msg = error.message.toLowerCase();
457091
+ return msg.includes("stream") || msg.includes("destroyed") || msg.includes("closed") || msg.includes("ended") || msg.includes("econnreset") || msg.includes("econnrefused") || msg.includes("epipe") || msg.includes("not connected") || msg.includes("transport") || error.code === "ERR_STREAM_DESTROYED";
457092
+ }
457093
+ return false;
457094
+ }
455807
457095
  async function executeOnExternalMCPService(serviceName, server, toolName, args2) {
455808
- const client = await getPersistentClient(serviceName, server);
455809
- logger.debug(`Using persistent MCP client for ${serviceName} tool ${toolName}`);
455810
- const timeout2 = server.timeout ?? 3e5;
455811
- const result2 = await client.callTool({
455812
- name: toolName,
455813
- arguments: args2
455814
- }, void 0, {
455815
- timeout: timeout2,
455816
- resetTimeoutOnProgress: true
455817
- });
455818
- logger.debug(`result from ${serviceName} tool ${toolName}:`, result2);
455819
- return result2.content;
457096
+ let retried = false;
457097
+ const attemptCall = async () => {
457098
+ const client = await getPersistentClient(serviceName, server);
457099
+ logger.debug(`Using persistent MCP client for ${serviceName} tool ${toolName}`);
457100
+ const timeout2 = server.timeout ?? 3e5;
457101
+ const result2 = await client.callTool({
457102
+ name: toolName,
457103
+ arguments: args2
457104
+ }, void 0, {
457105
+ timeout: timeout2,
457106
+ resetTimeoutOnProgress: true
457107
+ });
457108
+ logger.debug(`result from ${serviceName} tool ${toolName}:`, result2);
457109
+ return result2.content;
457110
+ };
457111
+ try {
457112
+ return await attemptCall();
457113
+ } catch (error) {
457114
+ if (!retried && isConnectionError(error)) {
457115
+ retried = true;
457116
+ logger.info(`Connection error for ${serviceName}, reconnecting and retrying...`);
457117
+ const clientInfo = persistentClients.get(serviceName);
457118
+ if (clientInfo) {
457119
+ try {
457120
+ await clientInfo.client.close();
457121
+ } catch {
457122
+ }
457123
+ resourceMonitor.trackMCPConnectionClosed(serviceName);
457124
+ persistentClients.delete(serviceName);
457125
+ }
457126
+ return await attemptCall();
457127
+ }
457128
+ throw error;
457129
+ }
455820
457130
  }
455821
457131
  var toolsCache, CACHE_DURATION, todoService, persistentClients, CLIENT_IDLE_TIMEOUT;
455822
457132
  var init_mcpToolsManager = __esm({
@@ -549841,11 +551151,29 @@ function MessageRenderer({ message, index, filteredMessages, terminalWidth, show
549841
551151
  const lines = content.split("\n");
549842
551152
  const titleLine = lines[0] || "";
549843
551153
  const treeLines = lines.slice(1);
551154
+ const ctxUsage = message.subAgentContextUsage;
551155
+ const showCtxBar = ctxUsage && ctxUsage.percentage > 0;
549844
551156
  return import_react79.default.createElement(
549845
551157
  import_react79.default.Fragment,
549846
551158
  null,
549847
551159
  import_react79.default.createElement(Text, { color: toolStatusColor }, removeAnsiCodes2(titleLine)),
549848
- treeLines.length > 0 && import_react79.default.createElement(Text, { color: theme14.colors.menuSecondary }, treeLines.map((line) => removeAnsiCodes2(line || "")).join("\n"))
551160
+ treeLines.length > 0 && import_react79.default.createElement(Text, { color: theme14.colors.menuSecondary }, treeLines.map((line) => removeAnsiCodes2(line || "")).join("\n")),
551161
+ showCtxBar && (() => {
551162
+ const pct = ctxUsage.percentage;
551163
+ const barWidth = 10;
551164
+ const filled = Math.round(pct / 100 * barWidth);
551165
+ const empty = barWidth - filled;
551166
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
551167
+ const barColor = pct >= 80 ? "red" : pct >= 65 ? "yellow" : pct >= 50 ? "cyan" : "gray";
551168
+ return import_react79.default.createElement(
551169
+ Text,
551170
+ { color: barColor, dimColor: true },
551171
+ "\u2514\u2500 Context: ",
551172
+ pct,
551173
+ "% ",
551174
+ bar
551175
+ );
551176
+ })()
549849
551177
  );
549850
551178
  }
549851
551179
  return import_react79.default.createElement(
@@ -559837,7 +561165,7 @@ var init_CustomCommandExecutionDisplay = __esm({
559837
561165
  });
559838
561166
 
559839
561167
  // dist/ui/components/tools/FileRollbackConfirmation.js
559840
- function FileRollbackConfirmation({ fileCount, filePaths, previewSessionId, previewTargetMessageIndex, onConfirm }) {
561168
+ function FileRollbackConfirmation({ fileCount, filePaths, notebookCount, previewSessionId, previewTargetMessageIndex, onConfirm }) {
559841
561169
  const { t } = useI18n();
559842
561170
  const [selectedIndex, setSelectedIndex] = (0, import_react117.useState)(0);
559843
561171
  const [showFullList, setShowFullList] = (0, import_react117.useState)(false);
@@ -560060,6 +561388,11 @@ function FileRollbackConfirmation({ fileCount, filePaths, previewSessionId, prev
560060
561388
  remainingCountCompact > 1 ? "s" : ""
560061
561389
  )
560062
561390
  ),
561391
+ notebookCount !== void 0 && notebookCount > 0 && import_react117.default.createElement(
561392
+ Box_default,
561393
+ { marginBottom: 1, marginLeft: 2 },
561394
+ import_react117.default.createElement(Text, { color: "magenta" }, t.fileRollback.notebookCount.replace("{count}", String(notebookCount)))
561395
+ ),
560063
561396
  !showFullList && import_react117.default.createElement(
560064
561397
  import_react117.default.Fragment,
560065
561398
  null,
@@ -565227,6 +566560,9 @@ function getToolResourceType(toolName) {
565227
566560
  if (toolName === "todo-update" || toolName === "todo-add" || toolName === "todo-delete") {
565228
566561
  return "todo-state";
565229
566562
  }
566563
+ if (toolName === "notebook-add" || toolName === "notebook-update" || toolName === "notebook-delete" || toolName === "notebook-list" || toolName === "notebook-query") {
566564
+ return "notebook-state";
566565
+ }
565230
566566
  if (toolName === "terminal-execute") {
565231
566567
  return "terminal-execution";
565232
566568
  }
@@ -565241,6 +566577,9 @@ function getResourceIdentifier(toolCall) {
565241
566577
  if (resourceType === "todo-state") {
565242
566578
  return "todo-state";
565243
566579
  }
566580
+ if (resourceType === "notebook-state") {
566581
+ return "notebook-state";
566582
+ }
565244
566583
  if (resourceType === "terminal-execution") {
565245
566584
  return "terminal-execution";
565246
566585
  }
@@ -565447,7 +566786,7 @@ function cleanOrphanedToolCalls(messages) {
565447
566786
  console.log(`[contextCompressor:cleanOrphanedToolCalls] Removed ${indicesToRemove.length} orphaned messages from compression input`);
565448
566787
  }
565449
566788
  }
565450
- function formatMessageForTranscript(msg) {
566789
+ function formatMessageForTranscript2(msg) {
565451
566790
  var _a21, _b14;
565452
566791
  if (msg.role === "tool") {
565453
566792
  return null;
@@ -565504,7 +566843,7 @@ function prepareMessagesForCompression(conversationMessages, customSystemPrompt)
565504
566843
  if (msg.role === "system") {
565505
566844
  continue;
565506
566845
  }
565507
- const formatted = formatMessageForTranscript(msg);
566846
+ const formatted = formatMessageForTranscript2(msg);
565508
566847
  if (formatted) {
565509
566848
  transcriptParts.push(formatted);
565510
566849
  }
@@ -567314,6 +568653,14 @@ var useConversation_exports = {};
567314
568653
  __export(useConversation_exports, {
567315
568654
  handleConversationWithTools: () => handleConversationWithTools
567316
568655
  });
568656
+ function formatTokenCount(tokens2) {
568657
+ if (!tokens2)
568658
+ return "0";
568659
+ if (tokens2 >= 1e3) {
568660
+ return `${(tokens2 / 1e3).toFixed(1)}K`;
568661
+ }
568662
+ return String(tokens2);
568663
+ }
567317
568664
  async function handleConversationWithTools(options3) {
567318
568665
  const {
567319
568666
  userContent,
@@ -567379,10 +568726,10 @@ async function handleConversationWithTools(options3) {
567379
568726
  }
567380
568727
  };
567381
568728
  try {
567382
- encoder = (0, import_tiktoken.encoding_for_model)("gpt-5");
568729
+ encoder = (0, import_tiktoken2.encoding_for_model)("gpt-5");
567383
568730
  resourceMonitor.trackEncoderCreated();
567384
568731
  } catch (e) {
567385
- encoder = (0, import_tiktoken.encoding_for_model)("gpt-3.5-turbo");
568732
+ encoder = (0, import_tiktoken2.encoding_for_model)("gpt-3.5-turbo");
567386
568733
  resourceMonitor.trackEncoderCreated();
567387
568734
  }
567388
568735
  setStreamTokenCount(0);
@@ -567677,18 +569024,147 @@ async function handleConversationWithTools(options3) {
567677
569024
  let subAgentTokenCount = 0;
567678
569025
  let lastSubAgentFlushTime = 0;
567679
569026
  const SUB_AGENT_FLUSH_INTERVAL = 100;
569027
+ const latestSubAgentCtxUsage = {};
567680
569028
  const toolResults = await executeToolCalls(
567681
569029
  approvedTools,
567682
569030
  controller.signal,
567683
569031
  setStreamTokenCount,
567684
569032
  async (subAgentMessage) => {
567685
569033
  setMessages((prev) => {
569034
+ var _a21;
569035
+ if (subAgentMessage.message.type === "context_usage") {
569036
+ const ctxData = {
569037
+ percentage: subAgentMessage.message.percentage,
569038
+ inputTokens: subAgentMessage.message.inputTokens,
569039
+ maxTokens: subAgentMessage.message.maxTokens
569040
+ };
569041
+ latestSubAgentCtxUsage[subAgentMessage.agentId] = ctxData;
569042
+ let targetIndex = -1;
569043
+ for (let i = prev.length - 1; i >= 0; i--) {
569044
+ const m = prev[i];
569045
+ if (m && m.role === "subagent" && ((_a21 = m.subAgent) == null ? void 0 : _a21.agentId) === subAgentMessage.agentId) {
569046
+ targetIndex = i;
569047
+ break;
569048
+ }
569049
+ }
569050
+ if (targetIndex !== -1) {
569051
+ const updated = [...prev];
569052
+ const existing = updated[targetIndex];
569053
+ if (existing) {
569054
+ updated[targetIndex] = {
569055
+ ...existing,
569056
+ subAgentContextUsage: ctxData
569057
+ };
569058
+ }
569059
+ return updated;
569060
+ }
569061
+ return prev;
569062
+ }
569063
+ if (subAgentMessage.message.type === "context_compressing") {
569064
+ const uiMsg = {
569065
+ role: "subagent",
569066
+ content: `\x1B[36m\u2687 ${subAgentMessage.agentName}\x1B[0m \x1B[33m\u2735 Auto-compressing context (${subAgentMessage.message.percentage}%)...\x1B[0m`,
569067
+ streaming: false,
569068
+ subAgent: {
569069
+ agentId: subAgentMessage.agentId,
569070
+ agentName: subAgentMessage.agentName,
569071
+ isComplete: false
569072
+ },
569073
+ subAgentInternal: true
569074
+ };
569075
+ return [...prev, uiMsg];
569076
+ }
569077
+ if (subAgentMessage.message.type === "context_compressed") {
569078
+ const msg = subAgentMessage.message;
569079
+ const uiMsg = {
569080
+ role: "subagent",
569081
+ content: `\x1B[36m\u2687 ${subAgentMessage.agentName}\x1B[0m \x1B[32m\u2735 Context compressed (~${formatTokenCount(msg.beforeTokens)} \u2192 ~${formatTokenCount(msg.afterTokensEstimate)})\x1B[0m`,
569082
+ streaming: false,
569083
+ messageStatus: "success",
569084
+ subAgent: {
569085
+ agentId: subAgentMessage.agentId,
569086
+ agentName: subAgentMessage.agentName,
569087
+ isComplete: false
569088
+ },
569089
+ subAgentInternal: true
569090
+ };
569091
+ return [...prev, uiMsg];
569092
+ }
569093
+ if (subAgentMessage.message.type === "inter_agent_sent") {
569094
+ const msg = subAgentMessage.message;
569095
+ const statusIcon = msg.success ? "\u2192" : "\u2717";
569096
+ const targetName = msg.targetAgentName || msg.targetAgentId;
569097
+ const truncatedContent = msg.content.length > 80 ? msg.content.substring(0, 80) + "..." : msg.content;
569098
+ const uiMsg = {
569099
+ role: "subagent",
569100
+ content: `\x1B[38;2;255;165;0m\u2687${statusIcon} [${subAgentMessage.agentName}] \u2192 [${targetName}]\x1B[0m: ${truncatedContent}`,
569101
+ streaming: false,
569102
+ messageStatus: msg.success ? "success" : "error",
569103
+ subAgent: {
569104
+ agentId: subAgentMessage.agentId,
569105
+ agentName: subAgentMessage.agentName,
569106
+ isComplete: false
569107
+ },
569108
+ subAgentInternal: true
569109
+ };
569110
+ return [...prev, uiMsg];
569111
+ }
569112
+ if (subAgentMessage.message.type === "inter_agent_received") {
569113
+ return prev;
569114
+ }
569115
+ if (subAgentMessage.message.type === "agent_spawned") {
569116
+ const msg = subAgentMessage.message;
569117
+ const promptText = msg.spawnedPrompt ? msg.spawnedPrompt.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim() : "";
569118
+ const truncatedPrompt = promptText.length > 100 ? promptText.substring(0, 100) + "..." : promptText;
569119
+ const promptLine = truncatedPrompt ? `
569120
+ \x1B[2m\u2514\u2500 prompt: "${truncatedPrompt}"\x1B[0m` : "";
569121
+ const uiMsg = {
569122
+ role: "subagent",
569123
+ content: `\x1B[38;2;150;120;255m\u2687\u2295 [${subAgentMessage.agentName}] spawned [${msg.spawnedAgentName}]\x1B[0m${promptLine}`,
569124
+ streaming: false,
569125
+ messageStatus: "success",
569126
+ subAgent: {
569127
+ agentId: subAgentMessage.agentId,
569128
+ agentName: subAgentMessage.agentName,
569129
+ isComplete: false
569130
+ },
569131
+ subAgentInternal: true
569132
+ };
569133
+ return [...prev, uiMsg];
569134
+ }
569135
+ if (subAgentMessage.message.type === "spawned_agent_completed") {
569136
+ const msg = subAgentMessage.message;
569137
+ const statusIcon = msg.success ? "\u2713" : "\u2717";
569138
+ const uiMsg = {
569139
+ role: "subagent",
569140
+ content: `\x1B[38;2;150;120;255m\u2687${statusIcon} Spawned [${msg.spawnedAgentName}] completed\x1B[0m (parent: ${subAgentMessage.agentName})`,
569141
+ streaming: false,
569142
+ messageStatus: msg.success ? "success" : "error",
569143
+ subAgent: {
569144
+ agentId: subAgentMessage.agentId,
569145
+ agentName: subAgentMessage.agentName,
569146
+ isComplete: false
569147
+ },
569148
+ subAgentInternal: true
569149
+ };
569150
+ return [...prev, uiMsg];
569151
+ }
567686
569152
  if (subAgentMessage.message.type === "tool_calls") {
567687
569153
  const toolCalls = subAgentMessage.message.tool_calls;
567688
569154
  if (toolCalls && toolCalls.length > 0) {
567689
- const timeConsumingTools = toolCalls.filter((tc) => isToolNeedTwoStepDisplay(tc.function.name));
567690
- const quickTools = toolCalls.filter((tc) => !isToolNeedTwoStepDisplay(tc.function.name));
569155
+ const internalAgentTools = /* @__PURE__ */ new Set([
569156
+ "send_message_to_agent",
569157
+ "query_agents_status",
569158
+ "spawn_sub_agent"
569159
+ ]);
569160
+ const displayableToolCalls = toolCalls.filter((tc) => !internalAgentTools.has(tc.function.name));
569161
+ if (displayableToolCalls.length === 0) {
569162
+ return prev;
569163
+ }
569164
+ const timeConsumingTools = displayableToolCalls.filter((tc) => isToolNeedTwoStepDisplay(tc.function.name));
569165
+ const quickTools = displayableToolCalls.filter((tc) => !isToolNeedTwoStepDisplay(tc.function.name));
567691
569166
  const newMessages = [];
569167
+ const inheritedCtxUsage = latestSubAgentCtxUsage[subAgentMessage.agentId];
567692
569168
  for (const toolCall of timeConsumingTools) {
567693
569169
  const toolDisplay = formatToolCallMessage(toolCall);
567694
569170
  let toolArgs;
@@ -567720,7 +569196,8 @@ async function handleConversationWithTools(options3) {
567720
569196
  agentName: subAgentMessage.agentName,
567721
569197
  isComplete: false
567722
569198
  },
567723
- subAgentInternal: true
569199
+ subAgentInternal: true,
569200
+ subAgentContextUsage: inheritedCtxUsage
567724
569201
  };
567725
569202
  newMessages.push(uiMsg);
567726
569203
  }
@@ -567744,7 +569221,8 @@ async function handleConversationWithTools(options3) {
567744
569221
  },
567745
569222
  subAgentInternal: true,
567746
569223
  // Store pending tool call IDs for later status update
567747
- pendingToolIds: quickTools.map((tc) => tc.id)
569224
+ pendingToolIds: quickTools.map((tc) => tc.id),
569225
+ subAgentContextUsage: inheritedCtxUsage
567748
569226
  };
567749
569227
  newMessages.push(uiMsg);
567750
569228
  }
@@ -567863,8 +569341,8 @@ async function handleConversationWithTools(options3) {
567863
569341
  return [...prev, uiMsg];
567864
569342
  }
567865
569343
  const pendingMsgIndex = prev.findIndex((m) => {
567866
- var _a21, _b14, _c6;
567867
- return m.role === "subagent" && ((_a21 = m.subAgent) == null ? void 0 : _a21.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && ((_c6 = m.pendingToolIds) == null ? void 0 : _c6.includes(msg.tool_call_id));
569344
+ var _a22, _b14, _c6;
569345
+ return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && ((_c6 = m.pendingToolIds) == null ? void 0 : _c6.includes(msg.tool_call_id));
567868
569346
  });
567869
569347
  if (pendingMsgIndex !== -1) {
567870
569348
  const updated = [...prev];
@@ -567881,8 +569359,8 @@ async function handleConversationWithTools(options3) {
567881
569359
  return prev;
567882
569360
  }
567883
569361
  const existingIndex = prev.findIndex((m) => {
567884
- var _a21, _b14;
567885
- return m.role === "subagent" && ((_a21 = m.subAgent) == null ? void 0 : _a21.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && m.streaming === true && !m.pendingToolIds;
569362
+ var _a22, _b14;
569363
+ return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && m.streaming === true && !m.pendingToolIds;
567886
569364
  });
567887
569365
  let contentToApply = "";
567888
569366
  if (subAgentMessage.message.type === "content") {
@@ -568146,6 +569624,46 @@ async function handleConversationWithTools(options3) {
568146
569624
  if (resultMessages.length > 0) {
568147
569625
  setMessages((prev) => [...prev, ...resultMessages]);
568148
569626
  }
569627
+ try {
569628
+ const { runningSubAgentTracker: runningSubAgentTracker2 } = await Promise.resolve().then(() => (init_runningSubAgentTracker(), runningSubAgentTracker_exports));
569629
+ const spawnedResults = runningSubAgentTracker2.drainSpawnedResults();
569630
+ if (spawnedResults.length > 0) {
569631
+ for (const sr of spawnedResults) {
569632
+ const statusIcon = sr.success ? "\u2713" : "\u2717";
569633
+ const resultSummary = sr.success ? sr.result.length > 500 ? sr.result.substring(0, 500) + "..." : sr.result : sr.error || "Unknown error";
569634
+ const spawnedContent = `[Spawned Sub-Agent Result] ${statusIcon} ${sr.agentName} (${sr.agentId}) \u2014 spawned by ${sr.spawnedBy.agentName}
569635
+ Prompt: ${sr.prompt}
569636
+ Result: ${resultSummary}`;
569637
+ conversationMessages.push({
569638
+ role: "user",
569639
+ content: spawnedContent
569640
+ });
569641
+ try {
569642
+ await saveMessage({
569643
+ role: "user",
569644
+ content: spawnedContent
569645
+ });
569646
+ } catch (error) {
569647
+ console.error("Failed to save spawned agent result:", error);
569648
+ }
569649
+ const uiMsg = {
569650
+ role: "subagent",
569651
+ content: `\x1B[38;2;150;120;255m\u2687${statusIcon} Spawned ${sr.agentName}\x1B[0m (by ${sr.spawnedBy.agentName}): ${sr.success ? "completed" : "failed"}`,
569652
+ streaming: false,
569653
+ messageStatus: sr.success ? "success" : "error",
569654
+ subAgent: {
569655
+ agentId: sr.agentId,
569656
+ agentName: sr.agentName,
569657
+ isComplete: true
569658
+ },
569659
+ subAgentInternal: true
569660
+ };
569661
+ setMessages((prev) => [...prev, uiMsg]);
569662
+ }
569663
+ }
569664
+ } catch (error) {
569665
+ console.error("Failed to process spawned agent results:", error);
569666
+ }
568149
569667
  if (options3.getPendingMessages && options3.clearPendingMessages) {
568150
569668
  const pendingMessages = options3.getPendingMessages();
568151
569669
  if (pendingMessages.length > 0) {
@@ -568338,11 +569856,11 @@ async function handleConversationWithTools(options3) {
568338
569856
  }
568339
569857
  return { usage: accumulatedUsage };
568340
569858
  }
568341
- var import_tiktoken;
569859
+ var import_tiktoken2;
568342
569860
  var init_useConversation = __esm({
568343
569861
  async "dist/hooks/conversation/useConversation.js"() {
568344
569862
  "use strict";
568345
- import_tiktoken = __toESM(require_tiktoken(), 1);
569863
+ import_tiktoken2 = __toESM(require_tiktoken(), 1);
568346
569864
  init_chat();
568347
569865
  init_responses();
568348
569866
  init_gemini();
@@ -571862,10 +573380,12 @@ ${errorMsg}`,
571862
573380
  }
571863
573381
  if (totalFileCount > 0) {
571864
573382
  const filePaths2 = await hashBasedSnapshotManager.getFilesToRollback(currentSession.id, selectedIndex);
573383
+ const nbCount2 = getNotebookRollbackCount(currentSession.id, selectedIndex);
571865
573384
  snapshotState.setPendingRollback({
571866
573385
  messageIndex: selectedIndex,
571867
573386
  fileCount: filePaths2.length,
571868
573387
  filePaths: filePaths2,
573388
+ notebookCount: nbCount2,
571869
573389
  message: cleanIDEContext(message),
571870
573390
  images,
571871
573391
  crossSessionRollback: true,
@@ -571898,11 +573418,13 @@ ${errorMsg}`,
571898
573418
  }
571899
573419
  }
571900
573420
  const filePaths = await hashBasedSnapshotManager.getFilesToRollback(currentSession.id, selectedIndex);
571901
- if (filePaths.length > 0) {
573421
+ const nbCount = getNotebookRollbackCount(currentSession.id, selectedIndex);
573422
+ if (filePaths.length > 0 || nbCount > 0) {
571902
573423
  snapshotState.setPendingRollback({
571903
573424
  messageIndex: selectedIndex,
571904
573425
  fileCount: filePaths.length,
571905
573426
  filePaths,
573427
+ notebookCount: nbCount,
571906
573428
  message: cleanIDEContext(message),
571907
573429
  images
571908
573430
  });
@@ -571923,6 +573445,11 @@ ${errorMsg}`,
571923
573445
  } else {
571924
573446
  await hashBasedSnapshotManager.rollbackToMessageIndex(currentSession.id, selectedIndex);
571925
573447
  }
573448
+ try {
573449
+ rollbackNotebooks(currentSession.id, selectedIndex);
573450
+ } catch (error) {
573451
+ console.error("Failed to rollback notebooks:", error);
573452
+ }
571926
573453
  }
571927
573454
  if (currentSession) {
571928
573455
  const messagesAfterSelected = messages.slice(selectedIndex);
@@ -571960,6 +573487,7 @@ ${errorMsg}`,
571960
573487
  }
571961
573488
  if (sessionTruncateIndex === 0 && currentSession) {
571962
573489
  await hashBasedSnapshotManager.clearAllSnapshots(currentSession.id);
573490
+ clearAllNotebookSnapshots(currentSession.id);
571963
573491
  await sessionManager.deleteSession(currentSession.id);
571964
573492
  sessionManager.clearCurrentSession();
571965
573493
  setMessages([]);
@@ -571972,6 +573500,9 @@ ${errorMsg}`,
571972
573500
  return;
571973
573501
  }
571974
573502
  await hashBasedSnapshotManager.deleteSnapshotsFromIndex(currentSession.id, selectedIndex);
573503
+ if (!rollbackFiles) {
573504
+ deleteNotebookSnapshotsFromIndex(currentSession.id, selectedIndex);
573505
+ }
571975
573506
  const snapshots = await hashBasedSnapshotManager.listSnapshots(currentSession.id);
571976
573507
  const counts = /* @__PURE__ */ new Map();
571977
573508
  for (const snapshot of snapshots) {
@@ -572337,6 +573868,7 @@ var init_useChatLogic = __esm({
572337
573868
  init_vscodeConnection();
572338
573869
  init_reindexCodebase();
572339
573870
  init_runningSubAgentTracker();
573871
+ init_notebookManager();
572340
573872
  }
572341
573873
  });
572342
573874
 
@@ -573918,7 +575450,7 @@ function ChatScreen({ autoResume, enableYolo, enablePlan }) {
573918
575450
  import_react143.default.createElement(PermissionsPanel2, { alwaysApprovedTools, onRemoveTool: removeFromAlwaysApproved, onClearAll: clearAllAlwaysApproved, onClose: () => setShowPermissionsPanel(false) })
573919
575451
  )
573920
575452
  ),
573921
- snapshotState.pendingRollback && import_react143.default.createElement(FileRollbackConfirmation, { fileCount: snapshotState.pendingRollback.fileCount, filePaths: snapshotState.pendingRollback.filePaths || [], previewSessionId: (_a21 = sessionManager.getCurrentSession()) == null ? void 0 : _a21.id, previewTargetMessageIndex: snapshotState.pendingRollback.messageIndex, onConfirm: handleRollbackConfirm }),
575453
+ snapshotState.pendingRollback && import_react143.default.createElement(FileRollbackConfirmation, { fileCount: snapshotState.pendingRollback.fileCount, filePaths: snapshotState.pendingRollback.filePaths || [], notebookCount: snapshotState.pendingRollback.notebookCount, previewSessionId: (_a21 = sessionManager.getCurrentSession()) == null ? void 0 : _a21.id, previewTargetMessageIndex: snapshotState.pendingRollback.messageIndex, onConfirm: handleRollbackConfirm }),
573922
575454
  !pendingToolConfirmation && !pendingUserQuestion && !bashSensitiveCommand && !terminalExecutionState.state.needsInput && !(panelState.showSessionPanel || panelState.showMcpPanel || panelState.showUsagePanel || panelState.showModelsPanel || panelState.showCustomCommandConfig || panelState.showSkillsCreation || panelState.showRoleCreation || panelState.showRoleDeletion || panelState.showRoleList || panelState.showWorkingDirPanel || panelState.showBranchPanel || showPermissionsPanel) && !snapshotState.pendingRollback && import_react143.default.createElement(ChatFooter, { onSubmit: handleMessageSubmit, onCommand: handleCommandExecution, onHistorySelect: handleHistorySelect, onSwitchProfile: handleSwitchProfile, handleProfileSelect, handleHistorySelect, showReviewCommitPanel: panelState.showReviewCommitPanel, setShowReviewCommitPanel: panelState.setShowReviewCommitPanel, onReviewCommitConfirm: handleReviewCommitConfirm, disabled: !!pendingToolConfirmation || !!bashSensitiveCommand || isExecutingTerminalCommand || isCompressing || streamingState.isStopping, isStopping: streamingState.isStopping, isProcessing: streamingState.isStreaming || isSaving || bashMode.state.isExecuting || isCompressing, chatHistory: messages, yoloMode, setYoloMode, planMode, setPlanMode, vulnerabilityHuntingMode, setVulnerabilityHuntingMode, contextUsage: streamingState.contextUsage ? {
573923
575455
  inputTokens: streamingState.contextUsage.prompt_tokens,
573924
575456
  maxContextTokens: getOpenAiConfig().maxContextTokens || 4e3,