@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 +393 -13
- package/dist/index.cjs +393 -13
- package/dist/static/logs.html +3 -3
- package/dist/static/settings.html +46 -11
- package/dist/static/settings.js +242 -18
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -20660,6 +20660,7 @@ __export(database_exports, {
|
|
|
20660
20660
|
getMCPServerById: () => getMCPServerById,
|
|
20661
20661
|
getPinnedPrompts: () => getPinnedPrompts,
|
|
20662
20662
|
getPromptById: () => getPromptById,
|
|
20663
|
+
getPromptConfigs: () => getPromptConfigs,
|
|
20663
20664
|
getRecentMCPServerErrors: () => getRecentMCPServerErrors,
|
|
20664
20665
|
getSelfProbeSettings: () => getSelfProbeSettings,
|
|
20665
20666
|
getToolEnableConfigs: () => getToolEnableConfigs,
|
|
@@ -20677,6 +20678,7 @@ __export(database_exports, {
|
|
|
20677
20678
|
queryLogs: () => queryLogs,
|
|
20678
20679
|
queryMCPServerLogs: () => queryMCPServerLogs,
|
|
20679
20680
|
reorderPrompts: () => reorderPrompts,
|
|
20681
|
+
resetPromptConfigs: () => resetPromptConfigs,
|
|
20680
20682
|
saveSelfProbeSettings: () => saveSelfProbeSettings,
|
|
20681
20683
|
setToolEnabled: () => setToolEnabled,
|
|
20682
20684
|
toggleMCPServerEnabled: () => toggleMCPServerEnabled,
|
|
@@ -20687,6 +20689,7 @@ __export(database_exports, {
|
|
|
20687
20689
|
updateCLITerminalActivity: () => updateCLITerminalActivity,
|
|
20688
20690
|
updateMCPServer: () => updateMCPServer,
|
|
20689
20691
|
updatePrompt: () => updatePrompt,
|
|
20692
|
+
updatePromptConfigs: () => updatePromptConfigs,
|
|
20690
20693
|
updateUserPreferences: () => updateUserPreferences
|
|
20691
20694
|
});
|
|
20692
20695
|
function hashPrompt(prompt) {
|
|
@@ -20984,6 +20987,21 @@ function createTables() {
|
|
|
20984
20987
|
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
20985
20988
|
)
|
|
20986
20989
|
`);
|
|
20990
|
+
db.exec(`
|
|
20991
|
+
CREATE TABLE IF NOT EXISTS prompt_configs (
|
|
20992
|
+
id TEXT PRIMARY KEY,
|
|
20993
|
+
name TEXT NOT NULL,
|
|
20994
|
+
display_name TEXT NOT NULL,
|
|
20995
|
+
content TEXT,
|
|
20996
|
+
first_order INTEGER DEFAULT 0,
|
|
20997
|
+
second_order INTEGER DEFAULT 0,
|
|
20998
|
+
enabled INTEGER DEFAULT 1,
|
|
20999
|
+
editable INTEGER DEFAULT 1,
|
|
21000
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
21001
|
+
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
21002
|
+
)
|
|
21003
|
+
`);
|
|
21004
|
+
initDefaultPromptConfigs();
|
|
20987
21005
|
}
|
|
20988
21006
|
function initDefaultSettings() {
|
|
20989
21007
|
if (!db) throw new Error("Database not initialized");
|
|
@@ -22378,7 +22396,104 @@ function saveSelfProbeSettings(settings) {
|
|
|
22378
22396
|
}
|
|
22379
22397
|
return getSelfProbeSettings();
|
|
22380
22398
|
}
|
|
22381
|
-
|
|
22399
|
+
function initDefaultPromptConfigs() {
|
|
22400
|
+
const db2 = tryGetDb();
|
|
22401
|
+
if (!db2) return;
|
|
22402
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22403
|
+
const existingIds = db2.prepare("SELECT id FROM prompt_configs").all().map((row) => row.id);
|
|
22404
|
+
const stmt = db2.prepare(`
|
|
22405
|
+
INSERT INTO prompt_configs (id, name, display_name, content, first_order, second_order, enabled, editable, created_at, updated_at)
|
|
22406
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
22407
|
+
`);
|
|
22408
|
+
for (const config2 of DEFAULT_PROMPT_CONFIGS) {
|
|
22409
|
+
if (!existingIds.includes(config2.id)) {
|
|
22410
|
+
stmt.run(
|
|
22411
|
+
config2.id,
|
|
22412
|
+
config2.name,
|
|
22413
|
+
config2.displayName,
|
|
22414
|
+
config2.content,
|
|
22415
|
+
config2.firstOrder,
|
|
22416
|
+
config2.secondOrder,
|
|
22417
|
+
config2.enabled ? 1 : 0,
|
|
22418
|
+
config2.editable ? 1 : 0,
|
|
22419
|
+
now,
|
|
22420
|
+
now
|
|
22421
|
+
);
|
|
22422
|
+
logger.info(`Added missing prompt config: ${config2.id}`);
|
|
22423
|
+
}
|
|
22424
|
+
}
|
|
22425
|
+
}
|
|
22426
|
+
function getPromptConfigs() {
|
|
22427
|
+
const db2 = tryGetDb();
|
|
22428
|
+
if (!db2) return [];
|
|
22429
|
+
const rows = db2.prepare(`
|
|
22430
|
+
SELECT id, name, display_name as displayName, content,
|
|
22431
|
+
first_order as firstOrder, second_order as secondOrder,
|
|
22432
|
+
enabled, editable, created_at as createdAt, updated_at as updatedAt
|
|
22433
|
+
FROM prompt_configs
|
|
22434
|
+
ORDER BY first_order ASC
|
|
22435
|
+
`).all();
|
|
22436
|
+
const aiSettings = getAISettings();
|
|
22437
|
+
return rows.map((row) => {
|
|
22438
|
+
let content = row.content;
|
|
22439
|
+
if (row.id === "system_prompt" && !content && aiSettings.systemPrompt) {
|
|
22440
|
+
content = aiSettings.systemPrompt;
|
|
22441
|
+
} else if (row.id === "mcp_tools" && !content && aiSettings.mcpToolsPrompt) {
|
|
22442
|
+
content = aiSettings.mcpToolsPrompt;
|
|
22443
|
+
}
|
|
22444
|
+
return {
|
|
22445
|
+
...row,
|
|
22446
|
+
content,
|
|
22447
|
+
enabled: row.enabled === 1,
|
|
22448
|
+
editable: row.editable === 1
|
|
22449
|
+
};
|
|
22450
|
+
});
|
|
22451
|
+
}
|
|
22452
|
+
function updatePromptConfigs(request) {
|
|
22453
|
+
const db2 = tryGetDb();
|
|
22454
|
+
if (!db2) return false;
|
|
22455
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22456
|
+
for (const prompt of request.prompts) {
|
|
22457
|
+
const updates = [];
|
|
22458
|
+
const values = [];
|
|
22459
|
+
if (prompt.firstOrder !== void 0) {
|
|
22460
|
+
updates.push("first_order = ?");
|
|
22461
|
+
values.push(prompt.firstOrder);
|
|
22462
|
+
}
|
|
22463
|
+
if (prompt.secondOrder !== void 0) {
|
|
22464
|
+
updates.push("second_order = ?");
|
|
22465
|
+
values.push(prompt.secondOrder);
|
|
22466
|
+
}
|
|
22467
|
+
if (prompt.enabled !== void 0) {
|
|
22468
|
+
updates.push("enabled = ?");
|
|
22469
|
+
values.push(prompt.enabled ? 1 : 0);
|
|
22470
|
+
}
|
|
22471
|
+
if (prompt.content !== void 0) {
|
|
22472
|
+
updates.push("content = ?");
|
|
22473
|
+
values.push(prompt.content);
|
|
22474
|
+
if (prompt.id === "system_prompt") {
|
|
22475
|
+
db2.prepare("UPDATE ai_settings SET system_prompt = ?, updated_at = ? WHERE id = 1").run(prompt.content || "", now);
|
|
22476
|
+
} else if (prompt.id === "mcp_tools") {
|
|
22477
|
+
db2.prepare("UPDATE ai_settings SET mcp_tools_prompt = ?, updated_at = ? WHERE id = 1").run(prompt.content || "", now);
|
|
22478
|
+
}
|
|
22479
|
+
}
|
|
22480
|
+
if (updates.length > 0) {
|
|
22481
|
+
updates.push("updated_at = ?");
|
|
22482
|
+
values.push(now);
|
|
22483
|
+
values.push(prompt.id);
|
|
22484
|
+
db2.prepare(`UPDATE prompt_configs SET ${updates.join(", ")} WHERE id = ?`).run(...values);
|
|
22485
|
+
}
|
|
22486
|
+
}
|
|
22487
|
+
return true;
|
|
22488
|
+
}
|
|
22489
|
+
function resetPromptConfigs() {
|
|
22490
|
+
const db2 = tryGetDb();
|
|
22491
|
+
if (!db2) return [];
|
|
22492
|
+
db2.prepare("DELETE FROM prompt_configs").run();
|
|
22493
|
+
initDefaultPromptConfigs();
|
|
22494
|
+
return getPromptConfigs();
|
|
22495
|
+
}
|
|
22496
|
+
var import_better_sqlite3, import_path2, import_fs2, import_crypto2, DB_DIR, DB_PATH, db, SYSTEM_PROMPT_VERSIONS, CURRENT_PROMPT_VERSION, DEFAULT_PROMPT_CONFIGS;
|
|
22382
22497
|
var init_database = __esm({
|
|
22383
22498
|
"src/utils/database.ts"() {
|
|
22384
22499
|
"use strict";
|
|
@@ -22425,6 +22540,14 @@ var init_database = __esm({
|
|
|
22425
22540
|
\u4FDD\u6301\u56DE\u61C9\u7C21\u77ED\uFF082-3\u53E5\u8A71\uFF09\uFF0C\u9664\u975E\u9700\u8981\u66F4\u8A73\u7D30\u7684\u8AAA\u660E\u3002`
|
|
22426
22541
|
};
|
|
22427
22542
|
CURRENT_PROMPT_VERSION = "v2";
|
|
22543
|
+
DEFAULT_PROMPT_CONFIGS = [
|
|
22544
|
+
{ id: "system_prompt", name: "System Prompt", displayName: "\u7CFB\u7D71\u63D0\u793A\u8A5E", content: null, firstOrder: 10, secondOrder: 10, enabled: true, editable: true },
|
|
22545
|
+
{ id: "mcp_tools", name: "MCP Tools", displayName: "MCP \u5DE5\u5177\u8AAA\u660E", content: null, firstOrder: 20, secondOrder: 0, enabled: true, editable: true },
|
|
22546
|
+
{ 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 },
|
|
22547
|
+
{ id: "user_context", name: "User Context", displayName: "\u7528\u6236\u4E0A\u4E0B\u6587", content: null, firstOrder: 30, secondOrder: 20, enabled: true, editable: false },
|
|
22548
|
+
{ id: "tool_results", name: "Tool Results", displayName: "\u5DE5\u5177\u57F7\u884C\u7D50\u679C", content: null, firstOrder: 0, secondOrder: 30, enabled: true, editable: false },
|
|
22549
|
+
{ id: "closing", name: "Closing", displayName: "\u7D50\u5C3E\u63D0\u793A", content: null, firstOrder: 100, secondOrder: 100, enabled: true, editable: true }
|
|
22550
|
+
];
|
|
22428
22551
|
}
|
|
22429
22552
|
});
|
|
22430
22553
|
|
|
@@ -22518,6 +22641,9 @@ var init_logger = __esm({
|
|
|
22518
22641
|
this.flushInterval = setInterval(() => {
|
|
22519
22642
|
this.flushToDatabase();
|
|
22520
22643
|
}, this.FLUSH_INTERVAL_MS);
|
|
22644
|
+
if (this.flushInterval.unref) {
|
|
22645
|
+
this.flushInterval.unref();
|
|
22646
|
+
}
|
|
22521
22647
|
process.on("beforeExit", () => {
|
|
22522
22648
|
this.flushToDatabase();
|
|
22523
22649
|
});
|
|
@@ -74680,6 +74806,107 @@ ${mcpPrompt}`;
|
|
|
74680
74806
|
}
|
|
74681
74807
|
});
|
|
74682
74808
|
|
|
74809
|
+
// src/utils/prompt-aggregator/components/mcp-tools-detailed.ts
|
|
74810
|
+
var MCPToolsDetailedComponent;
|
|
74811
|
+
var init_mcp_tools_detailed = __esm({
|
|
74812
|
+
"src/utils/prompt-aggregator/components/mcp-tools-detailed.ts"() {
|
|
74813
|
+
"use strict";
|
|
74814
|
+
init_cjs_shims();
|
|
74815
|
+
init_base_component();
|
|
74816
|
+
init_mcp_client_manager();
|
|
74817
|
+
MCPToolsDetailedComponent = class extends BasePromptComponent {
|
|
74818
|
+
constructor() {
|
|
74819
|
+
super("MCPToolsDetailed", 25);
|
|
74820
|
+
}
|
|
74821
|
+
build(context) {
|
|
74822
|
+
const { request } = context;
|
|
74823
|
+
if (!request.includeMCPTools) {
|
|
74824
|
+
return null;
|
|
74825
|
+
}
|
|
74826
|
+
try {
|
|
74827
|
+
const allTools = mcpClientManager.getAllTools();
|
|
74828
|
+
if (!allTools || allTools.length === 0) {
|
|
74829
|
+
return null;
|
|
74830
|
+
}
|
|
74831
|
+
let result = "## MCP \u5DE5\u5177\u8A73\u7D30\u4F7F\u7528\u8AAA\u660E\n\n";
|
|
74832
|
+
result += "\u4EE5\u4E0B\u662F\u6240\u6709\u53EF\u7528\u7684 MCP \u5DE5\u5177\u53CA\u5176\u8A73\u7D30\u4F7F\u7528\u65B9\u5F0F\uFF1A\n\n";
|
|
74833
|
+
for (const tool of allTools) {
|
|
74834
|
+
result += `### ${tool.name}
|
|
74835
|
+
|
|
74836
|
+
`;
|
|
74837
|
+
if (tool.description) {
|
|
74838
|
+
result += `**\u8AAA\u660E**: ${tool.description}
|
|
74839
|
+
|
|
74840
|
+
`;
|
|
74841
|
+
}
|
|
74842
|
+
if (tool.inputSchema) {
|
|
74843
|
+
result += "**\u53C3\u6578\u683C\u5F0F**:\n```json\n";
|
|
74844
|
+
result += JSON.stringify(tool.inputSchema, null, 2);
|
|
74845
|
+
result += "\n```\n\n";
|
|
74846
|
+
const schema = tool.inputSchema;
|
|
74847
|
+
if (schema.properties && typeof schema.properties === "object") {
|
|
74848
|
+
result += "**\u53C3\u6578\u8AAA\u660E**:\n";
|
|
74849
|
+
const props = schema.properties;
|
|
74850
|
+
const required2 = schema.required || [];
|
|
74851
|
+
for (const [propName, propDef] of Object.entries(props)) {
|
|
74852
|
+
const isRequired = required2.includes(propName);
|
|
74853
|
+
result += `- \`${propName}\``;
|
|
74854
|
+
if (propDef.type) result += ` (${propDef.type})`;
|
|
74855
|
+
if (isRequired) result += " **\u5FC5\u586B**";
|
|
74856
|
+
if (propDef.description) result += `: ${propDef.description}`;
|
|
74857
|
+
result += "\n";
|
|
74858
|
+
}
|
|
74859
|
+
result += "\n";
|
|
74860
|
+
}
|
|
74861
|
+
}
|
|
74862
|
+
result += "**\u8ABF\u7528\u7BC4\u4F8B**:\n```json\n";
|
|
74863
|
+
result += JSON.stringify({
|
|
74864
|
+
tool_calls: [{
|
|
74865
|
+
name: tool.name,
|
|
74866
|
+
arguments: this.generateExampleArgs(tool.inputSchema)
|
|
74867
|
+
}]
|
|
74868
|
+
}, null, 2);
|
|
74869
|
+
result += "\n```\n\n---\n\n";
|
|
74870
|
+
}
|
|
74871
|
+
return result;
|
|
74872
|
+
} catch {
|
|
74873
|
+
return null;
|
|
74874
|
+
}
|
|
74875
|
+
}
|
|
74876
|
+
generateExampleArgs(schema) {
|
|
74877
|
+
if (!schema || !schema.properties) {
|
|
74878
|
+
return {};
|
|
74879
|
+
}
|
|
74880
|
+
const result = {};
|
|
74881
|
+
const props = schema.properties;
|
|
74882
|
+
for (const [propName, propDef] of Object.entries(props)) {
|
|
74883
|
+
switch (propDef.type) {
|
|
74884
|
+
case "string":
|
|
74885
|
+
result[propName] = "<\u5B57\u4E32\u503C>";
|
|
74886
|
+
break;
|
|
74887
|
+
case "number":
|
|
74888
|
+
case "integer":
|
|
74889
|
+
result[propName] = 0;
|
|
74890
|
+
break;
|
|
74891
|
+
case "boolean":
|
|
74892
|
+
result[propName] = true;
|
|
74893
|
+
break;
|
|
74894
|
+
case "array":
|
|
74895
|
+
result[propName] = [];
|
|
74896
|
+
break;
|
|
74897
|
+
case "object":
|
|
74898
|
+
result[propName] = {};
|
|
74899
|
+
break;
|
|
74900
|
+
default:
|
|
74901
|
+
result[propName] = "<\u503C>";
|
|
74902
|
+
}
|
|
74903
|
+
}
|
|
74904
|
+
return result;
|
|
74905
|
+
}
|
|
74906
|
+
};
|
|
74907
|
+
}
|
|
74908
|
+
});
|
|
74909
|
+
|
|
74683
74910
|
// src/utils/prompt-aggregator/components/user-context.ts
|
|
74684
74911
|
var UserContextComponent;
|
|
74685
74912
|
var init_user_context = __esm({
|
|
@@ -74792,6 +75019,7 @@ var init_components = __esm({
|
|
|
74792
75019
|
init_system_prompt();
|
|
74793
75020
|
init_pinned_prompts();
|
|
74794
75021
|
init_mcp_tools();
|
|
75022
|
+
init_mcp_tools_detailed();
|
|
74795
75023
|
init_user_context();
|
|
74796
75024
|
init_tool_results();
|
|
74797
75025
|
init_ai_message();
|
|
@@ -74803,7 +75031,7 @@ var init_components = __esm({
|
|
|
74803
75031
|
function getPromptAggregator() {
|
|
74804
75032
|
return PromptAggregator.getInstance();
|
|
74805
75033
|
}
|
|
74806
|
-
var PromptAggregator;
|
|
75034
|
+
var COMPONENT_NAME_MAP, PromptAggregator;
|
|
74807
75035
|
var init_prompt_aggregator = __esm({
|
|
74808
75036
|
"src/utils/prompt-aggregator/prompt-aggregator.ts"() {
|
|
74809
75037
|
"use strict";
|
|
@@ -74812,6 +75040,14 @@ var init_prompt_aggregator = __esm({
|
|
|
74812
75040
|
init_database();
|
|
74813
75041
|
init_mcp_client_manager();
|
|
74814
75042
|
init_logger();
|
|
75043
|
+
COMPONENT_NAME_MAP = {
|
|
75044
|
+
"system_prompt": "SystemPrompt",
|
|
75045
|
+
"mcp_tools": "MCPToolsPrompt",
|
|
75046
|
+
"mcp_tools_detailed": "MCPToolsDetailed",
|
|
75047
|
+
"user_context": "UserContext",
|
|
75048
|
+
"tool_results": "ToolResults",
|
|
75049
|
+
"closing": "ClosingPrompt"
|
|
75050
|
+
};
|
|
74815
75051
|
PromptAggregator = class _PromptAggregator {
|
|
74816
75052
|
static instance;
|
|
74817
75053
|
components = [];
|
|
@@ -74830,6 +75066,7 @@ var init_prompt_aggregator = __esm({
|
|
|
74830
75066
|
this.register(new SystemPromptComponent());
|
|
74831
75067
|
this.register(new PinnedPromptsComponent());
|
|
74832
75068
|
this.register(new MCPToolsPromptComponent());
|
|
75069
|
+
this.register(new MCPToolsDetailedComponent());
|
|
74833
75070
|
this.register(new UserContextComponent());
|
|
74834
75071
|
this.register(new ToolResultsComponent());
|
|
74835
75072
|
this.register(new AIMessageComponent());
|
|
@@ -74845,14 +75082,21 @@ var init_prompt_aggregator = __esm({
|
|
|
74845
75082
|
aggregate(context) {
|
|
74846
75083
|
const sections = [];
|
|
74847
75084
|
const promptParts = [];
|
|
74848
|
-
|
|
75085
|
+
const configs = this.getPromptConfigsWithDefaults();
|
|
75086
|
+
const isFirstCall = context.isFirstCall !== false;
|
|
75087
|
+
const configuredComponents = this.components.map((component) => {
|
|
75088
|
+
const configId = Object.entries(COMPONENT_NAME_MAP).find(
|
|
75089
|
+
([, name]) => name === component.getName()
|
|
75090
|
+
)?.[0];
|
|
75091
|
+
const config2 = configId ? configs.find((c) => c.id === configId) : null;
|
|
75092
|
+
const order = config2 ? isFirstCall ? config2.firstOrder : config2.secondOrder : component.getOrder();
|
|
75093
|
+
const enabled = config2 ? config2.enabled : true;
|
|
75094
|
+
return { component, order, enabled };
|
|
75095
|
+
}).filter((item) => item.enabled && item.order > 0).sort((a, b) => a.order - b.order);
|
|
75096
|
+
for (const { component, order } of configuredComponents) {
|
|
74849
75097
|
const content = component.build(context);
|
|
74850
75098
|
if (content) {
|
|
74851
|
-
sections.push({
|
|
74852
|
-
name: component.getName(),
|
|
74853
|
-
content,
|
|
74854
|
-
order: component.getOrder()
|
|
74855
|
-
});
|
|
75099
|
+
sections.push({ name: component.getName(), content, order });
|
|
74856
75100
|
promptParts.push(content);
|
|
74857
75101
|
}
|
|
74858
75102
|
}
|
|
@@ -74943,6 +75187,21 @@ var init_prompt_aggregator = __esm({
|
|
|
74943
75187
|
getComponentNames() {
|
|
74944
75188
|
return this.components.map((c) => c.getName());
|
|
74945
75189
|
}
|
|
75190
|
+
getPromptConfigsWithDefaults() {
|
|
75191
|
+
try {
|
|
75192
|
+
const configs = getPromptConfigs();
|
|
75193
|
+
if (configs.length > 0) return configs;
|
|
75194
|
+
} catch {
|
|
75195
|
+
logger.warn("[PromptAggregator] \u7121\u6CD5\u5F9E\u8CC7\u6599\u5EAB\u7372\u53D6\u63D0\u793A\u8A5E\u914D\u7F6E\uFF0C\u4F7F\u7528\u9810\u8A2D\u503C");
|
|
75196
|
+
}
|
|
75197
|
+
return [
|
|
75198
|
+
{ id: "system_prompt", name: "System Prompt", displayName: "\u7CFB\u7D71\u63D0\u793A\u8A5E", content: null, firstOrder: 10, secondOrder: 10, enabled: true, editable: false, createdAt: "", updatedAt: "" },
|
|
75199
|
+
{ id: "mcp_tools", name: "MCP Tools", displayName: "MCP \u5DE5\u5177\u8AAA\u660E", content: null, firstOrder: 20, secondOrder: 0, enabled: true, editable: true, createdAt: "", updatedAt: "" },
|
|
75200
|
+
{ id: "user_context", name: "User Context", displayName: "\u7528\u6236\u4E0A\u4E0B\u6587", content: null, firstOrder: 30, secondOrder: 20, enabled: true, editable: true, createdAt: "", updatedAt: "" },
|
|
75201
|
+
{ 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: "" },
|
|
75202
|
+
{ id: "closing", name: "Closing", displayName: "\u7D50\u5C3E\u63D0\u793A", content: null, firstOrder: 40, secondOrder: 40, enabled: true, editable: true, createdAt: "", updatedAt: "" }
|
|
75203
|
+
];
|
|
75204
|
+
}
|
|
74946
75205
|
};
|
|
74947
75206
|
}
|
|
74948
75207
|
});
|
|
@@ -75675,8 +75934,25 @@ function cleanExpiredCache() {
|
|
|
75675
75934
|
function clearAICache() {
|
|
75676
75935
|
cache.clear();
|
|
75677
75936
|
}
|
|
75678
|
-
async function validateAPIKey(apiKey, model) {
|
|
75937
|
+
async function validateAPIKey(apiKey, model, apiUrl, openaiCompatible) {
|
|
75679
75938
|
try {
|
|
75939
|
+
const provider = getProviderFromUrl(apiUrl);
|
|
75940
|
+
if (openaiCompatible || provider === "openai" || provider === "nvidia" || provider === "zai") {
|
|
75941
|
+
const OpenAI = (await import("openai")).default;
|
|
75942
|
+
const client = new OpenAI({
|
|
75943
|
+
apiKey,
|
|
75944
|
+
baseURL: apiUrl || "https://api.openai.com/v1"
|
|
75945
|
+
});
|
|
75946
|
+
const response2 = await client.chat.completions.create({
|
|
75947
|
+
model,
|
|
75948
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
75949
|
+
max_tokens: 10
|
|
75950
|
+
});
|
|
75951
|
+
if (response2.choices && response2.choices.length > 0) {
|
|
75952
|
+
return { valid: true };
|
|
75953
|
+
}
|
|
75954
|
+
return { valid: false, error: "\u7121\u6CD5\u751F\u6210\u56DE\u61C9" };
|
|
75955
|
+
}
|
|
75680
75956
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
75681
75957
|
const generativeModel = genAI.getGenerativeModel({ model });
|
|
75682
75958
|
const result = await generativeModel.generateContent("Hello");
|
|
@@ -75693,6 +75969,16 @@ async function validateAPIKey(apiKey, model) {
|
|
|
75693
75969
|
};
|
|
75694
75970
|
}
|
|
75695
75971
|
}
|
|
75972
|
+
function getProviderFromUrl(apiUrl) {
|
|
75973
|
+
if (!apiUrl) return "google";
|
|
75974
|
+
const normalizedUrl = apiUrl.toLowerCase();
|
|
75975
|
+
if (normalizedUrl.includes("api.openai.com")) return "openai";
|
|
75976
|
+
if (normalizedUrl.includes("api.anthropic.com")) return "anthropic";
|
|
75977
|
+
if (normalizedUrl.includes("generativelanguage.googleapis.com")) return "google";
|
|
75978
|
+
if (normalizedUrl.includes("nvidia.com")) return "nvidia";
|
|
75979
|
+
if (normalizedUrl.includes("bigmodel.cn") || normalizedUrl.includes("z.ai")) return "zai";
|
|
75980
|
+
return "openai";
|
|
75981
|
+
}
|
|
75696
75982
|
function estimateTokenCount(text) {
|
|
75697
75983
|
const englishChars = (text.match(/[a-zA-Z0-9]/g) || []).length;
|
|
75698
75984
|
const chineseChars = (text.match(/[\u4e00-\u9fa5]/g) || []).length;
|
|
@@ -90395,7 +90681,7 @@ var WebServer = class {
|
|
|
90395
90681
|
this.app.post("/api/ai-settings/validate", async (req, res) => {
|
|
90396
90682
|
const startTime = Date.now();
|
|
90397
90683
|
try {
|
|
90398
|
-
let { apiKey } = req.body;
|
|
90684
|
+
let { apiKey, apiUrl, openaiCompatible } = req.body;
|
|
90399
90685
|
const { model } = req.body;
|
|
90400
90686
|
if (!model) {
|
|
90401
90687
|
const errorMsg = "\u6A21\u578B\u70BA\u5FC5\u586B\u6B04\u4F4D";
|
|
@@ -90415,6 +90701,7 @@ var WebServer = class {
|
|
|
90415
90701
|
return;
|
|
90416
90702
|
}
|
|
90417
90703
|
let usingDatabaseKey = false;
|
|
90704
|
+
let usingDatabaseUrl = false;
|
|
90418
90705
|
if (!apiKey) {
|
|
90419
90706
|
const settings = getAISettings();
|
|
90420
90707
|
if (!settings || !settings.apiKey || settings.apiKey === "YOUR_API_KEY_HERE") {
|
|
@@ -90437,13 +90724,18 @@ var WebServer = class {
|
|
|
90437
90724
|
}
|
|
90438
90725
|
apiKey = settings.apiKey;
|
|
90439
90726
|
usingDatabaseKey = true;
|
|
90727
|
+
if (!apiUrl) {
|
|
90728
|
+
apiUrl = settings.apiUrl;
|
|
90729
|
+
usingDatabaseUrl = true;
|
|
90730
|
+
}
|
|
90440
90731
|
logger.info("\u4F7F\u7528\u8CC7\u6599\u5EAB\u4E2D\u89E3\u5BC6\u7684 API Key \u9032\u884C\u9A57\u8B49");
|
|
90441
90732
|
logger.debug(`\u89E3\u5BC6\u5F8C\u7684 API Key \u9577\u5EA6: ${apiKey.length}, \u524D\u7DB4: ${apiKey.substring(0, 3)}...`);
|
|
90442
90733
|
} else {
|
|
90443
90734
|
logger.info("\u4F7F\u7528\u65B0\u8F38\u5165\u7684 API Key \u9032\u884C\u9A57\u8B49");
|
|
90444
90735
|
logger.debug(`\u65B0\u8F38\u5165\u7684 API Key \u9577\u5EA6: ${apiKey.length}, \u524D\u7DB4: ${apiKey.substring(0, 3)}...`);
|
|
90445
90736
|
}
|
|
90446
|
-
|
|
90737
|
+
logger.info(`\u9A57\u8B49\u4F7F\u7528 API URL: ${apiUrl} (\u8CC7\u6599\u5EAB: ${usingDatabaseUrl}), OpenAI \u76F8\u5BB9: ${openaiCompatible}`);
|
|
90738
|
+
const result = await validateAPIKey(apiKey, model, apiUrl, openaiCompatible);
|
|
90447
90739
|
if (result.valid) {
|
|
90448
90740
|
logger.info(`API Key \u9A57\u8B49\u6210\u529F (${usingDatabaseKey ? "\u8CC7\u6599\u5EAB" : "\u65B0\u8F38\u5165"})`);
|
|
90449
90741
|
logAPIRequest({
|
|
@@ -90606,6 +90898,68 @@ var WebServer = class {
|
|
|
90606
90898
|
});
|
|
90607
90899
|
}
|
|
90608
90900
|
});
|
|
90901
|
+
this.app.get("/api/settings/prompts", (req, res) => {
|
|
90902
|
+
try {
|
|
90903
|
+
const prompts = getPromptConfigs();
|
|
90904
|
+
res.json({ success: true, prompts });
|
|
90905
|
+
} catch (error2) {
|
|
90906
|
+
logger.error("\u7372\u53D6\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557:", error2);
|
|
90907
|
+
res.status(500).json({
|
|
90908
|
+
success: false,
|
|
90909
|
+
error: error2 instanceof Error ? error2.message : "\u7372\u53D6\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557"
|
|
90910
|
+
});
|
|
90911
|
+
}
|
|
90912
|
+
});
|
|
90913
|
+
this.app.put("/api/settings/prompts", (req, res) => {
|
|
90914
|
+
try {
|
|
90915
|
+
const { prompts } = req.body;
|
|
90916
|
+
if (!prompts || !Array.isArray(prompts)) {
|
|
90917
|
+
res.status(400).json({ success: false, error: "prompts \u5FC5\u9808\u662F\u9663\u5217" });
|
|
90918
|
+
return;
|
|
90919
|
+
}
|
|
90920
|
+
for (const prompt of prompts) {
|
|
90921
|
+
if (!prompt.id) {
|
|
90922
|
+
res.status(400).json({ success: false, error: "\u6BCF\u500B\u914D\u7F6E\u5FC5\u9808\u5305\u542B id" });
|
|
90923
|
+
return;
|
|
90924
|
+
}
|
|
90925
|
+
if (prompt.firstOrder !== void 0 && (prompt.firstOrder < 0 || prompt.firstOrder > 1e3)) {
|
|
90926
|
+
res.status(400).json({ success: false, error: "firstOrder \u5FC5\u9808\u5728 0-1000 \u4E4B\u9593" });
|
|
90927
|
+
return;
|
|
90928
|
+
}
|
|
90929
|
+
if (prompt.secondOrder !== void 0 && (prompt.secondOrder < 0 || prompt.secondOrder > 1e3)) {
|
|
90930
|
+
res.status(400).json({ success: false, error: "secondOrder \u5FC5\u9808\u5728 0-1000 \u4E4B\u9593" });
|
|
90931
|
+
return;
|
|
90932
|
+
}
|
|
90933
|
+
}
|
|
90934
|
+
const success = updatePromptConfigs({ prompts });
|
|
90935
|
+
if (success) {
|
|
90936
|
+
const updatedPrompts = getPromptConfigs();
|
|
90937
|
+
logger.info(`\u63D0\u793A\u8A5E\u914D\u7F6E\u5DF2\u66F4\u65B0: ${prompts.length} \u9805`);
|
|
90938
|
+
res.json({ success: true, prompts: updatedPrompts });
|
|
90939
|
+
} else {
|
|
90940
|
+
res.status(500).json({ success: false, error: "\u66F4\u65B0\u5931\u6557" });
|
|
90941
|
+
}
|
|
90942
|
+
} catch (error2) {
|
|
90943
|
+
logger.error("\u66F4\u65B0\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557:", error2);
|
|
90944
|
+
res.status(500).json({
|
|
90945
|
+
success: false,
|
|
90946
|
+
error: error2 instanceof Error ? error2.message : "\u66F4\u65B0\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557"
|
|
90947
|
+
});
|
|
90948
|
+
}
|
|
90949
|
+
});
|
|
90950
|
+
this.app.post("/api/settings/prompts/reset", (req, res) => {
|
|
90951
|
+
try {
|
|
90952
|
+
const prompts = resetPromptConfigs();
|
|
90953
|
+
logger.info("\u63D0\u793A\u8A5E\u914D\u7F6E\u5DF2\u91CD\u7F6E\u70BA\u9810\u8A2D\u503C");
|
|
90954
|
+
res.json({ success: true, prompts });
|
|
90955
|
+
} catch (error2) {
|
|
90956
|
+
logger.error("\u91CD\u7F6E\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557:", error2);
|
|
90957
|
+
res.status(500).json({
|
|
90958
|
+
success: false,
|
|
90959
|
+
error: error2 instanceof Error ? error2.message : "\u91CD\u7F6E\u63D0\u793A\u8A5E\u914D\u7F6E\u5931\u6557"
|
|
90960
|
+
});
|
|
90961
|
+
}
|
|
90962
|
+
});
|
|
90609
90963
|
this.app.get("/api/logs", (req, res) => {
|
|
90610
90964
|
try {
|
|
90611
90965
|
const options = {};
|
|
@@ -92269,9 +92623,35 @@ var MCPServer = class {
|
|
|
92269
92623
|
this.mcpServer.registerTool(
|
|
92270
92624
|
"collect_feedback",
|
|
92271
92625
|
{
|
|
92272
|
-
description:
|
|
92626
|
+
description: `Collect feedback from users about AI work. This tool opens a web interface for users to provide feedback.
|
|
92627
|
+
|
|
92628
|
+
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.`,
|
|
92273
92629
|
inputSchema: {
|
|
92274
|
-
work_summary: external_exports.string().describe(
|
|
92630
|
+
work_summary: external_exports.string().describe(`\u3010CRITICAL - THIS IS THE ONLY CONTENT SHOWN TO USERS\u3011
|
|
92631
|
+
|
|
92632
|
+
Include a COMPLETE Markdown report with ALL of the following sections:
|
|
92633
|
+
|
|
92634
|
+
## Required Sections:
|
|
92635
|
+
1. **\u{1F4CB} Task Summary** - Brief description of what was requested and accomplished
|
|
92636
|
+
2. **\u{1F4C1} Implementation Details** - Files created/modified with:
|
|
92637
|
+
- Full file paths
|
|
92638
|
+
- Key code snippets in fenced code blocks
|
|
92639
|
+
- Explanation of changes
|
|
92640
|
+
3. **\u2705 Status Table** - Markdown table showing completion status:
|
|
92641
|
+
| Item | Status | Notes |
|
|
92642
|
+
|------|--------|-------|
|
|
92643
|
+
| Feature A | \u2705 Done | ... |
|
|
92644
|
+
4. **\u{1F9EA} Test Results** - Build/test command outputs and outcomes
|
|
92645
|
+
5. **\u27A1\uFE0F Next Steps** - Actionable options in A/B/C format for user decision:
|
|
92646
|
+
- Option A: [action] - [description]
|
|
92647
|
+
- Option B: [action] - [description]
|
|
92648
|
+
6. **\u{1F3D7}\uFE0F Architecture** (if applicable) - ASCII diagrams or Mermaid code blocks
|
|
92649
|
+
|
|
92650
|
+
## Format Requirements:
|
|
92651
|
+
- Use Markdown: ## headings, \`code\`, **bold**, tables
|
|
92652
|
+
- Minimum 500 characters for non-trivial tasks
|
|
92653
|
+
- Be specific with file paths and code examples
|
|
92654
|
+
- Include ALL information user needs to make decisions`),
|
|
92275
92655
|
project_name: external_exports.string().optional().describe("\u5C08\u6848\u540D\u7A31\uFF08\u7528\u65BC Dashboard \u5206\u7D44\u986F\u793A\uFF09"),
|
|
92276
92656
|
project_path: external_exports.string().optional().describe("\u5C08\u6848\u8DEF\u5F91\uFF08\u7528\u65BC\u552F\u4E00\u8B58\u5225\u5C08\u6848\uFF09")
|
|
92277
92657
|
}
|
package/dist/static/logs.html
CHANGED
|
@@ -53,9 +53,7 @@
|
|
|
53
53
|
|
|
54
54
|
.logs-table-container {
|
|
55
55
|
background: var(--bg-primary);
|
|
56
|
-
border: 1px solid var(--border-color);
|
|
57
56
|
border-radius: var(--radius-md);
|
|
58
|
-
overflow: hidden;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
.logs-table {
|
|
@@ -178,15 +176,17 @@
|
|
|
178
176
|
display: flex;
|
|
179
177
|
flex-direction: column;
|
|
180
178
|
min-height: 0;
|
|
181
|
-
overflow:
|
|
179
|
+
overflow: visible;
|
|
182
180
|
}
|
|
183
181
|
|
|
184
182
|
.logs-table-wrapper {
|
|
185
183
|
flex: 1;
|
|
186
184
|
overflow-y: auto;
|
|
185
|
+
overflow-x: hidden;
|
|
187
186
|
border: 1px solid var(--border-color);
|
|
188
187
|
border-radius: 8px;
|
|
189
188
|
margin-bottom: 16px;
|
|
189
|
+
max-height: calc(100vh - 350px);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
.logs-table-wrapper::-webkit-scrollbar {
|
|
@@ -187,6 +187,31 @@
|
|
|
187
187
|
<option value="openai">OpenAI</option>
|
|
188
188
|
<option value="anthropic">Anthropic (Claude)</option>
|
|
189
189
|
<option value="google">Google (Gemini)</option>
|
|
190
|
+
<option value="nvidia">NVIDIA</option>
|
|
191
|
+
<option value="zai">Z.AI (Zhipu AI)</option>
|
|
192
|
+
</select>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div class="form-group">
|
|
196
|
+
<label class="form-label" for="apiUrl">API Endpoint</label>
|
|
197
|
+
<input type="url" id="apiUrl" class="form-input" placeholder="API 端點 URL">
|
|
198
|
+
<p class="form-help">可自定義 API 端點,留空使用預設值</p>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div class="form-group">
|
|
202
|
+
<div class="checkbox-group">
|
|
203
|
+
<input type="checkbox" id="openaiCompatible" />
|
|
204
|
+
<label for="openaiCompatible">OpenAI 相容模式</label>
|
|
205
|
+
</div>
|
|
206
|
+
<p class="form-help">啟用後使用 OpenAI API 格式(適用於自建或第三方相容服務)</p>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<!-- Z.AI 專用設定 -->
|
|
210
|
+
<div id="zaiExtSettings" class="form-group" style="display: none;">
|
|
211
|
+
<label class="form-label" for="zaiRegion">地區</label>
|
|
212
|
+
<select id="zaiRegion" class="form-select">
|
|
213
|
+
<option value="international">國際版 (api.z.ai)</option>
|
|
214
|
+
<option value="china">中國版 (bigmodel.cn)</option>
|
|
190
215
|
</select>
|
|
191
216
|
</div>
|
|
192
217
|
|
|
@@ -204,17 +229,6 @@
|
|
|
204
229
|
<input type="text" id="aiModel" class="form-input" placeholder="例如: gpt-4-turbo, claude-3-opus">
|
|
205
230
|
</div>
|
|
206
231
|
|
|
207
|
-
<div class="form-group">
|
|
208
|
-
<label class="form-label" for="systemPrompt">系統提示詞</label>
|
|
209
|
-
<textarea id="systemPrompt" class="form-textarea" placeholder="自定義系統提示詞..."></textarea>
|
|
210
|
-
<p class="form-help">留空將使用預設提示詞</p>
|
|
211
|
-
</div>
|
|
212
|
-
|
|
213
|
-
<div class="form-group">
|
|
214
|
-
<label class="form-label" for="mcpToolsPrompt">MCP 工具提示詞</label>
|
|
215
|
-
<textarea id="mcpToolsPrompt" class="form-textarea" placeholder="設定 MCP 工具的使用說明..."></textarea>
|
|
216
|
-
<p class="form-help">定義 AI 如何使用 MCP 工具。{project_name} 和 {project_path} 會被替換為實際值</p>
|
|
217
|
-
</div>
|
|
218
232
|
|
|
219
233
|
<div class="form-row" style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
|
|
220
234
|
<div class="form-group">
|
|
@@ -378,6 +392,27 @@
|
|
|
378
392
|
<button id="saveSelfProbeBtn" class="btn btn-primary">儲存設定</button>
|
|
379
393
|
</div>
|
|
380
394
|
</section>
|
|
395
|
+
|
|
396
|
+
<!-- AI 提示詞設定 -->
|
|
397
|
+
<section class="settings-section">
|
|
398
|
+
<h2 class="section-title">
|
|
399
|
+
<span class="icon">📝</span>
|
|
400
|
+
AI 提示詞設定
|
|
401
|
+
</h2>
|
|
402
|
+
<p class="form-help" style="margin-bottom: 16px;">
|
|
403
|
+
自定義 AI 回覆時使用的提示詞順序。第一次順序用於首次呼叫,第二次順序用於後續呼叫。順序為 0 表示不使用該組件。
|
|
404
|
+
</p>
|
|
405
|
+
|
|
406
|
+
<div id="promptConfigList" style="display: flex; flex-direction: column; gap: 16px;">
|
|
407
|
+
<div style="text-align: center; padding: 20px; color: var(--text-muted);">正在載入...</div>
|
|
408
|
+
</div>
|
|
409
|
+
|
|
410
|
+
<div class="form-actions" style="margin-top: 16px;">
|
|
411
|
+
<button id="resetPromptsBtn" class="btn btn-secondary">恢復預設</button>
|
|
412
|
+
<button id="savePromptsBtn" class="btn btn-primary">儲存提示詞設定</button>
|
|
413
|
+
</div>
|
|
414
|
+
</section>
|
|
415
|
+
|
|
381
416
|
</div>
|
|
382
417
|
|
|
383
418
|
<!-- Toast Container -->
|