Skip to content

Commit 8f52c80

Browse files
committed
Merge ziyong/useful-info-module into dev with conflict resolution
2 parents 19e2895 + e32c688 commit 8f52c80

22 files changed

Lines changed: 1487 additions & 41 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ dist
33
bundle
44
out
55
.snow
6+
/.vscode/settings.json
7+
ROLE.md

build-ncc.mjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ console.log('Building with ncc...');
1515
await execAsync('ncc build dist/cli.js -o bundle --minify');
1616

1717
// Copy WASM file
18-
copyFileSync(
19-
'node_modules/sql.js/dist/sql-wasm.wasm',
20-
'bundle/sql-wasm.wasm',
21-
);
18+
copyFileSync('node_modules/sql.js/dist/sql-wasm.wasm', 'bundle/sql-wasm.wasm');
2219

2320
// Rename index.js to cli.cjs
2421
if (existsSync('bundle/index.js')) {

build-shim.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { fileURLToPath as _fileURLToPath } from 'url';
2-
import { dirname as _dirname } from 'path';
3-
import { createRequire as _createRequire } from 'module';
1+
import {fileURLToPath as _fileURLToPath} from 'url';
2+
import {dirname as _dirname} from 'path';
3+
import {createRequire as _createRequire} from 'module';
44

55
export const __filename = _fileURLToPath(import.meta.url);
66
export const __dirname = _dirname(__filename);

build.mjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,7 @@ const __dirname = _fileURLToPath(new URL('.', import.meta.url));`,
5050
});
5151

5252
// Copy WASM files
53-
copyFileSync(
54-
'node_modules/sql.js/dist/sql-wasm.wasm',
55-
'bundle/sql-wasm.wasm',
56-
);
53+
copyFileSync('node_modules/sql.js/dist/sql-wasm.wasm', 'bundle/sql-wasm.wasm');
5754
copyFileSync(
5855
'node_modules/tiktoken/tiktoken_bg.wasm',
5956
'bundle/tiktoken_bg.wasm',

source/hooks/conversation/useCommandHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {exportMessagesToFile} from '../../utils/session/chatExporter.js';
1919
export async function executeContextCompression(): Promise<{
2020
uiMessages: Message[];
2121
usage: UsageInfo;
22+
preservedMessages?: Array<any>;
23+
summary?: string;
2224
} | null> {
2325
try {
2426
// 从会话文件读取真实的消息记录
@@ -142,6 +144,8 @@ export async function executeContextCompression(): Promise<{
142144
completion_tokens: compressionResult.usage.completion_tokens,
143145
total_tokens: compressionResult.usage.total_tokens,
144146
},
147+
preservedMessages: compressionResult.preservedMessages || [],
148+
summary: compressionResult.summary,
145149
};
146150
} catch (error) {
147151
console.error('Context compression failed:', error);

source/hooks/conversation/useConversation.ts

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {getSystemPrompt} from '../../api/systemPrompt.js';
1010
import {
1111
collectAllMCPTools,
1212
getTodoService,
13+
getUsefulInfoService,
1314
} from '../../utils/execution/mcpToolsManager.js';
1415
import {
1516
executeToolCalls,
@@ -19,6 +20,7 @@ import {getOpenAiConfig} from '../../utils/config/apiConfig.js';
1920
import {sessionManager} from '../../utils/session/sessionManager.js';
2021
import {formatTodoContext} from '../../utils/core/todoPreprocessor.js';
2122
import {unifiedHooksExecutor} from '../../utils/execution/unifiedHooksExecutor.js';
23+
import {formatUsefulInfoContext} from '../../utils/core/usefulInfoPreprocessor.js';
2224
import type {Message} from '../../ui/components/MessageList.js';
2325
import {filterToolsBySensitivity} from '../../utils/execution/yoloPermissionChecker.js';
2426
import {formatToolCallMessage} from '../../utils/ui/messageFormatter.js';
@@ -212,6 +214,22 @@ async function executeWithInternalRetry(
212214
});
213215
}
214216

217+
// Add useful information context if available
218+
const usefulInfoService = getUsefulInfoService();
219+
const usefulInfoList = await usefulInfoService.getUsefulInfoList(
220+
currentSession.id,
221+
);
222+
223+
if (usefulInfoList && usefulInfoList.items.length > 0) {
224+
const usefulInfoContext = await formatUsefulInfoContext(
225+
usefulInfoList.items,
226+
);
227+
conversationMessages.push({
228+
role: 'user',
229+
content: usefulInfoContext,
230+
});
231+
}
232+
215233
// Add history messages from session (includes tool_calls and tool results)
216234
// Load from session to get complete conversation history with tool interactions
217235
// Filter out internal sub-agent messages (marked with subAgentInternal: true)
@@ -1243,8 +1261,89 @@ async function executeWithInternalRetry(
12431261
// 压缩后需要重新构建conversationMessages
12441262
conversationMessages = [];
12451263
const session = sessionManager.getCurrentSession();
1264+
1265+
// 1. 添加系统消息
1266+
conversationMessages.push({
1267+
role: 'system',
1268+
content: getSystemPrompt(),
1269+
});
1270+
1271+
// 2. 如果有TODOs,添加TODO上下文
1272+
if (existingTodoList && existingTodoList.todos.length > 0) {
1273+
const todoContext = formatTodoContext(existingTodoList.todos);
1274+
conversationMessages.push({
1275+
role: 'user',
1276+
content: todoContext,
1277+
});
1278+
}
1279+
1280+
// 3. 压缩后重新获取并添加有用信息上下文
1281+
const usefulInfoService = getUsefulInfoService();
1282+
const updatedUsefulInfoList =
1283+
await usefulInfoService.getUsefulInfoList(session?.id || '');
1284+
1285+
if (
1286+
updatedUsefulInfoList &&
1287+
updatedUsefulInfoList.items.length > 0
1288+
) {
1289+
const usefulInfoContext = await formatUsefulInfoContext(
1290+
updatedUsefulInfoList.items,
1291+
);
1292+
conversationMessages.push({
1293+
role: 'user',
1294+
content: usefulInfoContext,
1295+
});
1296+
}
1297+
1298+
// 4. 添加压缩摘要
1299+
conversationMessages.push({
1300+
role: 'user',
1301+
content: `[Context Summary from Previous Conversation]\n\n${compressionResult.summary}`,
1302+
});
1303+
1304+
// 5. 添加保留的消息(未完成的工具调用链)
1305+
if (
1306+
compressionResult.preservedMessages &&
1307+
compressionResult.preservedMessages.length > 0
1308+
) {
1309+
for (const msg of compressionResult.preservedMessages) {
1310+
conversationMessages.push(msg);
1311+
}
1312+
}
1313+
1314+
// 6. 添加会话中的其他消息(排除已保留的)
12461315
if (session && session.messages.length > 0) {
1247-
conversationMessages.push(...session.messages);
1316+
// 获取已保留的消息ID集合,避免重复
1317+
const preservedIds = new Set(
1318+
compressionResult.preservedMessages?.map(
1319+
msg =>
1320+
msg.tool_call_id ||
1321+
(msg.tool_calls && msg.tool_calls[0]?.id) ||
1322+
`${msg.role}-${msg.content.slice(0, 20)}`,
1323+
) || [],
1324+
);
1325+
1326+
for (const sessionMsg of session.messages) {
1327+
const msgId =
1328+
sessionMsg.tool_call_id ||
1329+
(sessionMsg.tool_calls && sessionMsg.tool_calls[0]?.id) ||
1330+
`${sessionMsg.role}-${sessionMsg.content.slice(0, 20)}`;
1331+
1332+
// 跳过已保留的消息和工具消息
1333+
if (!preservedIds.has(msgId) && sessionMsg.role !== 'tool') {
1334+
conversationMessages.push({
1335+
role: sessionMsg.role,
1336+
content: sessionMsg.content,
1337+
...(sessionMsg.tool_calls && {
1338+
tool_calls: sessionMsg.tool_calls,
1339+
}),
1340+
...(sessionMsg.images && {images: sessionMsg.images}),
1341+
...(sessionMsg.reasoning && {
1342+
reasoning: sessionMsg.reasoning,
1343+
}),
1344+
});
1345+
}
1346+
}
12481347
}
12491348
}
12501349
} catch (error) {
@@ -1469,8 +1568,89 @@ async function executeWithInternalRetry(
14691568
// 压缩后需要重新构建conversationMessages
14701569
conversationMessages = [];
14711570
const session = sessionManager.getCurrentSession();
1571+
1572+
// 1. 添加系统消息
1573+
conversationMessages.push({
1574+
role: 'system',
1575+
content: getSystemPrompt(),
1576+
});
1577+
1578+
// 2. 如果有TODOs,添加TODO上下文
1579+
if (existingTodoList && existingTodoList.todos.length > 0) {
1580+
const todoContext = formatTodoContext(
1581+
existingTodoList.todos,
1582+
);
1583+
conversationMessages.push({
1584+
role: 'user',
1585+
content: todoContext,
1586+
});
1587+
}
1588+
1589+
// 3. 压缩后重新获取并添加有用信息上下文
1590+
const usefulInfoService = getUsefulInfoService();
1591+
const updatedUsefulInfoList =
1592+
await usefulInfoService.getUsefulInfoList(
1593+
session?.id || '',
1594+
);
1595+
1596+
if (
1597+
updatedUsefulInfoList &&
1598+
updatedUsefulInfoList.items.length > 0
1599+
) {
1600+
const usefulInfoContext = await formatUsefulInfoContext(
1601+
updatedUsefulInfoList.items,
1602+
);
1603+
conversationMessages.push({
1604+
role: 'user',
1605+
content: usefulInfoContext,
1606+
});
1607+
}
1608+
1609+
// 4. 添加压缩摘要
1610+
conversationMessages.push({
1611+
role: 'user',
1612+
content: `[Context Summary from Previous Conversation]\n\n${compressionResult.summary}`,
1613+
});
1614+
1615+
// 5. 添加保留的消息(未完成的工具调用链)
1616+
if (
1617+
compressionResult.preservedMessages &&
1618+
compressionResult.preservedMessages.length > 0
1619+
) {
1620+
for (const msg of compressionResult.preservedMessages) {
1621+
conversationMessages.push(msg);
1622+
}
1623+
}
1624+
1625+
// 6. 添加会话中的其他消息(排除已保留的)
14721626
if (session && session.messages.length > 0) {
1473-
conversationMessages.push(...session.messages);
1627+
// 获取已保留的消息ID集合,避免重复
1628+
const preservedIds = new Set(
1629+
compressionResult.preservedMessages?.map(
1630+
msg =>
1631+
msg.tool_call_id ||
1632+
(msg.tool_calls && msg.tool_calls[0]?.id) ||
1633+
`${msg.role}-${msg.content.slice(0, 20)}`,
1634+
) || [],
1635+
);
1636+
1637+
for (const sessionMsg of session.messages) {
1638+
const msgId =
1639+
sessionMsg.tool_call_id ||
1640+
(sessionMsg.tool_calls &&
1641+
sessionMsg.tool_calls[0]?.id) ||
1642+
`${sessionMsg.role}-${sessionMsg.content.slice(0, 20)}`;
1643+
1644+
// 跳过已保留的消息和工具消息
1645+
if (
1646+
preservedIds.has(msgId) ||
1647+
sessionMsg.role === 'tool'
1648+
) {
1649+
continue;
1650+
}
1651+
1652+
conversationMessages.push(sessionMsg);
1653+
}
14741654
}
14751655
}
14761656
} catch (error) {

source/hooks/conversation/useToolConfirmation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export function useToolConfirmation() {
5151
return (
5252
alwaysApprovedToolsRef.current.has(toolName) ||
5353
toolName.startsWith('todo-') ||
54+
toolName.startsWith('useful-info-') ||
5455
toolName.startsWith('subagent-')
5556
);
5657
},

source/i18n/lang/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ export const en: TranslationKeys = {
273273
codebaseTools: 'Codebase Search Tools',
274274
terminalTools: 'Terminal Tools',
275275
todoTools: 'TODO Management Tools',
276+
usefulInfoTools: 'Useful Information Tools',
276277
webSearchTools: 'Web Search Tools',
277278
ideTools: 'IDE Diagnostics Tools',
278279
userInteractionTools: 'User Interaction Tools',

source/i18n/lang/es.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ export const es: TranslationKeys = {
291291
aceTools: 'Herramientas de Búsqueda de Código ACE',
292292
codebaseTools: 'Herramientas de Búsqueda de Base de Código',
293293
terminalTools: 'Herramientas de Terminal',
294-
todoTools: 'Herramientas de Gestión TODO',
294+
todoTools: 'Herramientas de Gestión de TODO',
295+
usefulInfoTools: 'Herramientas de Información Útil',
295296
webSearchTools: 'Herramientas de Búsqueda Web',
296297
ideTools: 'Herramientas de Diagnóstico IDE',
297298
userInteractionTools: 'Herramientas de Interacción del Usuario',

source/i18n/lang/ja.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ export const ja: TranslationKeys = {
263263
codebaseTools: 'コードベース検索ツール',
264264
terminalTools: 'ターミナルツール',
265265
todoTools: 'TODO管理ツール',
266-
webSearchTools: 'Web検索ツール',
266+
usefulInfoTools: '有用情報ツール',
267+
webSearchTools: 'ウェブ検索ツール',
267268
ideTools: 'IDE診断ツール',
268269
userInteractionTools: 'ユーザー対話ツール',
269270
},

0 commit comments

Comments
 (0)