dsh-decision-layer 0.7.0 → 0.7.2
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/README.en.md +33 -19
- package/README.md +33 -21
- package/docs/en/DETAIL.md +20 -0
- package/docs/zh/DETAIL.md +20 -0
- package/lib/client.js +185 -35
- package/lib/host/backend.d.ts +15 -0
- package/lib/host/backend.js +149 -0
- package/lib/host/config-store.d.ts +12 -0
- package/lib/host/config-store.js +254 -0
- package/lib/host/danger-gate.d.ts +45 -0
- package/lib/host/danger-gate.js +196 -0
- package/lib/host/excerpt.d.ts +25 -0
- package/lib/host/excerpt.js +62 -0
- package/lib/host/index.d.ts +6 -0
- package/lib/host/index.js +290 -0
- package/lib/host/log-analyze.d.ts +121 -0
- package/lib/host/log-analyze.js +254 -0
- package/lib/host/log-read.d.ts +4 -0
- package/lib/host/log-read.js +34 -0
- package/lib/host/log-store.d.ts +15 -0
- package/lib/host/log-store.js +98 -0
- package/lib/host/loop-guard.d.ts +10 -0
- package/lib/host/loop-guard.js +52 -0
- package/lib/host/manager-api.d.ts +20 -0
- package/lib/host/manager-api.js +174 -0
- package/lib/host/narrowing.d.ts +48 -0
- package/lib/host/narrowing.js +213 -0
- package/lib/host/quality-trend.d.ts +14 -0
- package/lib/host/quality-trend.js +22 -0
- package/lib/host/self-check.d.ts +27 -0
- package/lib/host/self-check.js +104 -0
- package/lib/host/session-state.d.ts +19 -0
- package/lib/host/session-state.js +288 -0
- package/lib/host/state-store.d.ts +14 -0
- package/lib/host/state-store.js +109 -0
- package/lib/host/steer-once.d.ts +13 -0
- package/lib/host/steer-once.js +25 -0
- package/lib/host/task-completion.d.ts +29 -0
- package/lib/host/task-completion.js +148 -0
- package/lib/host/types.d.ts +343 -0
- package/lib/host/types.js +11 -0
- package/locale/en.json +2 -1
- package/locale/zh.json +2 -1
- package/package.json +19 -10
- package/service/.gitkeep +0 -0
- package/service/backend.mjs +0 -127
- package/service/config-store.mjs +0 -311
- package/service/danger-gate.mjs +0 -182
- package/service/dsh.mjs +0 -282
- package/service/log-analyze.mjs +0 -256
- package/service/log-read.mjs +0 -27
- package/service/log-store.mjs +0 -82
- package/service/loop-guard.mjs +0 -51
- package/service/manager-api.mjs +0 -137
- package/service/narrowing.mjs +0 -210
- package/service/quality-trend.mjs +0 -29
- package/service/self-check.mjs +0 -131
- package/service/session-state.mjs +0 -257
- package/service/state-store.mjs +0 -100
- package/service/steer-once.mjs +0 -25
- package/service/task-completion.mjs +0 -163
package/lib/client.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
window.__ModuleLoader__.load({
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var module = { exports: {} };
|
|
5
|
-
var exports = module.exports;
|
|
1
|
+
window.__ModuleLoader__.load({ id: 'dsh-decision-layer', factory: (require) => {
|
|
2
|
+
var module = { exports: {} }; var exports = module.exports;
|
|
3
|
+
"use strict";
|
|
6
4
|
var __defProp = Object.defineProperty;
|
|
7
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -65,6 +63,7 @@ var zh = {
|
|
|
65
63
|
narrowMore: " \u7B49 {count} \u4E2A",
|
|
66
64
|
narrowObserve: "\u4EC5\u89C2\u5BDF",
|
|
67
65
|
narrowEnforce: "\u5DF2\u751F\u6548",
|
|
66
|
+
narrowNotApplied: "\u672A\u751F\u6548",
|
|
68
67
|
checkPassRate: "\u901A\u8FC7\u7387",
|
|
69
68
|
narrowApplyRate: "\u6536\u7A84\u7387",
|
|
70
69
|
rateNa: "\u2014",
|
|
@@ -81,6 +80,8 @@ var zh = {
|
|
|
81
80
|
logCheck: "\u81EA\u68C0",
|
|
82
81
|
logNarrow: "\u6536\u7A84",
|
|
83
82
|
logComplete: "\u5B8C\u6210\u6838\u5BF9",
|
|
83
|
+
logTurn: "\u56DE\u5408 {turn}",
|
|
84
|
+
logTask: "\u573A\u666F\uFF08\u4EFB\u52A1\u8282\u9009\uFF09\uFF1A",
|
|
84
85
|
logSuggested: "\u6A21\u578B\u5EFA\u8BAE",
|
|
85
86
|
logEvalFailed: "\u8BC4\u4F30\u5931\u8D25",
|
|
86
87
|
logScore: "\u5F97\u5206",
|
|
@@ -90,7 +91,7 @@ var zh = {
|
|
|
90
91
|
logPathLabel: "\u8DEF\u5F84\uFF1A",
|
|
91
92
|
logSubjectLabel: "\u8BF7\u6C42\uFF1A",
|
|
92
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",
|
|
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
|
+
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\uFF1B\u81EA\u68C0\u884C\uFF08\u542B\u540E\u7AEF\u5931\u8D25\u884C\uFF09\u4F1A\u5E26\u672C\u56DE\u5408\u7684\u4EFB\u52A1\u8282\u9009\uFF08\u6700\u591A 512 \u5B57\uFF0C\u5DF2\u906E\u853D\u51ED\u636E\uFF09\u3002",
|
|
94
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",
|
|
95
96
|
actionDeny: "\u5DF2\u62D2\u7EDD",
|
|
96
97
|
actionAsk: "\u8F6C\u4EA4\u5BA1\u6279",
|
|
@@ -108,7 +109,7 @@ var zh = {
|
|
|
108
109
|
reasonConfig: "\u914D\u7F6E\u65E0\u6548",
|
|
109
110
|
reasonTooMany: "\u5019\u9009\u8FC7\u591A",
|
|
110
111
|
reasonTooManyCount: "\u5019\u9009 {count} \u4E2A\u504F\u591A",
|
|
111
|
-
reasonLowKeep: "\u4FDD\u7559\u8FC7\u5C11
|
|
112
|
+
reasonLowKeep: "\u4FDD\u7559\u8FC7\u5C11",
|
|
112
113
|
selfCheck: "\u4EA7\u51FA\u81EA\u68C0",
|
|
113
114
|
advancedSwitches: "\u4ECB\u5165\u5F00\u5173",
|
|
114
115
|
advancedParams: "\u6536\u7A84\u53C2\u6570",
|
|
@@ -118,11 +119,11 @@ var zh = {
|
|
|
118
119
|
narrowObserveLabel: "\u4EC5\u89C2\u5BDF\uFF08\u4E0D\u771F\u6B63\u9650\u5236\u5DE5\u5177\uFF09",
|
|
119
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",
|
|
120
121
|
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\
|
|
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\u53EA\u6709 mcp__openviking\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
123
|
narrowMaxLabel: "\u5019\u9009\u5DE5\u5177\u4E0A\u9650",
|
|
123
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",
|
|
124
125
|
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.
|
|
126
|
+
narrowThresholdHint: "\u76F8\u5173\u6027\u6982\u7387\u4F4E\u4E8E\u8FD9\u4E2A\u503C\u624D\u6458\u6389\u5DE5\u5177\uFF08\u9ED8\u8BA4 0.7\uFF0C\u504F\u6FC0\u8FDB\uFF1A\u53EA\u7559\u6A21\u578B\u8F83\u6709\u628A\u63E1\u5224\u4E3A\u76F8\u5173\u7684\u5DE5\u5177\uFF09\u3002\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\u6982\u7387\u63A5\u8FD1 0.5 \u8868\u793A\u6A21\u578B\u62FF\u4E0D\u51C6\uFF0C\u6309\u9ED8\u8BA4\u9608\u503C\u4F1A\u88AB\u6458\u6389\uFF1B\u60F3\u7559\u4F4F\u8FD9\u7C7B\u300C\u53EF\u80FD\u7528\u5230\u300D\u7684\u5DE5\u5177\uFF0C\u628A\u9608\u503C\u8C03\u4F4E\u3002\u53D6\u503C 0\u20131\u3002",
|
|
126
127
|
batchModeLabel: "\u5206\u6279\u7B56\u7565",
|
|
127
128
|
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
129
|
batchModeAuto: "\u81EA\u52A8",
|
|
@@ -159,7 +160,7 @@ var zh = {
|
|
|
159
160
|
featureCheck: "\u4EA7\u51FA\u81EA\u68C0",
|
|
160
161
|
featureCheckHint: "\u5173\u95ED\u540E\u4E0D\u518D\u5728\u56DE\u5408\u7ED3\u675F\u65F6\u7ED9\u6700\u7EC8\u56DE\u590D\u6253\u5206\u3002",
|
|
161
162
|
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\
|
|
163
|
+
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\u4E0D\u53D7\u5404\u51B3\u7B56\u70B9\u5F00\u5173\u5F71\u54CD\uFF0C\u4F46\u4F1A\u8BDD\u603B\u5F00\u5173\u5173\u95ED\u65F6\u540C\u6837\u6682\u505C\u3002",
|
|
163
164
|
featureComplete: "\u4EFB\u52A1\u5B8C\u6210\u6838\u5BF9",
|
|
164
165
|
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
166
|
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",
|
|
@@ -202,7 +203,15 @@ var zh = {
|
|
|
202
203
|
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
204
|
analysisTab: "\u51B3\u7B56\u5206\u6790",
|
|
204
205
|
analysisTitle: "\u51B3\u7B56\u5206\u6790",
|
|
205
|
-
analysisIntro: "\u57FA\u4E8E\u672C\u4F1A\u8BDD\u5DF2\u843D\u76D8\u7684\u51B3\u7B56\u65E5\u5FD7\u505A\
|
|
206
|
+
analysisIntro: "\u57FA\u4E8E\u672C\u4F1A\u8BDD\u5DF2\u843D\u76D8\u7684\u51B3\u7B56\u65E5\u5FD7\u505A\u805A\u5408\u4E0E\u4EBA\u5DE5\u6807\u6CE8\uFF1B\u9875\u5934\u5F00\u5173\u53EA\u63A7\u5236\u672C\u4F1A\u8BDD\u662F\u5426\u81EA\u52A8\u4ECB\u5165\uFF0C\u4E0D\u6539\u52A8\u5386\u53F2\u8BB0\u5F55\u3002",
|
|
207
|
+
analysisDecisionSwitch: "\u672C\u4F1A\u8BDD\u81EA\u52A8\u4ECB\u5165",
|
|
208
|
+
analysisDecisionOn: "\u5DF2\u5F00\u542F",
|
|
209
|
+
analysisDecisionOff: "\u5DF2\u5173\u95ED",
|
|
210
|
+
analysisDecisionUnavailable: "\u4E0D\u53EF\u7528",
|
|
211
|
+
analysisDecisionRetry: "\u8BFB\u53D6\u4F1A\u8BDD\u72B6\u6001\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5\u3002",
|
|
212
|
+
analysisDecisionHintOn: "\u70B9\u51FB\u5173\u95ED\u672C\u4F1A\u8BDD\u7684\u81EA\u52A8\u4ECB\u5165\uFF08\u542B\u9632\u5FAA\u73AF\uFF09\uFF1B\u5DF2\u4EA7\u751F\u7684\u51B3\u7B56\u8BB0\u5F55\u4E0D\u53D7\u5F71\u54CD\u3002",
|
|
213
|
+
analysisDecisionHintOff: "\u70B9\u51FB\u5F00\u542F\u540E\uFF0C\u672C\u4F1A\u8BDD\u7684\u95E8\u63A7\u3001\u81EA\u68C0\u3001\u6536\u7A84\u3001\u5B8C\u6210\u6838\u5BF9\u4E0E\u9632\u5FAA\u73AF\u4F1A\u81EA\u52A8\u4ECB\u5165\u3002",
|
|
214
|
+
analysisDecisionDisabled: "\u672C\u4F1A\u8BDD\u7684\u81EA\u52A8\u4ECB\u5165\u5DF2\u5173\u95ED\u3002\u5F00\u542F\u540E\uFF0C\u65B0\u7684\u56DE\u5408\u624D\u4F1A\u4EA7\u751F\u51B3\u7B56\u8BB0\u5F55\u3002",
|
|
206
215
|
analysisProfile: "\u8FC7\u7A0B\u753B\u50CF",
|
|
207
216
|
analysisMeanScore: "\u5E73\u5747\u5206",
|
|
208
217
|
analysisTrend: "\u8D28\u91CF\u8D8B\u52BF\u56DE\u6D4B",
|
|
@@ -251,6 +260,7 @@ var en = {
|
|
|
251
260
|
narrowMore: " and {count} in total",
|
|
252
261
|
narrowObserve: "observe",
|
|
253
262
|
narrowEnforce: "enforced",
|
|
263
|
+
narrowNotApplied: "not applied",
|
|
254
264
|
checkPassRate: "Pass rate",
|
|
255
265
|
narrowApplyRate: "Narrow rate",
|
|
256
266
|
rateNa: "\u2014",
|
|
@@ -267,6 +277,8 @@ var en = {
|
|
|
267
277
|
logCheck: "Self-check",
|
|
268
278
|
logNarrow: "Narrow",
|
|
269
279
|
logComplete: "Completion",
|
|
280
|
+
logTurn: "Turn {turn}",
|
|
281
|
+
logTask: "Context (task excerpt): ",
|
|
270
282
|
logSuggested: "model suggested",
|
|
271
283
|
logEvalFailed: "evaluation failed",
|
|
272
284
|
logScore: "score",
|
|
@@ -276,7 +288,7 @@ var en = {
|
|
|
276
288
|
logPathLabel: "path: ",
|
|
277
289
|
logSubjectLabel: "request: ",
|
|
278
290
|
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.",
|
|
291
|
+
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; every self-check row (including a failed one) carries this turn\u2019s task excerpt (up to 512 characters, credentials masked).",
|
|
280
292
|
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
293
|
actionDeny: "denied",
|
|
282
294
|
actionAsk: "sent to approval",
|
|
@@ -294,7 +306,7 @@ var en = {
|
|
|
294
306
|
reasonConfig: "invalid configuration",
|
|
295
307
|
reasonTooMany: "too many candidates",
|
|
296
308
|
reasonTooManyCount: "{count} candidates is too many",
|
|
297
|
-
reasonLowKeep: "too few kept
|
|
309
|
+
reasonLowKeep: "too few kept",
|
|
298
310
|
selfCheck: "Output self-check",
|
|
299
311
|
advancedSwitches: "Intervention switches",
|
|
300
312
|
advancedParams: "Narrowing parameters",
|
|
@@ -304,11 +316,11 @@ var en = {
|
|
|
304
316
|
narrowObserveLabel: "Observe only (do not restrict tools)",
|
|
305
317
|
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
318
|
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
|
|
319
|
+
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 only). Separate prefixes with commas or newlines; leave empty to keep nothing extra.",
|
|
308
320
|
narrowMaxLabel: "Candidate tool cap",
|
|
309
321
|
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
322
|
narrowThresholdLabel: "Drop threshold",
|
|
311
|
-
narrowThresholdHint:
|
|
323
|
+
narrowThresholdHint: "A tool is dropped only when its relevance probability is below this value (default 0.7, leaning aggressive: only tools the model rates as fairly relevant survive). Lower is more conservative (drops fewer), higher is more aggressive. A probability near 0.5 means the model is unsure and falls below the default, so lower the threshold to keep such may-need tools. Range 0\u20131.",
|
|
312
324
|
batchModeLabel: "Batch strategy",
|
|
313
325
|
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
326
|
batchModeAuto: "Auto",
|
|
@@ -345,7 +357,7 @@ var en = {
|
|
|
345
357
|
featureCheck: "Output self-check",
|
|
346
358
|
featureCheckHint: "When off, the final reply is no longer scored at the end of a turn.",
|
|
347
359
|
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
|
|
360
|
+
featureNarrowHint: "When off, tool relevance is no longer evaluated at the start of a turn. The loop guard is a deterministic local safeguard outside these switches, but the session master switch pauses it too.",
|
|
349
361
|
featureComplete: "Task completion check",
|
|
350
362
|
featureCompleteHint: "When off, the explicit deliverable conditions the user listed are no longer checked at turn end.",
|
|
351
363
|
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.",
|
|
@@ -388,7 +400,15 @@ var en = {
|
|
|
388
400
|
httpWarning: "This address uses unencrypted HTTP. Your API key and evaluation context will be sent in plaintext to this address.",
|
|
389
401
|
analysisTab: "Decision analysis",
|
|
390
402
|
analysisTitle: "Decision analysis",
|
|
391
|
-
analysisIntro: "
|
|
403
|
+
analysisIntro: "An aggregate and manual annotation over this session\u2019s persisted decision log. The switch in the header only controls automatic interventions for this session and never rewrites history.",
|
|
404
|
+
analysisDecisionSwitch: "Automatic interventions",
|
|
405
|
+
analysisDecisionOn: "on",
|
|
406
|
+
analysisDecisionOff: "off",
|
|
407
|
+
analysisDecisionUnavailable: "unavailable",
|
|
408
|
+
analysisDecisionRetry: "Could not read the session state. Click to retry.",
|
|
409
|
+
analysisDecisionHintOn: "Turn off automatic interventions for this session, including the loop guard. Existing decision records are unaffected.",
|
|
410
|
+
analysisDecisionHintOff: "Turn on automatic interventions (gate, self-check, narrowing, completion check, and loop guard) for this session.",
|
|
411
|
+
analysisDecisionDisabled: "Automatic interventions are off for this session. New decision records appear after you enable them.",
|
|
392
412
|
analysisProfile: "Process profile",
|
|
393
413
|
analysisMeanScore: "Mean score",
|
|
394
414
|
analysisTrend: "Quality-trend backtest",
|
|
@@ -418,6 +438,23 @@ async function request(path, init) {
|
|
|
418
438
|
return body.value;
|
|
419
439
|
}
|
|
420
440
|
|
|
441
|
+
// src/client/session-events.ts
|
|
442
|
+
var SESSION_ENABLED_EVENT = "dsh-decision-layer:session-enabled";
|
|
443
|
+
function announceSessionEnabled(change) {
|
|
444
|
+
if (typeof window === "undefined") return;
|
|
445
|
+
window.dispatchEvent(new window.CustomEvent(SESSION_ENABLED_EVENT, { detail: change }));
|
|
446
|
+
}
|
|
447
|
+
function onSessionEnabled(listener) {
|
|
448
|
+
if (typeof window === "undefined") return () => {
|
|
449
|
+
};
|
|
450
|
+
const handler = (event) => {
|
|
451
|
+
const change = event.detail;
|
|
452
|
+
if (change && typeof change.sessionId === "string" && typeof change.enabled === "boolean") listener(change);
|
|
453
|
+
};
|
|
454
|
+
window.addEventListener(SESSION_ENABLED_EVENT, handler);
|
|
455
|
+
return () => window.removeEventListener(SESSION_ENABLED_EVENT, handler);
|
|
456
|
+
}
|
|
457
|
+
|
|
421
458
|
// src/client/decision-log.tsx
|
|
422
459
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
423
460
|
var time = (at) => new Date(at).toLocaleTimeString();
|
|
@@ -439,6 +476,12 @@ function gateArgs({ t }, entry) {
|
|
|
439
476
|
const preview = value.length > 160 ? `${value.slice(0, 160)}\u2026` : value;
|
|
440
477
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "decision-log-cmd", title: `${label}${value}`, children: preview });
|
|
441
478
|
}
|
|
479
|
+
function turnTag(t, entry) {
|
|
480
|
+
return typeof entry.turn === "number" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-detail", children: [
|
|
481
|
+
" \xB7 ",
|
|
482
|
+
t("logTurn", { turn: entry.turn })
|
|
483
|
+
] }) : null;
|
|
484
|
+
}
|
|
442
485
|
function renderGate({ t }, entry) {
|
|
443
486
|
const tool = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "decision-log-tool", children: entry.tool ?? "\u2014" });
|
|
444
487
|
const args = gateArgs({ t }, entry);
|
|
@@ -506,7 +549,10 @@ function renderGate({ t }, entry) {
|
|
|
506
549
|
] });
|
|
507
550
|
}
|
|
508
551
|
function renderCheck({ t }, entry) {
|
|
509
|
-
const label = /* @__PURE__ */ (0, import_jsx_runtime.
|
|
552
|
+
const label = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
553
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { title: t("logCheckHint"), children: t("logCheck") }),
|
|
554
|
+
turnTag(t, entry)
|
|
555
|
+
] });
|
|
510
556
|
const subject = entry.subject ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-subject", title: `${t("logSubjectLabel")}${entry.subject}`, children: [
|
|
511
557
|
"\u300C",
|
|
512
558
|
entry.subject.length > 60 ? `${entry.subject.slice(0, 60)}\u2026` : entry.subject,
|
|
@@ -558,7 +604,10 @@ function renderCheck({ t }, entry) {
|
|
|
558
604
|
] });
|
|
559
605
|
}
|
|
560
606
|
function renderNarrow({ t }, entry) {
|
|
561
|
-
const label = /* @__PURE__ */ (0, import_jsx_runtime.
|
|
607
|
+
const label = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
608
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { title: t("logNarrowHint"), children: t("logNarrow") }),
|
|
609
|
+
turnTag(t, entry)
|
|
610
|
+
] });
|
|
562
611
|
if (entry.outcome === "error") return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
563
612
|
label,
|
|
564
613
|
" ",
|
|
@@ -574,9 +623,13 @@ function renderNarrow({ t }, entry) {
|
|
|
574
623
|
" \xB7 ",
|
|
575
624
|
guardText
|
|
576
625
|
] }) : null;
|
|
577
|
-
const
|
|
626
|
+
const notApplied = entry.applied === false || entry.reason === "low-keep" || entry.reason === "too-many-candidates";
|
|
627
|
+
const modeTag = entry.mode === "observe" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-detail", children: [
|
|
578
628
|
" \xB7 ",
|
|
579
|
-
|
|
629
|
+
t("narrowObserve")
|
|
630
|
+
] }) : dropped === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "decision-log-detail", children: [
|
|
631
|
+
" \xB7 ",
|
|
632
|
+
notApplied ? t("narrowNotApplied") : t("narrowEnforce")
|
|
580
633
|
] });
|
|
581
634
|
if (dropped === 0) {
|
|
582
635
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
@@ -682,7 +735,16 @@ function DecisionLogList({ entries, ratings, onRate, t, newestFirst = true }) {
|
|
|
682
735
|
const rows = newestFirst ? entries.slice().reverse() : entries.slice();
|
|
683
736
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "decision-log", children: rows.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: `decision-log-item decision-log-${outcomeTagOf(entry)}`, children: [
|
|
684
737
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "decision-log-time", children: time(entry.at) }),
|
|
685
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
738
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "decision-log-body", children: [
|
|
739
|
+
renderBody({ t }, entry),
|
|
740
|
+
entry.task ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "decision-log-context", children: [
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
|
|
742
|
+
t("logTask"),
|
|
743
|
+
entry.task.length > 60 ? `${entry.task.slice(0, 60)}\u2026` : entry.task
|
|
744
|
+
] }),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: entry.task })
|
|
746
|
+
] }) : null
|
|
747
|
+
] }),
|
|
686
748
|
entry.id && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RatingButtons, { id: entry.id, t, ratings, onRate })
|
|
687
749
|
] }, entry.id ?? `${entry.at}-${index}`)) });
|
|
688
750
|
}
|
|
@@ -796,6 +858,9 @@ function SessionPanel({ sessionId, t, useProjection }) {
|
|
|
796
858
|
live = false;
|
|
797
859
|
};
|
|
798
860
|
}, [sessionId, t]);
|
|
861
|
+
(0, import_react2.useEffect)(() => onSessionEnabled((change) => {
|
|
862
|
+
if (change.sessionId === sessionId) setEnabled(change.enabled);
|
|
863
|
+
}), [sessionId]);
|
|
799
864
|
const checkStatus = () => {
|
|
800
865
|
setStatus("checking");
|
|
801
866
|
void request("probe", { method: "POST" }).then((value) => {
|
|
@@ -837,6 +902,7 @@ function SessionPanel({ sessionId, t, useProjection }) {
|
|
|
837
902
|
body: JSON.stringify({ sessionId, enabled: next })
|
|
838
903
|
});
|
|
839
904
|
setEnabled(value.enabled);
|
|
905
|
+
announceSessionEnabled({ sessionId, enabled: value.enabled });
|
|
840
906
|
} catch {
|
|
841
907
|
setMessage(t("error"));
|
|
842
908
|
} finally {
|
|
@@ -1044,7 +1110,30 @@ function AnalysisView({ sessionId, t }) {
|
|
|
1044
1110
|
const [logPage, setLogPage] = (0, import_react3.useState)(1);
|
|
1045
1111
|
const [loaded, setLoaded] = (0, import_react3.useState)(false);
|
|
1046
1112
|
const [message, setMessage] = (0, import_react3.useState)("");
|
|
1113
|
+
const [enabled, setEnabled] = (0, import_react3.useState)(null);
|
|
1114
|
+
const [sessionError, setSessionError] = (0, import_react3.useState)(false);
|
|
1115
|
+
const [busy, setBusy] = (0, import_react3.useState)(false);
|
|
1047
1116
|
const { ratings, seed, annotate } = useAnnotations(sessionId, () => setMessage(t("annotateFailed")));
|
|
1117
|
+
const active = (0, import_react3.useRef)(sessionId);
|
|
1118
|
+
const loadSession = () => {
|
|
1119
|
+
const session = sessionId;
|
|
1120
|
+
setEnabled(null);
|
|
1121
|
+
setSessionError(false);
|
|
1122
|
+
void request(`session?sessionId=${encodeURIComponent(session)}`).then((value) => {
|
|
1123
|
+
if (active.current === session) setEnabled(value.enabled);
|
|
1124
|
+
}).catch(() => {
|
|
1125
|
+
if (active.current === session) setSessionError(true);
|
|
1126
|
+
});
|
|
1127
|
+
};
|
|
1128
|
+
(0, import_react3.useEffect)(() => {
|
|
1129
|
+
active.current = sessionId;
|
|
1130
|
+
setBusy(false);
|
|
1131
|
+
setMessage("");
|
|
1132
|
+
loadSession();
|
|
1133
|
+
}, [sessionId]);
|
|
1134
|
+
(0, import_react3.useEffect)(() => onSessionEnabled((change) => {
|
|
1135
|
+
if (change.sessionId === sessionId) setEnabled(change.enabled);
|
|
1136
|
+
}), [sessionId]);
|
|
1048
1137
|
(0, import_react3.useEffect)(() => {
|
|
1049
1138
|
let alive = true;
|
|
1050
1139
|
setMessage("");
|
|
@@ -1064,6 +1153,32 @@ function AnalysisView({ sessionId, t }) {
|
|
|
1064
1153
|
alive = false;
|
|
1065
1154
|
};
|
|
1066
1155
|
}, [sessionId, seed]);
|
|
1156
|
+
const toggleEnabled = async () => {
|
|
1157
|
+
if (sessionError) {
|
|
1158
|
+
loadSession();
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
if (enabled === null || busy) return;
|
|
1162
|
+
const next = !enabled;
|
|
1163
|
+
const session = sessionId;
|
|
1164
|
+
setBusy(true);
|
|
1165
|
+
try {
|
|
1166
|
+
const value = await request("session", {
|
|
1167
|
+
method: "PUT",
|
|
1168
|
+
headers: { "content-type": "application/json" },
|
|
1169
|
+
body: JSON.stringify({ sessionId: session, enabled: next })
|
|
1170
|
+
});
|
|
1171
|
+
if (active.current === session) {
|
|
1172
|
+
setEnabled(value.enabled);
|
|
1173
|
+
setMessage("");
|
|
1174
|
+
announceSessionEnabled({ sessionId: session, enabled: value.enabled });
|
|
1175
|
+
}
|
|
1176
|
+
} catch {
|
|
1177
|
+
if (active.current === session) setMessage(t("error"));
|
|
1178
|
+
} finally {
|
|
1179
|
+
if (active.current === session) setBusy(false);
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1067
1182
|
(0, import_react3.useEffect)(() => {
|
|
1068
1183
|
let alive = true;
|
|
1069
1184
|
void request(`logrows?sessionId=${encodeURIComponent(sessionId)}&page=${logPage}&pageSize=${LOG_PAGE_SIZE}`).then((value) => {
|
|
@@ -1080,9 +1195,30 @@ function AnalysisView({ sessionId, t }) {
|
|
|
1080
1195
|
const meanScore = profile && profile.check.scoreCount > 0 ? Math.round(profile.check.scoreSum / profile.check.scoreCount * 10) / 10 : null;
|
|
1081
1196
|
const completeTotal = profile ? profile.complete.satisfied + profile.complete.unsatisfied + profile.complete.insufficient : 0;
|
|
1082
1197
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "decision-analysis", role: "region", "aria-label": t("analysisTitle"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "decision-analysis-inner", children: [
|
|
1083
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.
|
|
1084
|
-
|
|
1085
|
-
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "decision-analysis-head", children: [
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "decision-analysis-heading", children: [
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "decision-analysis-title", children: t("analysisTitle") }),
|
|
1201
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "decision-muted decision-analysis-intro", children: t("analysisIntro") })
|
|
1202
|
+
] }),
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1204
|
+
"button",
|
|
1205
|
+
{
|
|
1206
|
+
type: "button",
|
|
1207
|
+
className: "decision-analysis-switch",
|
|
1208
|
+
"aria-pressed": enabled === true,
|
|
1209
|
+
"aria-busy": busy || enabled === null && !sessionError,
|
|
1210
|
+
disabled: busy || enabled === null && !sessionError,
|
|
1211
|
+
title: sessionError ? t("analysisDecisionRetry") : enabled === false ? t("analysisDecisionHintOff") : enabled === true ? t("analysisDecisionHintOn") : void 0,
|
|
1212
|
+
onClick: () => void toggleEnabled(),
|
|
1213
|
+
children: [
|
|
1214
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "decision-analysis-switch-dot", "aria-hidden": "true" }),
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("analysisDecisionSwitch") }),
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "decision-analysis-switch-state", children: sessionError ? t("analysisDecisionUnavailable") : enabled === null ? t("loading") : enabled ? t("analysisDecisionOn") : t("analysisDecisionOff") })
|
|
1217
|
+
]
|
|
1218
|
+
}
|
|
1219
|
+
)
|
|
1220
|
+
] }),
|
|
1221
|
+
loaded && (!analysis || analysis.totalDecisions === 0) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "decision-empty", role: "status", children: enabled === false ? t("analysisDecisionDisabled") : t("logEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1086
1222
|
profile && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "decision-analysis-section", children: [
|
|
1087
1223
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: t("analysisProfile") }),
|
|
1088
1224
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "decision-analysis-cards", children: [
|
|
@@ -1162,9 +1298,9 @@ async function request2(path, fetchFn, init) {
|
|
|
1162
1298
|
if (!response.ok || !body.ok || body.value === void 0) throw new Error(body.error || "Request failed");
|
|
1163
1299
|
return body.value;
|
|
1164
1300
|
}
|
|
1165
|
-
var DEFAULT_KEEP_PREFIXES = ["mcp__openviking"
|
|
1301
|
+
var DEFAULT_KEEP_PREFIXES = ["mcp__openviking"];
|
|
1166
1302
|
var DEFAULT_MAX_CANDIDATES = 20;
|
|
1167
|
-
var DEFAULT_THRESHOLD = 0.
|
|
1303
|
+
var DEFAULT_THRESHOLD = 0.7;
|
|
1168
1304
|
var DEFAULT_BATCH_MODE = "auto";
|
|
1169
1305
|
var DEFAULT_RUBRIC = [
|
|
1170
1306
|
"\u660E\u663E\u7B54\u975E\u6240\u95EE\uFF0C\u6216\u5B58\u5728\u4E25\u91CD\u9057\u6F0F / \u81EA\u76F8\u77DB\u76FE",
|
|
@@ -1641,7 +1777,7 @@ ${url}`)) return;
|
|
|
1641
1777
|
step: "any",
|
|
1642
1778
|
value: threshold,
|
|
1643
1779
|
disabled: !canEdit || !narrowOn,
|
|
1644
|
-
placeholder: "0.
|
|
1780
|
+
placeholder: "0.7",
|
|
1645
1781
|
onChange: (event) => {
|
|
1646
1782
|
setThreshold(event.target.value);
|
|
1647
1783
|
setAdvancedDirty(true);
|
|
@@ -1999,6 +2135,10 @@ var css = `
|
|
|
1999
2135
|
.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)}
|
|
2000
2136
|
.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
2137
|
.decision-log-subject{font-size:.74rem;color:var(--dsw-alias-label-secondary,#59636e);font-style:italic}
|
|
2138
|
+
.decision-log-context{margin-top:.25rem;font-size:.74rem;color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}
|
|
2139
|
+
.decision-log-context summary{cursor:pointer}
|
|
2140
|
+
.decision-log-context summary:focus-visible{outline:2px solid var(--dsw-alias-label-secondary);outline-offset:2px}
|
|
2141
|
+
.decision-log-context p{margin:.25rem 0 0}
|
|
2002
2142
|
.decision-log-verdict{font-weight:600}
|
|
2003
2143
|
.decision-log-deny .decision-log-verdict{color:#c0392b}
|
|
2004
2144
|
.decision-log-ok .decision-log-verdict{color:#1f8a70}
|
|
@@ -2101,10 +2241,22 @@ var css = `
|
|
|
2101
2241
|
/* Conversation-view "Decision analysis" tab. It reuses the card / stat / log
|
|
2102
2242
|
primitives above; this block only supplies the scroll container and section
|
|
2103
2243
|
rhythm, since the tab is not inside the modal's .decision-body wrapper. */
|
|
2104
|
-
.decision-analysis{height:100%;overflow:auto;color:var(--dsw-alias-label-primary,#202124);font:inherit}
|
|
2244
|
+
.decision-analysis{height:100%;overflow:auto;color:var(--dsw-alias-label-primary,#202124);font:inherit;--decision-analysis-accent:#1f5d50;--decision-analysis-accent-bg:rgba(31,93,80,.08);--decision-analysis-dot:#1f8a70;--decision-analysis-ring:rgba(31,138,112,.16)}
|
|
2105
2245
|
.decision-analysis-inner{max-width:52rem;margin:0 auto;padding:1.4rem 1.5rem 3rem}
|
|
2246
|
+
.decision-analysis-head{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;flex-wrap:wrap}
|
|
2247
|
+
.decision-analysis-heading{flex:1 1 18rem;min-width:0}
|
|
2106
2248
|
.decision-analysis-title{font-size:1.15rem;margin:0 0 .3rem}
|
|
2107
|
-
.decision-analysis-intro{margin:0
|
|
2249
|
+
.decision-analysis-intro{margin:0}
|
|
2250
|
+
/* The session-level automatic-intervention switch, mirrored from the dock panel.
|
|
2251
|
+
A pill button with a status dot: pressed = decisions on for this session. */
|
|
2252
|
+
.decision-analysis-switch{display:inline-flex;align-items:center;gap:.45rem;flex:0 0 auto;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2,#ccd3da);border-radius:999px;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);padding:.38rem .85rem;font:inherit;font-size:.8rem;font-weight:500;line-height:1.3;white-space:nowrap;cursor:pointer;transition:color .15s,border-color .15s,background .15s}
|
|
2253
|
+
.decision-analysis-switch:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eef1f3);color:var(--dsw-alias-label-primary,#202124)}
|
|
2254
|
+
.decision-analysis-switch[aria-pressed="true"]{border-color:var(--decision-analysis-accent);color:var(--decision-analysis-accent);background:var(--decision-analysis-accent-bg)}
|
|
2255
|
+
.decision-analysis-switch-dot{flex:0 0 auto;width:.5rem;height:.5rem;border-radius:50%;background:var(--dsw-alias-label-tertiary,#9aa5b1);transition:background .15s,box-shadow .15s}
|
|
2256
|
+
.decision-analysis-switch[aria-pressed="true"] .decision-analysis-switch-dot{background:var(--decision-analysis-dot);box-shadow:0 0 0 2px var(--decision-analysis-ring)}
|
|
2257
|
+
.decision-analysis-switch:disabled{opacity:.55;cursor:default}
|
|
2258
|
+
.decision-analysis-switch-state{font-weight:400;opacity:.8}
|
|
2259
|
+
.decision-analysis-switch:focus-visible{outline:2px solid var(--decision-analysis-accent);outline-offset:2px}
|
|
2108
2260
|
.decision-analysis-section{border-top:1px solid var(--dsw-alias-border-l2,#eceff1);margin-top:1.1rem;padding-top:1rem}
|
|
2109
2261
|
.decision-analysis-section>h3{font-size:.92rem;margin:0 0 .6rem}
|
|
2110
2262
|
.decision-analysis-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));gap:.7rem}
|
|
@@ -2130,7 +2282,7 @@ var css = `
|
|
|
2130
2282
|
.decision-pager button:disabled{opacity:.45;cursor:default}
|
|
2131
2283
|
.decision-pager-status{font-size:.8rem;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}
|
|
2132
2284
|
@media (prefers-color-scheme:dark){
|
|
2133
|
-
.decision-analysis{color:var(--dsw-alias-label-primary,#e6eaee)}
|
|
2285
|
+
.decision-analysis{color:var(--dsw-alias-label-primary,#e6eaee);--decision-analysis-accent:#8fdcc6;--decision-analysis-accent-bg:rgba(95,191,165,.14);--decision-analysis-dot:#3ecf9e;--decision-analysis-ring:rgba(62,207,158,.2)}
|
|
2134
2286
|
}
|
|
2135
2287
|
`;
|
|
2136
2288
|
function installStyles() {
|
|
@@ -2172,7 +2324,5 @@ function apply(ctx) {
|
|
|
2172
2324
|
(props) => props.view === "summary" ? props.t("summary") : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ConfigForm, { t: props.t })
|
|
2173
2325
|
));
|
|
2174
2326
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
}
|
|
2178
|
-
});
|
|
2327
|
+
return module.exports;
|
|
2328
|
+
} });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BackendConfig, EvaluateInput, EvaluateResult } from './types.js';
|
|
2
|
+
export type BackendError = Error & {
|
|
3
|
+
reason: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function validateRequest(input: unknown): EvaluateInput;
|
|
6
|
+
export declare function createBackend({ config, fetcher, timeoutMs, retryDelayMs }: {
|
|
7
|
+
config: () => Promise<BackendConfig>;
|
|
8
|
+
fetcher?: typeof fetch;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
retryDelayMs?: number;
|
|
11
|
+
}): {
|
|
12
|
+
evaluate(input: EvaluateInput, { signal }?: {
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}): Promise<EvaluateResult>;
|
|
15
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { setTimeout as wait } from "node:timers/promises";
|
|
2
|
+
import { DEFAULT_MODEL } from "./config-store.js";
|
|
3
|
+
import { isObject, isProbability } from "./types.js";
|
|
4
|
+
const REQUEST_LIMIT = 256 * 1024;
|
|
5
|
+
const RESPONSE_LIMIT = 1024 * 1024;
|
|
6
|
+
const isContent = (value) => typeof value === "string" ? value.trim().length > 0 : isObject(value) || Array.isArray(value);
|
|
7
|
+
function backendError(reason, message) {
|
|
8
|
+
const error = new Error(message);
|
|
9
|
+
error.reason = reason;
|
|
10
|
+
return error;
|
|
11
|
+
}
|
|
12
|
+
function validateRequest(input) {
|
|
13
|
+
if (!isObject(input) || !isContent(input.state) || !isObject(input.questions)) throw new Error("Invalid state or questions");
|
|
14
|
+
const questions = Object.entries(input.questions);
|
|
15
|
+
if (questions.length < 1 || questions.length > 64) throw new Error("Invalid question count");
|
|
16
|
+
for (const [id, question] of questions) {
|
|
17
|
+
if (!id.trim() || id.length > 160 || !isObject(question) || !isContent(question.instructions)) throw new Error("Invalid question");
|
|
18
|
+
if (question.type === "choice") {
|
|
19
|
+
const criteria = question.criteria;
|
|
20
|
+
if (!isObject(criteria) || Object.keys(criteria).length < 2 || Object.keys(criteria).length > 255 || Object.entries(criteria).some(([key, value]) => !key.trim() || value !== null && !isContent(value))) throw new Error("Invalid choice criteria");
|
|
21
|
+
} else if (question.type === "score") {
|
|
22
|
+
const criteria = question.criteria;
|
|
23
|
+
if (!Array.isArray(criteria) || criteria.length < 2 || criteria.length > 10 || !criteria.every(isContent)) throw new Error("Invalid score criteria");
|
|
24
|
+
} else if (question.type !== "noul" || question.criteria !== void 0 && (!isObject(question.criteria) || Object.keys(question.criteria).some((key) => !["true", "false"].includes(key)))) {
|
|
25
|
+
throw new Error("Invalid question type or criteria");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
let encoded;
|
|
29
|
+
try {
|
|
30
|
+
encoded = JSON.stringify(input, (_key, value) => {
|
|
31
|
+
if (typeof value === "function" || typeof value === "symbol" || typeof value === "bigint" || typeof value === "number" && !Number.isFinite(value)) throw new Error("Invalid JSON");
|
|
32
|
+
return value;
|
|
33
|
+
});
|
|
34
|
+
} catch {
|
|
35
|
+
throw new Error("Invalid JSON payload");
|
|
36
|
+
}
|
|
37
|
+
if (Buffer.byteLength(encoded) > REQUEST_LIMIT) throw new Error("Request too large");
|
|
38
|
+
return { state: input.state, questions: input.questions };
|
|
39
|
+
}
|
|
40
|
+
function validateAnswer(value, question) {
|
|
41
|
+
if (!isObject(value) || value.type !== question.type) throw backendError("invalid-response", "Invalid response answer");
|
|
42
|
+
if (question.type === "noul") {
|
|
43
|
+
if (!isProbability(value.noul)) throw backendError("invalid-response", "Invalid response probability");
|
|
44
|
+
return { type: "noul", noul: value.noul };
|
|
45
|
+
}
|
|
46
|
+
const keys = question.type === "choice" ? Object.keys(question.criteria) : question.criteria.map((_, i) => String(i));
|
|
47
|
+
const probabilities = value.probabilities;
|
|
48
|
+
if (!isObject(probabilities) || !isProbability(value.confidence) || Object.keys(probabilities).length !== keys.length || keys.some((key) => !isProbability(probabilities[key])) || Math.abs(keys.reduce((sum, key) => sum + Number(probabilities[key]), 0) - 1) > 0.02) throw backendError("invalid-response", "Invalid response probabilities");
|
|
49
|
+
const common = {
|
|
50
|
+
confidence: value.confidence,
|
|
51
|
+
probabilities: Object.fromEntries(keys.map((key) => [key, probabilities[key]]))
|
|
52
|
+
};
|
|
53
|
+
if (question.type === "choice") {
|
|
54
|
+
if (typeof value.choice !== "string" || !keys.includes(value.choice)) throw backendError("invalid-response", "Invalid response choice");
|
|
55
|
+
return { type: "choice", ...common, choice: value.choice };
|
|
56
|
+
}
|
|
57
|
+
if (typeof value.score !== "number" || !Number.isFinite(value.score) || value.score < 0 || value.score > keys.length - 1) throw backendError("invalid-response", "Invalid response score");
|
|
58
|
+
return { type: "score", ...common, score: value.score };
|
|
59
|
+
}
|
|
60
|
+
function validateResponse(value, questions) {
|
|
61
|
+
if (!isObject(value) || !isObject(value.answers) || typeof value.model !== "string") throw backendError("invalid-response", "Invalid response");
|
|
62
|
+
const raw = value.answers;
|
|
63
|
+
const answers = /* @__PURE__ */ Object.create(null);
|
|
64
|
+
for (const [id, question] of Object.entries(questions)) answers[id] = validateAnswer(raw[id], question);
|
|
65
|
+
const usage = value.usage;
|
|
66
|
+
return { model: value.model, answers, usage: isObject(usage) ? {
|
|
67
|
+
input_tokens: Number.isSafeInteger(usage.input_tokens) ? usage.input_tokens : 0,
|
|
68
|
+
output_tokens: Number.isSafeInteger(usage.output_tokens) ? usage.output_tokens : 0
|
|
69
|
+
} : void 0 };
|
|
70
|
+
}
|
|
71
|
+
async function boundedJson(response) {
|
|
72
|
+
const reader = response.body?.getReader();
|
|
73
|
+
if (!reader) throw backendError("invalid-response", "Invalid response body");
|
|
74
|
+
const chunks = [];
|
|
75
|
+
let size = 0;
|
|
76
|
+
try {
|
|
77
|
+
while (true) {
|
|
78
|
+
const { done, value } = await reader.read();
|
|
79
|
+
if (done) break;
|
|
80
|
+
size += value.byteLength;
|
|
81
|
+
if (size > RESPONSE_LIMIT) throw backendError("invalid-response", "Invalid response size");
|
|
82
|
+
chunks.push(value);
|
|
83
|
+
}
|
|
84
|
+
} finally {
|
|
85
|
+
await reader.cancel().catch(() => {
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
90
|
+
} catch {
|
|
91
|
+
throw backendError("invalid-response", "Invalid response JSON");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function createBackend({ config, fetcher = globalThis.fetch, timeoutMs = 2e4, retryDelayMs = 200 }) {
|
|
95
|
+
if (typeof config !== "function" || typeof fetcher !== "function" || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || !Number.isSafeInteger(retryDelayMs) || retryDelayMs < 0 || retryDelayMs > 5e3) {
|
|
96
|
+
throw new Error("Invalid backend dependencies");
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
async evaluate(input, { signal } = {}) {
|
|
100
|
+
const { state, questions } = validateRequest(input);
|
|
101
|
+
const settings = await config();
|
|
102
|
+
const key = settings.apiKey?.trim();
|
|
103
|
+
if (!key || /[\r\n]/.test(key)) throw backendError("config", "API key is required");
|
|
104
|
+
let url;
|
|
105
|
+
try {
|
|
106
|
+
url = new URL(settings.url);
|
|
107
|
+
} catch {
|
|
108
|
+
throw backendError("config", "Invalid backend URL");
|
|
109
|
+
}
|
|
110
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw backendError("config", "Invalid backend URL");
|
|
111
|
+
if (url.protocol === "http:" && settings.httpApprovedUrl !== settings.url) throw backendError("config", "HTTP URL requires confirmation");
|
|
112
|
+
const model = settings.model || DEFAULT_MODEL;
|
|
113
|
+
if (typeof model !== "string" || !model.trim() || /[\r\n]/.test(model)) throw backendError("config", "Invalid model");
|
|
114
|
+
const endpoint = new URL(url.href);
|
|
115
|
+
endpoint.pathname = `${url.pathname.replace(/\/+$/, "")}/v1/systemone`;
|
|
116
|
+
if (endpoint.origin !== url.origin) throw backendError("config", "Invalid backend endpoint");
|
|
117
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
118
|
+
const combined = signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
119
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
120
|
+
let reply;
|
|
121
|
+
try {
|
|
122
|
+
reply = await fetcher(endpoint.href, {
|
|
123
|
+
method: "POST",
|
|
124
|
+
redirect: "error",
|
|
125
|
+
signal: combined,
|
|
126
|
+
headers: { authorization: `Bearer ${key}`, "content-type": "application/json" },
|
|
127
|
+
body: JSON.stringify({ state, questions, model })
|
|
128
|
+
});
|
|
129
|
+
} catch {
|
|
130
|
+
throw backendError("unreachable", "Backend request failed or timed out");
|
|
131
|
+
}
|
|
132
|
+
if (reply.ok) return validateResponse(await boundedJson(reply), questions);
|
|
133
|
+
await reply.body?.cancel().catch(() => {
|
|
134
|
+
});
|
|
135
|
+
if (![429, 529].includes(reply.status) || attempt === 2) throw backendError("http-error", `Backend HTTP ${reply.status}`);
|
|
136
|
+
try {
|
|
137
|
+
await wait(retryDelayMs * (attempt + 1), void 0, { signal: combined });
|
|
138
|
+
} catch {
|
|
139
|
+
throw backendError("unreachable", "Backend request failed or timed out");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
throw backendError("http-error", "Backend retries exhausted");
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
createBackend,
|
|
148
|
+
validateRequest
|
|
149
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ConfigView, FeatureKey, Features, ResolvedConfig } from './types.js';
|
|
2
|
+
export declare const DEFAULT_URL = "https://api.typesafe.ai";
|
|
3
|
+
export declare const DEFAULT_MODEL = "jev-latest";
|
|
4
|
+
export declare function configPath(env?: Record<string, string | undefined>): string;
|
|
5
|
+
export declare const FEATURE_KEYS: readonly FeatureKey[];
|
|
6
|
+
export declare function featureEnabled(features: Features | undefined, key: FeatureKey): boolean;
|
|
7
|
+
export declare function loadConfig(path?: string): Promise<ConfigView>;
|
|
8
|
+
export declare function resolveConfig({ path, env }?: {
|
|
9
|
+
path?: string;
|
|
10
|
+
env?: Record<string, string | undefined>;
|
|
11
|
+
}): Promise<ResolvedConfig>;
|
|
12
|
+
export declare function saveConfig(input: Record<string, unknown>, path?: string): Promise<ConfigView>;
|