@hirohsu/user-web-feedback 2.8.18 → 2.8.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +59 -209
- package/dist/index.cjs +59 -209
- package/dist/static/modules/conversation-panel.js +132 -47
- package/dist/static/modules/feedback-handler.js +37 -8
- package/dist/static/style.css +106 -0
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -78376,6 +78376,15 @@ var init_prompt_aggregator = __esm({
|
|
|
78376
78376
|
getComponentNames() {
|
|
78377
78377
|
return this.components.map((c) => c.getName());
|
|
78378
78378
|
}
|
|
78379
|
+
getPromptConfigsForDebug() {
|
|
78380
|
+
const configs = this.getPromptConfigsWithDefaults();
|
|
78381
|
+
return configs.map((c) => ({
|
|
78382
|
+
id: c.id,
|
|
78383
|
+
enabled: c.enabled,
|
|
78384
|
+
firstOrder: c.firstOrder,
|
|
78385
|
+
secondOrder: c.secondOrder
|
|
78386
|
+
}));
|
|
78387
|
+
}
|
|
78379
78388
|
getPromptConfigsWithDefaults() {
|
|
78380
78389
|
try {
|
|
78381
78390
|
const configs = getPromptConfigs();
|
|
@@ -78478,61 +78487,6 @@ function formatToolResults(results) {
|
|
|
78478
78487
|
}
|
|
78479
78488
|
return lines.join("\n");
|
|
78480
78489
|
}
|
|
78481
|
-
function buildToolsPrompt(tools, projectName, projectPath) {
|
|
78482
|
-
if (tools.length === 0) {
|
|
78483
|
-
return "";
|
|
78484
|
-
}
|
|
78485
|
-
const lines = [];
|
|
78486
|
-
if (projectName || projectPath) {
|
|
78487
|
-
lines.push("");
|
|
78488
|
-
lines.push("## \u5C08\u6848\u80CC\u666F\u8CC7\u8A0A");
|
|
78489
|
-
lines.push(`\u7576\u524D\u5C08\u6848: ${projectName || "\u672A\u547D\u540D\u5C08\u6848"}`);
|
|
78490
|
-
if (projectPath) {
|
|
78491
|
-
lines.push(`\u5C08\u6848\u8DEF\u5F91: ${projectPath}`);
|
|
78492
|
-
}
|
|
78493
|
-
lines.push("");
|
|
78494
|
-
lines.push("**\u91CD\u8981\u6307\u793A**: \u5728\u56DE\u8986\u4E4B\u524D\uFF0C\u4F60\u61C9\u8A72\u5148\u4F7F\u7528 MCP \u5DE5\u5177\u4F86\u67E5\u8A62\u5C08\u6848\u7684\u80CC\u666F\u8CC7\u8A0A\uFF1A");
|
|
78495
|
-
lines.push("1. \u5C08\u6848\u7684\u67B6\u69CB\u548C\u7D50\u69CB\uFF08\u5982\u4F7F\u7528 get_symbols_overview, list_dir \u7B49\uFF09");
|
|
78496
|
-
lines.push("2. \u5C08\u6848\u7684\u958B\u767C\u8A08\u5283\u548C\u898F\u7BC4\uFF08\u5982\u8B80\u53D6 openspec \u76EE\u9304\u4E2D\u7684\u6587\u4EF6\uFF09");
|
|
78497
|
-
lines.push("3. \u7576\u524D\u7684\u4EFB\u52D9\u548C\u9032\u5EA6");
|
|
78498
|
-
lines.push("");
|
|
78499
|
-
lines.push("**\u8ACB\u52D9\u5FC5\u5148\u8ABF\u7528\u5DE5\u5177\u67E5\u8A62\u5C08\u6848\u8CC7\u8A0A**\uFF0C\u7136\u5F8C\u6839\u64DA\u67E5\u8A62\u7D50\u679C\u63D0\u4F9B\u7CBE\u78BA\u7684\u56DE\u8986\u3002");
|
|
78500
|
-
}
|
|
78501
|
-
lines.push("");
|
|
78502
|
-
lines.push("## MCP \u5DE5\u5177\u4F7F\u7528\u8AAA\u660E");
|
|
78503
|
-
lines.push("");
|
|
78504
|
-
lines.push("\u7576\u4F60\u9700\u8981\u4F7F\u7528\u5DE5\u5177\u6642\uFF0C\u8ACB\u56DE\u8986\u4E00\u500B JSON \u683C\u5F0F\u7684\u5DE5\u5177\u8ABF\u7528\u8ACB\u6C42\uFF08\u4E0D\u8981\u6709\u5176\u4ED6\u6587\u5B57\uFF09\uFF1A");
|
|
78505
|
-
lines.push("");
|
|
78506
|
-
lines.push("```json");
|
|
78507
|
-
lines.push("{");
|
|
78508
|
-
lines.push(' "tool_calls": [');
|
|
78509
|
-
lines.push(' { "name": "\u5DE5\u5177\u540D\u7A31", "arguments": { "\u53C3\u6578\u540D": "\u53C3\u6578\u503C" } }');
|
|
78510
|
-
lines.push(" ],");
|
|
78511
|
-
lines.push(' "message": "\u8AAA\u660E\u4F60\u6B63\u5728\u505A\u4EC0\u9EBC\uFF08\u53EF\u9078\uFF09"');
|
|
78512
|
-
lines.push("}");
|
|
78513
|
-
lines.push("```");
|
|
78514
|
-
lines.push("");
|
|
78515
|
-
lines.push("\u5DE5\u5177\u57F7\u884C\u5F8C\uFF0C\u7D50\u679C\u6703\u56DE\u50B3\u7D66\u4F60\u3002\u4F60\u53EF\u4EE5\u7E7C\u7E8C\u8ABF\u7528\u66F4\u591A\u5DE5\u5177\uFF0C\u6216\u6839\u64DA\u7D50\u679C\u63D0\u4F9B\u6700\u7D42\u56DE\u8986\u3002");
|
|
78516
|
-
lines.push("\u7576\u4F60\u4E0D\u9700\u8981\u8ABF\u7528\u5DE5\u5177\u6642\uFF0C\u76F4\u63A5\u4EE5\u7D14\u6587\u5B57\u56DE\u8986\u5373\u53EF\u3002");
|
|
78517
|
-
lines.push("");
|
|
78518
|
-
lines.push("## \u53EF\u7528\u5DE5\u5177\u5217\u8868");
|
|
78519
|
-
lines.push("");
|
|
78520
|
-
for (const tool of tools) {
|
|
78521
|
-
lines.push(`### ${tool.name}`);
|
|
78522
|
-
if (tool.description) {
|
|
78523
|
-
lines.push(tool.description);
|
|
78524
|
-
}
|
|
78525
|
-
if (tool.inputSchema) {
|
|
78526
|
-
lines.push("");
|
|
78527
|
-
lines.push("\u53C3\u6578\u683C\u5F0F:");
|
|
78528
|
-
lines.push("```json");
|
|
78529
|
-
lines.push(JSON.stringify(tool.inputSchema, null, 2));
|
|
78530
|
-
lines.push("```");
|
|
78531
|
-
}
|
|
78532
|
-
lines.push("");
|
|
78533
|
-
}
|
|
78534
|
-
return lines.join("\n");
|
|
78535
|
-
}
|
|
78536
78490
|
var init_mcp_tool_parser = __esm({
|
|
78537
78491
|
"src/utils/mcp-tool-parser.ts"() {
|
|
78538
78492
|
"use strict";
|
|
@@ -78885,131 +78839,91 @@ async function generateCLIReply(request, cliSettings) {
|
|
|
78885
78839
|
}
|
|
78886
78840
|
}
|
|
78887
78841
|
async function generateAPIReply(request) {
|
|
78842
|
+
const startTime = Date.now();
|
|
78888
78843
|
try {
|
|
78889
78844
|
const cacheKey = `${request.aiMessage}:${request.userContext || ""}`;
|
|
78890
78845
|
if (!request.toolResults) {
|
|
78891
78846
|
const cached2 = cache.get(cacheKey);
|
|
78892
78847
|
if (cached2 && Date.now() - cached2.timestamp < CACHE_TTL2) {
|
|
78893
78848
|
logger.debug("[AI Service] \u4F7F\u7528\u5FEB\u53D6\u56DE\u8986");
|
|
78894
|
-
return {
|
|
78895
|
-
success: true,
|
|
78896
|
-
reply: cached2.reply
|
|
78897
|
-
};
|
|
78849
|
+
return { success: true, reply: cached2.reply };
|
|
78898
78850
|
}
|
|
78899
78851
|
}
|
|
78900
78852
|
logger.debug("[AI Service] \u7372\u53D6 AI \u8A2D\u5B9A");
|
|
78901
78853
|
const settings = getAISettings();
|
|
78902
|
-
logger.debug("[AI Service] AI \u8A2D\u5B9A\u7372\u53D6\u5B8C\u6210", {
|
|
78903
|
-
hasApiKey: !!settings?.apiKey,
|
|
78904
|
-
model: settings?.model,
|
|
78905
|
-
hasMcpToolsPrompt: !!settings?.mcpToolsPrompt
|
|
78906
|
-
});
|
|
78907
78854
|
if (!settings || !settings.apiKey || settings.apiKey === "YOUR_API_KEY_HERE") {
|
|
78908
78855
|
logger.warn("[AI Service] API Key \u672A\u8A2D\u5B9A\u6216\u7121\u6548");
|
|
78909
|
-
return {
|
|
78910
|
-
success: false,
|
|
78911
|
-
error: "\u8ACB\u5148\u5728\u8A2D\u5B9A\u4E2D\u914D\u7F6E AI API Key"
|
|
78912
|
-
};
|
|
78856
|
+
return { success: false, error: "\u8ACB\u5148\u5728\u8A2D\u5B9A\u4E2D\u914D\u7F6E AI API Key" };
|
|
78913
78857
|
}
|
|
78914
|
-
|
|
78858
|
+
const aggregator = getPromptAggregator();
|
|
78859
|
+
const cliSettings = getCLISettings();
|
|
78860
|
+
let mcpTools = [];
|
|
78915
78861
|
if (request.includeMCPTools) {
|
|
78916
|
-
logger.debug("[AI Service] \u958B\u59CB\u7372\u53D6 MCP \u5DE5\u5177");
|
|
78917
78862
|
try {
|
|
78918
78863
|
const allTools = mcpClientManager.getAllTools();
|
|
78919
|
-
|
|
78920
|
-
|
|
78921
|
-
|
|
78922
|
-
|
|
78923
|
-
|
|
78924
|
-
|
|
78925
|
-
|
|
78926
|
-
logger.debug("[AI Service] \u9644\u52A0\u5DE5\u5177\u5217\u8868\u5230\u63D0\u793A\u8A5E");
|
|
78927
|
-
mcpToolsPrompt += "\n\n## \u53EF\u7528\u5DE5\u5177\u5217\u8868\n\n";
|
|
78928
|
-
for (const tool of allTools) {
|
|
78929
|
-
mcpToolsPrompt += `### ${tool.name}
|
|
78930
|
-
`;
|
|
78931
|
-
if (tool.description) {
|
|
78932
|
-
mcpToolsPrompt += `${tool.description}
|
|
78933
|
-
`;
|
|
78934
|
-
}
|
|
78935
|
-
if (tool.inputSchema) {
|
|
78936
|
-
mcpToolsPrompt += "\n\u53C3\u6578\u683C\u5F0F:\n```json\n";
|
|
78937
|
-
mcpToolsPrompt += JSON.stringify(tool.inputSchema, null, 2);
|
|
78938
|
-
mcpToolsPrompt += "\n```\n";
|
|
78939
|
-
}
|
|
78940
|
-
mcpToolsPrompt += "\n";
|
|
78941
|
-
}
|
|
78942
|
-
}
|
|
78943
|
-
} else {
|
|
78944
|
-
logger.debug("[AI Service] \u4F7F\u7528\u9810\u8A2D\u7684 buildToolsPrompt");
|
|
78945
|
-
mcpToolsPrompt = buildToolsPrompt(allTools, request.projectName, request.projectPath);
|
|
78946
|
-
}
|
|
78947
|
-
} catch (error2) {
|
|
78948
|
-
logger.warn("[AI Service] Failed to get MCP tools for AI prompt", error2);
|
|
78864
|
+
mcpTools = allTools.map((t) => ({
|
|
78865
|
+
name: t.name,
|
|
78866
|
+
description: t.description,
|
|
78867
|
+
inputSchema: t.inputSchema
|
|
78868
|
+
}));
|
|
78869
|
+
} catch {
|
|
78870
|
+
logger.warn("[AI Service] \u7121\u6CD5\u7372\u53D6 MCP \u5DE5\u5177");
|
|
78949
78871
|
}
|
|
78950
78872
|
}
|
|
78951
|
-
|
|
78952
|
-
|
|
78953
|
-
|
|
78954
|
-
|
|
78955
|
-
|
|
78873
|
+
const context = aggregator.buildContextSync(request, settings, cliSettings, mcpTools);
|
|
78874
|
+
context.mode = "api";
|
|
78875
|
+
const aggregated = aggregator.aggregate(context);
|
|
78876
|
+
const promptSent = aggregated.fullPrompt;
|
|
78877
|
+
logger.debug("[AI Service] PromptAggregator \u69CB\u5EFA\u5B8C\u6210", {
|
|
78878
|
+
componentCount: aggregated.sections.length,
|
|
78879
|
+
sections: aggregated.sections.map((s) => `${s.name}(order:${s.order})`),
|
|
78880
|
+
totalLength: promptSent.length,
|
|
78881
|
+
tokenEstimate: aggregated.metadata.tokenEstimate
|
|
78956
78882
|
});
|
|
78957
|
-
const
|
|
78958
|
-
settings.systemPrompt,
|
|
78959
|
-
request.aiMessage,
|
|
78960
|
-
request.userContext,
|
|
78961
|
-
mcpToolsPrompt,
|
|
78962
|
-
request.toolResults
|
|
78963
|
-
);
|
|
78964
|
-
const reply = await generateWithRetry(
|
|
78883
|
+
const reply = await generateWithRetryFromPrompt(
|
|
78965
78884
|
settings.apiKey,
|
|
78966
78885
|
settings.model,
|
|
78967
|
-
|
|
78968
|
-
request.aiMessage,
|
|
78969
|
-
request.userContext,
|
|
78886
|
+
promptSent,
|
|
78970
78887
|
settings.temperature,
|
|
78971
|
-
settings.maxTokens
|
|
78972
|
-
0,
|
|
78973
|
-
mcpToolsPrompt,
|
|
78974
|
-
request.toolResults
|
|
78888
|
+
settings.maxTokens
|
|
78975
78889
|
);
|
|
78976
|
-
|
|
78977
|
-
replyLength: reply.length
|
|
78978
|
-
});
|
|
78890
|
+
const elapsedMs = Date.now() - startTime;
|
|
78979
78891
|
if (!request.toolResults) {
|
|
78980
|
-
cache.set(cacheKey, {
|
|
78981
|
-
reply,
|
|
78982
|
-
timestamp: Date.now()
|
|
78983
|
-
});
|
|
78892
|
+
cache.set(cacheKey, { reply, timestamp: Date.now() });
|
|
78984
78893
|
cleanExpiredCache();
|
|
78985
78894
|
}
|
|
78986
|
-
|
|
78895
|
+
const promptConfigs = aggregator.getPromptConfigsForDebug();
|
|
78987
78896
|
return {
|
|
78988
78897
|
success: true,
|
|
78989
78898
|
reply,
|
|
78990
78899
|
promptSent,
|
|
78991
|
-
mode: "api"
|
|
78900
|
+
mode: "api",
|
|
78901
|
+
debug: {
|
|
78902
|
+
sections: aggregated.sections.map((s) => ({ name: s.name, order: s.order, length: s.content.length })),
|
|
78903
|
+
tokenEstimate: aggregated.metadata.tokenEstimate,
|
|
78904
|
+
totalPromptLength: promptSent.length,
|
|
78905
|
+
elapsedMs,
|
|
78906
|
+
model: settings.model,
|
|
78907
|
+
temperature: settings.temperature,
|
|
78908
|
+
maxTokens: settings.maxTokens,
|
|
78909
|
+
mcpToolsCount: mcpTools.length,
|
|
78910
|
+
componentCount: aggregated.sections.length,
|
|
78911
|
+
promptConfigs
|
|
78912
|
+
}
|
|
78992
78913
|
};
|
|
78993
78914
|
} catch (error2) {
|
|
78915
|
+
const elapsedMs = Date.now() - startTime;
|
|
78994
78916
|
logger.error("[AI Service] AI service error:", error2);
|
|
78995
78917
|
return {
|
|
78996
78918
|
success: false,
|
|
78997
78919
|
error: error2 instanceof Error ? error2.message : "\u672A\u77E5\u932F\u8AA4",
|
|
78998
|
-
mode: "api"
|
|
78920
|
+
mode: "api",
|
|
78921
|
+
debug: { elapsedMs }
|
|
78999
78922
|
};
|
|
79000
78923
|
}
|
|
79001
78924
|
}
|
|
79002
|
-
async function
|
|
78925
|
+
async function generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount = 0) {
|
|
79003
78926
|
try {
|
|
79004
|
-
logger.debug("[AI Service] generateWithRetry \u958B\u59CB", {
|
|
79005
|
-
model,
|
|
79006
|
-
retryCount,
|
|
79007
|
-
hasSystemPrompt: !!systemPrompt,
|
|
79008
|
-
hasMcpToolsPrompt: !!mcpToolsPrompt,
|
|
79009
|
-
hasToolResults: !!toolResults,
|
|
79010
|
-
temperature,
|
|
79011
|
-
maxTokens
|
|
79012
|
-
});
|
|
79013
78927
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
79014
78928
|
const generativeModel = genAI.getGenerativeModel({
|
|
79015
78929
|
model,
|
|
@@ -79018,45 +78932,20 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
79018
78932
|
maxOutputTokens: maxTokens ?? 1e3
|
|
79019
78933
|
}
|
|
79020
78934
|
});
|
|
79021
|
-
logger.debug("[AI Service] \
|
|
79022
|
-
const prompt = buildPrompt(systemPrompt, aiMessage, userContext, mcpToolsPrompt, toolResults);
|
|
79023
|
-
logger.debug("[AI Service] \u63D0\u793A\u8A5E\u69CB\u5EFA\u5B8C\u6210", {
|
|
79024
|
-
promptLength: prompt.length
|
|
79025
|
-
});
|
|
79026
|
-
logger.debug("[AI Service] \u958B\u59CB\u8ABF\u7528 Google Gemini API");
|
|
78935
|
+
logger.debug("[AI Service] \u958B\u59CB\u8ABF\u7528 API (PromptAggregator prompt)", { promptLength: prompt.length });
|
|
79027
78936
|
const result = await generativeModel.generateContent(prompt);
|
|
79028
|
-
logger.debug("[AI Service] API \u8ABF\u7528\u5B8C\u6210");
|
|
79029
78937
|
const response = await result.response;
|
|
79030
78938
|
const text = response.text();
|
|
79031
78939
|
if (!text) {
|
|
79032
78940
|
throw new Error("AI \u56DE\u8986\u70BA\u7A7A");
|
|
79033
78941
|
}
|
|
79034
|
-
logger.debug("[AI Service] \u56DE\u8986\u6587\u5B57\u7372\u53D6\u6210\u529F", {
|
|
79035
|
-
textLength: text.length
|
|
79036
|
-
});
|
|
79037
78942
|
return text;
|
|
79038
78943
|
} catch (error2) {
|
|
79039
|
-
logger.debug("[AI Service] generateWithRetry \u767C\u751F\u932F\u8AA4", {
|
|
79040
|
-
error: error2 instanceof Error ? error2.message : String(error2),
|
|
79041
|
-
retryCount
|
|
79042
|
-
});
|
|
79043
78944
|
if (error2 instanceof Error) {
|
|
79044
78945
|
if (error2.message.includes("429") || error2.message.includes("quota")) {
|
|
79045
78946
|
if (retryCount < MAX_RETRIES) {
|
|
79046
|
-
|
|
79047
|
-
|
|
79048
|
-
return generateWithRetry(
|
|
79049
|
-
apiKey,
|
|
79050
|
-
model,
|
|
79051
|
-
systemPrompt,
|
|
79052
|
-
aiMessage,
|
|
79053
|
-
userContext,
|
|
79054
|
-
temperature,
|
|
79055
|
-
maxTokens,
|
|
79056
|
-
retryCount + 1,
|
|
79057
|
-
mcpToolsPrompt,
|
|
79058
|
-
toolResults
|
|
79059
|
-
);
|
|
78947
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
78948
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
79060
78949
|
}
|
|
79061
78950
|
throw new Error("API \u914D\u984D\u5DF2\u7528\u76E1\u6216\u901F\u7387\u9650\u5236\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66");
|
|
79062
78951
|
}
|
|
@@ -79064,51 +78953,13 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
79064
78953
|
throw new Error("API Key \u7121\u6548\uFF0C\u8ACB\u6AA2\u67E5\u8A2D\u5B9A");
|
|
79065
78954
|
}
|
|
79066
78955
|
if (retryCount < MAX_RETRIES) {
|
|
79067
|
-
|
|
79068
|
-
|
|
79069
|
-
return generateWithRetry(
|
|
79070
|
-
apiKey,
|
|
79071
|
-
model,
|
|
79072
|
-
systemPrompt,
|
|
79073
|
-
aiMessage,
|
|
79074
|
-
userContext,
|
|
79075
|
-
temperature,
|
|
79076
|
-
maxTokens,
|
|
79077
|
-
retryCount + 1,
|
|
79078
|
-
mcpToolsPrompt,
|
|
79079
|
-
toolResults
|
|
79080
|
-
);
|
|
78956
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
78957
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
79081
78958
|
}
|
|
79082
78959
|
}
|
|
79083
78960
|
throw error2;
|
|
79084
78961
|
}
|
|
79085
78962
|
}
|
|
79086
|
-
function buildPrompt(systemPrompt, aiMessage, userContext, mcpToolsPrompt = "", toolResults) {
|
|
79087
|
-
let prompt = `${systemPrompt}
|
|
79088
|
-
|
|
79089
|
-
`;
|
|
79090
|
-
if (mcpToolsPrompt) {
|
|
79091
|
-
prompt += mcpToolsPrompt + "\n\n";
|
|
79092
|
-
}
|
|
79093
|
-
prompt += `AI \u5DE5\u4F5C\u532F\u5831\uFF1A
|
|
79094
|
-
${aiMessage}
|
|
79095
|
-
|
|
79096
|
-
`;
|
|
79097
|
-
if (userContext) {
|
|
79098
|
-
prompt += `\u4F7F\u7528\u8005\u4E0A\u4E0B\u6587\uFF1A
|
|
79099
|
-
${userContext}
|
|
79100
|
-
|
|
79101
|
-
`;
|
|
79102
|
-
}
|
|
79103
|
-
if (toolResults) {
|
|
79104
|
-
prompt += `\u5148\u524D\u5DE5\u5177\u57F7\u884C\u7D50\u679C\uFF1A
|
|
79105
|
-
${toolResults}
|
|
79106
|
-
|
|
79107
|
-
`;
|
|
79108
|
-
}
|
|
79109
|
-
prompt += "\u8ACB\u751F\u6210\u4E00\u500B\u7C21\u6F54\u3001\u5C08\u696D\u7684\u56DE\u61C9\uFF1A";
|
|
79110
|
-
return prompt;
|
|
79111
|
-
}
|
|
79112
78963
|
function sleep(ms) {
|
|
79113
78964
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
79114
78965
|
}
|
|
@@ -79208,7 +79059,6 @@ var init_ai_service = __esm({
|
|
|
79208
79059
|
init_cli_executor();
|
|
79209
79060
|
init_cli_detector();
|
|
79210
79061
|
init_prompt_aggregator2();
|
|
79211
|
-
init_mcp_tool_parser();
|
|
79212
79062
|
MAX_RETRIES = 3;
|
|
79213
79063
|
RETRY_DELAYS = [1e3, 2e3, 4e3];
|
|
79214
79064
|
cache = /* @__PURE__ */ new Map();
|
package/dist/index.cjs
CHANGED
|
@@ -75263,6 +75263,15 @@ var init_prompt_aggregator = __esm({
|
|
|
75263
75263
|
getComponentNames() {
|
|
75264
75264
|
return this.components.map((c) => c.getName());
|
|
75265
75265
|
}
|
|
75266
|
+
getPromptConfigsForDebug() {
|
|
75267
|
+
const configs = this.getPromptConfigsWithDefaults();
|
|
75268
|
+
return configs.map((c) => ({
|
|
75269
|
+
id: c.id,
|
|
75270
|
+
enabled: c.enabled,
|
|
75271
|
+
firstOrder: c.firstOrder,
|
|
75272
|
+
secondOrder: c.secondOrder
|
|
75273
|
+
}));
|
|
75274
|
+
}
|
|
75266
75275
|
getPromptConfigsWithDefaults() {
|
|
75267
75276
|
try {
|
|
75268
75277
|
const configs = getPromptConfigs();
|
|
@@ -75365,61 +75374,6 @@ function formatToolResults(results) {
|
|
|
75365
75374
|
}
|
|
75366
75375
|
return lines.join("\n");
|
|
75367
75376
|
}
|
|
75368
|
-
function buildToolsPrompt(tools, projectName, projectPath) {
|
|
75369
|
-
if (tools.length === 0) {
|
|
75370
|
-
return "";
|
|
75371
|
-
}
|
|
75372
|
-
const lines = [];
|
|
75373
|
-
if (projectName || projectPath) {
|
|
75374
|
-
lines.push("");
|
|
75375
|
-
lines.push("## \u5C08\u6848\u80CC\u666F\u8CC7\u8A0A");
|
|
75376
|
-
lines.push(`\u7576\u524D\u5C08\u6848: ${projectName || "\u672A\u547D\u540D\u5C08\u6848"}`);
|
|
75377
|
-
if (projectPath) {
|
|
75378
|
-
lines.push(`\u5C08\u6848\u8DEF\u5F91: ${projectPath}`);
|
|
75379
|
-
}
|
|
75380
|
-
lines.push("");
|
|
75381
|
-
lines.push("**\u91CD\u8981\u6307\u793A**: \u5728\u56DE\u8986\u4E4B\u524D\uFF0C\u4F60\u61C9\u8A72\u5148\u4F7F\u7528 MCP \u5DE5\u5177\u4F86\u67E5\u8A62\u5C08\u6848\u7684\u80CC\u666F\u8CC7\u8A0A\uFF1A");
|
|
75382
|
-
lines.push("1. \u5C08\u6848\u7684\u67B6\u69CB\u548C\u7D50\u69CB\uFF08\u5982\u4F7F\u7528 get_symbols_overview, list_dir \u7B49\uFF09");
|
|
75383
|
-
lines.push("2. \u5C08\u6848\u7684\u958B\u767C\u8A08\u5283\u548C\u898F\u7BC4\uFF08\u5982\u8B80\u53D6 openspec \u76EE\u9304\u4E2D\u7684\u6587\u4EF6\uFF09");
|
|
75384
|
-
lines.push("3. \u7576\u524D\u7684\u4EFB\u52D9\u548C\u9032\u5EA6");
|
|
75385
|
-
lines.push("");
|
|
75386
|
-
lines.push("**\u8ACB\u52D9\u5FC5\u5148\u8ABF\u7528\u5DE5\u5177\u67E5\u8A62\u5C08\u6848\u8CC7\u8A0A**\uFF0C\u7136\u5F8C\u6839\u64DA\u67E5\u8A62\u7D50\u679C\u63D0\u4F9B\u7CBE\u78BA\u7684\u56DE\u8986\u3002");
|
|
75387
|
-
}
|
|
75388
|
-
lines.push("");
|
|
75389
|
-
lines.push("## MCP \u5DE5\u5177\u4F7F\u7528\u8AAA\u660E");
|
|
75390
|
-
lines.push("");
|
|
75391
|
-
lines.push("\u7576\u4F60\u9700\u8981\u4F7F\u7528\u5DE5\u5177\u6642\uFF0C\u8ACB\u56DE\u8986\u4E00\u500B JSON \u683C\u5F0F\u7684\u5DE5\u5177\u8ABF\u7528\u8ACB\u6C42\uFF08\u4E0D\u8981\u6709\u5176\u4ED6\u6587\u5B57\uFF09\uFF1A");
|
|
75392
|
-
lines.push("");
|
|
75393
|
-
lines.push("```json");
|
|
75394
|
-
lines.push("{");
|
|
75395
|
-
lines.push(' "tool_calls": [');
|
|
75396
|
-
lines.push(' { "name": "\u5DE5\u5177\u540D\u7A31", "arguments": { "\u53C3\u6578\u540D": "\u53C3\u6578\u503C" } }');
|
|
75397
|
-
lines.push(" ],");
|
|
75398
|
-
lines.push(' "message": "\u8AAA\u660E\u4F60\u6B63\u5728\u505A\u4EC0\u9EBC\uFF08\u53EF\u9078\uFF09"');
|
|
75399
|
-
lines.push("}");
|
|
75400
|
-
lines.push("```");
|
|
75401
|
-
lines.push("");
|
|
75402
|
-
lines.push("\u5DE5\u5177\u57F7\u884C\u5F8C\uFF0C\u7D50\u679C\u6703\u56DE\u50B3\u7D66\u4F60\u3002\u4F60\u53EF\u4EE5\u7E7C\u7E8C\u8ABF\u7528\u66F4\u591A\u5DE5\u5177\uFF0C\u6216\u6839\u64DA\u7D50\u679C\u63D0\u4F9B\u6700\u7D42\u56DE\u8986\u3002");
|
|
75403
|
-
lines.push("\u7576\u4F60\u4E0D\u9700\u8981\u8ABF\u7528\u5DE5\u5177\u6642\uFF0C\u76F4\u63A5\u4EE5\u7D14\u6587\u5B57\u56DE\u8986\u5373\u53EF\u3002");
|
|
75404
|
-
lines.push("");
|
|
75405
|
-
lines.push("## \u53EF\u7528\u5DE5\u5177\u5217\u8868");
|
|
75406
|
-
lines.push("");
|
|
75407
|
-
for (const tool of tools) {
|
|
75408
|
-
lines.push(`### ${tool.name}`);
|
|
75409
|
-
if (tool.description) {
|
|
75410
|
-
lines.push(tool.description);
|
|
75411
|
-
}
|
|
75412
|
-
if (tool.inputSchema) {
|
|
75413
|
-
lines.push("");
|
|
75414
|
-
lines.push("\u53C3\u6578\u683C\u5F0F:");
|
|
75415
|
-
lines.push("```json");
|
|
75416
|
-
lines.push(JSON.stringify(tool.inputSchema, null, 2));
|
|
75417
|
-
lines.push("```");
|
|
75418
|
-
}
|
|
75419
|
-
lines.push("");
|
|
75420
|
-
}
|
|
75421
|
-
return lines.join("\n");
|
|
75422
|
-
}
|
|
75423
75377
|
var init_mcp_tool_parser = __esm({
|
|
75424
75378
|
"src/utils/mcp-tool-parser.ts"() {
|
|
75425
75379
|
"use strict";
|
|
@@ -75772,131 +75726,91 @@ async function generateCLIReply(request, cliSettings) {
|
|
|
75772
75726
|
}
|
|
75773
75727
|
}
|
|
75774
75728
|
async function generateAPIReply(request) {
|
|
75729
|
+
const startTime = Date.now();
|
|
75775
75730
|
try {
|
|
75776
75731
|
const cacheKey = `${request.aiMessage}:${request.userContext || ""}`;
|
|
75777
75732
|
if (!request.toolResults) {
|
|
75778
75733
|
const cached2 = cache.get(cacheKey);
|
|
75779
75734
|
if (cached2 && Date.now() - cached2.timestamp < CACHE_TTL2) {
|
|
75780
75735
|
logger.debug("[AI Service] \u4F7F\u7528\u5FEB\u53D6\u56DE\u8986");
|
|
75781
|
-
return {
|
|
75782
|
-
success: true,
|
|
75783
|
-
reply: cached2.reply
|
|
75784
|
-
};
|
|
75736
|
+
return { success: true, reply: cached2.reply };
|
|
75785
75737
|
}
|
|
75786
75738
|
}
|
|
75787
75739
|
logger.debug("[AI Service] \u7372\u53D6 AI \u8A2D\u5B9A");
|
|
75788
75740
|
const settings = getAISettings();
|
|
75789
|
-
logger.debug("[AI Service] AI \u8A2D\u5B9A\u7372\u53D6\u5B8C\u6210", {
|
|
75790
|
-
hasApiKey: !!settings?.apiKey,
|
|
75791
|
-
model: settings?.model,
|
|
75792
|
-
hasMcpToolsPrompt: !!settings?.mcpToolsPrompt
|
|
75793
|
-
});
|
|
75794
75741
|
if (!settings || !settings.apiKey || settings.apiKey === "YOUR_API_KEY_HERE") {
|
|
75795
75742
|
logger.warn("[AI Service] API Key \u672A\u8A2D\u5B9A\u6216\u7121\u6548");
|
|
75796
|
-
return {
|
|
75797
|
-
success: false,
|
|
75798
|
-
error: "\u8ACB\u5148\u5728\u8A2D\u5B9A\u4E2D\u914D\u7F6E AI API Key"
|
|
75799
|
-
};
|
|
75743
|
+
return { success: false, error: "\u8ACB\u5148\u5728\u8A2D\u5B9A\u4E2D\u914D\u7F6E AI API Key" };
|
|
75800
75744
|
}
|
|
75801
|
-
|
|
75745
|
+
const aggregator = getPromptAggregator();
|
|
75746
|
+
const cliSettings = getCLISettings();
|
|
75747
|
+
let mcpTools = [];
|
|
75802
75748
|
if (request.includeMCPTools) {
|
|
75803
|
-
logger.debug("[AI Service] \u958B\u59CB\u7372\u53D6 MCP \u5DE5\u5177");
|
|
75804
75749
|
try {
|
|
75805
75750
|
const allTools = mcpClientManager.getAllTools();
|
|
75806
|
-
|
|
75807
|
-
|
|
75808
|
-
|
|
75809
|
-
|
|
75810
|
-
|
|
75811
|
-
|
|
75812
|
-
|
|
75813
|
-
logger.debug("[AI Service] \u9644\u52A0\u5DE5\u5177\u5217\u8868\u5230\u63D0\u793A\u8A5E");
|
|
75814
|
-
mcpToolsPrompt += "\n\n## \u53EF\u7528\u5DE5\u5177\u5217\u8868\n\n";
|
|
75815
|
-
for (const tool of allTools) {
|
|
75816
|
-
mcpToolsPrompt += `### ${tool.name}
|
|
75817
|
-
`;
|
|
75818
|
-
if (tool.description) {
|
|
75819
|
-
mcpToolsPrompt += `${tool.description}
|
|
75820
|
-
`;
|
|
75821
|
-
}
|
|
75822
|
-
if (tool.inputSchema) {
|
|
75823
|
-
mcpToolsPrompt += "\n\u53C3\u6578\u683C\u5F0F:\n```json\n";
|
|
75824
|
-
mcpToolsPrompt += JSON.stringify(tool.inputSchema, null, 2);
|
|
75825
|
-
mcpToolsPrompt += "\n```\n";
|
|
75826
|
-
}
|
|
75827
|
-
mcpToolsPrompt += "\n";
|
|
75828
|
-
}
|
|
75829
|
-
}
|
|
75830
|
-
} else {
|
|
75831
|
-
logger.debug("[AI Service] \u4F7F\u7528\u9810\u8A2D\u7684 buildToolsPrompt");
|
|
75832
|
-
mcpToolsPrompt = buildToolsPrompt(allTools, request.projectName, request.projectPath);
|
|
75833
|
-
}
|
|
75834
|
-
} catch (error2) {
|
|
75835
|
-
logger.warn("[AI Service] Failed to get MCP tools for AI prompt", error2);
|
|
75751
|
+
mcpTools = allTools.map((t) => ({
|
|
75752
|
+
name: t.name,
|
|
75753
|
+
description: t.description,
|
|
75754
|
+
inputSchema: t.inputSchema
|
|
75755
|
+
}));
|
|
75756
|
+
} catch {
|
|
75757
|
+
logger.warn("[AI Service] \u7121\u6CD5\u7372\u53D6 MCP \u5DE5\u5177");
|
|
75836
75758
|
}
|
|
75837
75759
|
}
|
|
75838
|
-
|
|
75839
|
-
|
|
75840
|
-
|
|
75841
|
-
|
|
75842
|
-
|
|
75760
|
+
const context = aggregator.buildContextSync(request, settings, cliSettings, mcpTools);
|
|
75761
|
+
context.mode = "api";
|
|
75762
|
+
const aggregated = aggregator.aggregate(context);
|
|
75763
|
+
const promptSent = aggregated.fullPrompt;
|
|
75764
|
+
logger.debug("[AI Service] PromptAggregator \u69CB\u5EFA\u5B8C\u6210", {
|
|
75765
|
+
componentCount: aggregated.sections.length,
|
|
75766
|
+
sections: aggregated.sections.map((s) => `${s.name}(order:${s.order})`),
|
|
75767
|
+
totalLength: promptSent.length,
|
|
75768
|
+
tokenEstimate: aggregated.metadata.tokenEstimate
|
|
75843
75769
|
});
|
|
75844
|
-
const
|
|
75845
|
-
settings.systemPrompt,
|
|
75846
|
-
request.aiMessage,
|
|
75847
|
-
request.userContext,
|
|
75848
|
-
mcpToolsPrompt,
|
|
75849
|
-
request.toolResults
|
|
75850
|
-
);
|
|
75851
|
-
const reply = await generateWithRetry(
|
|
75770
|
+
const reply = await generateWithRetryFromPrompt(
|
|
75852
75771
|
settings.apiKey,
|
|
75853
75772
|
settings.model,
|
|
75854
|
-
|
|
75855
|
-
request.aiMessage,
|
|
75856
|
-
request.userContext,
|
|
75773
|
+
promptSent,
|
|
75857
75774
|
settings.temperature,
|
|
75858
|
-
settings.maxTokens
|
|
75859
|
-
0,
|
|
75860
|
-
mcpToolsPrompt,
|
|
75861
|
-
request.toolResults
|
|
75775
|
+
settings.maxTokens
|
|
75862
75776
|
);
|
|
75863
|
-
|
|
75864
|
-
replyLength: reply.length
|
|
75865
|
-
});
|
|
75777
|
+
const elapsedMs = Date.now() - startTime;
|
|
75866
75778
|
if (!request.toolResults) {
|
|
75867
|
-
cache.set(cacheKey, {
|
|
75868
|
-
reply,
|
|
75869
|
-
timestamp: Date.now()
|
|
75870
|
-
});
|
|
75779
|
+
cache.set(cacheKey, { reply, timestamp: Date.now() });
|
|
75871
75780
|
cleanExpiredCache();
|
|
75872
75781
|
}
|
|
75873
|
-
|
|
75782
|
+
const promptConfigs = aggregator.getPromptConfigsForDebug();
|
|
75874
75783
|
return {
|
|
75875
75784
|
success: true,
|
|
75876
75785
|
reply,
|
|
75877
75786
|
promptSent,
|
|
75878
|
-
mode: "api"
|
|
75787
|
+
mode: "api",
|
|
75788
|
+
debug: {
|
|
75789
|
+
sections: aggregated.sections.map((s) => ({ name: s.name, order: s.order, length: s.content.length })),
|
|
75790
|
+
tokenEstimate: aggregated.metadata.tokenEstimate,
|
|
75791
|
+
totalPromptLength: promptSent.length,
|
|
75792
|
+
elapsedMs,
|
|
75793
|
+
model: settings.model,
|
|
75794
|
+
temperature: settings.temperature,
|
|
75795
|
+
maxTokens: settings.maxTokens,
|
|
75796
|
+
mcpToolsCount: mcpTools.length,
|
|
75797
|
+
componentCount: aggregated.sections.length,
|
|
75798
|
+
promptConfigs
|
|
75799
|
+
}
|
|
75879
75800
|
};
|
|
75880
75801
|
} catch (error2) {
|
|
75802
|
+
const elapsedMs = Date.now() - startTime;
|
|
75881
75803
|
logger.error("[AI Service] AI service error:", error2);
|
|
75882
75804
|
return {
|
|
75883
75805
|
success: false,
|
|
75884
75806
|
error: error2 instanceof Error ? error2.message : "\u672A\u77E5\u932F\u8AA4",
|
|
75885
|
-
mode: "api"
|
|
75807
|
+
mode: "api",
|
|
75808
|
+
debug: { elapsedMs }
|
|
75886
75809
|
};
|
|
75887
75810
|
}
|
|
75888
75811
|
}
|
|
75889
|
-
async function
|
|
75812
|
+
async function generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount = 0) {
|
|
75890
75813
|
try {
|
|
75891
|
-
logger.debug("[AI Service] generateWithRetry \u958B\u59CB", {
|
|
75892
|
-
model,
|
|
75893
|
-
retryCount,
|
|
75894
|
-
hasSystemPrompt: !!systemPrompt,
|
|
75895
|
-
hasMcpToolsPrompt: !!mcpToolsPrompt,
|
|
75896
|
-
hasToolResults: !!toolResults,
|
|
75897
|
-
temperature,
|
|
75898
|
-
maxTokens
|
|
75899
|
-
});
|
|
75900
75814
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
75901
75815
|
const generativeModel = genAI.getGenerativeModel({
|
|
75902
75816
|
model,
|
|
@@ -75905,45 +75819,20 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
75905
75819
|
maxOutputTokens: maxTokens ?? 1e3
|
|
75906
75820
|
}
|
|
75907
75821
|
});
|
|
75908
|
-
logger.debug("[AI Service] \
|
|
75909
|
-
const prompt = buildPrompt(systemPrompt, aiMessage, userContext, mcpToolsPrompt, toolResults);
|
|
75910
|
-
logger.debug("[AI Service] \u63D0\u793A\u8A5E\u69CB\u5EFA\u5B8C\u6210", {
|
|
75911
|
-
promptLength: prompt.length
|
|
75912
|
-
});
|
|
75913
|
-
logger.debug("[AI Service] \u958B\u59CB\u8ABF\u7528 Google Gemini API");
|
|
75822
|
+
logger.debug("[AI Service] \u958B\u59CB\u8ABF\u7528 API (PromptAggregator prompt)", { promptLength: prompt.length });
|
|
75914
75823
|
const result = await generativeModel.generateContent(prompt);
|
|
75915
|
-
logger.debug("[AI Service] API \u8ABF\u7528\u5B8C\u6210");
|
|
75916
75824
|
const response = await result.response;
|
|
75917
75825
|
const text = response.text();
|
|
75918
75826
|
if (!text) {
|
|
75919
75827
|
throw new Error("AI \u56DE\u8986\u70BA\u7A7A");
|
|
75920
75828
|
}
|
|
75921
|
-
logger.debug("[AI Service] \u56DE\u8986\u6587\u5B57\u7372\u53D6\u6210\u529F", {
|
|
75922
|
-
textLength: text.length
|
|
75923
|
-
});
|
|
75924
75829
|
return text;
|
|
75925
75830
|
} catch (error2) {
|
|
75926
|
-
logger.debug("[AI Service] generateWithRetry \u767C\u751F\u932F\u8AA4", {
|
|
75927
|
-
error: error2 instanceof Error ? error2.message : String(error2),
|
|
75928
|
-
retryCount
|
|
75929
|
-
});
|
|
75930
75831
|
if (error2 instanceof Error) {
|
|
75931
75832
|
if (error2.message.includes("429") || error2.message.includes("quota")) {
|
|
75932
75833
|
if (retryCount < MAX_RETRIES) {
|
|
75933
|
-
|
|
75934
|
-
|
|
75935
|
-
return generateWithRetry(
|
|
75936
|
-
apiKey,
|
|
75937
|
-
model,
|
|
75938
|
-
systemPrompt,
|
|
75939
|
-
aiMessage,
|
|
75940
|
-
userContext,
|
|
75941
|
-
temperature,
|
|
75942
|
-
maxTokens,
|
|
75943
|
-
retryCount + 1,
|
|
75944
|
-
mcpToolsPrompt,
|
|
75945
|
-
toolResults
|
|
75946
|
-
);
|
|
75834
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
75835
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
75947
75836
|
}
|
|
75948
75837
|
throw new Error("API \u914D\u984D\u5DF2\u7528\u76E1\u6216\u901F\u7387\u9650\u5236\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66");
|
|
75949
75838
|
}
|
|
@@ -75951,51 +75840,13 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
75951
75840
|
throw new Error("API Key \u7121\u6548\uFF0C\u8ACB\u6AA2\u67E5\u8A2D\u5B9A");
|
|
75952
75841
|
}
|
|
75953
75842
|
if (retryCount < MAX_RETRIES) {
|
|
75954
|
-
|
|
75955
|
-
|
|
75956
|
-
return generateWithRetry(
|
|
75957
|
-
apiKey,
|
|
75958
|
-
model,
|
|
75959
|
-
systemPrompt,
|
|
75960
|
-
aiMessage,
|
|
75961
|
-
userContext,
|
|
75962
|
-
temperature,
|
|
75963
|
-
maxTokens,
|
|
75964
|
-
retryCount + 1,
|
|
75965
|
-
mcpToolsPrompt,
|
|
75966
|
-
toolResults
|
|
75967
|
-
);
|
|
75843
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
75844
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
75968
75845
|
}
|
|
75969
75846
|
}
|
|
75970
75847
|
throw error2;
|
|
75971
75848
|
}
|
|
75972
75849
|
}
|
|
75973
|
-
function buildPrompt(systemPrompt, aiMessage, userContext, mcpToolsPrompt = "", toolResults) {
|
|
75974
|
-
let prompt = `${systemPrompt}
|
|
75975
|
-
|
|
75976
|
-
`;
|
|
75977
|
-
if (mcpToolsPrompt) {
|
|
75978
|
-
prompt += mcpToolsPrompt + "\n\n";
|
|
75979
|
-
}
|
|
75980
|
-
prompt += `AI \u5DE5\u4F5C\u532F\u5831\uFF1A
|
|
75981
|
-
${aiMessage}
|
|
75982
|
-
|
|
75983
|
-
`;
|
|
75984
|
-
if (userContext) {
|
|
75985
|
-
prompt += `\u4F7F\u7528\u8005\u4E0A\u4E0B\u6587\uFF1A
|
|
75986
|
-
${userContext}
|
|
75987
|
-
|
|
75988
|
-
`;
|
|
75989
|
-
}
|
|
75990
|
-
if (toolResults) {
|
|
75991
|
-
prompt += `\u5148\u524D\u5DE5\u5177\u57F7\u884C\u7D50\u679C\uFF1A
|
|
75992
|
-
${toolResults}
|
|
75993
|
-
|
|
75994
|
-
`;
|
|
75995
|
-
}
|
|
75996
|
-
prompt += "\u8ACB\u751F\u6210\u4E00\u500B\u7C21\u6F54\u3001\u5C08\u696D\u7684\u56DE\u61C9\uFF1A";
|
|
75997
|
-
return prompt;
|
|
75998
|
-
}
|
|
75999
75850
|
function sleep(ms) {
|
|
76000
75851
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
76001
75852
|
}
|
|
@@ -76095,7 +75946,6 @@ var init_ai_service = __esm({
|
|
|
76095
75946
|
init_cli_executor();
|
|
76096
75947
|
init_cli_detector();
|
|
76097
75948
|
init_prompt_aggregator2();
|
|
76098
|
-
init_mcp_tool_parser();
|
|
76099
75949
|
MAX_RETRIES = 3;
|
|
76100
75950
|
RETRY_DELAYS = [1e3, 2e3, 4e3];
|
|
76101
75951
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* conversation-panel.js
|
|
3
3
|
* 對話面板元件 - 顯示 AI 對話流程
|
|
4
|
-
* 支援
|
|
4
|
+
* 支援 7 種對話條目類型: prompt, thinking, tool, result, ai, error, debug
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { escapeHtml } from './ui-helpers.js';
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* 對話條目類型
|
|
11
|
-
*/
|
|
12
9
|
export const ConversationEntryType = {
|
|
13
10
|
PROMPT: 'prompt',
|
|
14
11
|
THINKING: 'thinking',
|
|
15
12
|
TOOL: 'tool',
|
|
16
13
|
RESULT: 'result',
|
|
17
14
|
AI: 'ai',
|
|
18
|
-
ERROR: 'error'
|
|
15
|
+
ERROR: 'error',
|
|
16
|
+
DEBUG: 'debug'
|
|
19
17
|
};
|
|
20
18
|
|
|
21
|
-
/**
|
|
22
|
-
* 對話條目視覺配置
|
|
23
|
-
*/
|
|
24
19
|
const entryConfig = {
|
|
25
20
|
prompt: {
|
|
26
21
|
icon: '📤',
|
|
@@ -57,12 +52,15 @@ const entryConfig = {
|
|
|
57
52
|
title: '錯誤',
|
|
58
53
|
className: 'entry-error',
|
|
59
54
|
borderColor: 'var(--accent-red)'
|
|
55
|
+
},
|
|
56
|
+
debug: {
|
|
57
|
+
icon: '🐛',
|
|
58
|
+
title: 'Debug',
|
|
59
|
+
className: 'entry-debug',
|
|
60
|
+
borderColor: 'var(--accent-orange, #f97316)'
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
63
|
|
|
63
|
-
/**
|
|
64
|
-
* 建立對話面板容器
|
|
65
|
-
*/
|
|
66
64
|
export function createConversationPanel() {
|
|
67
65
|
const panel = document.createElement('div');
|
|
68
66
|
panel.id = 'conversationPanel';
|
|
@@ -73,14 +71,18 @@ export function createConversationPanel() {
|
|
|
73
71
|
<span class="icon">💬</span>
|
|
74
72
|
<span id="conversationTitle">AI 對話</span>
|
|
75
73
|
</div>
|
|
76
|
-
<div class="conversation-
|
|
77
|
-
<
|
|
78
|
-
|
|
74
|
+
<div class="conversation-header-right">
|
|
75
|
+
<div class="conversation-mode">
|
|
76
|
+
<span class="mode-indicator" id="conversationModeIndicator"></span>
|
|
77
|
+
<span id="conversationMode">準備中</span>
|
|
78
|
+
</div>
|
|
79
|
+
<label class="debug-toggle" title="顯示 Debug 資訊">
|
|
80
|
+
<input type="checkbox" id="debugToggle">
|
|
81
|
+
<span>🐛</span>
|
|
82
|
+
</label>
|
|
79
83
|
</div>
|
|
80
84
|
</div>
|
|
81
|
-
<div class="conversation-body" id="conversationBody">
|
|
82
|
-
<!-- 對話條目會動態添加 -->
|
|
83
|
-
</div>
|
|
85
|
+
<div class="conversation-body" id="conversationBody"></div>
|
|
84
86
|
<div class="conversation-footer">
|
|
85
87
|
<button type="button" id="closeConversation" class="btn btn-secondary">關閉</button>
|
|
86
88
|
</div>
|
|
@@ -88,9 +90,6 @@ export function createConversationPanel() {
|
|
|
88
90
|
return panel;
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
/**
|
|
92
|
-
* 建立對話條目元素
|
|
93
|
-
*/
|
|
94
93
|
export function createConversationEntry(type, content, options = {}) {
|
|
95
94
|
const config = entryConfig[type] || entryConfig.ai;
|
|
96
95
|
const entry = document.createElement('div');
|
|
@@ -98,7 +97,7 @@ export function createConversationEntry(type, content, options = {}) {
|
|
|
98
97
|
entry.style.borderLeftColor = config.borderColor;
|
|
99
98
|
|
|
100
99
|
const titleText = options.title || config.title;
|
|
101
|
-
const collapsed = options.collapsed ?? (type === 'prompt' || type === 'tool');
|
|
100
|
+
const collapsed = options.collapsed ?? (type === 'prompt' || type === 'tool' || type === 'debug');
|
|
102
101
|
const timestamp = options.timestamp ? formatTimestamp(options.timestamp) : '';
|
|
103
102
|
|
|
104
103
|
let contentHtml = '';
|
|
@@ -126,8 +125,93 @@ export function createConversationEntry(type, content, options = {}) {
|
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
/**
|
|
129
|
-
*
|
|
128
|
+
* 建立 Debug 資訊條目(結構化表格)
|
|
130
129
|
*/
|
|
130
|
+
export function createDebugEntry(debugInfo, options = {}) {
|
|
131
|
+
const config = entryConfig.debug;
|
|
132
|
+
const entry = document.createElement('div');
|
|
133
|
+
entry.className = `conversation-entry ${config.className}`;
|
|
134
|
+
entry.style.borderLeftColor = config.borderColor;
|
|
135
|
+
|
|
136
|
+
const titleText = options.title || config.title;
|
|
137
|
+
const collapsed = options.collapsed ?? true;
|
|
138
|
+
const timestamp = options.timestamp ? formatTimestamp(options.timestamp) : '';
|
|
139
|
+
|
|
140
|
+
let bodyHtml = '<div class="debug-info-grid">';
|
|
141
|
+
|
|
142
|
+
if (debugInfo.elapsedMs !== undefined) {
|
|
143
|
+
bodyHtml += debugRow('⏱️ 耗時', `${debugInfo.elapsedMs} ms`);
|
|
144
|
+
}
|
|
145
|
+
if (debugInfo.model) {
|
|
146
|
+
bodyHtml += debugRow('🧠 模型', debugInfo.model);
|
|
147
|
+
}
|
|
148
|
+
if (debugInfo.temperature !== undefined) {
|
|
149
|
+
bodyHtml += debugRow('🌡️ Temperature', debugInfo.temperature);
|
|
150
|
+
}
|
|
151
|
+
if (debugInfo.maxTokens !== undefined) {
|
|
152
|
+
bodyHtml += debugRow('📏 Max Tokens', debugInfo.maxTokens);
|
|
153
|
+
}
|
|
154
|
+
if (debugInfo.tokenEstimate !== undefined) {
|
|
155
|
+
bodyHtml += debugRow('🔢 Token 預估', `~${debugInfo.tokenEstimate}`);
|
|
156
|
+
}
|
|
157
|
+
if (debugInfo.totalPromptLength !== undefined) {
|
|
158
|
+
bodyHtml += debugRow('📐 Prompt 長度', `${debugInfo.totalPromptLength} chars`);
|
|
159
|
+
}
|
|
160
|
+
if (debugInfo.componentCount !== undefined) {
|
|
161
|
+
bodyHtml += debugRow('🧩 組件數量', debugInfo.componentCount);
|
|
162
|
+
}
|
|
163
|
+
if (debugInfo.mcpToolsCount !== undefined) {
|
|
164
|
+
bodyHtml += debugRow('🔧 MCP 工具數', debugInfo.mcpToolsCount);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
bodyHtml += '</div>';
|
|
168
|
+
|
|
169
|
+
if (debugInfo.sections && debugInfo.sections.length > 0) {
|
|
170
|
+
bodyHtml += '<div class="debug-sections">';
|
|
171
|
+
bodyHtml += '<div class="debug-section-title">📋 提示詞區段順序(實際送出)</div>';
|
|
172
|
+
bodyHtml += '<table class="debug-table"><thead><tr><th>#</th><th>區段名稱</th><th>順序</th><th>長度</th></tr></thead><tbody>';
|
|
173
|
+
debugInfo.sections.forEach((s, i) => {
|
|
174
|
+
bodyHtml += `<tr><td>${i + 1}</td><td>${escapeHtml(s.name)}</td><td>${s.order}</td><td>${s.length} chars</td></tr>`;
|
|
175
|
+
});
|
|
176
|
+
bodyHtml += '</tbody></table></div>';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (debugInfo.promptConfigs && debugInfo.promptConfigs.length > 0) {
|
|
180
|
+
bodyHtml += '<div class="debug-sections">';
|
|
181
|
+
bodyHtml += '<div class="debug-section-title">⚙️ 提示詞配置(設定值)</div>';
|
|
182
|
+
bodyHtml += '<table class="debug-table"><thead><tr><th>ID</th><th>啟用</th><th>第一次</th><th>第二次</th></tr></thead><tbody>';
|
|
183
|
+
debugInfo.promptConfigs.forEach(c => {
|
|
184
|
+
const enabledIcon = c.enabled ? '✅' : '❌';
|
|
185
|
+
bodyHtml += `<tr><td>${escapeHtml(c.id)}</td><td>${enabledIcon}</td><td>${c.firstOrder}</td><td>${c.secondOrder}</td></tr>`;
|
|
186
|
+
});
|
|
187
|
+
bodyHtml += '</tbody></table></div>';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (debugInfo.error) {
|
|
191
|
+
bodyHtml += `<div class="debug-error">❌ 錯誤: ${escapeHtml(debugInfo.error)}</div>`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
entry.innerHTML = `
|
|
195
|
+
<details ${collapsed ? '' : 'open'}>
|
|
196
|
+
<summary class="entry-summary">
|
|
197
|
+
<span class="entry-icon">${config.icon}</span>
|
|
198
|
+
<span class="entry-title">${titleText}</span>
|
|
199
|
+
${timestamp ? `<span class="entry-timestamp">${timestamp}</span>` : ''}
|
|
200
|
+
${options.badge ? `<span class="entry-badge">${options.badge}</span>` : ''}
|
|
201
|
+
</summary>
|
|
202
|
+
<div class="entry-body debug-body">
|
|
203
|
+
${bodyHtml}
|
|
204
|
+
</div>
|
|
205
|
+
</details>
|
|
206
|
+
`;
|
|
207
|
+
|
|
208
|
+
return entry;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function debugRow(label, value) {
|
|
212
|
+
return `<div class="debug-row"><span class="debug-label">${label}</span><span class="debug-value">${escapeHtml(String(value))}</span></div>`;
|
|
213
|
+
}
|
|
214
|
+
|
|
131
215
|
export function addConversationEntry(type, content, options = {}) {
|
|
132
216
|
const body = document.getElementById('conversationBody');
|
|
133
217
|
if (!body) return null;
|
|
@@ -135,13 +219,25 @@ export function addConversationEntry(type, content, options = {}) {
|
|
|
135
219
|
const entry = createConversationEntry(type, content, options);
|
|
136
220
|
body.appendChild(entry);
|
|
137
221
|
body.scrollTop = body.scrollHeight;
|
|
222
|
+
return entry;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function addDebugEntry(debugInfo, options = {}) {
|
|
226
|
+
const body = document.getElementById('conversationBody');
|
|
227
|
+
if (!body) return null;
|
|
228
|
+
|
|
229
|
+
const entry = createDebugEntry(debugInfo, options);
|
|
230
|
+
body.appendChild(entry);
|
|
231
|
+
body.scrollTop = body.scrollHeight;
|
|
232
|
+
|
|
233
|
+
const debugToggle = document.getElementById('debugToggle');
|
|
234
|
+
if (debugToggle && !debugToggle.checked) {
|
|
235
|
+
entry.style.display = 'none';
|
|
236
|
+
}
|
|
138
237
|
|
|
139
238
|
return entry;
|
|
140
239
|
}
|
|
141
240
|
|
|
142
|
-
/**
|
|
143
|
-
* 清空對話面板
|
|
144
|
-
*/
|
|
145
241
|
export function clearConversationPanel() {
|
|
146
242
|
const body = document.getElementById('conversationBody');
|
|
147
243
|
if (body) {
|
|
@@ -149,9 +245,6 @@ export function clearConversationPanel() {
|
|
|
149
245
|
}
|
|
150
246
|
}
|
|
151
247
|
|
|
152
|
-
/**
|
|
153
|
-
* 更新對話面板模式顯示
|
|
154
|
-
*/
|
|
155
248
|
export function updateConversationMode(mode, cliTool = null) {
|
|
156
249
|
const modeElement = document.getElementById('conversationMode');
|
|
157
250
|
const indicator = document.getElementById('conversationModeIndicator');
|
|
@@ -176,9 +269,6 @@ export function updateConversationMode(mode, cliTool = null) {
|
|
|
176
269
|
}
|
|
177
270
|
}
|
|
178
271
|
|
|
179
|
-
/**
|
|
180
|
-
* 更新對話面板標題
|
|
181
|
-
*/
|
|
182
272
|
export function updateConversationTitle(title) {
|
|
183
273
|
const titleElement = document.getElementById('conversationTitle');
|
|
184
274
|
if (titleElement) {
|
|
@@ -186,9 +276,6 @@ export function updateConversationTitle(title) {
|
|
|
186
276
|
}
|
|
187
277
|
}
|
|
188
278
|
|
|
189
|
-
/**
|
|
190
|
-
* 顯示對話面板
|
|
191
|
-
*/
|
|
192
279
|
export function showConversationPanel() {
|
|
193
280
|
let panel = document.getElementById('aiConversationPanel');
|
|
194
281
|
if (!panel) {
|
|
@@ -202,14 +289,21 @@ export function showConversationPanel() {
|
|
|
202
289
|
if (closeBtn) {
|
|
203
290
|
closeBtn.onclick = hideConversationPanel;
|
|
204
291
|
}
|
|
292
|
+
|
|
293
|
+
const debugToggle = panel.querySelector('#debugToggle');
|
|
294
|
+
if (debugToggle) {
|
|
295
|
+
debugToggle.addEventListener('change', (e) => {
|
|
296
|
+
const show = e.target.checked;
|
|
297
|
+
panel.querySelectorAll('.entry-debug').forEach(el => {
|
|
298
|
+
el.style.display = show ? '' : 'none';
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
}
|
|
205
302
|
}
|
|
206
303
|
panel.style.display = 'flex';
|
|
207
304
|
clearConversationPanel();
|
|
208
305
|
}
|
|
209
306
|
|
|
210
|
-
/**
|
|
211
|
-
* 隱藏對話面板
|
|
212
|
-
*/
|
|
213
307
|
export function hideConversationPanel() {
|
|
214
308
|
const panel = document.getElementById('aiConversationPanel');
|
|
215
309
|
if (panel) {
|
|
@@ -217,17 +311,11 @@ export function hideConversationPanel() {
|
|
|
217
311
|
}
|
|
218
312
|
}
|
|
219
313
|
|
|
220
|
-
/**
|
|
221
|
-
* 格式化時間戳記
|
|
222
|
-
*/
|
|
223
314
|
function formatTimestamp(timestamp) {
|
|
224
315
|
const date = new Date(timestamp);
|
|
225
316
|
return date.toLocaleTimeString('zh-TW', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
226
317
|
}
|
|
227
318
|
|
|
228
|
-
/**
|
|
229
|
-
* 新增思考中動畫條目
|
|
230
|
-
*/
|
|
231
319
|
export function addThinkingEntry(message = 'AI 思考中...') {
|
|
232
320
|
return addConversationEntry(ConversationEntryType.THINKING, message, {
|
|
233
321
|
collapsed: false,
|
|
@@ -235,13 +323,10 @@ export function addThinkingEntry(message = 'AI 思考中...') {
|
|
|
235
323
|
});
|
|
236
324
|
}
|
|
237
325
|
|
|
238
|
-
/**
|
|
239
|
-
* 移除思考中條目
|
|
240
|
-
*/
|
|
241
326
|
export function removeThinkingEntry() {
|
|
242
327
|
const body = document.getElementById('conversationBody');
|
|
243
328
|
if (!body) return;
|
|
244
|
-
|
|
329
|
+
|
|
245
330
|
const thinkingEntries = body.querySelectorAll('.entry-thinking');
|
|
246
331
|
thinkingEntries.forEach(entry => entry.remove());
|
|
247
332
|
}
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
showConversationPanel,
|
|
39
39
|
hideConversationPanel,
|
|
40
40
|
addConversationEntry,
|
|
41
|
+
addDebugEntry,
|
|
41
42
|
clearConversationPanel,
|
|
42
43
|
updateConversationMode,
|
|
43
44
|
updateConversationTitle,
|
|
@@ -170,10 +171,18 @@ export async function generateAIReply() {
|
|
|
170
171
|
const data = await response.json();
|
|
171
172
|
removeThinkingEntry();
|
|
172
173
|
|
|
174
|
+
if (data.debug) {
|
|
175
|
+
addDebugEntry(data.debug, {
|
|
176
|
+
title: "Debug 資訊",
|
|
177
|
+
collapsed: true,
|
|
178
|
+
timestamp: Date.now(),
|
|
179
|
+
badge: data.debug.elapsedMs ? `${data.debug.elapsedMs}ms` : undefined,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
173
183
|
if (data.success) {
|
|
174
184
|
updateConversationMode(data.mode, data.cliTool);
|
|
175
185
|
|
|
176
|
-
// 如果有 fallback 原因,顯示通知
|
|
177
186
|
if (data.fallbackReason) {
|
|
178
187
|
showToast("warning", "模式切換", data.fallbackReason);
|
|
179
188
|
}
|
|
@@ -199,7 +208,6 @@ export async function generateAIReply() {
|
|
|
199
208
|
document.getElementById("feedbackText").value = finalReply;
|
|
200
209
|
updateCharCount();
|
|
201
210
|
|
|
202
|
-
// 如果是 fallback,badge 顯示不同的樣式
|
|
203
211
|
let badge = data.mode === "cli" ? `CLI (${data.cliTool})` : "API";
|
|
204
212
|
if (data.fallbackReason) {
|
|
205
213
|
badge = "API (fallback)";
|
|
@@ -905,6 +913,15 @@ export async function generateAIReplyWithTools() {
|
|
|
905
913
|
const data = await response.json();
|
|
906
914
|
removeThinkingEntry();
|
|
907
915
|
|
|
916
|
+
if (data.debug) {
|
|
917
|
+
addDebugEntry(data.debug, {
|
|
918
|
+
title: `Debug (第 ${round} 輪)`,
|
|
919
|
+
collapsed: true,
|
|
920
|
+
timestamp: Date.now(),
|
|
921
|
+
badge: data.debug.elapsedMs ? `${data.debug.elapsedMs}ms` : undefined,
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
|
|
908
925
|
if (!data.success) {
|
|
909
926
|
addConversationEntry(ConversationEntryType.ERROR, data.error || "AI 回覆失敗", {
|
|
910
927
|
title: "錯誤",
|
|
@@ -917,12 +934,10 @@ export async function generateAIReplyWithTools() {
|
|
|
917
934
|
|
|
918
935
|
updateConversationMode(data.mode, data.cliTool);
|
|
919
936
|
|
|
920
|
-
// 如果有 fallback 原因,顯示通知
|
|
921
937
|
if (data.fallbackReason) {
|
|
922
938
|
showToast("warning", "模式切換", data.fallbackReason);
|
|
923
939
|
}
|
|
924
940
|
|
|
925
|
-
// 如果是 fallback,badge 顯示不同的樣式
|
|
926
941
|
let badgeTools1 = data.mode === "cli" ? `CLI (${data.cliTool})` : "API";
|
|
927
942
|
if (data.fallbackReason) {
|
|
928
943
|
badgeTools1 = "API (fallback)";
|
|
@@ -1092,10 +1107,18 @@ export async function triggerAutoAIReply() {
|
|
|
1092
1107
|
const data = await response.json();
|
|
1093
1108
|
removeThinkingEntry();
|
|
1094
1109
|
|
|
1110
|
+
if (data.debug) {
|
|
1111
|
+
addDebugEntry(data.debug, {
|
|
1112
|
+
title: "Debug 資訊 (自動回覆)",
|
|
1113
|
+
collapsed: true,
|
|
1114
|
+
timestamp: Date.now(),
|
|
1115
|
+
badge: data.debug.elapsedMs ? `${data.debug.elapsedMs}ms` : undefined,
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1095
1119
|
if (data.success) {
|
|
1096
1120
|
updateConversationMode(data.mode, data.cliTool);
|
|
1097
1121
|
|
|
1098
|
-
// 如果有 fallback 原因,顯示通知
|
|
1099
1122
|
if (data.fallbackReason) {
|
|
1100
1123
|
showToast("warning", "模式切換", data.fallbackReason);
|
|
1101
1124
|
}
|
|
@@ -1108,7 +1131,6 @@ export async function triggerAutoAIReply() {
|
|
|
1108
1131
|
finalReply = "以下為我的回覆:\n" + data.reply;
|
|
1109
1132
|
}
|
|
1110
1133
|
|
|
1111
|
-
// 如果是 fallback,badge 顯示不同的樣式
|
|
1112
1134
|
let badgeAuto1 = data.mode === "cli" ? `CLI (${data.cliTool})` : "API";
|
|
1113
1135
|
if (data.fallbackReason) {
|
|
1114
1136
|
badgeAuto1 = "API (fallback)";
|
|
@@ -1224,6 +1246,15 @@ export async function triggerAutoAIReply() {
|
|
|
1224
1246
|
const data = await response.json();
|
|
1225
1247
|
removeThinkingEntry();
|
|
1226
1248
|
|
|
1249
|
+
if (data.debug) {
|
|
1250
|
+
addDebugEntry(data.debug, {
|
|
1251
|
+
title: `Debug (自動第 ${round} 輪)`,
|
|
1252
|
+
collapsed: true,
|
|
1253
|
+
timestamp: Date.now(),
|
|
1254
|
+
badge: data.debug.elapsedMs ? `${data.debug.elapsedMs}ms` : undefined,
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1227
1258
|
if (!data.success) {
|
|
1228
1259
|
addConversationEntry(ConversationEntryType.ERROR, data.error || "AI 回覆失敗", {
|
|
1229
1260
|
title: "錯誤",
|
|
@@ -1236,12 +1267,10 @@ export async function triggerAutoAIReply() {
|
|
|
1236
1267
|
|
|
1237
1268
|
updateConversationMode(data.mode, data.cliTool);
|
|
1238
1269
|
|
|
1239
|
-
// 如果有 fallback 原因,顯示通知
|
|
1240
1270
|
if (data.fallbackReason) {
|
|
1241
1271
|
showToast("warning", "模式切換", data.fallbackReason);
|
|
1242
1272
|
}
|
|
1243
1273
|
|
|
1244
|
-
// 如果是 fallback,badge 顯示不同的樣式
|
|
1245
1274
|
let badgeAuto2 = data.mode === "cli" ? `CLI (${data.cliTool})` : "API";
|
|
1246
1275
|
if (data.fallbackReason) {
|
|
1247
1276
|
badgeAuto2 = "API (fallback)";
|
package/dist/static/style.css
CHANGED
|
@@ -2075,6 +2075,112 @@ textarea.form-control {
|
|
|
2075
2075
|
border-left-color: var(--accent-red);
|
|
2076
2076
|
}
|
|
2077
2077
|
|
|
2078
|
+
.conversation-entry.entry-debug {
|
|
2079
|
+
border-left-color: var(--accent-orange, #f97316);
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
.conversation-header-right {
|
|
2083
|
+
display: flex;
|
|
2084
|
+
align-items: center;
|
|
2085
|
+
gap: var(--spacing-sm);
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
.debug-toggle {
|
|
2089
|
+
display: flex;
|
|
2090
|
+
align-items: center;
|
|
2091
|
+
gap: 4px;
|
|
2092
|
+
cursor: pointer;
|
|
2093
|
+
font-size: 14px;
|
|
2094
|
+
user-select: none;
|
|
2095
|
+
opacity: 0.6;
|
|
2096
|
+
transition: opacity 0.2s;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
.debug-toggle:hover {
|
|
2100
|
+
opacity: 1;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
.debug-toggle input[type="checkbox"] {
|
|
2104
|
+
width: 14px;
|
|
2105
|
+
height: 14px;
|
|
2106
|
+
cursor: pointer;
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
.debug-info-grid {
|
|
2110
|
+
display: grid;
|
|
2111
|
+
grid-template-columns: 1fr 1fr;
|
|
2112
|
+
gap: 4px 16px;
|
|
2113
|
+
margin-bottom: 8px;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
.debug-row {
|
|
2117
|
+
display: flex;
|
|
2118
|
+
justify-content: space-between;
|
|
2119
|
+
padding: 3px 8px;
|
|
2120
|
+
border-radius: 4px;
|
|
2121
|
+
background: var(--bg-primary);
|
|
2122
|
+
font-size: 12px;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
.debug-label {
|
|
2126
|
+
color: var(--text-secondary);
|
|
2127
|
+
font-weight: 500;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
.debug-value {
|
|
2131
|
+
color: var(--text-primary);
|
|
2132
|
+
font-family: "Consolas", "Monaco", monospace;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
.debug-sections {
|
|
2136
|
+
margin-top: 8px;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
.debug-section-title {
|
|
2140
|
+
font-size: 12px;
|
|
2141
|
+
font-weight: 600;
|
|
2142
|
+
color: var(--text-secondary);
|
|
2143
|
+
margin-bottom: 4px;
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
.debug-table {
|
|
2147
|
+
width: 100%;
|
|
2148
|
+
border-collapse: collapse;
|
|
2149
|
+
font-size: 12px;
|
|
2150
|
+
font-family: "Consolas", "Monaco", monospace;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
.debug-table th,
|
|
2154
|
+
.debug-table td {
|
|
2155
|
+
padding: 4px 8px;
|
|
2156
|
+
border: 1px solid var(--border-color);
|
|
2157
|
+
text-align: left;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
.debug-table th {
|
|
2161
|
+
background: var(--bg-hover);
|
|
2162
|
+
color: var(--text-secondary);
|
|
2163
|
+
font-weight: 600;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
.debug-table td {
|
|
2167
|
+
color: var(--text-primary);
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
.debug-error {
|
|
2171
|
+
margin-top: 8px;
|
|
2172
|
+
padding: 6px 10px;
|
|
2173
|
+
background: rgba(239, 68, 68, 0.1);
|
|
2174
|
+
border: 1px solid rgba(239, 68, 68, 0.3);
|
|
2175
|
+
border-radius: 4px;
|
|
2176
|
+
font-size: 12px;
|
|
2177
|
+
color: var(--accent-red);
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
.debug-body {
|
|
2181
|
+
font-size: 12px;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2078
2184
|
.entry-summary {
|
|
2079
2185
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
2080
2186
|
cursor: pointer;
|