@hirohsu/user-web-feedback 2.8.18 → 2.8.20
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 +64 -213
- package/dist/index.cjs +64 -213
- 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
|
@@ -78231,11 +78231,11 @@ var init_prompt_aggregator = __esm({
|
|
|
78231
78231
|
init_logger();
|
|
78232
78232
|
COMPONENT_NAME_MAP = {
|
|
78233
78233
|
"system_prompt": "SystemPrompt",
|
|
78234
|
-
"mcp_tools": "
|
|
78234
|
+
"mcp_tools": "MCPTools",
|
|
78235
78235
|
"mcp_tools_detailed": "MCPToolsDetailed",
|
|
78236
78236
|
"user_context": "UserContext",
|
|
78237
78237
|
"tool_results": "ToolResults",
|
|
78238
|
-
"closing": "
|
|
78238
|
+
"closing": "Closing"
|
|
78239
78239
|
};
|
|
78240
78240
|
PromptAggregator = class _PromptAggregator {
|
|
78241
78241
|
static instance;
|
|
@@ -78274,9 +78274,10 @@ var init_prompt_aggregator = __esm({
|
|
|
78274
78274
|
const configs = this.getPromptConfigsWithDefaults();
|
|
78275
78275
|
const isFirstCall = context.isFirstCall !== false;
|
|
78276
78276
|
const configuredComponents = this.components.map((component) => {
|
|
78277
|
-
const
|
|
78277
|
+
const configEntry = Object.entries(COMPONENT_NAME_MAP).find(
|
|
78278
78278
|
([, name]) => name === component.getName()
|
|
78279
|
-
)
|
|
78279
|
+
);
|
|
78280
|
+
const configId = configEntry?.[0];
|
|
78280
78281
|
const config2 = configId ? configs.find((c) => c.id === configId) : null;
|
|
78281
78282
|
const order = config2 ? isFirstCall ? config2.firstOrder : config2.secondOrder : component.getOrder();
|
|
78282
78283
|
const enabled = config2 ? config2.enabled : true;
|
|
@@ -78376,6 +78377,15 @@ var init_prompt_aggregator = __esm({
|
|
|
78376
78377
|
getComponentNames() {
|
|
78377
78378
|
return this.components.map((c) => c.getName());
|
|
78378
78379
|
}
|
|
78380
|
+
getPromptConfigsForDebug() {
|
|
78381
|
+
const configs = this.getPromptConfigsWithDefaults();
|
|
78382
|
+
return configs.map((c) => ({
|
|
78383
|
+
id: c.id,
|
|
78384
|
+
enabled: c.enabled,
|
|
78385
|
+
firstOrder: c.firstOrder,
|
|
78386
|
+
secondOrder: c.secondOrder
|
|
78387
|
+
}));
|
|
78388
|
+
}
|
|
78379
78389
|
getPromptConfigsWithDefaults() {
|
|
78380
78390
|
try {
|
|
78381
78391
|
const configs = getPromptConfigs();
|
|
@@ -78478,61 +78488,6 @@ function formatToolResults(results) {
|
|
|
78478
78488
|
}
|
|
78479
78489
|
return lines.join("\n");
|
|
78480
78490
|
}
|
|
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
78491
|
var init_mcp_tool_parser = __esm({
|
|
78537
78492
|
"src/utils/mcp-tool-parser.ts"() {
|
|
78538
78493
|
"use strict";
|
|
@@ -78885,131 +78840,91 @@ async function generateCLIReply(request, cliSettings) {
|
|
|
78885
78840
|
}
|
|
78886
78841
|
}
|
|
78887
78842
|
async function generateAPIReply(request) {
|
|
78843
|
+
const startTime = Date.now();
|
|
78888
78844
|
try {
|
|
78889
78845
|
const cacheKey = `${request.aiMessage}:${request.userContext || ""}`;
|
|
78890
78846
|
if (!request.toolResults) {
|
|
78891
78847
|
const cached2 = cache.get(cacheKey);
|
|
78892
78848
|
if (cached2 && Date.now() - cached2.timestamp < CACHE_TTL2) {
|
|
78893
78849
|
logger.debug("[AI Service] \u4F7F\u7528\u5FEB\u53D6\u56DE\u8986");
|
|
78894
|
-
return {
|
|
78895
|
-
success: true,
|
|
78896
|
-
reply: cached2.reply
|
|
78897
|
-
};
|
|
78850
|
+
return { success: true, reply: cached2.reply };
|
|
78898
78851
|
}
|
|
78899
78852
|
}
|
|
78900
78853
|
logger.debug("[AI Service] \u7372\u53D6 AI \u8A2D\u5B9A");
|
|
78901
78854
|
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
78855
|
if (!settings || !settings.apiKey || settings.apiKey === "YOUR_API_KEY_HERE") {
|
|
78908
78856
|
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
|
-
};
|
|
78857
|
+
return { success: false, error: "\u8ACB\u5148\u5728\u8A2D\u5B9A\u4E2D\u914D\u7F6E AI API Key" };
|
|
78913
78858
|
}
|
|
78914
|
-
|
|
78859
|
+
const aggregator = getPromptAggregator();
|
|
78860
|
+
const cliSettings = getCLISettings();
|
|
78861
|
+
let mcpTools = [];
|
|
78915
78862
|
if (request.includeMCPTools) {
|
|
78916
|
-
logger.debug("[AI Service] \u958B\u59CB\u7372\u53D6 MCP \u5DE5\u5177");
|
|
78917
78863
|
try {
|
|
78918
78864
|
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);
|
|
78865
|
+
mcpTools = allTools.map((t) => ({
|
|
78866
|
+
name: t.name,
|
|
78867
|
+
description: t.description,
|
|
78868
|
+
inputSchema: t.inputSchema
|
|
78869
|
+
}));
|
|
78870
|
+
} catch {
|
|
78871
|
+
logger.warn("[AI Service] \u7121\u6CD5\u7372\u53D6 MCP \u5DE5\u5177");
|
|
78949
78872
|
}
|
|
78950
78873
|
}
|
|
78951
|
-
|
|
78952
|
-
|
|
78953
|
-
|
|
78954
|
-
|
|
78955
|
-
|
|
78874
|
+
const context = aggregator.buildContextSync(request, settings, cliSettings, mcpTools);
|
|
78875
|
+
context.mode = "api";
|
|
78876
|
+
const aggregated = aggregator.aggregate(context);
|
|
78877
|
+
const promptSent = aggregated.fullPrompt;
|
|
78878
|
+
logger.debug("[AI Service] PromptAggregator \u69CB\u5EFA\u5B8C\u6210", {
|
|
78879
|
+
componentCount: aggregated.sections.length,
|
|
78880
|
+
sections: aggregated.sections.map((s) => `${s.name}(order:${s.order})`),
|
|
78881
|
+
totalLength: promptSent.length,
|
|
78882
|
+
tokenEstimate: aggregated.metadata.tokenEstimate
|
|
78956
78883
|
});
|
|
78957
|
-
const
|
|
78958
|
-
settings.systemPrompt,
|
|
78959
|
-
request.aiMessage,
|
|
78960
|
-
request.userContext,
|
|
78961
|
-
mcpToolsPrompt,
|
|
78962
|
-
request.toolResults
|
|
78963
|
-
);
|
|
78964
|
-
const reply = await generateWithRetry(
|
|
78884
|
+
const reply = await generateWithRetryFromPrompt(
|
|
78965
78885
|
settings.apiKey,
|
|
78966
78886
|
settings.model,
|
|
78967
|
-
|
|
78968
|
-
request.aiMessage,
|
|
78969
|
-
request.userContext,
|
|
78887
|
+
promptSent,
|
|
78970
78888
|
settings.temperature,
|
|
78971
|
-
settings.maxTokens
|
|
78972
|
-
0,
|
|
78973
|
-
mcpToolsPrompt,
|
|
78974
|
-
request.toolResults
|
|
78889
|
+
settings.maxTokens
|
|
78975
78890
|
);
|
|
78976
|
-
|
|
78977
|
-
replyLength: reply.length
|
|
78978
|
-
});
|
|
78891
|
+
const elapsedMs = Date.now() - startTime;
|
|
78979
78892
|
if (!request.toolResults) {
|
|
78980
|
-
cache.set(cacheKey, {
|
|
78981
|
-
reply,
|
|
78982
|
-
timestamp: Date.now()
|
|
78983
|
-
});
|
|
78893
|
+
cache.set(cacheKey, { reply, timestamp: Date.now() });
|
|
78984
78894
|
cleanExpiredCache();
|
|
78985
78895
|
}
|
|
78986
|
-
|
|
78896
|
+
const promptConfigs = aggregator.getPromptConfigsForDebug();
|
|
78987
78897
|
return {
|
|
78988
78898
|
success: true,
|
|
78989
78899
|
reply,
|
|
78990
78900
|
promptSent,
|
|
78991
|
-
mode: "api"
|
|
78901
|
+
mode: "api",
|
|
78902
|
+
debug: {
|
|
78903
|
+
sections: aggregated.sections.map((s) => ({ name: s.name, order: s.order, length: s.content.length })),
|
|
78904
|
+
tokenEstimate: aggregated.metadata.tokenEstimate,
|
|
78905
|
+
totalPromptLength: promptSent.length,
|
|
78906
|
+
elapsedMs,
|
|
78907
|
+
model: settings.model,
|
|
78908
|
+
temperature: settings.temperature,
|
|
78909
|
+
maxTokens: settings.maxTokens,
|
|
78910
|
+
mcpToolsCount: mcpTools.length,
|
|
78911
|
+
componentCount: aggregated.sections.length,
|
|
78912
|
+
promptConfigs
|
|
78913
|
+
}
|
|
78992
78914
|
};
|
|
78993
78915
|
} catch (error2) {
|
|
78916
|
+
const elapsedMs = Date.now() - startTime;
|
|
78994
78917
|
logger.error("[AI Service] AI service error:", error2);
|
|
78995
78918
|
return {
|
|
78996
78919
|
success: false,
|
|
78997
78920
|
error: error2 instanceof Error ? error2.message : "\u672A\u77E5\u932F\u8AA4",
|
|
78998
|
-
mode: "api"
|
|
78921
|
+
mode: "api",
|
|
78922
|
+
debug: { elapsedMs }
|
|
78999
78923
|
};
|
|
79000
78924
|
}
|
|
79001
78925
|
}
|
|
79002
|
-
async function
|
|
78926
|
+
async function generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount = 0) {
|
|
79003
78927
|
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
78928
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
79014
78929
|
const generativeModel = genAI.getGenerativeModel({
|
|
79015
78930
|
model,
|
|
@@ -79018,45 +78933,20 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
79018
78933
|
maxOutputTokens: maxTokens ?? 1e3
|
|
79019
78934
|
}
|
|
79020
78935
|
});
|
|
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");
|
|
78936
|
+
logger.debug("[AI Service] \u958B\u59CB\u8ABF\u7528 API (PromptAggregator prompt)", { promptLength: prompt.length });
|
|
79027
78937
|
const result = await generativeModel.generateContent(prompt);
|
|
79028
|
-
logger.debug("[AI Service] API \u8ABF\u7528\u5B8C\u6210");
|
|
79029
78938
|
const response = await result.response;
|
|
79030
78939
|
const text = response.text();
|
|
79031
78940
|
if (!text) {
|
|
79032
78941
|
throw new Error("AI \u56DE\u8986\u70BA\u7A7A");
|
|
79033
78942
|
}
|
|
79034
|
-
logger.debug("[AI Service] \u56DE\u8986\u6587\u5B57\u7372\u53D6\u6210\u529F", {
|
|
79035
|
-
textLength: text.length
|
|
79036
|
-
});
|
|
79037
78943
|
return text;
|
|
79038
78944
|
} 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
78945
|
if (error2 instanceof Error) {
|
|
79044
78946
|
if (error2.message.includes("429") || error2.message.includes("quota")) {
|
|
79045
78947
|
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
|
-
);
|
|
78948
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
78949
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
79060
78950
|
}
|
|
79061
78951
|
throw new Error("API \u914D\u984D\u5DF2\u7528\u76E1\u6216\u901F\u7387\u9650\u5236\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66");
|
|
79062
78952
|
}
|
|
@@ -79064,51 +78954,13 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
79064
78954
|
throw new Error("API Key \u7121\u6548\uFF0C\u8ACB\u6AA2\u67E5\u8A2D\u5B9A");
|
|
79065
78955
|
}
|
|
79066
78956
|
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
|
-
);
|
|
78957
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
78958
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
79081
78959
|
}
|
|
79082
78960
|
}
|
|
79083
78961
|
throw error2;
|
|
79084
78962
|
}
|
|
79085
78963
|
}
|
|
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
78964
|
function sleep(ms) {
|
|
79113
78965
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
79114
78966
|
}
|
|
@@ -79208,7 +79060,6 @@ var init_ai_service = __esm({
|
|
|
79208
79060
|
init_cli_executor();
|
|
79209
79061
|
init_cli_detector();
|
|
79210
79062
|
init_prompt_aggregator2();
|
|
79211
|
-
init_mcp_tool_parser();
|
|
79212
79063
|
MAX_RETRIES = 3;
|
|
79213
79064
|
RETRY_DELAYS = [1e3, 2e3, 4e3];
|
|
79214
79065
|
cache = /* @__PURE__ */ new Map();
|
package/dist/index.cjs
CHANGED
|
@@ -75118,11 +75118,11 @@ var init_prompt_aggregator = __esm({
|
|
|
75118
75118
|
init_logger();
|
|
75119
75119
|
COMPONENT_NAME_MAP = {
|
|
75120
75120
|
"system_prompt": "SystemPrompt",
|
|
75121
|
-
"mcp_tools": "
|
|
75121
|
+
"mcp_tools": "MCPTools",
|
|
75122
75122
|
"mcp_tools_detailed": "MCPToolsDetailed",
|
|
75123
75123
|
"user_context": "UserContext",
|
|
75124
75124
|
"tool_results": "ToolResults",
|
|
75125
|
-
"closing": "
|
|
75125
|
+
"closing": "Closing"
|
|
75126
75126
|
};
|
|
75127
75127
|
PromptAggregator = class _PromptAggregator {
|
|
75128
75128
|
static instance;
|
|
@@ -75161,9 +75161,10 @@ var init_prompt_aggregator = __esm({
|
|
|
75161
75161
|
const configs = this.getPromptConfigsWithDefaults();
|
|
75162
75162
|
const isFirstCall = context.isFirstCall !== false;
|
|
75163
75163
|
const configuredComponents = this.components.map((component) => {
|
|
75164
|
-
const
|
|
75164
|
+
const configEntry = Object.entries(COMPONENT_NAME_MAP).find(
|
|
75165
75165
|
([, name]) => name === component.getName()
|
|
75166
|
-
)
|
|
75166
|
+
);
|
|
75167
|
+
const configId = configEntry?.[0];
|
|
75167
75168
|
const config2 = configId ? configs.find((c) => c.id === configId) : null;
|
|
75168
75169
|
const order = config2 ? isFirstCall ? config2.firstOrder : config2.secondOrder : component.getOrder();
|
|
75169
75170
|
const enabled = config2 ? config2.enabled : true;
|
|
@@ -75263,6 +75264,15 @@ var init_prompt_aggregator = __esm({
|
|
|
75263
75264
|
getComponentNames() {
|
|
75264
75265
|
return this.components.map((c) => c.getName());
|
|
75265
75266
|
}
|
|
75267
|
+
getPromptConfigsForDebug() {
|
|
75268
|
+
const configs = this.getPromptConfigsWithDefaults();
|
|
75269
|
+
return configs.map((c) => ({
|
|
75270
|
+
id: c.id,
|
|
75271
|
+
enabled: c.enabled,
|
|
75272
|
+
firstOrder: c.firstOrder,
|
|
75273
|
+
secondOrder: c.secondOrder
|
|
75274
|
+
}));
|
|
75275
|
+
}
|
|
75266
75276
|
getPromptConfigsWithDefaults() {
|
|
75267
75277
|
try {
|
|
75268
75278
|
const configs = getPromptConfigs();
|
|
@@ -75365,61 +75375,6 @@ function formatToolResults(results) {
|
|
|
75365
75375
|
}
|
|
75366
75376
|
return lines.join("\n");
|
|
75367
75377
|
}
|
|
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
75378
|
var init_mcp_tool_parser = __esm({
|
|
75424
75379
|
"src/utils/mcp-tool-parser.ts"() {
|
|
75425
75380
|
"use strict";
|
|
@@ -75772,131 +75727,91 @@ async function generateCLIReply(request, cliSettings) {
|
|
|
75772
75727
|
}
|
|
75773
75728
|
}
|
|
75774
75729
|
async function generateAPIReply(request) {
|
|
75730
|
+
const startTime = Date.now();
|
|
75775
75731
|
try {
|
|
75776
75732
|
const cacheKey = `${request.aiMessage}:${request.userContext || ""}`;
|
|
75777
75733
|
if (!request.toolResults) {
|
|
75778
75734
|
const cached2 = cache.get(cacheKey);
|
|
75779
75735
|
if (cached2 && Date.now() - cached2.timestamp < CACHE_TTL2) {
|
|
75780
75736
|
logger.debug("[AI Service] \u4F7F\u7528\u5FEB\u53D6\u56DE\u8986");
|
|
75781
|
-
return {
|
|
75782
|
-
success: true,
|
|
75783
|
-
reply: cached2.reply
|
|
75784
|
-
};
|
|
75737
|
+
return { success: true, reply: cached2.reply };
|
|
75785
75738
|
}
|
|
75786
75739
|
}
|
|
75787
75740
|
logger.debug("[AI Service] \u7372\u53D6 AI \u8A2D\u5B9A");
|
|
75788
75741
|
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
75742
|
if (!settings || !settings.apiKey || settings.apiKey === "YOUR_API_KEY_HERE") {
|
|
75795
75743
|
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
|
-
};
|
|
75744
|
+
return { success: false, error: "\u8ACB\u5148\u5728\u8A2D\u5B9A\u4E2D\u914D\u7F6E AI API Key" };
|
|
75800
75745
|
}
|
|
75801
|
-
|
|
75746
|
+
const aggregator = getPromptAggregator();
|
|
75747
|
+
const cliSettings = getCLISettings();
|
|
75748
|
+
let mcpTools = [];
|
|
75802
75749
|
if (request.includeMCPTools) {
|
|
75803
|
-
logger.debug("[AI Service] \u958B\u59CB\u7372\u53D6 MCP \u5DE5\u5177");
|
|
75804
75750
|
try {
|
|
75805
75751
|
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);
|
|
75752
|
+
mcpTools = allTools.map((t) => ({
|
|
75753
|
+
name: t.name,
|
|
75754
|
+
description: t.description,
|
|
75755
|
+
inputSchema: t.inputSchema
|
|
75756
|
+
}));
|
|
75757
|
+
} catch {
|
|
75758
|
+
logger.warn("[AI Service] \u7121\u6CD5\u7372\u53D6 MCP \u5DE5\u5177");
|
|
75836
75759
|
}
|
|
75837
75760
|
}
|
|
75838
|
-
|
|
75839
|
-
|
|
75840
|
-
|
|
75841
|
-
|
|
75842
|
-
|
|
75761
|
+
const context = aggregator.buildContextSync(request, settings, cliSettings, mcpTools);
|
|
75762
|
+
context.mode = "api";
|
|
75763
|
+
const aggregated = aggregator.aggregate(context);
|
|
75764
|
+
const promptSent = aggregated.fullPrompt;
|
|
75765
|
+
logger.debug("[AI Service] PromptAggregator \u69CB\u5EFA\u5B8C\u6210", {
|
|
75766
|
+
componentCount: aggregated.sections.length,
|
|
75767
|
+
sections: aggregated.sections.map((s) => `${s.name}(order:${s.order})`),
|
|
75768
|
+
totalLength: promptSent.length,
|
|
75769
|
+
tokenEstimate: aggregated.metadata.tokenEstimate
|
|
75843
75770
|
});
|
|
75844
|
-
const
|
|
75845
|
-
settings.systemPrompt,
|
|
75846
|
-
request.aiMessage,
|
|
75847
|
-
request.userContext,
|
|
75848
|
-
mcpToolsPrompt,
|
|
75849
|
-
request.toolResults
|
|
75850
|
-
);
|
|
75851
|
-
const reply = await generateWithRetry(
|
|
75771
|
+
const reply = await generateWithRetryFromPrompt(
|
|
75852
75772
|
settings.apiKey,
|
|
75853
75773
|
settings.model,
|
|
75854
|
-
|
|
75855
|
-
request.aiMessage,
|
|
75856
|
-
request.userContext,
|
|
75774
|
+
promptSent,
|
|
75857
75775
|
settings.temperature,
|
|
75858
|
-
settings.maxTokens
|
|
75859
|
-
0,
|
|
75860
|
-
mcpToolsPrompt,
|
|
75861
|
-
request.toolResults
|
|
75776
|
+
settings.maxTokens
|
|
75862
75777
|
);
|
|
75863
|
-
|
|
75864
|
-
replyLength: reply.length
|
|
75865
|
-
});
|
|
75778
|
+
const elapsedMs = Date.now() - startTime;
|
|
75866
75779
|
if (!request.toolResults) {
|
|
75867
|
-
cache.set(cacheKey, {
|
|
75868
|
-
reply,
|
|
75869
|
-
timestamp: Date.now()
|
|
75870
|
-
});
|
|
75780
|
+
cache.set(cacheKey, { reply, timestamp: Date.now() });
|
|
75871
75781
|
cleanExpiredCache();
|
|
75872
75782
|
}
|
|
75873
|
-
|
|
75783
|
+
const promptConfigs = aggregator.getPromptConfigsForDebug();
|
|
75874
75784
|
return {
|
|
75875
75785
|
success: true,
|
|
75876
75786
|
reply,
|
|
75877
75787
|
promptSent,
|
|
75878
|
-
mode: "api"
|
|
75788
|
+
mode: "api",
|
|
75789
|
+
debug: {
|
|
75790
|
+
sections: aggregated.sections.map((s) => ({ name: s.name, order: s.order, length: s.content.length })),
|
|
75791
|
+
tokenEstimate: aggregated.metadata.tokenEstimate,
|
|
75792
|
+
totalPromptLength: promptSent.length,
|
|
75793
|
+
elapsedMs,
|
|
75794
|
+
model: settings.model,
|
|
75795
|
+
temperature: settings.temperature,
|
|
75796
|
+
maxTokens: settings.maxTokens,
|
|
75797
|
+
mcpToolsCount: mcpTools.length,
|
|
75798
|
+
componentCount: aggregated.sections.length,
|
|
75799
|
+
promptConfigs
|
|
75800
|
+
}
|
|
75879
75801
|
};
|
|
75880
75802
|
} catch (error2) {
|
|
75803
|
+
const elapsedMs = Date.now() - startTime;
|
|
75881
75804
|
logger.error("[AI Service] AI service error:", error2);
|
|
75882
75805
|
return {
|
|
75883
75806
|
success: false,
|
|
75884
75807
|
error: error2 instanceof Error ? error2.message : "\u672A\u77E5\u932F\u8AA4",
|
|
75885
|
-
mode: "api"
|
|
75808
|
+
mode: "api",
|
|
75809
|
+
debug: { elapsedMs }
|
|
75886
75810
|
};
|
|
75887
75811
|
}
|
|
75888
75812
|
}
|
|
75889
|
-
async function
|
|
75813
|
+
async function generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount = 0) {
|
|
75890
75814
|
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
75815
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
75901
75816
|
const generativeModel = genAI.getGenerativeModel({
|
|
75902
75817
|
model,
|
|
@@ -75905,45 +75820,20 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
75905
75820
|
maxOutputTokens: maxTokens ?? 1e3
|
|
75906
75821
|
}
|
|
75907
75822
|
});
|
|
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");
|
|
75823
|
+
logger.debug("[AI Service] \u958B\u59CB\u8ABF\u7528 API (PromptAggregator prompt)", { promptLength: prompt.length });
|
|
75914
75824
|
const result = await generativeModel.generateContent(prompt);
|
|
75915
|
-
logger.debug("[AI Service] API \u8ABF\u7528\u5B8C\u6210");
|
|
75916
75825
|
const response = await result.response;
|
|
75917
75826
|
const text = response.text();
|
|
75918
75827
|
if (!text) {
|
|
75919
75828
|
throw new Error("AI \u56DE\u8986\u70BA\u7A7A");
|
|
75920
75829
|
}
|
|
75921
|
-
logger.debug("[AI Service] \u56DE\u8986\u6587\u5B57\u7372\u53D6\u6210\u529F", {
|
|
75922
|
-
textLength: text.length
|
|
75923
|
-
});
|
|
75924
75830
|
return text;
|
|
75925
75831
|
} 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
75832
|
if (error2 instanceof Error) {
|
|
75931
75833
|
if (error2.message.includes("429") || error2.message.includes("quota")) {
|
|
75932
75834
|
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
|
-
);
|
|
75835
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
75836
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
75947
75837
|
}
|
|
75948
75838
|
throw new Error("API \u914D\u984D\u5DF2\u7528\u76E1\u6216\u901F\u7387\u9650\u5236\uFF0C\u8ACB\u7A0D\u5F8C\u518D\u8A66");
|
|
75949
75839
|
}
|
|
@@ -75951,51 +75841,13 @@ async function generateWithRetry(apiKey, model, systemPrompt, aiMessage, userCon
|
|
|
75951
75841
|
throw new Error("API Key \u7121\u6548\uFF0C\u8ACB\u6AA2\u67E5\u8A2D\u5B9A");
|
|
75952
75842
|
}
|
|
75953
75843
|
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
|
-
);
|
|
75844
|
+
await sleep(RETRY_DELAYS[retryCount] || 4e3);
|
|
75845
|
+
return generateWithRetryFromPrompt(apiKey, model, prompt, temperature, maxTokens, retryCount + 1);
|
|
75968
75846
|
}
|
|
75969
75847
|
}
|
|
75970
75848
|
throw error2;
|
|
75971
75849
|
}
|
|
75972
75850
|
}
|
|
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
75851
|
function sleep(ms) {
|
|
76000
75852
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
76001
75853
|
}
|
|
@@ -76095,7 +75947,6 @@ var init_ai_service = __esm({
|
|
|
76095
75947
|
init_cli_executor();
|
|
76096
75948
|
init_cli_detector();
|
|
76097
75949
|
init_prompt_aggregator2();
|
|
76098
|
-
init_mcp_tool_parser();
|
|
76099
75950
|
MAX_RETRIES = 3;
|
|
76100
75951
|
RETRY_DELAYS = [1e3, 2e3, 4e3];
|
|
76101
75952
|
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;
|