dsh-decision-layer 0.6.3 → 0.7.0

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/lib/client.js CHANGED
@@ -32,324 +32,379 @@ __export(index_exports, {
32
32
  module.exports = __toCommonJS(index_exports);
33
33
 
34
34
  // src/client/i18n.ts
35
- var dictionaries = {
36
- zh: {
37
- summary: "\u5371\u9669\u8C03\u7528\u95E8\u63A7\u3001\u4EA7\u51FA\u81EA\u68C0\u4E0E\u9632\u5FAA\u73AF\uFF0C\u7531\u53EF\u63D2\u62D4\u88C1\u51B3\u6A21\u578B\u9A71\u52A8\u3002",
38
- button: "\u51B3\u7B56\u5C42",
39
- title: "\u51B3\u7B56\u5C42",
40
- close: "\u5173\u95ED",
41
- metrics: "\u81EA\u52A8\u88C1\u51B3\u7EDF\u8BA1",
42
- triggerDecisions: "\u51B3\u7B56",
43
- empty: "\u5C1A\u65E0\u81EA\u52A8\u88C1\u51B3\u3002\u624B\u52A8\u88C1\u51B3\u4E0D\u8BA1\u5165\u8FD9\u91CC\u3002",
44
- attempts: "\u8BC4\u4F30\u6B21\u6570",
45
- failures: "\u5931\u8D25\u56DE\u9000",
46
- suggestions: "\u6A21\u578B\u5EFA\u8BAE\uFF08\u653E\u884C / \u8BE2\u95EE / \u62D2\u7EDD\uFF09",
47
- actual: "\u5B9E\u9645\u5BBF\u4E3B\u7ED3\u679C\uFF08\u653E\u884C / \u62D2\u7EDD\uFF09",
48
- checkAttempts: "\u81EA\u68C0\u8BC4\u4F30\u6B21\u6570",
49
- checkLow: "\u4F4E\u5206",
50
- checkOk: "\u901A\u8FC7",
51
- settings: "\u4F1A\u8BDD\u8BBE\u7F6E",
52
- cardGate: "\u5371\u9669\u95E8\u63A7",
53
- cardCheck: "\u4EA7\u51FA\u81EA\u68C0",
54
- cardNarrow: "\u5DE5\u5177\u6536\u7A84",
55
- cardComplete: "\u5B8C\u6210\u6838\u5BF9",
56
- cardTimes: " \u6B21",
57
- allow: "\u653E\u884C",
58
- ask: "\u8BE2\u95EE",
59
- deny: "\u62D2\u7EDD",
60
- actualShort: "\u5B9E\u9645\u7ED3\u679C",
61
- narrowAppliedLabel: "\u6536\u7A84",
62
- narrowDroppedLabel: "\u6458\u9664\u5DE5\u5177",
63
- narrowDropped: "\u6458\u9664",
64
- narrowKept: "\u672A\u6536\u7A84",
65
- narrowKeptCount: "\u4FDD\u7559",
66
- narrowMore: " \u7B49 {count} \u4E2A",
67
- narrowObserve: "\u4EC5\u89C2\u5BDF",
68
- narrowEnforce: "\u5DF2\u751F\u6548",
69
- checkPassRate: "\u901A\u8FC7\u7387",
70
- narrowApplyRate: "\u6536\u7A84\u7387",
71
- rateNa: "\u2014",
72
- enabled: "\u672C\u4F1A\u8BDD\u5185\u542F\u7528\u81EA\u52A8\u4ECB\u5165",
73
- backendStatus: "\u540E\u7AEF\u8FDE\u63A5",
74
- statusChecking: "\u68C0\u6D4B\u4E2D\u2026",
75
- statusIdle: "\u672A\u68C0\u6D4B",
76
- statusOk: "\u6B63\u5E38",
77
- statusDown: "\u4E0D\u53EF\u7528",
78
- recheck: "\u91CD\u65B0\u68C0\u6D4B",
79
- log: "\u51B3\u7B56\u65E5\u5FD7",
80
- logEmpty: "\u672C\u4F1A\u8BDD\u5C1A\u65E0\u51B3\u7B56\u8BB0\u5F55\u3002",
81
- logGate: "\u95E8\u63A7",
82
- logCheck: "\u81EA\u68C0",
83
- logNarrow: "\u6536\u7A84",
84
- logComplete: "\u5B8C\u6210\u6838\u5BF9",
85
- logSuggested: "\u6A21\u578B\u5EFA\u8BAE",
86
- logEvalFailed: "\u8BC4\u4F30\u5931\u8D25",
87
- logScore: "\u5F97\u5206",
88
- logConnection: "\u8FDE\u63A5",
89
- logConfidence: "\u7F6E\u4FE1\u5EA6",
90
- logCommandLabel: "\u547D\u4EE4\uFF1A",
91
- logPathLabel: "\u8DEF\u5F84\uFF1A",
92
- logSubjectLabel: "\u8BF7\u6C42\uFF1A",
93
- logScoreHint: "\u5F97\u5206\u4E3A\u5404\u6863\u4F4D\u6309\u6982\u7387\u52A0\u6743\u7684\u7ED3\u679C\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\uFF08\u5982 1.4\uFF09\uFF0C\u6EE1\u5206\u4E3A\u9876\u6863\u53F7 2\u3002",
94
- logCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u540E\uFF0C\u628A\u8FD9\u8F6E AI \u7684\u6700\u7EC8\u56DE\u590D\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\uFF0C\u6309\u300C\u4E25\u91CD\u9057\u6F0F/\u81EA\u76F8\u77DB\u76FE \u2192 \u6709\u5C0F\u9057\u6F0F \u2192 \u5B8C\u6574\u51C6\u786E\u300D\u4E09\u6863\u6253\u4E00\u4E2A 0\u20132 \u7684\u8D28\u91CF\u5206\uFF0C\u7528\u6765\u53D1\u73B0\u9057\u6F0F\u6216\u77DB\u76FE\u3002",
95
- logNarrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u628A\u8FD9\u8F6E\u4EFB\u52A1\u4E0E\u5F53\u524D\u53EF\u7528\u5DE5\u5177\u9010\u4E2A\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u76F8\u5173\u6027\uFF08noul\uFF09\uFF0C\u6458\u6389\u660E\u663E\u7528\u4E0D\u4E0A\u7684\u5DE5\u5177\uFF0C\u53EA\u5728\u5F53\u524D\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u96C6\u5408\u5185\u53D6\u4EA4\u96C6\u3001\u7EDD\u4E0D\u6269\u6743\uFF1B\u300C\u4EC5\u89C2\u5BDF\u300D\u53EA\u8BB0\u5F55\u5EFA\u8BAE\uFF0C\u300C\u5DF2\u751F\u6548\u300D\u624D\u771F\u6B63\u5BF9\u672C\u56DE\u5408\u9650\u5236\u5DE5\u5177\u3002",
96
- actionDeny: "\u5DF2\u62D2\u7EDD",
97
- actionAsk: "\u8F6C\u4EA4\u5BA1\u6279",
98
- actionPass: "\u672A\u5E72\u9884",
99
- gatePassThrough: "\u672A\u5E72\u9884\uFF08\u6309\u539F\u8DEF\u5F84\u6267\u884C\uFF09",
100
- checkResultLow: "\u5F97\u5206\u504F\u4F4E",
101
- checkResultOk: "\u901A\u8FC7",
102
- checkResultLowNoisy: "\u5F97\u5206\u504F\u4F4E\uFF08\u4F4E\u7F6E\u4FE1\uFF09",
103
- checkNoiseTag: "\u566A\u58F0\uFF0C\u53EF\u5FFD\u7565",
104
- checkNoiseHint: "\u6A21\u578B\u5BF9\u8FD9\u6B21\u6253\u5206\u51E0\u4E4E\u6CA1\u6709\u628A\u63E1\uFF08\u7F6E\u4FE1\u5EA6\u6781\u4F4E\uFF09\uFF0C\u8FD9\u6761\u4F4E\u5206\u4E0D\u8BA1\u5165\u8D28\u91CF\u8D8B\u52BF\u3001\u4E5F\u4E0D\u89E6\u53D1\u4EFB\u4F55\u8865\u5B8C\uFF0C\u89C6\u4F5C\u566A\u58F0\u5FFD\u7565\u5373\u53EF\u3002\u771F\u6B63\u503C\u5F97\u5173\u6CE8\u7684\u662F\u8FDE\u7EED\u591A\u6B21\u9AD8\u7F6E\u4FE1\u7684\u4F4E\u5206\u3002",
105
- reasonUnavailable: "\u540E\u7AEF\u4E0D\u53EF\u8FBE",
106
- reasonHttpError: "\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF",
107
- reasonInvalidResponse: "\u54CD\u5E94\u683C\u5F0F\u4E0D\u7B26",
108
- reasonLowConfidence: "\u7F6E\u4FE1\u5EA6\u4E0D\u8DB3",
109
- reasonConfig: "\u914D\u7F6E\u65E0\u6548",
110
- reasonTooMany: "\u5019\u9009\u8FC7\u591A",
111
- reasonTooManyCount: "\u5019\u9009 {count} \u4E2A\u504F\u591A",
112
- reasonLowKeep: "\u4FDD\u7559\u8FC7\u5C11\uFF0C\u672A\u751F\u6548",
113
- selfCheck: "\u4EA7\u51FA\u81EA\u68C0",
114
- advancedSwitches: "\u4ECB\u5165\u5F00\u5173",
115
- advancedParams: "\u6536\u7A84\u53C2\u6570",
116
- selfCheckSteer: "\u5F97\u5206\u504F\u4F4E\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
117
- selfCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\uFF080\u20132\uFF0C\u6309\u5404\u6863\u4F4D\u6982\u7387\u52A0\u6743\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\u5982 1.4\uFF09\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u4F4E\u5206\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u5F97\u5206\u504F\u4F4E\uFF08\u22641\uFF09\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\uFF0C\u8BA9 AI \u590D\u6838\u6709\u65E0\u9057\u6F0F\u6216\u77DB\u76FE\u5E76\u8865\u5B8C\uFF1B\u7F6E\u4FE1\u5EA6\u504F\u4F4E\u7684\u6253\u5206\u53EA\u8BB0\u5F55\u3001\u4E0D\u6253\u65AD\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
118
- narrow: "\u5DE5\u5177\u6536\u7A84",
119
- narrowObserveLabel: "\u4EC5\u89C2\u5BDF\uFF08\u4E0D\u771F\u6B63\u9650\u5236\u5DE5\u5177\uFF09",
120
- narrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u7528\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u5F53\u524D\u53EF\u9009\u5DE5\u5177\u4E0E\u8FD9\u8F6E\u4EFB\u52A1\u7684\u76F8\u5173\u6027\uFF0C\u6458\u6389\u7528\u4E0D\u4E0A\u7684\uFF1B\u8BFB\u5199\u3001\u7F16\u8F91\u3001Shell\u3001\u68C0\u7D22\u3001\u5F85\u529E\u7B49\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u5224\u5B9A\u3002\u9ED8\u8BA4\u771F\u6B63\u751F\u6548\uFF1A\u672C\u56DE\u5408\u53EA\u4FDD\u7559\u5224\u4E3A\u76F8\u5173\u7684\u5DE5\u5177\uFF0C\u4E14\u53EA\u5728\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u8303\u56F4\u5185\u53D6\u4EA4\u96C6\u3001\u4E0D\u6269\u6743\u3002\u5F00\u542F\u300C\u4EC5\u89C2\u5BDF\u300D\u540E\u53EA\u628A\u53EF\u6458\u6389\u7684\u5DE5\u5177\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6539\u52A8\u5DE5\u5177\u96C6\u3002\u4E09\u91CD\u4FDD\u62A4\uFF1A\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\uFF1B\u53EF\u9009\u5DE5\u5177\u8D85\u8FC7 20 \u4E2A\u65F6\u81EA\u52A8\u53EA\u89C2\u5BDF\u4E0D\u9650\u5236\uFF1B\u4FDD\u7559\u4E0B\u6765\u4E0D\u8DB3 5 \u4E2A\u65F6\u89C6\u4E3A\u5224\u5B9A\u4E0D\u53EF\u4FE1\u3001\u8DF3\u8FC7\u3002",
121
- narrowKeepLabel: "\u59CB\u7EC8\u4FDD\u7559\u7684\u5DE5\u5177\u524D\u7F00",
122
- narrowKeepHint: "\u540D\u5B57\u4EE5\u8FD9\u4E9B\u524D\u7F00\u5F00\u5934\u7684\u5DE5\u5177\u6C38\u8FDC\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u76F8\u5173\u6027\u5224\u5B9A\uFF0C\u9002\u5408\u8BB0\u5FC6/\u68C0\u7D22\u8FD9\u7C7B\u300C\u5E38\u9A7B\u3001\u6309\u9700\u89E6\u53D1\u300D\u7684\u5DE5\u5177\uFF08\u9ED8\u8BA4\u542B mcp__openviking\u3001team_task_\uFF09\u3002\u7528\u82F1\u6587\u9017\u53F7\u6216\u6362\u884C\u5206\u9694\u591A\u4E2A\u524D\u7F00\uFF1B\u7559\u7A7A\u5219\u4E0D\u989D\u5916\u4FDD\u7559\u3002",
123
- narrowMaxLabel: "\u5019\u9009\u5DE5\u5177\u4E0A\u9650",
124
- narrowMaxHint: "\u4E00\u56DE\u5408\u91CC\u53C2\u4E0E\u5224\u5B9A\u7684\u300C\u53EF\u9009\u5DE5\u5177\u300D\u8D85\u8FC7\u8FD9\u4E2A\u6570\uFF08\u9ED8\u8BA4 20\uFF09\uFF0C\u5C31\u81EA\u52A8\u964D\u7EA7\u4E3A\u4EC5\u89C2\u5BDF\u3001\u4E0D\u771F\u6B63\u6536\u7A84\uFF0C\u907F\u514D\u4E00\u6B21\u585E\u592A\u591A\u5DE5\u5177\u8BA9\u6A21\u578B\u8BEF\u6458\u3002\u53D6\u503C 1\u2013200\uFF0C\u8C03\u5927\u66F4\u503E\u5411\u771F\u6B63\u6536\u7A84\u3002\u6838\u5FC3\u5DE5\u5177\u4E0E\u4FDD\u7559\u524D\u7F00\u547D\u4E2D\u7684\u5DE5\u5177\u4E0D\u8BA1\u5165\u3002",
125
- narrowThresholdLabel: "\u6458\u9664\u9608\u503C",
126
- narrowThresholdHint: "\u76F8\u5173\u6027\u6982\u7387\u4F4E\u4E8E\u8FD9\u4E2A\u503C\u624D\u6458\u6389\u5DE5\u5177\uFF08\u9ED8\u8BA4 0.3\uFF09\u3002\u6982\u7387\u63A5\u8FD1 0.5 \u8868\u793A\u6A21\u578B\u62FF\u4E0D\u51C6\u3001\u5E76\u975E\u300C\u4E2D\u7B49\u76F8\u5173\u300D\uFF0C\u6B64\u65F6\u4FDD\u7559\u66F4\u7A33\u59A5\uFF1B\u8C03\u4F4E\u66F4\u4FDD\u5B88\uFF08\u5C11\u6458\u3001\u5B81\u53EF\u591A\u7559\uFF09\uFF0C\u8C03\u9AD8\u66F4\u6FC0\u8FDB\uFF08\u591A\u6458\uFF09\u3002\u53D6\u503C 0\u20131\u3002",
127
- features: "\u51B3\u7B56\u70B9\u5F00\u5173",
128
- basicFeatures: "\u57FA\u7840\u529F\u80FD",
129
- advancedConfig: "\u9AD8\u7EA7\u914D\u7F6E",
130
- featureGate: "\u5371\u9669\u95E8\u63A7",
131
- featureGateHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5BF9\u7834\u574F\u6027\u5DE5\u5177\u8C03\u7528\u505A\u62E6\u622A\u8BC4\u4F30\uFF0C\u8C03\u7528\u53EA\u53D7\u5BBF\u4E3B\u539F\u751F\u6743\u9650\u7EA6\u675F\u3002",
132
- featureCheck: "\u4EA7\u51FA\u81EA\u68C0",
133
- featureCheckHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\u3002",
134
- featureNarrow: "\u5DE5\u5177\u6536\u7A84",
135
- featureNarrowHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u5F00\u59CB\u65F6\u8BC4\u4F30\u5DE5\u5177\u76F8\u5173\u6027\u3002\u9632\u5FAA\u73AF\u4E3A\u786E\u5B9A\u6027\u672C\u5730\u4FDD\u62A4\uFF0C\u59CB\u7EC8\u751F\u6548\uFF0C\u4E0D\u5728\u6B64\u5F00\u5173\u8303\u56F4\u3002",
136
- featureComplete: "\u4EFB\u52A1\u5B8C\u6210\u6838\u5BF9",
137
- featureCompleteHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u9010\u9879\u6838\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u4EA4\u4ED8\u6761\u4EF6\u3002",
138
- trendWarnHint: "\u672C\u4F1A\u8BDD\u6700\u8FD1\u8FDE\u7EED\u51E0\u8F6E\u4EA7\u51FA\u8D28\u91CF\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u53EF\u80FD\u662F\u4EFB\u52A1\u96BE\u5EA6\u4E0A\u5347\u6216\u6A21\u578B\u72B6\u6001\u6CE2\u52A8\uFF0C\u5EFA\u8BAE\u5C1D\u8BD5\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\u3002",
139
- trendSevereHint: "\u672C\u4F1A\u8BDD\u4EA7\u51FA\u8D28\u91CF\u6301\u7EED\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u5EFA\u8BAE\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\uFF0C\u6216\u91CD\u5F00\u4F1A\u8BDD\u3002",
140
- rateGroup: "\u6807\u6CE8\u8FD9\u6B21\u5224\u65AD",
141
- rateGood: "\u5224\u5BF9\u4E86",
142
- rateBad: "\u5224\u9519\u4E86",
143
- rateUnsure: "\u8BF4\u4E0D\u51C6",
144
- rateSummary: "\u5DF2\u6807\u6CE8 {rated} \u6761\uFF08\u5224\u5BF9 {good} / \u5224\u9519 {bad} / \u8BF4\u4E0D\u51C6 {unsure}\uFF09",
145
- annotateFailed: "\u6807\u6CE8\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
146
- completeSteer: "\u6709\u672A\u6EE1\u8DB3\u6761\u4EF6\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
147
- completeHint: "\u56DE\u5408\u7ED3\u675F\u65F6\uFF0C\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u591A\u4E2A\u4EA4\u4ED8\u6761\u4EF6\uFF08\u7F16\u53F7 / \u9879\u76EE\u7B26\u53F7 / \u591A\u547D\u4EE4\uFF09\u9010\u9879\u5224\u5B9A\u300C\u5DF2\u6EE1\u8DB3 / \u672A\u6EE1\u8DB3 / \u8BC1\u636E\u4E0D\u8DB3\u300D\uFF0C\u4EE5\u5DE5\u5177\u8BC1\u636E\u4E3A\u51C6\u3001\u56DE\u590D\u81EA\u79F0\u5B8C\u6210\u4E0D\u7B97\u8BC1\u636E\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u7ED3\u679C\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u786E\u6709\u6761\u4EF6\u88AB\u5224\u300C\u672A\u6EE1\u8DB3\u300D\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\u8BA9 AI \u590D\u6838\u8865\u5B8C\uFF1B\u300C\u8BC1\u636E\u4E0D\u8DB3\u300D\u4E0D\u89E6\u53D1\u8865\u5B8C\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
148
- completeResultOk: "\u6761\u4EF6\u9F50\u5907",
149
- completeResultUnsatisfied: "\u6709\u672A\u6EE1\u8DB3",
150
- completeConditions: "\u6761\u4EF6",
151
- completeSatisfied: "\u6EE1\u8DB3",
152
- completeUnsatisfied: "\u672A\u6EE1\u8DB3",
153
- completeInsufficient: "\u8BC1\u636E\u4E0D\u8DB3",
154
- completeSteered: "\u5DF2\u8865\u4E00\u8F6E",
155
- backend: "\u88C1\u51B3\u540E\u7AEF",
156
- url: "\u670D\u52A1\u5730\u5740",
157
- model: "\u6A21\u578B",
158
- key: "API Key",
159
- keyHintSaved: "\u5DF2\u4FDD\u5B58\u4E00\u4E2A Key\u3002\u7559\u7A7A\u5E76\u4FDD\u5B58\uFF1D\u6CBF\u7528\u5B83\uFF08\u4E0D\u6539\u52A8\uFF09\uFF1B\u586B\u65B0\u503C\u5E76\u4FDD\u5B58\uFF1D\u8986\u76D6\u5B83\u3002",
160
- keyHintEmpty: "\u5C1A\u672A\u4FDD\u5B58 Key\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u586B\u5165\u5219\u4FDD\u5B58\u5230\u672C\u673A\u3002",
161
- removeKey: "\u5220\u9664\u5DF2\u4FDD\u5B58\u7684 Key",
162
- removeKeyHint: "\u628A\u672C\u63D2\u4EF6\u4FDD\u5B58\u5728\u672C\u673A\u7684 Key \u6C38\u4E45\u5220\u9664\uFF0C\u4E4B\u540E\u81EA\u52A8\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u4E0D\u5F71\u54CD\u4F60\u5728\u522B\u5904\u914D\u7F6E\u7684\u51ED\u636E\u3002",
163
- removeKeyButton: "\u5220\u9664",
164
- removeKeyConfirm: "\u786E\u5B9A\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684 API Key\uFF1F\u5220\u9664\u540E\u5C06\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u7684 Key\u3002",
165
- removeKeyDone: "\u5DF2\u5220\u9664\u4FDD\u5B58\u7684 Key",
166
- save: "\u4FDD\u5B58\u914D\u7F6E",
167
- saveAdvanced: "\u4FDD\u5B58\u9AD8\u7EA7\u914D\u7F6E",
168
- probe: "\u6D4B\u8BD5\u8FDE\u63A5",
169
- saved: "\u914D\u7F6E\u5DF2\u4FDD\u5B58",
170
- connected: "\u8FDE\u63A5\u6210\u529F",
171
- unavailable: "\u8FDE\u63A5\u4E0D\u53EF\u7528",
172
- error: "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
173
- loading: "\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u72B6\u6001",
174
- destination: "\u88C1\u51B3\u65F6\u4F1A\u5411\u4EE5\u4E0B\u540E\u7AEF\u53D1\u9001\u5FC5\u8981\u7684\u8BC4\u4F30\u4E0A\u4E0B\u6587\uFF1A",
175
- httpWarning: "\u6B64\u5730\u5740\u4F7F\u7528\u672A\u52A0\u5BC6\u7684 HTTP\u3002\u786E\u8BA4\u540E\uFF0CAPI Key \u4E0E\u8BC4\u4F30\u4E0A\u4E0B\u6587\u5C06\u4EE5\u660E\u6587\u53D1\u9001\u81F3\u8BE5\u5730\u5740\u3002",
176
- analysisTab: "\u51B3\u7B56\u5206\u6790",
177
- analysisTitle: "\u51B3\u7B56\u5206\u6790",
178
- analysisIntro: "\u57FA\u4E8E\u672C\u4F1A\u8BDD\u5DF2\u843D\u76D8\u7684\u51B3\u7B56\u65E5\u5FD7\u505A\u53EA\u8BFB\u805A\u5408\u4E0E\u4EBA\u5DE5\u6807\u6CE8\uFF0C\u4E0D\u6539\u53D8\u4EFB\u4F55 agent \u884C\u4E3A\u3002",
179
- analysisProfile: "\u8FC7\u7A0B\u753B\u50CF",
180
- analysisMeanScore: "\u5E73\u5747\u5206",
181
- analysisTrend: "\u8D28\u91CF\u8D8B\u52BF\u56DE\u6D4B",
182
- analysisTrendWarn: "\u544A\u8B66\u89E6\u53D1",
183
- analysisTrendSevere: "\u4E25\u91CD\u89E6\u53D1",
184
- analysisTrendMaxRun: "\u6700\u957F\u8FDE\u7EED\u4F4E\u5206",
185
- analysisTrendNote: "\u7528\u5F53\u524D\u9608\u503C\u628A\u672C\u4F1A\u8BDD\u7684\u81EA\u68C0\u5206\u6570\u6309\u65F6\u95F4\u91CD\u653E\uFF0C\u7EDF\u8BA1\u544A\u8B66\u672C\u4F1A\u300C\u4F1A\u300D\u89E6\u53D1\u51E0\u6B21\uFF0C\u7528\u4E8E\u6821\u51C6\u9608\u503C\uFF0C\u4E0D\u662F\u5B9E\u65F6\u4FE1\u53F7\u3002",
186
- analysisAccuracy: "\u5224\u65AD\u51C6\u786E\u5EA6",
187
- analysisAccuracyEmpty: "\u5C1A\u672A\u6807\u6CE8\u4EFB\u4F55\u51B3\u7B56\u3002\u5728\u4E0B\u65B9\u51B3\u7B56\u5217\u8868\u9010\u6761\u6807\u6CE8\u300C\u5224\u5BF9 / \u5224\u9519 / \u8BF4\u4E0D\u51C6\u300D\u540E\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u6C47\u603B\u3002",
188
- analysisLogNote: "\u6807\u6CE8\u5728\u6B64\u4E0E\u4ECB\u5165\u9762\u677F\u540C\u6E90\uFF1A\u4EFB\u4E00\u5904\u6807\u6CE8\u90FD\u5199\u5165\u540C\u4E00\u4EFD\u65E5\u5FD7\u3001\u6309\u51B3\u7B56 id \u5173\u8054\u3001\u53D6\u6700\u65B0\u3002",
189
- analysisLogTruncated: "\u672C\u4F1A\u8BDD\u6682\u65E0\u53EF\u5C55\u793A\u7684\u51B3\u7B56\u8BB0\u5F55\u3002",
190
- pagerPrev: "\u4E0A\u4E00\u9875",
191
- pagerNext: "\u4E0B\u4E00\u9875",
192
- pagerStatus: "\u7B2C {page}/{pages} \u9875 \xB7 \u5171 {total} \u6761"
193
- },
194
- en: {
195
- summary: "A danger-call gate, output self-check, and loop guard driven by a pluggable adjudication model.",
196
- button: "Decision layer",
197
- title: "Decision layer",
198
- close: "Close",
199
- metrics: "Automatic decisions",
200
- triggerDecisions: "decisions",
201
- empty: "No automatic decisions yet. Manual verdicts are not counted here.",
202
- attempts: "Evaluations",
203
- failures: "Fallback failures",
204
- suggestions: "Model suggestions (allow / ask / deny)",
205
- actual: "Actual host outcomes (allow / deny)",
206
- checkAttempts: "Self-check evaluations",
207
- checkLow: "Low",
208
- checkOk: "Passed",
209
- settings: "Session settings",
210
- cardGate: "Danger gate",
211
- cardCheck: "Output self-check",
212
- cardNarrow: "Tool narrowing",
213
- cardComplete: "Task completion",
214
- cardTimes: "",
215
- allow: "Allow",
216
- ask: "Ask",
217
- deny: "Deny",
218
- actualShort: "Actual",
219
- narrowAppliedLabel: "Narrowed",
220
- narrowDroppedLabel: "Tools dropped",
221
- narrowDropped: "dropped",
222
- narrowKept: "kept all",
223
- narrowKeptCount: "kept",
224
- narrowMore: " and {count} in total",
225
- narrowObserve: "observe",
226
- narrowEnforce: "enforced",
227
- checkPassRate: "Pass rate",
228
- narrowApplyRate: "Narrow rate",
229
- rateNa: "\u2014",
230
- enabled: "Enable automatic interventions in this session",
231
- backendStatus: "Backend",
232
- statusChecking: "Checking\u2026",
233
- statusIdle: "Not checked",
234
- statusOk: "Connected",
235
- statusDown: "Unavailable",
236
- recheck: "Recheck",
237
- log: "Decision log",
238
- logEmpty: "No decisions recorded for this session yet.",
239
- logGate: "Gate",
240
- logCheck: "Self-check",
241
- logNarrow: "Narrow",
242
- logComplete: "Completion",
243
- logSuggested: "model suggested",
244
- logEvalFailed: "evaluation failed",
245
- logScore: "score",
246
- logConnection: "connection",
247
- logConfidence: "confidence",
248
- logCommandLabel: "command: ",
249
- logPathLabel: "path: ",
250
- logSubjectLabel: "request: ",
251
- logScoreHint: "The score is a probability-weighted mean across the levels, so it can be fractional (e.g. 1.4); the top score is the highest level number, 2.",
252
- logCheckHint: "After each turn, the AI\u2019s final reply for that turn is sent to the adjudication model, which grades its quality on three levels (severe omission/contradiction \u2192 minor gaps \u2192 complete and accurate) as a 0\u20132 score, to catch omissions or contradictions.",
253
- logNarrowHint: "At the start of each turn, the current task and each available tool are sent to the adjudication model (a noul per tool) to judge relevance, dropping tools clearly not needed. It only intersects the host-allowed set and never expands it; observe merely logs the suggestion, enforced actually restricts the tools for this turn.",
254
- actionDeny: "denied",
255
- actionAsk: "sent to approval",
256
- actionPass: "no intervention",
257
- gatePassThrough: "no intervention (proceeded on its original path)",
258
- checkResultLow: "low score",
259
- checkResultOk: "passed",
260
- checkResultLowNoisy: "low score (low confidence)",
261
- checkNoiseTag: "noise, ignore",
262
- checkNoiseHint: "The model had almost no confidence in this score (near-zero confidence). This low score does not count toward the quality trend and triggers no re-prompt \u2014 treat it as noise. What matters is several consecutive high-confidence low scores.",
263
- reasonUnavailable: "backend unreachable",
264
- reasonHttpError: "backend returned an error",
265
- reasonInvalidResponse: "unexpected response shape",
266
- reasonLowConfidence: "low confidence",
267
- reasonConfig: "invalid configuration",
268
- reasonTooMany: "too many candidates",
269
- reasonTooManyCount: "{count} candidates is too many",
270
- reasonLowKeep: "too few kept, not enforced",
271
- selfCheck: "Output self-check",
272
- advancedSwitches: "Intervention switches",
273
- advancedParams: "Narrowing parameters",
274
- selfCheckSteer: "Auto re-prompt on a low score",
275
- selfCheckHint: "Each turn ends by scoring the final reply (0\u20132, a probability-weighted mean across the levels, so it can be fractional like 1.4). Off: low scores are only logged, the conversation is not interrupted. On: when the score is low (\u22641) and the model is confident enough, one prompt is appended on your behalf asking the AI to review for gaps or contradictions and finish the work; low-confidence scores are only logged, never interrupt, and at most one prompt per turn.",
276
- narrow: "Tool narrowing",
277
- narrowObserveLabel: "Observe only (do not restrict tools)",
278
- narrowHint: "At the start of each turn, the adjudication model judges how relevant each optional tool is to the task and drops the ones not needed; core tools (read, write, edit, shell, search, todos) are always kept and never judged. Enforced by default: only the relevant tools are kept for this turn, intersected with the host-allowed set and never expanded. Turn on Observe only to just log the tools that could be dropped, without changing the tool set. Three safeguards: core tools always kept; more than 20 optional tools falls back to observe only; fewer than 5 tools remaining is treated as untrustworthy and skipped.",
279
- narrowKeepLabel: "Always-kept tool prefixes",
280
- narrowKeepHint: "Tools whose names start with any of these prefixes are always kept and never judged for relevance \u2014 good for resident, on-demand tools like memory/retrieval (defaults to mcp__openviking and team_task_). Separate prefixes with commas or newlines; leave empty to keep nothing extra.",
281
- narrowMaxLabel: "Candidate tool cap",
282
- narrowMaxHint: "When more than this many optional tools are judged in one turn (default 20), narrowing downgrades to observe only instead of actually restricting, so a large surface is never mass-pruned. Range 1\u2013200; a higher value leans toward actually narrowing. Core tools and keep-prefix matches do not count.",
283
- narrowThresholdLabel: "Drop threshold",
284
- narrowThresholdHint: 'A tool is dropped only when its relevance probability is below this value (default 0.3). A probability near 0.5 means the model is unsure, not "moderately relevant", so keeping is safer there; lower is more conservative (drops fewer), higher is more aggressive. Range 0\u20131.',
285
- features: "Decision points",
286
- basicFeatures: "Basic features",
287
- advancedConfig: "Advanced settings",
288
- featureGate: "Danger gate",
289
- featureGateHint: "When off, destructive tool calls are no longer evaluated for interception and are only bound by the host permission rules.",
290
- featureCheck: "Output self-check",
291
- featureCheckHint: "When off, the final reply is no longer scored at the end of a turn.",
292
- featureNarrow: "Tool narrowing",
293
- featureNarrowHint: "When off, tool relevance is no longer evaluated at the start of a turn. The loop guard is a deterministic local safeguard that is always on and not covered by this switch.",
294
- featureComplete: "Task completion check",
295
- featureCompleteHint: "When off, the explicit deliverable conditions the user listed are no longer checked at turn end.",
296
- trendWarnHint: "Output quality has been low for a few consecutive turns this session (high confidence). It may be rising task difficulty or model drift \u2014 consider adjusting the prompt or switching models.",
297
- trendSevereHint: "Output quality has stayed low this session (high confidence). Consider adjusting the prompt, switching models, or starting a new session.",
298
- rateGroup: "Rate this decision",
299
- rateGood: "Correct",
300
- rateBad: "Wrong",
301
- rateUnsure: "Unsure",
302
- rateSummary: "Rated {rated} ({good} correct / {bad} wrong / {unsure} unsure)",
303
- annotateFailed: "Could not save the rating. Please retry.",
304
- completeSteer: "Auto re-prompt on an unmet condition",
305
- completeHint: "At turn end, each explicit deliverable condition the user listed (numbered / bulleted / multi-command) is judged satisfied / unsatisfied / insufficient evidence, with tool evidence as the source of truth \u2014 a reply claiming completion is not evidence. Off: results are only logged, the conversation is not interrupted. On: when a condition is confidently judged unsatisfied, one prompt is appended on your behalf asking the AI to review and finish it; insufficient evidence never triggers a re-prompt, and at most one per turn.",
306
- completeResultOk: "conditions met",
307
- completeResultUnsatisfied: "unmet found",
308
- completeConditions: "conditions",
309
- completeSatisfied: "met",
310
- completeUnsatisfied: "unmet",
311
- completeInsufficient: "insufficient",
312
- completeSteered: "re-prompted",
313
- backend: "Decision backend",
314
- url: "Server URL",
315
- model: "Model",
316
- key: "API key",
317
- keyHintSaved: "A key is saved. Leave blank and save to keep it; enter a new value and save to overwrite it.",
318
- keyHintEmpty: "No key saved yet. Leave blank to use an environment credential, or enter one to save it locally.",
319
- removeKey: "Delete saved API key",
320
- removeKeyHint: "Permanently deletes the key this plugin stored locally, then falls back to the environment credential; credentials configured elsewhere are untouched.",
321
- removeKeyButton: "Delete",
322
- removeKeyConfirm: "Delete the locally saved API key? It will fall back to the environment credential.",
323
- removeKeyDone: "Saved key deleted",
324
- save: "Save configuration",
325
- saveAdvanced: "Save advanced settings",
326
- probe: "Test connection",
327
- saved: "Configuration saved",
328
- connected: "Connected",
329
- unavailable: "Connection unavailable",
330
- error: "Request failed. Please retry.",
331
- loading: "Loading session settings",
332
- destination: "Decisions send the necessary evaluation context to this backend:",
333
- httpWarning: "This address uses unencrypted HTTP. Your API key and evaluation context will be sent in plaintext to this address.",
334
- analysisTab: "Decision analysis",
335
- analysisTitle: "Decision analysis",
336
- analysisIntro: "A read-only aggregate and manual annotation over this session\u2019s persisted decision log. It changes no agent behavior.",
337
- analysisProfile: "Process profile",
338
- analysisMeanScore: "Mean score",
339
- analysisTrend: "Quality-trend backtest",
340
- analysisTrendWarn: "Warn fires",
341
- analysisTrendSevere: "Severe fires",
342
- analysisTrendMaxRun: "Longest low run",
343
- analysisTrendNote: "Replays this session\u2019s self-check scores in time order under the current thresholds to count how often the alarm would fire \u2014 a calibration aid, not a live signal.",
344
- analysisAccuracy: "Decision accuracy",
345
- analysisAccuracyEmpty: "No decisions rated yet. Rate rows below as correct / wrong / unsure and a summary appears here.",
346
- analysisLogNote: "Ratings here share one source with the intervention panel: a rating on either surface writes to the same log, keyed by decision id, latest wins.",
347
- analysisLogTruncated: "No decision rows to show for this session.",
348
- pagerPrev: "Prev",
349
- pagerNext: "Next",
350
- pagerStatus: "Page {page}/{pages} \xB7 {total} total"
351
- }
35
+ var zh = {
36
+ summary: "\u5371\u9669\u8C03\u7528\u95E8\u63A7\u3001\u4EA7\u51FA\u81EA\u68C0\u4E0E\u9632\u5FAA\u73AF\uFF0C\u7531\u53EF\u63D2\u62D4\u88C1\u51B3\u6A21\u578B\u9A71\u52A8\u3002",
37
+ button: "\u51B3\u7B56\u5C42",
38
+ title: "\u51B3\u7B56\u5C42",
39
+ close: "\u5173\u95ED",
40
+ metrics: "\u81EA\u52A8\u88C1\u51B3\u7EDF\u8BA1",
41
+ triggerDecisions: "\u51B3\u7B56",
42
+ empty: "\u5C1A\u65E0\u81EA\u52A8\u88C1\u51B3\u3002\u624B\u52A8\u88C1\u51B3\u4E0D\u8BA1\u5165\u8FD9\u91CC\u3002",
43
+ attempts: "\u8BC4\u4F30\u6B21\u6570",
44
+ failures: "\u5931\u8D25\u56DE\u9000",
45
+ suggestions: "\u6A21\u578B\u5EFA\u8BAE\uFF08\u653E\u884C / \u8BE2\u95EE / \u62D2\u7EDD\uFF09",
46
+ actual: "\u5B9E\u9645\u5BBF\u4E3B\u7ED3\u679C\uFF08\u653E\u884C / \u62D2\u7EDD\uFF09",
47
+ checkAttempts: "\u81EA\u68C0\u8BC4\u4F30\u6B21\u6570",
48
+ checkLow: "\u4F4E\u5206",
49
+ checkOk: "\u901A\u8FC7",
50
+ settings: "\u4F1A\u8BDD\u8BBE\u7F6E",
51
+ cardGate: "\u5371\u9669\u95E8\u63A7",
52
+ cardCheck: "\u4EA7\u51FA\u81EA\u68C0",
53
+ cardNarrow: "\u5DE5\u5177\u6536\u7A84",
54
+ cardComplete: "\u5B8C\u6210\u6838\u5BF9",
55
+ cardTimes: " \u6B21",
56
+ allow: "\u653E\u884C",
57
+ ask: "\u8BE2\u95EE",
58
+ deny: "\u62D2\u7EDD",
59
+ actualShort: "\u5B9E\u9645\u7ED3\u679C",
60
+ narrowAppliedLabel: "\u6536\u7A84",
61
+ narrowDroppedLabel: "\u6458\u9664\u5DE5\u5177",
62
+ narrowDropped: "\u6458\u9664",
63
+ narrowKept: "\u672A\u6536\u7A84",
64
+ narrowKeptCount: "\u4FDD\u7559",
65
+ narrowMore: " \u7B49 {count} \u4E2A",
66
+ narrowObserve: "\u4EC5\u89C2\u5BDF",
67
+ narrowEnforce: "\u5DF2\u751F\u6548",
68
+ checkPassRate: "\u901A\u8FC7\u7387",
69
+ narrowApplyRate: "\u6536\u7A84\u7387",
70
+ rateNa: "\u2014",
71
+ enabled: "\u672C\u4F1A\u8BDD\u5185\u542F\u7528\u81EA\u52A8\u4ECB\u5165",
72
+ backendStatus: "\u540E\u7AEF\u8FDE\u63A5",
73
+ statusChecking: "\u68C0\u6D4B\u4E2D\u2026",
74
+ statusIdle: "\u672A\u68C0\u6D4B",
75
+ statusOk: "\u6B63\u5E38",
76
+ statusDown: "\u4E0D\u53EF\u7528",
77
+ recheck: "\u91CD\u65B0\u68C0\u6D4B",
78
+ log: "\u51B3\u7B56\u65E5\u5FD7",
79
+ logEmpty: "\u672C\u4F1A\u8BDD\u5C1A\u65E0\u51B3\u7B56\u8BB0\u5F55\u3002",
80
+ logGate: "\u95E8\u63A7",
81
+ logCheck: "\u81EA\u68C0",
82
+ logNarrow: "\u6536\u7A84",
83
+ logComplete: "\u5B8C\u6210\u6838\u5BF9",
84
+ logSuggested: "\u6A21\u578B\u5EFA\u8BAE",
85
+ logEvalFailed: "\u8BC4\u4F30\u5931\u8D25",
86
+ logScore: "\u5F97\u5206",
87
+ logConnection: "\u8FDE\u63A5",
88
+ logConfidence: "\u7F6E\u4FE1\u5EA6",
89
+ logCommandLabel: "\u547D\u4EE4\uFF1A",
90
+ logPathLabel: "\u8DEF\u5F84\uFF1A",
91
+ logSubjectLabel: "\u8BF7\u6C42\uFF1A",
92
+ logScoreHint: "\u5F97\u5206\u4E3A\u5404\u6863\u4F4D\u6309\u6982\u7387\u52A0\u6743\u7684\u7ED3\u679C\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\uFF08\u5982 1.4\uFF09\uFF0C\u6EE1\u5206\u4E3A\u9876\u6863\u53F7 2\u3002",
93
+ logCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u540E\uFF0C\u628A\u8FD9\u8F6E AI \u7684\u6700\u7EC8\u56DE\u590D\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\uFF0C\u6309\u300C\u4E25\u91CD\u9057\u6F0F/\u81EA\u76F8\u77DB\u76FE \u2192 \u6709\u5C0F\u9057\u6F0F \u2192 \u5B8C\u6574\u51C6\u786E\u300D\u4E09\u6863\u6253\u4E00\u4E2A 0\u20132 \u7684\u8D28\u91CF\u5206\uFF0C\u7528\u6765\u53D1\u73B0\u9057\u6F0F\u6216\u77DB\u76FE\u3002",
94
+ logNarrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u628A\u8FD9\u8F6E\u4EFB\u52A1\u4E0E\u5F53\u524D\u53EF\u7528\u5DE5\u5177\u9010\u4E2A\u4EA4\u7ED9\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u76F8\u5173\u6027\uFF08noul\uFF09\uFF0C\u6458\u6389\u660E\u663E\u7528\u4E0D\u4E0A\u7684\u5DE5\u5177\uFF0C\u53EA\u5728\u5F53\u524D\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u96C6\u5408\u5185\u53D6\u4EA4\u96C6\u3001\u7EDD\u4E0D\u6269\u6743\uFF1B\u300C\u4EC5\u89C2\u5BDF\u300D\u53EA\u8BB0\u5F55\u5EFA\u8BAE\uFF0C\u300C\u5DF2\u751F\u6548\u300D\u624D\u771F\u6B63\u5BF9\u672C\u56DE\u5408\u9650\u5236\u5DE5\u5177\u3002",
95
+ actionDeny: "\u5DF2\u62D2\u7EDD",
96
+ actionAsk: "\u8F6C\u4EA4\u5BA1\u6279",
97
+ actionPass: "\u672A\u5E72\u9884",
98
+ gatePassThrough: "\u672A\u5E72\u9884\uFF08\u6309\u539F\u8DEF\u5F84\u6267\u884C\uFF09",
99
+ checkResultLow: "\u5F97\u5206\u504F\u4F4E",
100
+ checkResultOk: "\u901A\u8FC7",
101
+ checkResultLowNoisy: "\u5F97\u5206\u504F\u4F4E\uFF08\u4F4E\u7F6E\u4FE1\uFF09",
102
+ checkNoiseTag: "\u566A\u58F0\uFF0C\u53EF\u5FFD\u7565",
103
+ checkNoiseHint: "\u6A21\u578B\u5BF9\u8FD9\u6B21\u6253\u5206\u51E0\u4E4E\u6CA1\u6709\u628A\u63E1\uFF08\u7F6E\u4FE1\u5EA6\u6781\u4F4E\uFF09\uFF0C\u8FD9\u6761\u4F4E\u5206\u4E0D\u8BA1\u5165\u8D28\u91CF\u8D8B\u52BF\u3001\u4E5F\u4E0D\u89E6\u53D1\u4EFB\u4F55\u8865\u5B8C\uFF0C\u89C6\u4F5C\u566A\u58F0\u5FFD\u7565\u5373\u53EF\u3002\u771F\u6B63\u503C\u5F97\u5173\u6CE8\u7684\u662F\u8FDE\u7EED\u591A\u6B21\u9AD8\u7F6E\u4FE1\u7684\u4F4E\u5206\u3002",
104
+ reasonUnavailable: "\u540E\u7AEF\u4E0D\u53EF\u8FBE",
105
+ reasonHttpError: "\u540E\u7AEF\u8FD4\u56DE\u9519\u8BEF",
106
+ reasonInvalidResponse: "\u54CD\u5E94\u683C\u5F0F\u4E0D\u7B26",
107
+ reasonLowConfidence: "\u7F6E\u4FE1\u5EA6\u4E0D\u8DB3",
108
+ reasonConfig: "\u914D\u7F6E\u65E0\u6548",
109
+ reasonTooMany: "\u5019\u9009\u8FC7\u591A",
110
+ reasonTooManyCount: "\u5019\u9009 {count} \u4E2A\u504F\u591A",
111
+ reasonLowKeep: "\u4FDD\u7559\u8FC7\u5C11\uFF0C\u672A\u751F\u6548",
112
+ selfCheck: "\u4EA7\u51FA\u81EA\u68C0",
113
+ advancedSwitches: "\u4ECB\u5165\u5F00\u5173",
114
+ advancedParams: "\u6536\u7A84\u53C2\u6570",
115
+ selfCheckSteer: "\u5F97\u5206\u504F\u4F4E\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
116
+ selfCheckHint: "\u6BCF\u56DE\u5408\u7ED3\u675F\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\uFF080\u20132\uFF0C\u6309\u5404\u6863\u4F4D\u6982\u7387\u52A0\u6743\uFF0C\u53EF\u80FD\u662F\u5C0F\u6570\u5982 1.4\uFF09\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u4F4E\u5206\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u5F97\u5206\u504F\u4F4E\uFF08\u22641\uFF09\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\uFF0C\u8BA9 AI \u590D\u6838\u6709\u65E0\u9057\u6F0F\u6216\u77DB\u76FE\u5E76\u8865\u5B8C\uFF1B\u7F6E\u4FE1\u5EA6\u504F\u4F4E\u7684\u6253\u5206\u53EA\u8BB0\u5F55\u3001\u4E0D\u6253\u65AD\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
117
+ narrow: "\u5DE5\u5177\u6536\u7A84",
118
+ narrowObserveLabel: "\u4EC5\u89C2\u5BDF\uFF08\u4E0D\u771F\u6B63\u9650\u5236\u5DE5\u5177\uFF09",
119
+ narrowHint: "\u6BCF\u56DE\u5408\u5F00\u59CB\u65F6\uFF0C\u7528\u88C1\u51B3\u6A21\u578B\u5224\u65AD\u5F53\u524D\u53EF\u9009\u5DE5\u5177\u4E0E\u8FD9\u8F6E\u4EFB\u52A1\u7684\u76F8\u5173\u6027\uFF0C\u6458\u6389\u7528\u4E0D\u4E0A\u7684\uFF1B\u8BFB\u5199\u3001\u7F16\u8F91\u3001Shell\u3001\u68C0\u7D22\u3001\u5F85\u529E\u7B49\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u5224\u5B9A\u3002\u9ED8\u8BA4\u771F\u6B63\u751F\u6548\uFF1A\u672C\u56DE\u5408\u53EA\u4FDD\u7559\u5224\u4E3A\u76F8\u5173\u7684\u5DE5\u5177\uFF0C\u4E14\u53EA\u5728\u5BBF\u4E3B\u5DF2\u5141\u8BB8\u7684\u8303\u56F4\u5185\u53D6\u4EA4\u96C6\u3001\u4E0D\u6269\u6743\u3002\u5F00\u542F\u300C\u4EC5\u89C2\u5BDF\u300D\u540E\u53EA\u628A\u53EF\u6458\u6389\u7684\u5DE5\u5177\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6539\u52A8\u5DE5\u5177\u96C6\u3002\u4E09\u91CD\u4FDD\u62A4\uFF1A\u6838\u5FC3\u5DE5\u5177\u59CB\u7EC8\u4FDD\u7559\uFF1B\u53EF\u9009\u5DE5\u5177\u8D85\u8FC7 20 \u4E2A\u65F6\u81EA\u52A8\u53EA\u89C2\u5BDF\u4E0D\u9650\u5236\uFF1B\u4FDD\u7559\u4E0B\u6765\u4E0D\u8DB3 5 \u4E2A\u65F6\u89C6\u4E3A\u5224\u5B9A\u4E0D\u53EF\u4FE1\u3001\u8DF3\u8FC7\u3002",
120
+ narrowKeepLabel: "\u59CB\u7EC8\u4FDD\u7559\u7684\u5DE5\u5177\u524D\u7F00",
121
+ narrowKeepHint: "\u540D\u5B57\u4EE5\u8FD9\u4E9B\u524D\u7F00\u5F00\u5934\u7684\u5DE5\u5177\u6C38\u8FDC\u4FDD\u7559\u3001\u4E0D\u53C2\u4E0E\u76F8\u5173\u6027\u5224\u5B9A\uFF0C\u9002\u5408\u8BB0\u5FC6/\u68C0\u7D22\u8FD9\u7C7B\u300C\u5E38\u9A7B\u3001\u6309\u9700\u89E6\u53D1\u300D\u7684\u5DE5\u5177\uFF08\u9ED8\u8BA4\u542B mcp__openviking\u3001team_task_\uFF09\u3002\u7528\u82F1\u6587\u9017\u53F7\u6216\u6362\u884C\u5206\u9694\u591A\u4E2A\u524D\u7F00\uFF1B\u7559\u7A7A\u5219\u4E0D\u989D\u5916\u4FDD\u7559\u3002",
122
+ narrowMaxLabel: "\u5019\u9009\u5DE5\u5177\u4E0A\u9650",
123
+ narrowMaxHint: "\u4E00\u56DE\u5408\u91CC\u53C2\u4E0E\u5224\u5B9A\u7684\u300C\u53EF\u9009\u5DE5\u5177\u300D\u8D85\u8FC7\u8FD9\u4E2A\u6570\uFF08\u9ED8\u8BA4 20\uFF09\uFF0C\u5C31\u81EA\u52A8\u964D\u7EA7\u4E3A\u4EC5\u89C2\u5BDF\u3001\u4E0D\u771F\u6B63\u6536\u7A84\uFF0C\u907F\u514D\u4E00\u6B21\u585E\u592A\u591A\u5DE5\u5177\u8BA9\u6A21\u578B\u8BEF\u6458\u3002\u53D6\u503C 1\u2013200\uFF0C\u8C03\u5927\u66F4\u503E\u5411\u771F\u6B63\u6536\u7A84\u3002\u6838\u5FC3\u5DE5\u5177\u4E0E\u4FDD\u7559\u524D\u7F00\u547D\u4E2D\u7684\u5DE5\u5177\u4E0D\u8BA1\u5165\u3002",
124
+ narrowThresholdLabel: "\u6458\u9664\u9608\u503C",
125
+ narrowThresholdHint: "\u76F8\u5173\u6027\u6982\u7387\u4F4E\u4E8E\u8FD9\u4E2A\u503C\u624D\u6458\u6389\u5DE5\u5177\uFF08\u9ED8\u8BA4 0.3\uFF09\u3002\u6982\u7387\u63A5\u8FD1 0.5 \u8868\u793A\u6A21\u578B\u62FF\u4E0D\u51C6\u3001\u5E76\u975E\u300C\u4E2D\u7B49\u76F8\u5173\u300D\uFF0C\u6B64\u65F6\u4FDD\u7559\u66F4\u7A33\u59A5\uFF1B\u8C03\u4F4E\u66F4\u4FDD\u5B88\uFF08\u5C11\u6458\u3001\u5B81\u53EF\u591A\u7559\uFF09\uFF0C\u8C03\u9AD8\u66F4\u6FC0\u8FDB\uFF08\u591A\u6458\uFF09\u3002\u53D6\u503C 0\u20131\u3002",
126
+ batchModeLabel: "\u5206\u6279\u7B56\u7565",
127
+ batchModeHint: "\u300C\u81EA\u52A8\u300D\uFF08\u9ED8\u8BA4\uFF09\u5148\u6574\u6279\u53D1\u4E00\u6B21\u8BF7\u6C42\uFF0C\u9047\u5230\u4E0A\u4E0B\u6587\u8D85\u9650\u518D\u81EA\u52A8\u964D\u7EA7\u4E3A\u9010\u5DE5\u5177\u5E76\u8BB0\u4F4F\uFF1B\u300C\u6574\u6279\u300D\u4E00\u6B21\u5224\u5B8C\u5168\u90E8\u5DE5\u5177\uFF0C\u9002\u5408\u5927\u4E0A\u4E0B\u6587\u540E\u7AEF\uFF08\u5982 Jev\uFF09\uFF1B\u300C\u9010\u5DE5\u5177\u300D\u6BCF\u4E2A\u5DE5\u5177\u4E00\u6B21\u8BF7\u6C42\u3001\u5E76\u53D1\u6267\u884C\uFF0C\u9002\u5408\u5C0F\u4E0A\u4E0B\u6587\u540E\u7AEF\uFF08\u5982\u672C\u5730 tev1\uFF0C\u7EA6 2050 token \u5355\u8BF7\u6C42\u4E0A\u9650\uFF09\u3002",
128
+ batchModeAuto: "\u81EA\u52A8",
129
+ batchModeSingle: "\u6574\u6279",
130
+ batchModeSplit: "\u9010\u5DE5\u5177",
131
+ advancedThresholds: "\u5E72\u9884\u9608\u503C",
132
+ gateMinConfidenceLabel: "\u95E8\u63A7\u62E6\u622A\u7F6E\u4FE1\u5EA6",
133
+ gateMinConfidenceHint: "\u6A21\u578B\u5224\u300C\u62D2\u7EDD\u300D\u7684\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u624D\u771F\u6B63\u62E6\u4E0B\u5371\u9669\u8C03\u7528\uFF08\u9ED8\u8BA4 0.6\uFF09\u3002\u8C03\u4F4E\u66F4\u5BB9\u6613\u62E6\u3001\u4E5F\u53EF\u80FD\u8BEF\u62E6\u6B63\u5E38\u547D\u4EE4\uFF1B\u8C03\u9AD8\u66F4\u5BBD\u677E\u3001\u66F4\u591A\u653E\u884C\u3002\u53D6\u503C 0\u20131\u3002",
134
+ checkMinConfidenceLabel: "\u81EA\u68C0\u8865\u5B8C\u7F6E\u4FE1\u5EA6",
135
+ checkMinConfidenceHint: "\u81EA\u68C0\u5F97\u5206\u504F\u4F4E\u65F6\uFF0C\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u624D\u81EA\u52A8\u8865\u4E00\u8F6E\uFF08\u9ED8\u8BA4 0.4\uFF09\uFF1B\u4F4E\u4E8E\u5B83\u53EA\u8BB0\u5F55\u3001\u4E0D\u6253\u65AD\u3002\u53D6\u503C 0\u20131\u3002",
136
+ lowScoreThresholdLabel: "\u4F4E\u5206\u9608\u503C",
137
+ lowScoreThresholdHint: "\u5F97\u5206\u5C0F\u4E8E\u7B49\u4E8E\u8FD9\u4E2A\u503C\u7B97\u300C\u504F\u4F4E\u300D\uFF08\u9ED8\u8BA4 1\uFF0C\u8BC4\u5206\u8303\u56F4 0\u20132\uFF09\u3002\u53D6\u503C 0\u20139 \u7684\u6574\u6570\u3002",
138
+ trendMinConfidenceLabel: "\u8D8B\u52BF\u544A\u8B66\u7F6E\u4FE1\u5EA6",
139
+ trendMinConfidenceHint: "\u53EA\u6709\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u7684\u4F4E\u5206\u624D\u8BA1\u5165\u8D28\u91CF\u8D8B\u52BF\uFF08\u9ED8\u8BA4 0.6\uFF09\uFF0C\u907F\u514D\u628A\u6A21\u578B\u6CA1\u628A\u63E1\u7684\u4F4E\u5206\u5F53\u6210\u771F\u5B9E\u4E0B\u6ED1\u3002\u53D6\u503C 0\u20131\u3002",
140
+ trendRunLabel: "\u544A\u8B66\u8FDE\u7EED\u6B21\u6570",
141
+ trendRunHint: "\u8FDE\u7EED\u8FD9\u4E48\u591A\u6B21\u9AD8\u7F6E\u4FE1\u4F4E\u5206\u53D1\u51FA\u300C\u544A\u8B66\u300D\uFF08\u9ED8\u8BA4 3\uFF09\u3002\u53D6\u503C 2\u201310\u3002",
142
+ trendSevereRunLabel: "\u4E25\u91CD\u8FDE\u7EED\u6B21\u6570",
143
+ trendSevereRunHint: "\u8FDE\u7EED\u8FD9\u4E48\u591A\u6B21\u9AD8\u7F6E\u4FE1\u4F4E\u5206\u5347\u7EA7\u4E3A\u300C\u4E25\u91CD\u300D\u544A\u8B66\uFF08\u9ED8\u8BA4 5\uFF09\u3002\u5FC5\u987B\u5927\u4E8E\u544A\u8B66\u8FDE\u7EED\u6B21\u6570\uFF0C\u53D6\u503C 2\u201320\u3002",
144
+ completeMinConfidenceLabel: "\u5B8C\u6210\u6838\u5BF9\u7F6E\u4FE1\u5EA6",
145
+ completeMinConfidenceHint: "\u5224\u5B9A\u67D0\u6761\u4EF6\u300C\u672A\u6EE1\u8DB3\u300D\u7684\u7F6E\u4FE1\u5EA6\u8FBE\u5230\u8FD9\u4E2A\u503C\u624D\u81EA\u52A8\u8865\u4E00\u8F6E\uFF08\u9ED8\u8BA4 0.4\uFF09\u3002\u53D6\u503C 0\u20131\u3002",
146
+ minConditionsLabel: "\u6700\u5C11\u4EA4\u4ED8\u6761\u4EF6\u6570",
147
+ minConditionsHint: "\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u6761\u4EF6\u8FBE\u5230\u8FD9\u4E2A\u6570\u91CF\u624D\u505A\u5B8C\u6210\u6838\u5BF9\uFF08\u9ED8\u8BA4 2\uFF09\u3002\u53D6\u503C 2\u201320\u3002",
148
+ advancedRubric: "\u81EA\u68C0\u6863\u4F4D",
149
+ selfCheckRubricLabel: "\u8BC4\u5206\u6863\u4F4D",
150
+ selfCheckRubricHint: "\u6BCF\u884C\u4E00\u6863\u3001\u7531\u4F4E\u5230\u9AD8\uFF0C\u7528\u4E8E\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\uFF08\u9ED8\u8BA4\u4E09\u6863\uFF0C\u5BF9\u5E94 0\u20132 \u5206\uFF09\u3002\u81F3\u5C11 2 \u6863\u3001\u6700\u591A 10 \u6863\uFF0C\u6BCF\u6863\u4E0D\u8D85\u8FC7 256 \u5B57\u3002\u4E0D\u5408\u89C4\u65F6\u4E0D\u4F1A\u4FDD\u5B58\uFF0C\u4F1A\u5728\u4E0B\u65B9\u63D0\u793A\u5177\u4F53\u95EE\u9898\u3002",
151
+ rubricTooFew: "\u81F3\u5C11\u9700\u8981 2 \u6863\uFF08\u6BCF\u884C\u4E00\u6863\uFF09\u3002",
152
+ rubricTooMany: "\u6700\u591A 10 \u6863\uFF0C\u8BF7\u5220\u6389\u591A\u4F59\u7684\u6863\u4F4D\u3002",
153
+ rubricLevelTooLong: "\u7B2C {line} \u6863\u8D85\u8FC7 256 \u5B57\uFF0C\u8BF7\u7CBE\u7B80\u540E\u518D\u4FDD\u5B58\u3002",
154
+ features: "\u51B3\u7B56\u70B9\u5F00\u5173",
155
+ basicFeatures: "\u57FA\u7840\u529F\u80FD",
156
+ advancedConfig: "\u9AD8\u7EA7\u914D\u7F6E",
157
+ featureGate: "\u5371\u9669\u95E8\u63A7",
158
+ featureGateHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5BF9\u7834\u574F\u6027\u5DE5\u5177\u8C03\u7528\u505A\u62E6\u622A\u8BC4\u4F30\uFF0C\u8C03\u7528\u53EA\u53D7\u5BBF\u4E3B\u539F\u751F\u6743\u9650\u7EA6\u675F\u3002",
159
+ featureCheck: "\u4EA7\u51FA\u81EA\u68C0",
160
+ featureCheckHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\u3002",
161
+ featureNarrow: "\u5DE5\u5177\u6536\u7A84",
162
+ featureNarrowHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u5F00\u59CB\u65F6\u8BC4\u4F30\u5DE5\u5177\u76F8\u5173\u6027\u3002\u9632\u5FAA\u73AF\u4E3A\u786E\u5B9A\u6027\u672C\u5730\u4FDD\u62A4\uFF0C\u59CB\u7EC8\u751F\u6548\uFF0C\u4E0D\u5728\u6B64\u5F00\u5173\u8303\u56F4\u3002",
163
+ featureComplete: "\u4EFB\u52A1\u5B8C\u6210\u6838\u5BF9",
164
+ featureCompleteHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u9010\u9879\u6838\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u4EA4\u4ED8\u6761\u4EF6\u3002",
165
+ trendWarnHint: "\u672C\u4F1A\u8BDD\u6700\u8FD1\u8FDE\u7EED\u51E0\u8F6E\u4EA7\u51FA\u8D28\u91CF\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u53EF\u80FD\u662F\u4EFB\u52A1\u96BE\u5EA6\u4E0A\u5347\u6216\u6A21\u578B\u72B6\u6001\u6CE2\u52A8\uFF0C\u5EFA\u8BAE\u5C1D\u8BD5\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\u3002",
166
+ trendSevereHint: "\u672C\u4F1A\u8BDD\u4EA7\u51FA\u8D28\u91CF\u6301\u7EED\u504F\u4F4E\uFF08\u9AD8\u7F6E\u4FE1\uFF09\u3002\u5EFA\u8BAE\u8C03\u6574 prompt \u6216\u66F4\u6362\u6A21\u578B\uFF0C\u6216\u91CD\u5F00\u4F1A\u8BDD\u3002",
167
+ rateGroup: "\u6807\u6CE8\u8FD9\u6B21\u5224\u65AD",
168
+ rateGood: "\u5224\u5BF9\u4E86",
169
+ rateBad: "\u5224\u9519\u4E86",
170
+ rateUnsure: "\u8BF4\u4E0D\u51C6",
171
+ rateSummary: "\u5DF2\u6807\u6CE8 {rated} \u6761\uFF08\u5224\u5BF9 {good} / \u5224\u9519 {bad} / \u8BF4\u4E0D\u51C6 {unsure}\uFF09",
172
+ annotateFailed: "\u6807\u6CE8\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
173
+ completeSteer: "\u6709\u672A\u6EE1\u8DB3\u6761\u4EF6\u65F6\u81EA\u52A8\u8865\u4E00\u8F6E",
174
+ completeHint: "\u56DE\u5408\u7ED3\u675F\u65F6\uFF0C\u5BF9\u7528\u6237\u660E\u786E\u5217\u51FA\u7684\u591A\u4E2A\u4EA4\u4ED8\u6761\u4EF6\uFF08\u7F16\u53F7 / \u9879\u76EE\u7B26\u53F7 / \u591A\u547D\u4EE4\uFF09\u9010\u9879\u5224\u5B9A\u300C\u5DF2\u6EE1\u8DB3 / \u672A\u6EE1\u8DB3 / \u8BC1\u636E\u4E0D\u8DB3\u300D\uFF0C\u4EE5\u5DE5\u5177\u8BC1\u636E\u4E3A\u51C6\u3001\u56DE\u590D\u81EA\u79F0\u5B8C\u6210\u4E0D\u7B97\u8BC1\u636E\u3002\u5173\u95ED\uFF1A\u53EA\u628A\u7ED3\u679C\u8BB0\u8FDB\u65E5\u5FD7\u548C\u7EDF\u8BA1\uFF0C\u4E0D\u6253\u65AD\u5BF9\u8BDD\u3002\u5F00\u542F\uFF1A\u786E\u6709\u6761\u4EF6\u88AB\u5224\u300C\u672A\u6EE1\u8DB3\u300D\u4E14\u6A21\u578B\u6709\u628A\u63E1\u65F6\uFF0C\u81EA\u52A8\u4EE5\u4F60\u7684\u540D\u4E49\u8FFD\u52A0\u4E00\u6761\u63D0\u793A\u8BA9 AI \u590D\u6838\u8865\u5B8C\uFF1B\u300C\u8BC1\u636E\u4E0D\u8DB3\u300D\u4E0D\u89E6\u53D1\u8865\u5B8C\uFF0C\u540C\u4E00\u56DE\u5408\u6700\u591A\u8865\u4E00\u6B21\u3002",
175
+ completeResultOk: "\u6761\u4EF6\u9F50\u5907",
176
+ completeResultUnsatisfied: "\u6709\u672A\u6EE1\u8DB3",
177
+ completeConditions: "\u6761\u4EF6",
178
+ completeSatisfied: "\u6EE1\u8DB3",
179
+ completeUnsatisfied: "\u672A\u6EE1\u8DB3",
180
+ completeInsufficient: "\u8BC1\u636E\u4E0D\u8DB3",
181
+ completeSteered: "\u5DF2\u8865\u4E00\u8F6E",
182
+ backend: "\u88C1\u51B3\u540E\u7AEF",
183
+ url: "\u670D\u52A1\u5730\u5740",
184
+ model: "\u6A21\u578B",
185
+ key: "API Key",
186
+ keyHintSaved: "\u5DF2\u4FDD\u5B58\u4E00\u4E2A Key\u3002\u7559\u7A7A\u5E76\u4FDD\u5B58\uFF1D\u6CBF\u7528\u5B83\uFF08\u4E0D\u6539\u52A8\uFF09\uFF1B\u586B\u65B0\u503C\u5E76\u4FDD\u5B58\uFF1D\u8986\u76D6\u5B83\u3002",
187
+ keyHintEmpty: "\u5C1A\u672A\u4FDD\u5B58 Key\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u586B\u5165\u5219\u4FDD\u5B58\u5230\u672C\u673A\u3002",
188
+ removeKey: "\u5220\u9664\u5DF2\u4FDD\u5B58\u7684 Key",
189
+ removeKeyHint: "\u628A\u672C\u63D2\u4EF6\u4FDD\u5B58\u5728\u672C\u673A\u7684 Key \u6C38\u4E45\u5220\u9664\uFF0C\u4E4B\u540E\u81EA\u52A8\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u91CC\u7684 Key\uFF1B\u4E0D\u5F71\u54CD\u4F60\u5728\u522B\u5904\u914D\u7F6E\u7684\u51ED\u636E\u3002",
190
+ removeKeyButton: "\u5220\u9664",
191
+ removeKeyConfirm: "\u786E\u5B9A\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684 API Key\uFF1F\u5220\u9664\u540E\u5C06\u56DE\u843D\u5230\u73AF\u5883\u53D8\u91CF\u7684 Key\u3002",
192
+ removeKeyDone: "\u5DF2\u5220\u9664\u4FDD\u5B58\u7684 Key",
193
+ save: "\u4FDD\u5B58\u914D\u7F6E",
194
+ saveAdvanced: "\u4FDD\u5B58\u9AD8\u7EA7\u914D\u7F6E",
195
+ probe: "\u6D4B\u8BD5\u8FDE\u63A5",
196
+ saved: "\u914D\u7F6E\u5DF2\u4FDD\u5B58",
197
+ connected: "\u8FDE\u63A5\u6210\u529F",
198
+ unavailable: "\u8FDE\u63A5\u4E0D\u53EF\u7528",
199
+ error: "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
200
+ loading: "\u6B63\u5728\u8BFB\u53D6\u4F1A\u8BDD\u72B6\u6001",
201
+ destination: "\u88C1\u51B3\u65F6\u4F1A\u5411\u4EE5\u4E0B\u540E\u7AEF\u53D1\u9001\u5FC5\u8981\u7684\u8BC4\u4F30\u4E0A\u4E0B\u6587\uFF1A",
202
+ httpWarning: "\u6B64\u5730\u5740\u4F7F\u7528\u672A\u52A0\u5BC6\u7684 HTTP\u3002\u786E\u8BA4\u540E\uFF0CAPI Key \u4E0E\u8BC4\u4F30\u4E0A\u4E0B\u6587\u5C06\u4EE5\u660E\u6587\u53D1\u9001\u81F3\u8BE5\u5730\u5740\u3002",
203
+ analysisTab: "\u51B3\u7B56\u5206\u6790",
204
+ analysisTitle: "\u51B3\u7B56\u5206\u6790",
205
+ analysisIntro: "\u57FA\u4E8E\u672C\u4F1A\u8BDD\u5DF2\u843D\u76D8\u7684\u51B3\u7B56\u65E5\u5FD7\u505A\u53EA\u8BFB\u805A\u5408\u4E0E\u4EBA\u5DE5\u6807\u6CE8\uFF0C\u4E0D\u6539\u53D8\u4EFB\u4F55 agent \u884C\u4E3A\u3002",
206
+ analysisProfile: "\u8FC7\u7A0B\u753B\u50CF",
207
+ analysisMeanScore: "\u5E73\u5747\u5206",
208
+ analysisTrend: "\u8D28\u91CF\u8D8B\u52BF\u56DE\u6D4B",
209
+ analysisTrendWarn: "\u544A\u8B66\u89E6\u53D1",
210
+ analysisTrendSevere: "\u4E25\u91CD\u89E6\u53D1",
211
+ analysisTrendMaxRun: "\u6700\u957F\u8FDE\u7EED\u4F4E\u5206",
212
+ analysisTrendNote: "\u7528\u5F53\u524D\u9608\u503C\u628A\u672C\u4F1A\u8BDD\u7684\u81EA\u68C0\u5206\u6570\u6309\u65F6\u95F4\u91CD\u653E\uFF0C\u7EDF\u8BA1\u544A\u8B66\u672C\u4F1A\u300C\u4F1A\u300D\u89E6\u53D1\u51E0\u6B21\uFF0C\u7528\u4E8E\u6821\u51C6\u9608\u503C\uFF0C\u4E0D\u662F\u5B9E\u65F6\u4FE1\u53F7\u3002",
213
+ analysisAccuracy: "\u5224\u65AD\u51C6\u786E\u5EA6",
214
+ analysisAccuracyEmpty: "\u5C1A\u672A\u6807\u6CE8\u4EFB\u4F55\u51B3\u7B56\u3002\u5728\u4E0B\u65B9\u51B3\u7B56\u5217\u8868\u9010\u6761\u6807\u6CE8\u300C\u5224\u5BF9 / \u5224\u9519 / \u8BF4\u4E0D\u51C6\u300D\u540E\uFF0C\u8FD9\u91CC\u7ED9\u51FA\u6C47\u603B\u3002",
215
+ analysisLogNote: "\u6807\u6CE8\u5728\u6B64\u4E0E\u4ECB\u5165\u9762\u677F\u540C\u6E90\uFF1A\u4EFB\u4E00\u5904\u6807\u6CE8\u90FD\u5199\u5165\u540C\u4E00\u4EFD\u65E5\u5FD7\u3001\u6309\u51B3\u7B56 id \u5173\u8054\u3001\u53D6\u6700\u65B0\u3002",
216
+ analysisLogTruncated: "\u672C\u4F1A\u8BDD\u6682\u65E0\u53EF\u5C55\u793A\u7684\u51B3\u7B56\u8BB0\u5F55\u3002",
217
+ pagerPrev: "\u4E0A\u4E00\u9875",
218
+ pagerNext: "\u4E0B\u4E00\u9875",
219
+ pagerStatus: "\u7B2C {page}/{pages} \u9875 \xB7 \u5171 {total} \u6761"
220
+ };
221
+ var en = {
222
+ summary: "A danger-call gate, output self-check, and loop guard driven by a pluggable adjudication model.",
223
+ button: "Decision layer",
224
+ title: "Decision layer",
225
+ close: "Close",
226
+ metrics: "Automatic decisions",
227
+ triggerDecisions: "decisions",
228
+ empty: "No automatic decisions yet. Manual verdicts are not counted here.",
229
+ attempts: "Evaluations",
230
+ failures: "Fallback failures",
231
+ suggestions: "Model suggestions (allow / ask / deny)",
232
+ actual: "Actual host outcomes (allow / deny)",
233
+ checkAttempts: "Self-check evaluations",
234
+ checkLow: "Low",
235
+ checkOk: "Passed",
236
+ settings: "Session settings",
237
+ cardGate: "Danger gate",
238
+ cardCheck: "Output self-check",
239
+ cardNarrow: "Tool narrowing",
240
+ cardComplete: "Task completion",
241
+ cardTimes: "",
242
+ allow: "Allow",
243
+ ask: "Ask",
244
+ deny: "Deny",
245
+ actualShort: "Actual",
246
+ narrowAppliedLabel: "Narrowed",
247
+ narrowDroppedLabel: "Tools dropped",
248
+ narrowDropped: "dropped",
249
+ narrowKept: "kept all",
250
+ narrowKeptCount: "kept",
251
+ narrowMore: " and {count} in total",
252
+ narrowObserve: "observe",
253
+ narrowEnforce: "enforced",
254
+ checkPassRate: "Pass rate",
255
+ narrowApplyRate: "Narrow rate",
256
+ rateNa: "\u2014",
257
+ enabled: "Enable automatic interventions in this session",
258
+ backendStatus: "Backend",
259
+ statusChecking: "Checking\u2026",
260
+ statusIdle: "Not checked",
261
+ statusOk: "Connected",
262
+ statusDown: "Unavailable",
263
+ recheck: "Recheck",
264
+ log: "Decision log",
265
+ logEmpty: "No decisions recorded for this session yet.",
266
+ logGate: "Gate",
267
+ logCheck: "Self-check",
268
+ logNarrow: "Narrow",
269
+ logComplete: "Completion",
270
+ logSuggested: "model suggested",
271
+ logEvalFailed: "evaluation failed",
272
+ logScore: "score",
273
+ logConnection: "connection",
274
+ logConfidence: "confidence",
275
+ logCommandLabel: "command: ",
276
+ logPathLabel: "path: ",
277
+ logSubjectLabel: "request: ",
278
+ logScoreHint: "The score is a probability-weighted mean across the levels, so it can be fractional (e.g. 1.4); the top score is the highest level number, 2.",
279
+ logCheckHint: "After each turn, the AI\u2019s final reply for that turn is sent to the adjudication model, which grades its quality on three levels (severe omission/contradiction \u2192 minor gaps \u2192 complete and accurate) as a 0\u20132 score, to catch omissions or contradictions.",
280
+ logNarrowHint: "At the start of each turn, the current task and each available tool are sent to the adjudication model (a noul per tool) to judge relevance, dropping tools clearly not needed. It only intersects the host-allowed set and never expands it; observe merely logs the suggestion, enforced actually restricts the tools for this turn.",
281
+ actionDeny: "denied",
282
+ actionAsk: "sent to approval",
283
+ actionPass: "no intervention",
284
+ gatePassThrough: "no intervention (proceeded on its original path)",
285
+ checkResultLow: "low score",
286
+ checkResultOk: "passed",
287
+ checkResultLowNoisy: "low score (low confidence)",
288
+ checkNoiseTag: "noise, ignore",
289
+ checkNoiseHint: "The model had almost no confidence in this score (near-zero confidence). This low score does not count toward the quality trend and triggers no re-prompt \u2014 treat it as noise. What matters is several consecutive high-confidence low scores.",
290
+ reasonUnavailable: "backend unreachable",
291
+ reasonHttpError: "backend returned an error",
292
+ reasonInvalidResponse: "unexpected response shape",
293
+ reasonLowConfidence: "low confidence",
294
+ reasonConfig: "invalid configuration",
295
+ reasonTooMany: "too many candidates",
296
+ reasonTooManyCount: "{count} candidates is too many",
297
+ reasonLowKeep: "too few kept, not enforced",
298
+ selfCheck: "Output self-check",
299
+ advancedSwitches: "Intervention switches",
300
+ advancedParams: "Narrowing parameters",
301
+ selfCheckSteer: "Auto re-prompt on a low score",
302
+ selfCheckHint: "Each turn ends by scoring the final reply (0\u20132, a probability-weighted mean across the levels, so it can be fractional like 1.4). Off: low scores are only logged, the conversation is not interrupted. On: when the score is low (\u22641) and the model is confident enough, one prompt is appended on your behalf asking the AI to review for gaps or contradictions and finish the work; low-confidence scores are only logged, never interrupt, and at most one prompt per turn.",
303
+ narrow: "Tool narrowing",
304
+ narrowObserveLabel: "Observe only (do not restrict tools)",
305
+ narrowHint: "At the start of each turn, the adjudication model judges how relevant each optional tool is to the task and drops the ones not needed; core tools (read, write, edit, shell, search, todos) are always kept and never judged. Enforced by default: only the relevant tools are kept for this turn, intersected with the host-allowed set and never expanded. Turn on Observe only to just log the tools that could be dropped, without changing the tool set. Three safeguards: core tools always kept; more than 20 optional tools falls back to observe only; fewer than 5 tools remaining is treated as untrustworthy and skipped.",
306
+ narrowKeepLabel: "Always-kept tool prefixes",
307
+ narrowKeepHint: "Tools whose names start with any of these prefixes are always kept and never judged for relevance \u2014 good for resident, on-demand tools like memory/retrieval (defaults to mcp__openviking and team_task_). Separate prefixes with commas or newlines; leave empty to keep nothing extra.",
308
+ narrowMaxLabel: "Candidate tool cap",
309
+ narrowMaxHint: "When more than this many optional tools are judged in one turn (default 20), narrowing downgrades to observe only instead of actually restricting, so a large surface is never mass-pruned. Range 1\u2013200; a higher value leans toward actually narrowing. Core tools and keep-prefix matches do not count.",
310
+ narrowThresholdLabel: "Drop threshold",
311
+ narrowThresholdHint: 'A tool is dropped only when its relevance probability is below this value (default 0.3). A probability near 0.5 means the model is unsure, not "moderately relevant", so keeping is safer there; lower is more conservative (drops fewer), higher is more aggressive. Range 0\u20131.',
312
+ batchModeLabel: "Batch strategy",
313
+ batchModeHint: "Auto (default) sends one whole-batch request first and, on a context overflow, falls back to one request per tool and remembers it; Single judges every tool in one request, best for a large-context backend (e.g. Jev); Split sends one request per tool concurrently, for a small-context backend (e.g. a local tev1 with a ~2050-token request limit).",
314
+ batchModeAuto: "Auto",
315
+ batchModeSingle: "Single",
316
+ batchModeSplit: "Split",
317
+ advancedThresholds: "Intervention thresholds",
318
+ gateMinConfidenceLabel: "Gate block confidence",
319
+ gateMinConfidenceHint: 'A "deny" verdict blocks a dangerous call only when the model is at least this confident (default 0.6). Lower blocks more and may block legitimate commands; higher is more permissive. Range 0\u20131.',
320
+ checkMinConfidenceLabel: "Self-check re-prompt confidence",
321
+ checkMinConfidenceHint: "On a low score, the supplemental prompt fires only when the model is at least this confident (default 0.4); below it the score is only logged. Range 0\u20131.",
322
+ lowScoreThresholdLabel: "Low-score threshold",
323
+ lowScoreThresholdHint: "A score at or below this counts as low (default 1; the scale is 0\u20132). Integer, 0\u20139.",
324
+ trendMinConfidenceLabel: "Trend alarm confidence",
325
+ trendMinConfidenceHint: "Only low scores at least this confident count toward the quality trend (default 0.6), so an unsure low score is not read as a real decline. Range 0\u20131.",
326
+ trendRunLabel: "Warn after",
327
+ trendRunHint: "This many consecutive high-confidence low scores raise a warning (default 3). Integer, 2\u201310.",
328
+ trendSevereRunLabel: "Severe after",
329
+ trendSevereRunHint: "This many consecutive high-confidence low scores escalate to severe (default 5). Must exceed the warn count; integer, 2\u201320.",
330
+ completeMinConfidenceLabel: "Completion re-prompt confidence",
331
+ completeMinConfidenceHint: "A condition judged unmet triggers the supplemental step only at this confidence or above (default 0.4). Range 0\u20131.",
332
+ minConditionsLabel: "Minimum listed conditions",
333
+ minConditionsHint: "The completion check runs only when the user listed at least this many explicit conditions (default 2). Integer, 2\u201320.",
334
+ advancedRubric: "Grading levels",
335
+ selfCheckRubricLabel: "Grading levels",
336
+ selfCheckRubricHint: "One level per line, lowest first, used to score the final reply (three levels by default, i.e. scores 0\u20132). At least 2 and at most 10 levels, 256 characters each. An invalid list is not saved; the specific problem is shown below the box.",
337
+ rubricTooFew: "At least 2 levels are required (one per line).",
338
+ rubricTooMany: "At most 10 levels are allowed; remove the extra ones.",
339
+ rubricLevelTooLong: "Level {line} exceeds 256 characters; shorten it before saving.",
340
+ features: "Decision points",
341
+ basicFeatures: "Basic features",
342
+ advancedConfig: "Advanced settings",
343
+ featureGate: "Danger gate",
344
+ featureGateHint: "When off, destructive tool calls are no longer evaluated for interception and are only bound by the host permission rules.",
345
+ featureCheck: "Output self-check",
346
+ featureCheckHint: "When off, the final reply is no longer scored at the end of a turn.",
347
+ featureNarrow: "Tool narrowing",
348
+ featureNarrowHint: "When off, tool relevance is no longer evaluated at the start of a turn. The loop guard is a deterministic local safeguard that is always on and not covered by this switch.",
349
+ featureComplete: "Task completion check",
350
+ featureCompleteHint: "When off, the explicit deliverable conditions the user listed are no longer checked at turn end.",
351
+ trendWarnHint: "Output quality has been low for a few consecutive turns this session (high confidence). It may be rising task difficulty or model drift \u2014 consider adjusting the prompt or switching models.",
352
+ trendSevereHint: "Output quality has stayed low this session (high confidence). Consider adjusting the prompt, switching models, or starting a new session.",
353
+ rateGroup: "Rate this decision",
354
+ rateGood: "Correct",
355
+ rateBad: "Wrong",
356
+ rateUnsure: "Unsure",
357
+ rateSummary: "Rated {rated} ({good} correct / {bad} wrong / {unsure} unsure)",
358
+ annotateFailed: "Could not save the rating. Please retry.",
359
+ completeSteer: "Auto re-prompt on an unmet condition",
360
+ completeHint: "At turn end, each explicit deliverable condition the user listed (numbered / bulleted / multi-command) is judged satisfied / unsatisfied / insufficient evidence, with tool evidence as the source of truth \u2014 a reply claiming completion is not evidence. Off: results are only logged, the conversation is not interrupted. On: when a condition is confidently judged unsatisfied, one prompt is appended on your behalf asking the AI to review and finish it; insufficient evidence never triggers a re-prompt, and at most one per turn.",
361
+ completeResultOk: "conditions met",
362
+ completeResultUnsatisfied: "unmet found",
363
+ completeConditions: "conditions",
364
+ completeSatisfied: "met",
365
+ completeUnsatisfied: "unmet",
366
+ completeInsufficient: "insufficient",
367
+ completeSteered: "re-prompted",
368
+ backend: "Decision backend",
369
+ url: "Server URL",
370
+ model: "Model",
371
+ key: "API key",
372
+ keyHintSaved: "A key is saved. Leave blank and save to keep it; enter a new value and save to overwrite it.",
373
+ keyHintEmpty: "No key saved yet. Leave blank to use an environment credential, or enter one to save it locally.",
374
+ removeKey: "Delete saved API key",
375
+ removeKeyHint: "Permanently deletes the key this plugin stored locally, then falls back to the environment credential; credentials configured elsewhere are untouched.",
376
+ removeKeyButton: "Delete",
377
+ removeKeyConfirm: "Delete the locally saved API key? It will fall back to the environment credential.",
378
+ removeKeyDone: "Saved key deleted",
379
+ save: "Save configuration",
380
+ saveAdvanced: "Save advanced settings",
381
+ probe: "Test connection",
382
+ saved: "Configuration saved",
383
+ connected: "Connected",
384
+ unavailable: "Connection unavailable",
385
+ error: "Request failed. Please retry.",
386
+ loading: "Loading session settings",
387
+ destination: "Decisions send the necessary evaluation context to this backend:",
388
+ httpWarning: "This address uses unencrypted HTTP. Your API key and evaluation context will be sent in plaintext to this address.",
389
+ analysisTab: "Decision analysis",
390
+ analysisTitle: "Decision analysis",
391
+ analysisIntro: "A read-only aggregate and manual annotation over this session\u2019s persisted decision log. It changes no agent behavior.",
392
+ analysisProfile: "Process profile",
393
+ analysisMeanScore: "Mean score",
394
+ analysisTrend: "Quality-trend backtest",
395
+ analysisTrendWarn: "Warn fires",
396
+ analysisTrendSevere: "Severe fires",
397
+ analysisTrendMaxRun: "Longest low run",
398
+ analysisTrendNote: "Replays this session\u2019s self-check scores in time order under the current thresholds to count how often the alarm would fire \u2014 a calibration aid, not a live signal.",
399
+ analysisAccuracy: "Decision accuracy",
400
+ analysisAccuracyEmpty: "No decisions rated yet. Rate rows below as correct / wrong / unsure and a summary appears here.",
401
+ analysisLogNote: "Ratings here share one source with the intervention panel: a rating on either surface writes to the same log, keyed by decision id, latest wins.",
402
+ analysisLogTruncated: "No decision rows to show for this session.",
403
+ pagerPrev: "Prev",
404
+ pagerNext: "Next",
405
+ pagerStatus: "Page {page}/{pages} \xB7 {total} total"
352
406
  };
407
+ var dictionaries = { zh, en };
353
408
 
354
409
  // src/client/panel.tsx
355
410
  var import_react2 = require("react");
@@ -452,7 +507,11 @@ function renderGate({ t }, entry) {
452
507
  }
453
508
  function renderCheck({ t }, entry) {
454
509
  const label = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { title: t("logCheckHint"), children: t("logCheck") });
455
- const subject = entry.subject ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "decision-log-cmd", title: `${t("logSubjectLabel")}${entry.subject}`, children: entry.subject.length > 60 ? `${entry.subject.slice(0, 60)}\u2026` : entry.subject }) : null;
510
+ const subject = entry.subject ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-subject", title: `${t("logSubjectLabel")}${entry.subject}`, children: [
511
+ "\u300C",
512
+ entry.subject.length > 60 ? `${entry.subject.slice(0, 60)}\u2026` : entry.subject,
513
+ "\u300D"
514
+ ] }) : null;
456
515
  if (entry.outcome === "error") return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
457
516
  label,
458
517
  subject ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
@@ -696,6 +755,7 @@ var import_jsx_runtime3 = require("react/jsx-runtime");
696
755
  function DecisionPanel(props) {
697
756
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SessionPanel, { ...props }, props.sessionId);
698
757
  }
758
+ var NO_PROJECTION = () => void 0;
699
759
  function Bar({ allow, ask, deny }) {
700
760
  const total = allow + ask + deny;
701
761
  if (total === 0) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "decision-bar decision-bar-empty", "aria-hidden": "true" });
@@ -706,7 +766,7 @@ function Bar({ allow, ask, deny }) {
706
766
  deny > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "decision-bar-deny", style: { width: pct(deny) } })
707
767
  ] });
708
768
  }
709
- function SessionPanel({ sessionId, t }) {
769
+ function SessionPanel({ sessionId, t, useProjection }) {
710
770
  const dialog = (0, import_react2.useRef)(null);
711
771
  const trigger = (0, import_react2.useRef)(null);
712
772
  const mounted = (0, import_react2.useRef)(true);
@@ -791,6 +851,11 @@ function SessionPanel({ sessionId, t }) {
791
851
  const checkPassRate = metrics?.check && checkValid > 0 ? Math.round((checkValid - metrics.check.low) / checkValid * 100) : null;
792
852
  const narrowValid = metrics?.narrow ? metrics.narrow.attempts - metrics.narrow.failures : 0;
793
853
  const narrowApplyRate = metrics?.narrow && narrowValid > 0 ? Math.round(metrics.narrow.applied / narrowValid * 100) : null;
854
+ const readProjection = useProjection ?? NO_PROJECTION;
855
+ const pressure = readProjection("contextPressure");
856
+ const usedTokens = pressure?.projectedTokens ?? pressure?.pressureTokens;
857
+ const contextReady = useProjection === void 0 || usedTokens !== void 0 && pressure?.contextWindow !== void 0;
858
+ if (!contextReady) return null;
794
859
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
795
860
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { ref: trigger, className: `decision-trigger decision-trend-${severity}`, type: "button", "aria-haspopup": "dialog", "aria-expanded": open, "aria-busy": enabled === null, "aria-label": t("button"), title: trendTitle, onClick: () => setOpen(true), children: [
796
861
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { className: "decision-trigger-icon", width: "15", height: "15", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
@@ -1100,6 +1165,51 @@ async function request2(path, fetchFn, init) {
1100
1165
  var DEFAULT_KEEP_PREFIXES = ["mcp__openviking", "team_task_"];
1101
1166
  var DEFAULT_MAX_CANDIDATES = 20;
1102
1167
  var DEFAULT_THRESHOLD = 0.3;
1168
+ var DEFAULT_BATCH_MODE = "auto";
1169
+ var DEFAULT_RUBRIC = [
1170
+ "\u660E\u663E\u7B54\u975E\u6240\u95EE\uFF0C\u6216\u5B58\u5728\u4E25\u91CD\u9057\u6F0F / \u81EA\u76F8\u77DB\u76FE",
1171
+ "\u57FA\u672C\u7B54\u5230\u95EE\u9898\uFF0C\u4F46\u6709\u53EF\u5BDF\u89C9\u7684\u9057\u6F0F\u6216\u4E0D\u4E25\u8C28",
1172
+ "\u5B8C\u6574\u3001\u51C6\u786E\u3001\u65E0\u81EA\u76F8\u77DB\u76FE\u5730\u56DE\u5E94\u4E86\u8BF7\u6C42"
1173
+ ];
1174
+ var THRESHOLD_DEFAULTS = {
1175
+ gateMin: 0.6,
1176
+ checkMin: 0.4,
1177
+ lowScore: 1,
1178
+ trendMin: 0.6,
1179
+ trendRun: 3,
1180
+ trendSevere: 5,
1181
+ completeMin: 0.4,
1182
+ minConditions: 2
1183
+ };
1184
+ var defaultThresholds = () => Object.fromEntries(
1185
+ Object.entries(THRESHOLD_DEFAULTS).map(([name, value]) => [name, String(value)])
1186
+ );
1187
+ var RUBRIC_MAX_LEVELS = 10;
1188
+ var RUBRIC_MAX_LEVEL_LENGTH = 256;
1189
+ var thresholdsOf = (value) => {
1190
+ const trendRun = value.checkSettings?.trendRun ?? THRESHOLD_DEFAULTS.trendRun;
1191
+ return {
1192
+ gateMin: String(value.gateSettings?.minConfidence ?? THRESHOLD_DEFAULTS.gateMin),
1193
+ checkMin: String(value.checkSettings?.minConfidence ?? THRESHOLD_DEFAULTS.checkMin),
1194
+ lowScore: String(value.checkSettings?.lowScoreThreshold ?? THRESHOLD_DEFAULTS.lowScore),
1195
+ trendMin: String(value.checkSettings?.trendMinConfidence ?? THRESHOLD_DEFAULTS.trendMin),
1196
+ trendRun: String(trendRun),
1197
+ // The service derives an unset severe tier from the warn tier
1198
+ // (self-check.mjs: Math.max(trendRun + 1, 5)), so mirror that here or the box
1199
+ // reports a value the service is not using.
1200
+ trendSevere: String(value.checkSettings?.trendSevereRun ?? Math.max(trendRun + 1, THRESHOLD_DEFAULTS.trendSevere)),
1201
+ completeMin: String(value.completeSettings?.minConfidence ?? THRESHOLD_DEFAULTS.completeMin),
1202
+ minConditions: String(value.completeSettings?.minConditions ?? THRESHOLD_DEFAULTS.minConditions)
1203
+ };
1204
+ };
1205
+ var clampNumber = (raw, fallback, min, max, integer = false) => {
1206
+ const parsed = integer ? Number.parseInt(raw, 10) : Number.parseFloat(raw);
1207
+ if (!Number.isFinite(parsed)) return fallback;
1208
+ const clamped = Math.min(max, Math.max(min, parsed));
1209
+ return integer ? Math.round(clamped) : clamped;
1210
+ };
1211
+ var rubricLevels = (text) => text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1212
+ var rubricOf = (settings) => (settings?.rubric ?? DEFAULT_RUBRIC).join("\n");
1103
1213
  var parsePrefixes = (text) => Array.from(new Set(text.split(/[,\r\n]+/).map((line) => line.trim()).filter(Boolean)));
1104
1214
  var prefixesText = (settings) => (settings?.keepPrefixes ?? DEFAULT_KEEP_PREFIXES).join("\n");
1105
1215
  var maxCandidatesOf = (settings) => settings?.maxCandidates ?? DEFAULT_MAX_CANDIDATES;
@@ -1151,6 +1261,9 @@ function ConfigForm({ t, fetchFn = fetch }) {
1151
1261
  const [keepPrefixes, setKeepPrefixes] = (0, import_react4.useState)(DEFAULT_KEEP_PREFIXES.join("\n"));
1152
1262
  const [maxCandidates, setMaxCandidates] = (0, import_react4.useState)(String(DEFAULT_MAX_CANDIDATES));
1153
1263
  const [threshold, setThreshold] = (0, import_react4.useState)(String(DEFAULT_THRESHOLD));
1264
+ const [batchMode, setBatchMode] = (0, import_react4.useState)(DEFAULT_BATCH_MODE);
1265
+ const [rubric, setRubric] = (0, import_react4.useState)(DEFAULT_RUBRIC.join("\n"));
1266
+ const [thresholds, setThresholds] = (0, import_react4.useState)(defaultThresholds);
1154
1267
  const [gateOn, setGateOn] = (0, import_react4.useState)(true);
1155
1268
  const [checkOn, setCheckOn] = (0, import_react4.useState)(true);
1156
1269
  const [narrowOn, setNarrowOn] = (0, import_react4.useState)(true);
@@ -1179,6 +1292,13 @@ function ConfigForm({ t, fetchFn = fetch }) {
1179
1292
  setKeepPrefixes(prefixesText(value.narrowSettings));
1180
1293
  setMaxCandidates(String(maxCandidatesOf(value.narrowSettings)));
1181
1294
  setThreshold(String(thresholdOf(value.narrowSettings)));
1295
+ setBatchMode(value.narrowSettings?.batchMode ?? DEFAULT_BATCH_MODE);
1296
+ setRubric(rubricOf(value.checkSettings));
1297
+ setThresholds(thresholdsOf(value));
1298
+ };
1299
+ const setThresholdField = (key2, next) => {
1300
+ setThresholds((previous) => ({ ...previous, [key2]: next }));
1301
+ setAdvancedDirty(true);
1182
1302
  };
1183
1303
  const applyConfig = (value) => {
1184
1304
  applyBackend(value);
@@ -1220,28 +1340,76 @@ function ConfigForm({ t, fetchFn = fetch }) {
1220
1340
  }
1221
1341
  };
1222
1342
  const featureState = () => ({ gate: gateOn, check: checkOn, narrow: narrowOn, complete: completeOn });
1343
+ const canEdit = ready && !busy;
1344
+ const rubricIssue = (() => {
1345
+ const levels = rubricLevels(rubric);
1346
+ if (levels.length < 2) return t("rubricTooFew");
1347
+ if (levels.length > RUBRIC_MAX_LEVELS) return t("rubricTooMany");
1348
+ const tooLong = levels.findIndex((level) => level.length > RUBRIC_MAX_LEVEL_LENGTH);
1349
+ return tooLong >= 0 ? t("rubricLevelTooLong", { line: tooLong + 1 }) : void 0;
1350
+ })();
1223
1351
  const saveAdvanced = async (event) => {
1224
1352
  event.preventDefault();
1225
- const parsedCap = Number.parseInt(maxCandidates, 10);
1226
- const cap = Number.isFinite(parsedCap) ? Math.min(200, Math.max(1, parsedCap)) : DEFAULT_MAX_CANDIDATES;
1227
- const parsedThreshold = Number.parseFloat(threshold);
1228
- const thresh = Number.isFinite(parsedThreshold) ? Math.min(1, Math.max(0, parsedThreshold)) : DEFAULT_THRESHOLD;
1353
+ if (rubricIssue) {
1354
+ setMessage({ text: rubricIssue, ok: false });
1355
+ return;
1356
+ }
1357
+ const cap = clampNumber(maxCandidates, DEFAULT_MAX_CANDIDATES, 1, 200, true);
1358
+ const thresh = clampNumber(threshold, DEFAULT_THRESHOLD, 0, 1);
1359
+ const trendRun = clampNumber(thresholds.trendRun, THRESHOLD_DEFAULTS.trendRun, 2, 10, true);
1360
+ const trendSevereRun = Math.max(
1361
+ trendRun + 1,
1362
+ clampNumber(thresholds.trendSevere, THRESHOLD_DEFAULTS.trendSevere, 2, 20, true)
1363
+ );
1229
1364
  setBusy(true);
1230
1365
  try {
1231
1366
  const value = await request2("config", fetchFn, {
1232
1367
  method: "PUT",
1233
1368
  headers: { "content-type": "application/json" },
1234
1369
  body: JSON.stringify({
1235
- checkSettings: { mode: checkMode },
1236
- narrowSettings: { mode: narrowMode, keepPrefixes: parsePrefixes(keepPrefixes), maxCandidates: cap, threshold: thresh },
1237
- completeSettings: { mode: completeMode }
1370
+ gateSettings: {
1371
+ ...config.gateSettings,
1372
+ minConfidence: clampNumber(thresholds.gateMin, THRESHOLD_DEFAULTS.gateMin, 0, 1)
1373
+ },
1374
+ checkSettings: {
1375
+ ...config.checkSettings,
1376
+ mode: checkMode,
1377
+ rubric: rubricLevels(rubric),
1378
+ lowScoreThreshold: clampNumber(thresholds.lowScore, THRESHOLD_DEFAULTS.lowScore, 0, 9, true),
1379
+ minConfidence: clampNumber(thresholds.checkMin, THRESHOLD_DEFAULTS.checkMin, 0, 1),
1380
+ trendMinConfidence: clampNumber(thresholds.trendMin, THRESHOLD_DEFAULTS.trendMin, 0, 1),
1381
+ trendRun,
1382
+ trendSevereRun
1383
+ },
1384
+ narrowSettings: {
1385
+ ...config.narrowSettings,
1386
+ mode: narrowMode,
1387
+ keepPrefixes: parsePrefixes(keepPrefixes),
1388
+ maxCandidates: cap,
1389
+ threshold: thresh,
1390
+ batchMode
1391
+ },
1392
+ completeSettings: {
1393
+ ...config.completeSettings,
1394
+ mode: completeMode,
1395
+ minConditions: clampNumber(thresholds.minConditions, THRESHOLD_DEFAULTS.minConditions, 2, 20, true),
1396
+ minConfidence: clampNumber(thresholds.completeMin, THRESHOLD_DEFAULTS.completeMin, 0, 1)
1397
+ }
1238
1398
  })
1239
1399
  });
1400
+ setConfig((previous) => ({
1401
+ ...previous,
1402
+ gateSettings: value.gateSettings ?? previous.gateSettings,
1403
+ checkSettings: value.checkSettings ?? previous.checkSettings,
1404
+ narrowSettings: value.narrowSettings ?? previous.narrowSettings,
1405
+ completeSettings: value.completeSettings ?? previous.completeSettings
1406
+ }));
1240
1407
  applyAdvanced(value);
1241
1408
  setAdvancedDirty(false);
1242
1409
  setMessage({ text: t("saved"), ok: true });
1243
- } catch {
1244
- setMessage({ text: t("error"), ok: false });
1410
+ } catch (error) {
1411
+ const reason = error instanceof Error && error.message && error.message !== "Request failed" ? error.message : "";
1412
+ setMessage({ text: reason ? `${t("error")} (${reason})` : t("error"), ok: false });
1245
1413
  } finally {
1246
1414
  setBusy(false);
1247
1415
  }
@@ -1319,7 +1487,7 @@ ${url}`)) return;
1319
1487
  {
1320
1488
  label: t("featureGate"),
1321
1489
  checked: gateOn,
1322
- disabled: !ready || busy,
1490
+ disabled: !canEdit,
1323
1491
  onChange: (next) => {
1324
1492
  setGateOn(next);
1325
1493
  void toggleFeature({ ...featureState(), gate: next }, () => setGateOn(!next));
@@ -1332,7 +1500,7 @@ ${url}`)) return;
1332
1500
  {
1333
1501
  label: t("featureCheck"),
1334
1502
  checked: checkOn,
1335
- disabled: !ready || busy,
1503
+ disabled: !canEdit,
1336
1504
  onChange: (next) => {
1337
1505
  setCheckOn(next);
1338
1506
  void toggleFeature({ ...featureState(), check: next }, () => setCheckOn(!next));
@@ -1345,7 +1513,7 @@ ${url}`)) return;
1345
1513
  {
1346
1514
  label: t("featureNarrow"),
1347
1515
  checked: narrowOn,
1348
- disabled: !ready || busy,
1516
+ disabled: !canEdit,
1349
1517
  onChange: (next) => {
1350
1518
  setNarrowOn(next);
1351
1519
  void toggleFeature({ ...featureState(), narrow: next }, () => setNarrowOn(!next));
@@ -1358,7 +1526,7 @@ ${url}`)) return;
1358
1526
  {
1359
1527
  label: t("featureComplete"),
1360
1528
  checked: completeOn,
1361
- disabled: !ready || busy,
1529
+ disabled: !canEdit,
1362
1530
  onChange: (next) => {
1363
1531
  setCompleteOn(next);
1364
1532
  void toggleFeature({ ...featureState(), complete: next }, () => setCompleteOn(!next));
@@ -1385,7 +1553,7 @@ ${url}`)) return;
1385
1553
  {
1386
1554
  label: t("selfCheckSteer"),
1387
1555
  checked: checkMode === "steer",
1388
- disabled: !ready || !checkOn,
1556
+ disabled: !canEdit || !checkOn,
1389
1557
  onChange: (next) => {
1390
1558
  setCheckMode(next ? "steer" : "observe");
1391
1559
  setAdvancedDirty(true);
@@ -1398,7 +1566,7 @@ ${url}`)) return;
1398
1566
  {
1399
1567
  label: t("narrowObserveLabel"),
1400
1568
  checked: narrowMode === "observe",
1401
- disabled: !ready || !narrowOn,
1569
+ disabled: !canEdit || !narrowOn,
1402
1570
  onChange: (next) => {
1403
1571
  setNarrowMode(next ? "observe" : "enforce");
1404
1572
  setAdvancedDirty(true);
@@ -1411,7 +1579,7 @@ ${url}`)) return;
1411
1579
  {
1412
1580
  label: t("completeSteer"),
1413
1581
  checked: completeMode === "steer",
1414
- disabled: !ready || !completeOn,
1582
+ disabled: !canEdit || !completeOn,
1415
1583
  onChange: (next) => {
1416
1584
  setCompleteMode(next ? "steer" : "observe");
1417
1585
  setAdvancedDirty(true);
@@ -1430,7 +1598,7 @@ ${url}`)) return;
1430
1598
  className: "decision-prefixes",
1431
1599
  rows: 3,
1432
1600
  value: keepPrefixes,
1433
- disabled: !ready || !narrowOn,
1601
+ disabled: !canEdit || !narrowOn,
1434
1602
  placeholder: "mcp__openviking",
1435
1603
  onChange: (event) => {
1436
1604
  setKeepPrefixes(event.target.value);
@@ -1451,7 +1619,7 @@ ${url}`)) return;
1451
1619
  max: 200,
1452
1620
  step: 1,
1453
1621
  value: maxCandidates,
1454
- disabled: !ready || !narrowOn,
1622
+ disabled: !canEdit || !narrowOn,
1455
1623
  placeholder: "20",
1456
1624
  onChange: (event) => {
1457
1625
  setMaxCandidates(event.target.value);
@@ -1470,9 +1638,9 @@ ${url}`)) return;
1470
1638
  type: "number",
1471
1639
  min: 0,
1472
1640
  max: 1,
1473
- step: 0.05,
1641
+ step: "any",
1474
1642
  value: threshold,
1475
- disabled: !ready || !narrowOn,
1643
+ disabled: !canEdit || !narrowOn,
1476
1644
  placeholder: "0.3",
1477
1645
  onChange: (event) => {
1478
1646
  setThreshold(event.target.value);
@@ -1481,10 +1649,193 @@ ${url}`)) return;
1481
1649
  }
1482
1650
  ),
1483
1651
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("narrowThresholdHint") })
1652
+ ] }),
1653
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1654
+ t("batchModeLabel"),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1656
+ "select",
1657
+ {
1658
+ className: "decision-select",
1659
+ value: batchMode,
1660
+ disabled: !canEdit || !narrowOn,
1661
+ onChange: (event) => {
1662
+ setBatchMode(event.target.value);
1663
+ setAdvancedDirty(true);
1664
+ },
1665
+ children: [
1666
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "auto", children: t("batchModeAuto") }),
1667
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "single", children: t("batchModeSingle") }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "split", children: t("batchModeSplit") })
1669
+ ]
1670
+ }
1671
+ ),
1672
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("batchModeHint") })
1484
1673
  ] })
1674
+ ] }),
1675
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-field-block decision-field-block-wide", children: [
1676
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "decision-subhead", children: t("advancedThresholds") }),
1677
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-threshold-grid", children: [
1678
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1679
+ t("gateMinConfidenceLabel"),
1680
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1681
+ "input",
1682
+ {
1683
+ className: "decision-narrow-cap",
1684
+ type: "number",
1685
+ min: 0,
1686
+ max: 1,
1687
+ step: "any",
1688
+ value: thresholds.gateMin,
1689
+ disabled: !canEdit || !gateOn,
1690
+ onChange: (event) => setThresholdField("gateMin", event.target.value)
1691
+ }
1692
+ ),
1693
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("gateMinConfidenceHint") })
1694
+ ] }),
1695
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1696
+ t("checkMinConfidenceLabel"),
1697
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1698
+ "input",
1699
+ {
1700
+ className: "decision-narrow-cap",
1701
+ type: "number",
1702
+ min: 0,
1703
+ max: 1,
1704
+ step: "any",
1705
+ value: thresholds.checkMin,
1706
+ disabled: !canEdit || !checkOn,
1707
+ onChange: (event) => setThresholdField("checkMin", event.target.value)
1708
+ }
1709
+ ),
1710
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("checkMinConfidenceHint") })
1711
+ ] }),
1712
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1713
+ t("lowScoreThresholdLabel"),
1714
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1715
+ "input",
1716
+ {
1717
+ className: "decision-narrow-cap",
1718
+ type: "number",
1719
+ min: 0,
1720
+ max: 9,
1721
+ step: 1,
1722
+ value: thresholds.lowScore,
1723
+ disabled: !canEdit || !checkOn,
1724
+ onChange: (event) => setThresholdField("lowScore", event.target.value)
1725
+ }
1726
+ ),
1727
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("lowScoreThresholdHint") })
1728
+ ] }),
1729
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1730
+ t("trendMinConfidenceLabel"),
1731
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1732
+ "input",
1733
+ {
1734
+ className: "decision-narrow-cap",
1735
+ type: "number",
1736
+ min: 0,
1737
+ max: 1,
1738
+ step: "any",
1739
+ value: thresholds.trendMin,
1740
+ disabled: !canEdit || !checkOn,
1741
+ onChange: (event) => setThresholdField("trendMin", event.target.value)
1742
+ }
1743
+ ),
1744
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("trendMinConfidenceHint") })
1745
+ ] }),
1746
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1747
+ t("trendRunLabel"),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1749
+ "input",
1750
+ {
1751
+ className: "decision-narrow-cap",
1752
+ type: "number",
1753
+ min: 2,
1754
+ max: 10,
1755
+ step: 1,
1756
+ value: thresholds.trendRun,
1757
+ disabled: !canEdit || !checkOn,
1758
+ onChange: (event) => setThresholdField("trendRun", event.target.value)
1759
+ }
1760
+ ),
1761
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("trendRunHint") })
1762
+ ] }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1764
+ t("trendSevereRunLabel"),
1765
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1766
+ "input",
1767
+ {
1768
+ className: "decision-narrow-cap",
1769
+ type: "number",
1770
+ min: 2,
1771
+ max: 20,
1772
+ step: 1,
1773
+ value: thresholds.trendSevere,
1774
+ disabled: !canEdit || !checkOn,
1775
+ onChange: (event) => setThresholdField("trendSevere", event.target.value)
1776
+ }
1777
+ ),
1778
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("trendSevereRunHint") })
1779
+ ] }),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1781
+ t("completeMinConfidenceLabel"),
1782
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1783
+ "input",
1784
+ {
1785
+ className: "decision-narrow-cap",
1786
+ type: "number",
1787
+ min: 0,
1788
+ max: 1,
1789
+ step: "any",
1790
+ value: thresholds.completeMin,
1791
+ disabled: !canEdit || !completeOn,
1792
+ onChange: (event) => setThresholdField("completeMin", event.target.value)
1793
+ }
1794
+ ),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("completeMinConfidenceHint") })
1796
+ ] }),
1797
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field decision-field-inline", children: [
1798
+ t("minConditionsLabel"),
1799
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1800
+ "input",
1801
+ {
1802
+ className: "decision-narrow-cap",
1803
+ type: "number",
1804
+ min: 2,
1805
+ max: 20,
1806
+ step: 1,
1807
+ value: thresholds.minConditions,
1808
+ disabled: !canEdit || !completeOn,
1809
+ onChange: (event) => setThresholdField("minConditions", event.target.value)
1810
+ }
1811
+ ),
1812
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("minConditionsHint") })
1813
+ ] })
1814
+ ] })
1815
+ ] }),
1816
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-field-block decision-field-block-wide", children: [
1817
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "decision-subhead", children: t("advancedRubric") }),
1818
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "decision-field", children: [
1819
+ t("selfCheckRubricLabel"),
1820
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1821
+ "textarea",
1822
+ {
1823
+ className: "decision-prefixes",
1824
+ rows: 4,
1825
+ value: rubric,
1826
+ disabled: !canEdit || !checkOn,
1827
+ onChange: (event) => {
1828
+ setRubric(event.target.value);
1829
+ setAdvancedDirty(true);
1830
+ }
1831
+ }
1832
+ ),
1833
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("selfCheckRubricHint") })
1834
+ ] }),
1835
+ rubricIssue && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "status", className: "decision-muted decision-message-warn", children: rubricIssue })
1485
1836
  ] })
1486
1837
  ] }),
1487
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "decision-actions", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: busy || !ready || !advancedDirty, type: "submit", children: t("saveAdvanced") }) })
1838
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "decision-actions", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: !canEdit || !advancedDirty || Boolean(rubricIssue), type: "submit", children: t("saveAdvanced") }) })
1488
1839
  ] })
1489
1840
  ] }),
1490
1841
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
@@ -1504,7 +1855,7 @@ ${url}`)) return;
1504
1855
  {
1505
1856
  type: "url",
1506
1857
  value: config.url,
1507
- disabled: !ready,
1858
+ disabled: !canEdit,
1508
1859
  placeholder: "https://api.typesafe.ai",
1509
1860
  onChange: (event) => {
1510
1861
  setConfig({ ...config, url: event.target.value });
@@ -1520,7 +1871,7 @@ ${url}`)) return;
1520
1871
  "input",
1521
1872
  {
1522
1873
  value: config.model,
1523
- disabled: !ready,
1874
+ disabled: !canEdit,
1524
1875
  placeholder: "jev-latest",
1525
1876
  onChange: (event) => {
1526
1877
  setConfig({ ...config, model: event.target.value });
@@ -1538,7 +1889,7 @@ ${url}`)) return;
1538
1889
  type: "password",
1539
1890
  autoComplete: "off",
1540
1891
  value: key,
1541
- disabled: !ready,
1892
+ disabled: !canEdit,
1542
1893
  placeholder: config.apiKeySet ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : "",
1543
1894
  onChange: (event) => {
1544
1895
  setKey(event.target.value);
@@ -1550,8 +1901,8 @@ ${url}`)) return;
1550
1901
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: config.apiKeySet ? t("keyHintSaved") : t("keyHintEmpty") })
1551
1902
  ] }),
1552
1903
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "decision-actions", children: [
1553
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: busy || !ready, type: "submit", children: t("save") }),
1554
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "decision-secondary", disabled: busy || !ready || backendDirty, type: "button", onClick: () => void probe(), children: t("probe") }),
1904
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { disabled: !canEdit, type: "submit", children: t("save") }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "decision-secondary", disabled: !canEdit || backendDirty, type: "button", onClick: () => void probe(), children: t("probe") }),
1555
1906
  probeResult && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { role: "status", className: `decision-probe-result${probeResult.ok ? " decision-message-ok" : " decision-message-warn"}`, children: probeResult.text })
1556
1907
  ] })
1557
1908
  ] }),
@@ -1560,7 +1911,7 @@ ${url}`)) return;
1560
1911
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "decision-danger-title", children: t("removeKey") }),
1561
1912
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { className: "decision-muted", children: t("removeKeyHint") })
1562
1913
  ] }),
1563
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "decision-danger-button", disabled: busy || !ready, onClick: () => void removeSavedKey(), children: t("removeKeyButton") })
1914
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "decision-danger-button", disabled: !canEdit, onClick: () => void removeSavedKey(), children: t("removeKeyButton") })
1564
1915
  ] })
1565
1916
  ] }),
1566
1917
  message && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { role: "status", className: `decision-message${message.ok ? " decision-message-ok" : " decision-message-warn"}`, children: message.text })
@@ -1647,6 +1998,7 @@ var css = `
1647
1998
  .decision-rate-summary{margin-top:.5rem}
1648
1999
  .decision-log-tool{font-size:.76rem;padding:.05rem .35rem;border-radius:5px;background:var(--dsw-alias-bg-layer-1,#f2f4f6);color:var(--dsw-alias-label-primary,#202124)}
1649
2000
  .decision-log-cmd{font-size:.74rem;padding:.05rem .35rem;border-radius:5px;background:var(--dsw-alias-bg-layer-1,#f2f4f6);color:var(--dsw-alias-label-secondary,#59636e);word-break:break-all}
2001
+ .decision-log-subject{font-size:.74rem;color:var(--dsw-alias-label-secondary,#59636e);font-style:italic}
1650
2002
  .decision-log-verdict{font-weight:600}
1651
2003
  .decision-log-deny .decision-log-verdict{color:#c0392b}
1652
2004
  .decision-log-ok .decision-log-verdict{color:#1f8a70}
@@ -1695,13 +2047,14 @@ var css = `
1695
2047
  .decision-config form{display:grid;gap:1rem;margin-top:.8rem}
1696
2048
  .decision-field{display:grid;gap:.4rem;font-size:.82rem;font-weight:600}
1697
2049
  .decision-field .decision-muted{font-weight:400;margin:.1rem 0 0}
1698
- .decision-config input:not([type=checkbox]){box-sizing:border-box;width:100%;min-height:2.4rem;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:8px;padding:.4rem .7rem;background:var(--dsw-alias-bg-layer-2,#fff);color:inherit;font:inherit;font-weight:400}
1699
- .decision-config input:not([type=checkbox]):disabled{background:var(--dsw-alias-bg-layer-1,#f6f8fa);opacity:.7}
2050
+ .decision-config :is(input:not([type=checkbox]),select){box-sizing:border-box;width:100%;min-height:2.4rem;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:8px;padding:.4rem .7rem;background:var(--dsw-alias-bg-layer-2,#fff);color:inherit;font:inherit;font-weight:400}
2051
+ .decision-config :is(input:not([type=checkbox]),select):disabled{background:var(--dsw-alias-bg-layer-1,#f6f8fa);opacity:.7}
1700
2052
  .decision-config textarea{box-sizing:border-box;width:100%;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:8px;padding:.4rem .7rem;background:var(--dsw-alias-bg-layer-2,#fff);color:inherit;font:inherit;font-weight:400;resize:vertical;min-height:3.4rem}
1701
2053
  .decision-config textarea:disabled{background:var(--dsw-alias-bg-layer-1,#f6f8fa);opacity:.7}
1702
2054
  .decision-field-textarea{margin-top:.7rem}
1703
2055
  .decision-field-inline{margin-top:.7rem}
1704
2056
  .decision-narrow-cap{width:6rem!important}
2057
+ .decision-select{width:11rem!important}
1705
2058
  .decision-prefixes{font-family:var(--dsw-alias-font-mono,ui-monospace,SFMono-Regular,Menlo,monospace)!important;line-height:1.5}
1706
2059
 
1707
2060
  .decision-field-block{display:grid;gap:.35rem}
@@ -1710,6 +2063,11 @@ var css = `
1710
2063
  .decision-advanced-grid{display:grid;grid-template-columns:1fr;gap:1.1rem;align-items:start;justify-content:start}
1711
2064
  .decision-advanced-grid .decision-field-block+.decision-field-block{margin-top:0}
1712
2065
  @container (min-width:34rem){.decision-advanced-grid{grid-template-columns:repeat(2,minmax(0,28rem));column-gap:2rem}}
2066
+ /* A block that needs the full row width (the threshold list, the rubric box);
2067
+ its own fields flow into as many columns as fit, so eight numeric fields do
2068
+ not stretch one grid cell to ~50rem of height beside a mostly empty one. */
2069
+ .decision-field-block-wide{grid-column:1/-1}
2070
+ .decision-threshold-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));gap:.9rem 1.6rem;align-items:start}
1713
2071
  .decision-subhead{font-size:.86rem;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e)}
1714
2072
  .decision-toggle{display:flex;align-items:center;justify-content:space-between;gap:1rem;font-size:.86rem;font-weight:600;cursor:pointer}
1715
2073
  .decision-toggle-text{flex:1 1 auto}