@hirohsu/user-web-feedback 2.8.1 → 2.8.8

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 CHANGED
@@ -3302,6 +3302,7 @@ __export(database_exports, {
3302
3302
  getMCPServerById: () => getMCPServerById,
3303
3303
  getPinnedPrompts: () => getPinnedPrompts,
3304
3304
  getPromptById: () => getPromptById,
3305
+ getPromptConfigs: () => getPromptConfigs,
3305
3306
  getRecentMCPServerErrors: () => getRecentMCPServerErrors,
3306
3307
  getSelfProbeSettings: () => getSelfProbeSettings,
3307
3308
  getToolEnableConfigs: () => getToolEnableConfigs,
@@ -3319,6 +3320,7 @@ __export(database_exports, {
3319
3320
  queryLogs: () => queryLogs,
3320
3321
  queryMCPServerLogs: () => queryMCPServerLogs,
3321
3322
  reorderPrompts: () => reorderPrompts,
3323
+ resetPromptConfigs: () => resetPromptConfigs,
3322
3324
  saveSelfProbeSettings: () => saveSelfProbeSettings,
3323
3325
  setToolEnabled: () => setToolEnabled,
3324
3326
  toggleMCPServerEnabled: () => toggleMCPServerEnabled,
@@ -3329,6 +3331,7 @@ __export(database_exports, {
3329
3331
  updateCLITerminalActivity: () => updateCLITerminalActivity,
3330
3332
  updateMCPServer: () => updateMCPServer,
3331
3333
  updatePrompt: () => updatePrompt,
3334
+ updatePromptConfigs: () => updatePromptConfigs,
3332
3335
  updateUserPreferences: () => updateUserPreferences
3333
3336
  });
3334
3337
  function hashPrompt(prompt) {
@@ -3626,6 +3629,21 @@ function createTables() {
3626
3629
  updated_at TEXT DEFAULT CURRENT_TIMESTAMP
3627
3630
  )
3628
3631
  `);
3632
+ db.exec(`
3633
+ CREATE TABLE IF NOT EXISTS prompt_configs (
3634
+ id TEXT PRIMARY KEY,
3635
+ name TEXT NOT NULL,
3636
+ display_name TEXT NOT NULL,
3637
+ content TEXT,
3638
+ first_order INTEGER DEFAULT 0,
3639
+ second_order INTEGER DEFAULT 0,
3640
+ enabled INTEGER DEFAULT 1,
3641
+ editable INTEGER DEFAULT 1,
3642
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
3643
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP
3644
+ )
3645
+ `);
3646
+ initDefaultPromptConfigs();
3629
3647
  }
3630
3648
  function initDefaultSettings() {
3631
3649
  if (!db) throw new Error("Database not initialized");
@@ -5020,7 +5038,104 @@ function saveSelfProbeSettings(settings) {
5020
5038
  }
5021
5039
  return getSelfProbeSettings();
5022
5040
  }
5023
- var import_better_sqlite3, import_path2, import_fs2, import_crypto2, DB_DIR, DB_PATH, db, SYSTEM_PROMPT_VERSIONS, CURRENT_PROMPT_VERSION;
5041
+ function initDefaultPromptConfigs() {
5042
+ const db2 = tryGetDb();
5043
+ if (!db2) return;
5044
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5045
+ const existingIds = db2.prepare("SELECT id FROM prompt_configs").all().map((row) => row.id);
5046
+ const stmt = db2.prepare(`
5047
+ INSERT INTO prompt_configs (id, name, display_name, content, first_order, second_order, enabled, editable, created_at, updated_at)
5048
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5049
+ `);
5050
+ for (const config2 of DEFAULT_PROMPT_CONFIGS) {
5051
+ if (!existingIds.includes(config2.id)) {
5052
+ stmt.run(
5053
+ config2.id,
5054
+ config2.name,
5055
+ config2.displayName,
5056
+ config2.content,
5057
+ config2.firstOrder,
5058
+ config2.secondOrder,
5059
+ config2.enabled ? 1 : 0,
5060
+ config2.editable ? 1 : 0,
5061
+ now,
5062
+ now
5063
+ );
5064
+ logger.info(`Added missing prompt config: ${config2.id}`);
5065
+ }
5066
+ }
5067
+ }
5068
+ function getPromptConfigs() {
5069
+ const db2 = tryGetDb();
5070
+ if (!db2) return [];
5071
+ const rows = db2.prepare(`
5072
+ SELECT id, name, display_name as displayName, content,
5073
+ first_order as firstOrder, second_order as secondOrder,
5074
+ enabled, editable, created_at as createdAt, updated_at as updatedAt
5075
+ FROM prompt_configs
5076
+ ORDER BY first_order ASC
5077
+ `).all();
5078
+ const aiSettings = getAISettings();
5079
+ return rows.map((row) => {
5080
+ let content = row.content;
5081
+ if (row.id === "system_prompt" && !content && aiSettings.systemPrompt) {
5082
+ content = aiSettings.systemPrompt;
5083
+ } else if (row.id === "mcp_tools" && !content && aiSettings.mcpToolsPrompt) {
5084
+ content = aiSettings.mcpToolsPrompt;
5085
+ }
5086
+ return {
5087
+ ...row,
5088
+ content,
5089
+ enabled: row.enabled === 1,
5090
+ editable: row.editable === 1
5091
+ };
5092
+ });
5093
+ }
5094
+ function updatePromptConfigs(request) {
5095
+ const db2 = tryGetDb();
5096
+ if (!db2) return false;
5097
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5098
+ for (const prompt of request.prompts) {
5099
+ const updates = [];
5100
+ const values = [];
5101
+ if (prompt.firstOrder !== void 0) {
5102
+ updates.push("first_order = ?");
5103
+ values.push(prompt.firstOrder);
5104
+ }
5105
+ if (prompt.secondOrder !== void 0) {
5106
+ updates.push("second_order = ?");
5107
+ values.push(prompt.secondOrder);
5108
+ }
5109
+ if (prompt.enabled !== void 0) {
5110
+ updates.push("enabled = ?");
5111
+ values.push(prompt.enabled ? 1 : 0);
5112
+ }
5113
+ if (prompt.content !== void 0) {
5114
+ updates.push("content = ?");
5115
+ values.push(prompt.content);
5116
+ if (prompt.id === "system_prompt") {
5117
+ db2.prepare("UPDATE ai_settings SET system_prompt = ?, updated_at = ? WHERE id = 1").run(prompt.content || "", now);
5118
+ } else if (prompt.id === "mcp_tools") {
5119
+ db2.prepare("UPDATE ai_settings SET mcp_tools_prompt = ?, updated_at = ? WHERE id = 1").run(prompt.content || "", now);
5120
+ }
5121
+ }
5122
+ if (updates.length > 0) {
5123
+ updates.push("updated_at = ?");
5124
+ values.push(now);
5125
+ values.push(prompt.id);
5126
+ db2.prepare(`UPDATE prompt_configs SET ${updates.join(", ")} WHERE id = ?`).run(...values);
5127
+ }
5128
+ }
5129
+ return true;
5130
+ }
5131
+ function resetPromptConfigs() {
5132
+ const db2 = tryGetDb();
5133
+ if (!db2) return [];
5134
+ db2.prepare("DELETE FROM prompt_configs").run();
5135
+ initDefaultPromptConfigs();
5136
+ return getPromptConfigs();
5137
+ }
5138
+ var import_better_sqlite3, import_path2, import_fs2, import_crypto2, DB_DIR, DB_PATH, db, SYSTEM_PROMPT_VERSIONS, CURRENT_PROMPT_VERSION, DEFAULT_PROMPT_CONFIGS;
5024
5139
  var init_database = __esm({
5025
5140
  "src/utils/database.ts"() {
5026
5141
  "use strict";
@@ -5067,6 +5182,14 @@ var init_database = __esm({
5067
5182
  \u4FDD\u6301\u56DE\u61C9\u7C21\u77ED\uFF082-3\u53E5\u8A71\uFF09\uFF0C\u9664\u975E\u9700\u8981\u66F4\u8A73\u7D30\u7684\u8AAA\u660E\u3002`
5068
5183
  };
5069
5184
  CURRENT_PROMPT_VERSION = "v2";
5185
+ DEFAULT_PROMPT_CONFIGS = [
5186
+ { id: "system_prompt", name: "System Prompt", displayName: "\u7CFB\u7D71\u63D0\u793A\u8A5E", content: null, firstOrder: 10, secondOrder: 10, enabled: true, editable: true },
5187
+ { id: "mcp_tools", name: "MCP Tools", displayName: "MCP \u5DE5\u5177\u8AAA\u660E", content: null, firstOrder: 20, secondOrder: 0, enabled: true, editable: true },
5188
+ { id: "mcp_tools_detailed", name: "MCP Tools Detailed", displayName: "MCP \u5DE5\u5177\u8A73\u7D30\u5217\u8868", content: null, firstOrder: 25, secondOrder: 15, enabled: true, editable: false },
5189
+ { id: "user_context", name: "User Context", displayName: "\u7528\u6236\u4E0A\u4E0B\u6587", content: null, firstOrder: 30, secondOrder: 20, enabled: true, editable: false },
5190
+ { id: "tool_results", name: "Tool Results", displayName: "\u5DE5\u5177\u57F7\u884C\u7D50\u679C", content: null, firstOrder: 0, secondOrder: 30, enabled: true, editable: false },
5191
+ { id: "closing", name: "Closing", displayName: "\u7D50\u5C3E\u63D0\u793A", content: null, firstOrder: 100, secondOrder: 100, enabled: true, editable: true }
5192
+ ];
5070
5193
  }
5071
5194
  });
5072
5195
 
@@ -5160,6 +5283,9 @@ var init_logger = __esm({
5160
5283
  this.flushInterval = setInterval(() => {
5161
5284
  this.flushToDatabase();
5162
5285
  }, this.FLUSH_INTERVAL_MS);
5286
+ if (this.flushInterval.unref) {
5287
+ this.flushInterval.unref();
5288
+ }
5163
5289
  process.on("beforeExit", () => {
5164
5290
  this.flushToDatabase();
5165
5291
  });
@@ -77793,6 +77919,107 @@ ${mcpPrompt}`;
77793
77919
  }
77794
77920
  });
77795
77921
 
77922
+ // src/utils/prompt-aggregator/components/mcp-tools-detailed.ts
77923
+ var MCPToolsDetailedComponent;
77924
+ var init_mcp_tools_detailed = __esm({
77925
+ "src/utils/prompt-aggregator/components/mcp-tools-detailed.ts"() {
77926
+ "use strict";
77927
+ init_cjs_shims();
77928
+ init_base_component();
77929
+ init_mcp_client_manager();
77930
+ MCPToolsDetailedComponent = class extends BasePromptComponent {
77931
+ constructor() {
77932
+ super("MCPToolsDetailed", 25);
77933
+ }
77934
+ build(context) {
77935
+ const { request } = context;
77936
+ if (!request.includeMCPTools) {
77937
+ return null;
77938
+ }
77939
+ try {
77940
+ const allTools = mcpClientManager.getAllTools();
77941
+ if (!allTools || allTools.length === 0) {
77942
+ return null;
77943
+ }
77944
+ let result = "## MCP \u5DE5\u5177\u8A73\u7D30\u4F7F\u7528\u8AAA\u660E\n\n";
77945
+ result += "\u4EE5\u4E0B\u662F\u6240\u6709\u53EF\u7528\u7684 MCP \u5DE5\u5177\u53CA\u5176\u8A73\u7D30\u4F7F\u7528\u65B9\u5F0F\uFF1A\n\n";
77946
+ for (const tool of allTools) {
77947
+ result += `### ${tool.name}
77948
+
77949
+ `;
77950
+ if (tool.description) {
77951
+ result += `**\u8AAA\u660E**: ${tool.description}
77952
+
77953
+ `;
77954
+ }
77955
+ if (tool.inputSchema) {
77956
+ result += "**\u53C3\u6578\u683C\u5F0F**:\n```json\n";
77957
+ result += JSON.stringify(tool.inputSchema, null, 2);
77958
+ result += "\n```\n\n";
77959
+ const schema = tool.inputSchema;
77960
+ if (schema.properties && typeof schema.properties === "object") {
77961
+ result += "**\u53C3\u6578\u8AAA\u660E**:\n";
77962
+ const props = schema.properties;
77963
+ const required2 = schema.required || [];
77964
+ for (const [propName, propDef] of Object.entries(props)) {
77965
+ const isRequired = required2.includes(propName);
77966
+ result += `- \`${propName}\``;
77967
+ if (propDef.type) result += ` (${propDef.type})`;
77968
+ if (isRequired) result += " **\u5FC5\u586B**";
77969
+ if (propDef.description) result += `: ${propDef.description}`;
77970
+ result += "\n";
77971
+ }
77972
+ result += "\n";
77973
+ }
77974
+ }
77975
+ result += "**\u8ABF\u7528\u7BC4\u4F8B**:\n```json\n";
77976
+ result += JSON.stringify({
77977
+ tool_calls: [{
77978
+ name: tool.name,
77979
+ arguments: this.generateExampleArgs(tool.inputSchema)
77980
+ }]
77981
+ }, null, 2);
77982
+ result += "\n```\n\n---\n\n";
77983
+ }
77984
+ return result;
77985
+ } catch {
77986
+ return null;
77987
+ }
77988
+ }
77989
+ generateExampleArgs(schema) {
77990
+ if (!schema || !schema.properties) {
77991
+ return {};
77992
+ }
77993
+ const result = {};
77994
+ const props = schema.properties;
77995
+ for (const [propName, propDef] of Object.entries(props)) {
77996
+ switch (propDef.type) {
77997
+ case "string":
77998
+ result[propName] = "<\u5B57\u4E32\u503C>";
77999
+ break;
78000
+ case "number":
78001
+ case "integer":
78002
+ result[propName] = 0;
78003
+ break;
78004
+ case "boolean":
78005
+ result[propName] = true;
78006
+ break;
78007
+ case "array":
78008
+ result[propName] = [];
78009
+ break;
78010
+ case "object":
78011
+ result[propName] = {};
78012
+ break;
78013
+ default:
78014
+ result[propName] = "<\u503C>";
78015
+ }
78016
+ }
78017
+ return result;
78018
+ }
78019
+ };
78020
+ }
78021
+ });
78022
+
77796
78023
  // src/utils/prompt-aggregator/components/user-context.ts
77797
78024
  var UserContextComponent;
77798
78025
  var init_user_context = __esm({
@@ -77905,6 +78132,7 @@ var init_components = __esm({
77905
78132
  init_system_prompt();
77906
78133
  init_pinned_prompts();
77907
78134
  init_mcp_tools();
78135
+ init_mcp_tools_detailed();
77908
78136
  init_user_context();
77909
78137
  init_tool_results();
77910
78138
  init_ai_message();
@@ -77916,7 +78144,7 @@ var init_components = __esm({
77916
78144
  function getPromptAggregator() {
77917
78145
  return PromptAggregator.getInstance();
77918
78146
  }
77919
- var PromptAggregator;
78147
+ var COMPONENT_NAME_MAP, PromptAggregator;
77920
78148
  var init_prompt_aggregator = __esm({
77921
78149
  "src/utils/prompt-aggregator/prompt-aggregator.ts"() {
77922
78150
  "use strict";
@@ -77925,6 +78153,14 @@ var init_prompt_aggregator = __esm({
77925
78153
  init_database();
77926
78154
  init_mcp_client_manager();
77927
78155
  init_logger();
78156
+ COMPONENT_NAME_MAP = {
78157
+ "system_prompt": "SystemPrompt",
78158
+ "mcp_tools": "MCPToolsPrompt",
78159
+ "mcp_tools_detailed": "MCPToolsDetailed",
78160
+ "user_context": "UserContext",
78161
+ "tool_results": "ToolResults",
78162
+ "closing": "ClosingPrompt"
78163
+ };
77928
78164
  PromptAggregator = class _PromptAggregator {
77929
78165
  static instance;
77930
78166
  components = [];
@@ -77943,6 +78179,7 @@ var init_prompt_aggregator = __esm({
77943
78179
  this.register(new SystemPromptComponent());
77944
78180
  this.register(new PinnedPromptsComponent());
77945
78181
  this.register(new MCPToolsPromptComponent());
78182
+ this.register(new MCPToolsDetailedComponent());
77946
78183
  this.register(new UserContextComponent());
77947
78184
  this.register(new ToolResultsComponent());
77948
78185
  this.register(new AIMessageComponent());
@@ -77958,14 +78195,21 @@ var init_prompt_aggregator = __esm({
77958
78195
  aggregate(context) {
77959
78196
  const sections = [];
77960
78197
  const promptParts = [];
77961
- for (const component of this.components) {
78198
+ const configs = this.getPromptConfigsWithDefaults();
78199
+ const isFirstCall = context.isFirstCall !== false;
78200
+ const configuredComponents = this.components.map((component) => {
78201
+ const configId = Object.entries(COMPONENT_NAME_MAP).find(
78202
+ ([, name]) => name === component.getName()
78203
+ )?.[0];
78204
+ const config2 = configId ? configs.find((c) => c.id === configId) : null;
78205
+ const order = config2 ? isFirstCall ? config2.firstOrder : config2.secondOrder : component.getOrder();
78206
+ const enabled = config2 ? config2.enabled : true;
78207
+ return { component, order, enabled };
78208
+ }).filter((item) => item.enabled && item.order > 0).sort((a, b) => a.order - b.order);
78209
+ for (const { component, order } of configuredComponents) {
77962
78210
  const content = component.build(context);
77963
78211
  if (content) {
77964
- sections.push({
77965
- name: component.getName(),
77966
- content,
77967
- order: component.getOrder()
77968
- });
78212
+ sections.push({ name: component.getName(), content, order });
77969
78213
  promptParts.push(content);
77970
78214
  }
77971
78215
  }
@@ -78056,6 +78300,21 @@ var init_prompt_aggregator = __esm({
78056
78300
  getComponentNames() {
78057
78301
  return this.components.map((c) => c.getName());
78058
78302
  }
78303
+ getPromptConfigsWithDefaults() {
78304
+ try {
78305
+ const configs = getPromptConfigs();
78306
+ if (configs.length > 0) return configs;
78307
+ } catch {
78308
+ logger.warn("[PromptAggregator] \u7121\u6CD5\u5F9E\u8CC7\u6599\u5EAB\u7372\u53D6\u63D0\u793A\u8A5E\u914D\u7F6E\uFF0C\u4F7F\u7528\u9810\u8A2D\u503C");
78309
+ }
78310
+ return [
78311
+ { id: "system_prompt", name: "System Prompt", displayName: "\u7CFB\u7D71\u63D0\u793A\u8A5E", content: null, firstOrder: 10, secondOrder: 10, enabled: true, editable: false, createdAt: "", updatedAt: "" },
78312
+ { id: "mcp_tools", name: "MCP Tools", displayName: "MCP \u5DE5\u5177\u8AAA\u660E", content: null, firstOrder: 20, secondOrder: 0, enabled: true, editable: true, createdAt: "", updatedAt: "" },
78313
+ { id: "user_context", name: "User Context", displayName: "\u7528\u6236\u4E0A\u4E0B\u6587", content: null, firstOrder: 30, secondOrder: 20, enabled: true, editable: true, createdAt: "", updatedAt: "" },
78314
+ { id: "tool_results", name: "Tool Results", displayName: "\u5DE5\u5177\u57F7\u884C\u7D50\u679C", content: null, firstOrder: 0, secondOrder: 30, enabled: true, editable: false, createdAt: "", updatedAt: "" },
78315
+ { id: "closing", name: "Closing", displayName: "\u7D50\u5C3E\u63D0\u793A", content: null, firstOrder: 40, secondOrder: 40, enabled: true, editable: true, createdAt: "", updatedAt: "" }
78316
+ ];
78317
+ }
78059
78318
  };
78060
78319
  }
78061
78320
  });
@@ -78788,8 +79047,25 @@ function cleanExpiredCache() {
78788
79047
  function clearAICache() {
78789
79048
  cache.clear();
78790
79049
  }
78791
- async function validateAPIKey(apiKey, model) {
79050
+ async function validateAPIKey(apiKey, model, apiUrl, openaiCompatible) {
78792
79051
  try {
79052
+ const provider = getProviderFromUrl(apiUrl);
79053
+ if (openaiCompatible || provider === "openai" || provider === "nvidia" || provider === "zai") {
79054
+ const OpenAI = (await import("openai")).default;
79055
+ const client = new OpenAI({
79056
+ apiKey,
79057
+ baseURL: apiUrl || "https://api.openai.com/v1"
79058
+ });
79059
+ const response2 = await client.chat.completions.create({
79060
+ model,
79061
+ messages: [{ role: "user", content: "Hello" }],
79062
+ max_tokens: 10
79063
+ });
79064
+ if (response2.choices && response2.choices.length > 0) {
79065
+ return { valid: true };
79066
+ }
79067
+ return { valid: false, error: "\u7121\u6CD5\u751F\u6210\u56DE\u61C9" };
79068
+ }
78793
79069
  const genAI = new GoogleGenerativeAI(apiKey);
78794
79070
  const generativeModel = genAI.getGenerativeModel({ model });
78795
79071
  const result = await generativeModel.generateContent("Hello");
@@ -78806,6 +79082,16 @@ async function validateAPIKey(apiKey, model) {
78806
79082
  };
78807
79083
  }
78808
79084
  }
79085
+ function getProviderFromUrl(apiUrl) {
79086
+ if (!apiUrl) return "google";
79087
+ const normalizedUrl = apiUrl.toLowerCase();
79088
+ if (normalizedUrl.includes("api.openai.com")) return "openai";
79089
+ if (normalizedUrl.includes("api.anthropic.com")) return "anthropic";
79090
+ if (normalizedUrl.includes("generativelanguage.googleapis.com")) return "google";
79091
+ if (normalizedUrl.includes("nvidia.com")) return "nvidia";
79092
+ if (normalizedUrl.includes("bigmodel.cn") || normalizedUrl.includes("z.ai")) return "zai";
79093
+ return "openai";
79094
+ }
78809
79095
  function estimateTokenCount(text) {
78810
79096
  const englishChars = (text.match(/[a-zA-Z0-9]/g) || []).length;
78811
79097
  const chineseChars = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
@@ -93380,7 +93666,7 @@ var WebServer = class {
93380
93666
  this.app.post("/api/ai-settings/validate", async (req, res) => {
93381
93667
  const startTime = Date.now();
93382
93668
  try {
93383
- let { apiKey } = req.body;
93669
+ let { apiKey, apiUrl, openaiCompatible } = req.body;
93384
93670
  const { model } = req.body;
93385
93671
  if (!model) {
93386
93672
  const errorMsg = "\u6A21\u578B\u70BA\u5FC5\u586B\u6B04\u4F4D";
@@ -93400,6 +93686,7 @@ var WebServer = class {
93400
93686
  return;
93401
93687
  }
93402
93688
  let usingDatabaseKey = false;
93689
+ let usingDatabaseUrl = false;
93403
93690
  if (!apiKey) {
93404
93691
  const settings = getAISettings();
93405
93692
  if (!settings || !settings.apiKey || settings.apiKey === "YOUR_API_KEY_HERE") {
@@ -93422,13 +93709,18 @@ var WebServer = class {
93422
93709
  }
93423
93710
  apiKey = settings.apiKey;
93424
93711
  usingDatabaseKey = true;
93712
+ if (!apiUrl) {
93713
+ apiUrl = settings.apiUrl;
93714
+ usingDatabaseUrl = true;
93715
+ }
93425
93716
  logger.info("\u4F7F\u7528\u8CC7\u6599\u5EAB\u4E2D\u89E3\u5BC6\u7684 API Key \u9032\u884C\u9A57\u8B49");
93426
93717
  logger.debug(`\u89E3\u5BC6\u5F8C\u7684 API Key \u9577\u5EA6: ${apiKey.length}, \u524D\u7DB4: ${apiKey.substring(0, 3)}...`);
93427
93718
  } else {
93428
93719
  logger.info("\u4F7F\u7528\u65B0\u8F38\u5165\u7684 API Key \u9032\u884C\u9A57\u8B49");
93429
93720
  logger.debug(`\u65B0\u8F38\u5165\u7684 API Key \u9577\u5EA6: ${apiKey.length}, \u524D\u7DB4: ${apiKey.substring(0, 3)}...`);
93430
93721
  }
93431
- const result = await validateAPIKey(apiKey, model);
93722
+ logger.info(`\u9A57\u8B49\u4F7F\u7528 API URL: ${apiUrl} (\u8CC7\u6599\u5EAB: ${usingDatabaseUrl}), OpenAI \u76F8\u5BB9: ${openaiCompatible}`);
93723
+ const result = await validateAPIKey(apiKey, model, apiUrl, openaiCompatible);
93432
93724
  if (result.valid) {
93433
93725
  logger.info(`API Key \u9A57\u8B49\u6210\u529F (${usingDatabaseKey ? "\u8CC7\u6599\u5EAB" : "\u65B0\u8F38\u5165"})`);
93434
93726
  logAPIRequest({
@@ -93591,6 +93883,68 @@ var WebServer = class {
93591
93883
  });
93592
93884
  }
93593
93885
  });
93886
+ this.app.get("/api/settings/prompts", (req, res) => {
93887
+ try {
93888
+ const prompts = getPromptConfigs();
93889
+ res.json({ success: true, prompts });
93890
+ } catch (error2) {
93891
+ logger.error("\u7372\u53D6\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557:", error2);
93892
+ res.status(500).json({
93893
+ success: false,
93894
+ error: error2 instanceof Error ? error2.message : "\u7372\u53D6\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557"
93895
+ });
93896
+ }
93897
+ });
93898
+ this.app.put("/api/settings/prompts", (req, res) => {
93899
+ try {
93900
+ const { prompts } = req.body;
93901
+ if (!prompts || !Array.isArray(prompts)) {
93902
+ res.status(400).json({ success: false, error: "prompts \u5FC5\u9808\u662F\u9663\u5217" });
93903
+ return;
93904
+ }
93905
+ for (const prompt of prompts) {
93906
+ if (!prompt.id) {
93907
+ res.status(400).json({ success: false, error: "\u6BCF\u500B\u914D\u7F6E\u5FC5\u9808\u5305\u542B id" });
93908
+ return;
93909
+ }
93910
+ if (prompt.firstOrder !== void 0 && (prompt.firstOrder < 0 || prompt.firstOrder > 1e3)) {
93911
+ res.status(400).json({ success: false, error: "firstOrder \u5FC5\u9808\u5728 0-1000 \u4E4B\u9593" });
93912
+ return;
93913
+ }
93914
+ if (prompt.secondOrder !== void 0 && (prompt.secondOrder < 0 || prompt.secondOrder > 1e3)) {
93915
+ res.status(400).json({ success: false, error: "secondOrder \u5FC5\u9808\u5728 0-1000 \u4E4B\u9593" });
93916
+ return;
93917
+ }
93918
+ }
93919
+ const success = updatePromptConfigs({ prompts });
93920
+ if (success) {
93921
+ const updatedPrompts = getPromptConfigs();
93922
+ logger.info(`\u63D0\u793A\u8A5E\u914D\u7F6E\u5DF2\u66F4\u65B0: ${prompts.length} \u9805`);
93923
+ res.json({ success: true, prompts: updatedPrompts });
93924
+ } else {
93925
+ res.status(500).json({ success: false, error: "\u66F4\u65B0\u5931\u6557" });
93926
+ }
93927
+ } catch (error2) {
93928
+ logger.error("\u66F4\u65B0\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557:", error2);
93929
+ res.status(500).json({
93930
+ success: false,
93931
+ error: error2 instanceof Error ? error2.message : "\u66F4\u65B0\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557"
93932
+ });
93933
+ }
93934
+ });
93935
+ this.app.post("/api/settings/prompts/reset", (req, res) => {
93936
+ try {
93937
+ const prompts = resetPromptConfigs();
93938
+ logger.info("\u63D0\u793A\u8A5E\u914D\u7F6E\u5DF2\u91CD\u7F6E\u70BA\u9810\u8A2D\u503C");
93939
+ res.json({ success: true, prompts });
93940
+ } catch (error2) {
93941
+ logger.error("\u91CD\u7F6E\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557:", error2);
93942
+ res.status(500).json({
93943
+ success: false,
93944
+ error: error2 instanceof Error ? error2.message : "\u91CD\u7F6E\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557"
93945
+ });
93946
+ }
93947
+ });
93594
93948
  this.app.get("/api/logs", (req, res) => {
93595
93949
  try {
93596
93950
  const options = {};
@@ -95254,9 +95608,35 @@ var MCPServer = class {
95254
95608
  this.mcpServer.registerTool(
95255
95609
  "collect_feedback",
95256
95610
  {
95257
- description: "Collect feedback from users about AI work summary. This tool opens a web interface for users to provide feedback on the AI's work.",
95611
+ description: `Collect feedback from users about AI work. This tool opens a web interface for users to provide feedback.
95612
+
95613
+ CRITICAL: The 'work_summary' field is the PRIMARY and ONLY content displayed to users in the feedback UI. You MUST include ALL relevant information in this field as a comprehensive Markdown-formatted report. The UI renders Markdown, so use headings, tables, code blocks, and lists for better readability.`,
95258
95614
  inputSchema: {
95259
- work_summary: external_exports.string().describe("AI\u5DE5\u4F5C\u532F\u5831\u5167\u5BB9\uFF0C\u63CF\u8FF0AI\u5B8C\u6210\u7684\u5DE5\u4F5C\u548C\u7D50\u679C"),
95615
+ work_summary: external_exports.string().describe(`\u3010CRITICAL - THIS IS THE ONLY CONTENT SHOWN TO USERS\u3011
95616
+
95617
+ Include a COMPLETE Markdown report with ALL of the following sections:
95618
+
95619
+ ## Required Sections:
95620
+ 1. **\u{1F4CB} Task Summary** - Brief description of what was requested and accomplished
95621
+ 2. **\u{1F4C1} Implementation Details** - Files created/modified with:
95622
+ - Full file paths
95623
+ - Key code snippets in fenced code blocks
95624
+ - Explanation of changes
95625
+ 3. **\u2705 Status Table** - Markdown table showing completion status:
95626
+ | Item | Status | Notes |
95627
+ |------|--------|-------|
95628
+ | Feature A | \u2705 Done | ... |
95629
+ 4. **\u{1F9EA} Test Results** - Build/test command outputs and outcomes
95630
+ 5. **\u27A1\uFE0F Next Steps** - Actionable options in A/B/C format for user decision:
95631
+ - Option A: [action] - [description]
95632
+ - Option B: [action] - [description]
95633
+ 6. **\u{1F3D7}\uFE0F Architecture** (if applicable) - ASCII diagrams or Mermaid code blocks
95634
+
95635
+ ## Format Requirements:
95636
+ - Use Markdown: ## headings, \`code\`, **bold**, tables
95637
+ - Minimum 500 characters for non-trivial tasks
95638
+ - Be specific with file paths and code examples
95639
+ - Include ALL information user needs to make decisions`),
95260
95640
  project_name: external_exports.string().optional().describe("\u5C08\u6848\u540D\u7A31\uFF08\u7528\u65BC Dashboard \u5206\u7D44\u986F\u793A\uFF09"),
95261
95641
  project_path: external_exports.string().optional().describe("\u5C08\u6848\u8DEF\u5F91\uFF08\u7528\u65BC\u552F\u4E00\u8B58\u5225\u5C08\u6848\uFF09")
95262
95642
  }