dsh-opendesign-corouter 0.1.6 → 0.1.7
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.md +11 -11
- package/lib/catalog.d.ts +2 -2
- package/lib/client.js +148 -60
- package/lib/device-auth.d.ts +1 -1
- package/lib/generated/typert.host.js +10 -6
- package/lib/generated/typert.remote-client.js +10 -6
- package/lib/index.js +34 -19
- package/lib/index.js.map +2 -2
- package/lib/remote.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ dsh plugin --profile web add dsh-opendesign-corouter
|
|
|
32
32
|
也可打开 [Actions → CI](https://github.com/KouzakiUmi/dsh-opendesign-corouter/actions/workflows/ci.yml),从成功构建下载 **`dsh-opendesign-corouter-build`** artifact。登录 GitHub 后解压 ZIP,取得 `.tgz` 与 `.sha256`,再安装本地包:
|
|
33
33
|
|
|
34
34
|
```console
|
|
35
|
-
dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.
|
|
35
|
+
dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.7.tgz
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
`web` 只是示例,请替换为目标 Profile。Desktop 使用桌面安装器提供的 `dsh` 入口;独立公共 CLI 不能代管保留的 `desktop` Profile。安装后的启用与重载按目标 DSH 的管理流程进行。
|
|
@@ -48,16 +48,16 @@ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.6.tgz
|
|
|
48
48
|
|
|
49
49
|
## 功能预览
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### 模型分组与默认参数
|
|
52
52
|
|
|
53
53
|
| Provider | 模型数 | 用途 |
|
|
54
54
|
| --- | ---: | --- |
|
|
55
55
|
| `opendesign-corouter-plan` | 13 | Core / Design Plan 附赠通道,含预检确认覆盖的 MiniMax M3.1 Flash |
|
|
56
56
|
| `opendesign-corouter-paid` | 25 | Plan 套餐模型及其他钱包付费模型 |
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
上表为内置目录。模型页可通过当前配置网关的 OpenAI 兼容 `/models` 接口刷新目录,逐个启用或停用模型,并配置温度、top-p、默认输出上限、上下文预算及思考深度。停用同时影响模型选择器和直接调用;参数会保存并应用到实际请求。媒体生成接口不在对话目录中,未知能力不按名称猜测。
|
|
59
59
|
|
|
60
|
-
推理协议可选 **OpenAI Chat Completions、OpenAI Responses、Anthropic Messages
|
|
60
|
+
推理协议可选 **OpenAI Chat Completions、OpenAI Responses、Anthropic Messages**。模型发现始终使用当前网关的 OpenAI 兼容 `/models` 接口,不随推理协议切换。
|
|
61
61
|
|
|
62
62
|
> **分组不等于计费隔离。** 赠送额度耗尽后是否转扣套餐余额或钱包,由服务端和账号权益决定。选择“套餐赠送”不能保证绝不消耗钱包余额。
|
|
63
63
|
|
|
@@ -72,7 +72,7 @@ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.6.tgz
|
|
|
72
72
|
|
|
73
73
|
### 桌面优先,也能独立登录
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
点击“开始设备授权”后,插件在临时 Chrome 窗口打开官方授权页。也可用“复制授权链接”在常用浏览器完成确认;复制不可用时会显示可选取的链接。确认后自动保存授权,取消或到期时结束等待并关闭临时窗口。
|
|
76
76
|
|
|
77
77
|
<picture>
|
|
78
78
|
<source media="(prefers-color-scheme: dark)" srcset="docs/previews/theme-dark.png">
|
|
@@ -83,13 +83,13 @@ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.6.tgz
|
|
|
83
83
|
|
|
84
84
|
独立开关,默认开启。参考 [dsh-empty-turn-guard](https://github.com/FYTXY/dsh-empty-turn-guard),将“正常 stop、没有工具调用、答案为空或只剩协议残渣”的工具对话标成 `EMPTY_RESPONSE`。
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
检测到空回答后,由 DSH 的重试策略决定是否重试,**重复请求可能额外消耗额度**。该监控仅用于套餐赠送模型的工具对话。
|
|
87
87
|
|
|
88
88
|
## 使用前先知道
|
|
89
89
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
90
|
+
- **额度数据**:来自官方服务及桌面端,部分接口可能随上游变化;实际扣款以控制台和账单为准。
|
|
91
|
+
- **凭据存储**:API Key 和设备授权由 DSH 凭据服务保存,落盘保护取决于宿主与本机权限,详见[安全说明](SECURITY.md)。
|
|
92
|
+
- **验证状态**:已完成真实设备授权、模型目录读取和逐模型计费预检,以及类型、隔离加载、离线界面与主题检查。真实推理和已安装 Profile 的完整联调仍待验证。
|
|
93
93
|
|
|
94
94
|
## 兼容性
|
|
95
95
|
|
|
@@ -98,10 +98,10 @@ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.6.tgz
|
|
|
98
98
|
| 目标 DSH Core | `0.2.1-rc.3`,以官方同版本发布包验证 |
|
|
99
99
|
| Core 声明范围 | `>=0.2.1-rc.3 <0.3.0-0`,范围内其他版本不代表已实测 |
|
|
100
100
|
| Node.js | `>=24.9.0` |
|
|
101
|
-
| 独立登录 |
|
|
101
|
+
| 独立登录 | 自动打开需本机 Chrome;也可复制链接到常用浏览器确认 |
|
|
102
102
|
| 默认推理接口 | `https://amr-link.open-design.ai/v1/chat/completions` |
|
|
103
103
|
|
|
104
|
-
CI 在 Windows 与 Ubuntu 执行构建、类型检查及隔离测试;Ubuntu
|
|
104
|
+
CI 在 Windows 与 Ubuntu 执行构建、类型检查及隔离测试;Ubuntu 另执行四页签浏览器和亮暗主题检查。[开发与验证范围](docs/development.md)
|
|
105
105
|
|
|
106
106
|
## 开发与构建
|
|
107
107
|
|
package/lib/catalog.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `data-model-module="design-plan"` 12 款归 `plan`;其余在售对话模型归 `paid`。
|
|
9
9
|
* - `plan` 12 款的 contextWindow / maxOutputTokens / inputModalities / reasoningEfforts
|
|
10
10
|
* 来自 Go 侧 `dsh-opendesign-go` 0.1.9 的 MODEL_DEFAULTS(同一 `amr-link` endpoint 部署资料),
|
|
11
|
-
*
|
|
11
|
+
* 作为部署参考,尚无官网能力数值的独立佐证;只用于对应的原有 12 款模型。
|
|
12
12
|
* - 客户端桌面安装(Open Design 0.26.1)不内联 CoRouter 目录;其
|
|
13
13
|
* `vela model preset --format json` 只有 11 个旧预设 id(见 docs/client-evidence.md),
|
|
14
14
|
* 与本表不同代,故不用于本目录。
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* 走 `/api/v1/media/*`,不应出现在对话模型列表里,避免选中后 chat 请求必败。
|
|
28
28
|
*
|
|
29
29
|
* `paid` 25 款及新增 M3.1 Flash 的能力字段一律缺省:没有可核实的能力数值,
|
|
30
|
-
*
|
|
30
|
+
* 未知模态保持缺省;`['text']` 仅表示已确认的纯文本输入。
|
|
31
31
|
*/
|
|
32
32
|
export interface CatalogModel {
|
|
33
33
|
id: string;
|
package/lib/client.js
CHANGED
|
@@ -20054,9 +20054,9 @@ function amount(value, label, negative = false) {
|
|
|
20054
20054
|
if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
|
|
20055
20055
|
return value;
|
|
20056
20056
|
}
|
|
20057
|
-
function positiveInteger(value, label, max) {
|
|
20057
|
+
function positiveInteger(value, label, max, min = 1) {
|
|
20058
20058
|
const result = count(value, label);
|
|
20059
|
-
if (result
|
|
20059
|
+
if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
|
|
20060
20060
|
return result;
|
|
20061
20061
|
}
|
|
20062
20062
|
function parseEfforts(value) {
|
|
@@ -20159,9 +20159,9 @@ function parseStatusConfig(value) {
|
|
|
20159
20159
|
apiKeyEnv,
|
|
20160
20160
|
...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
|
|
20161
20161
|
...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
|
|
20162
|
-
...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
|
|
20163
|
-
...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
|
|
20164
|
-
...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
|
|
20162
|
+
...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
|
|
20163
|
+
...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
|
|
20164
|
+
...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
|
|
20165
20165
|
};
|
|
20166
20166
|
}
|
|
20167
20167
|
function parseStatus(value) {
|
|
@@ -20174,9 +20174,13 @@ function parseStatus(value) {
|
|
|
20174
20174
|
if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
|
|
20175
20175
|
ids.add(model.id);
|
|
20176
20176
|
}
|
|
20177
|
+
const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
|
|
20178
|
+
const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
|
|
20179
|
+
if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
|
|
20177
20180
|
return {
|
|
20178
20181
|
revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
|
|
20179
|
-
apiKeyConfigured
|
|
20182
|
+
apiKeyConfigured,
|
|
20183
|
+
...apiKeySource === void 0 ? {} : { apiKeySource },
|
|
20180
20184
|
...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
|
|
20181
20185
|
quota: parseQuotaSnapshot(value.quota),
|
|
20182
20186
|
login: parseLoginState(value.login),
|
|
@@ -20264,7 +20268,7 @@ var LOGIN_LABELS = {
|
|
|
20264
20268
|
};
|
|
20265
20269
|
var QUOTA_LABELS = {
|
|
20266
20270
|
ok: "\u989D\u5EA6\u4FE1\u606F\u5DF2\u66F4\u65B0",
|
|
20267
|
-
partial: "\
|
|
20271
|
+
partial: "\u989D\u5EA6\u6570\u636E\u6682\u672A\u5B8C\u6574",
|
|
20268
20272
|
"need-login": "\u9700\u8981\u767B\u5F55\u540E\u8BFB\u53D6\u989D\u5EA6",
|
|
20269
20273
|
error: "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u989D\u5EA6"
|
|
20270
20274
|
};
|
|
@@ -20278,7 +20282,9 @@ function installStyles() {
|
|
|
20278
20282
|
.odc-tab{flex:none;border:1px solid transparent;border-radius:8px;padding:7px 13px;background:transparent;color:var(--dsw-alias-label-secondary,inherit);font:inherit;cursor:pointer}.odc-tab:hover{background:var(--dsw-alias-bg-layer-1,transparent)}.odc-tab[aria-selected=true]{color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l3,transparent);background:var(--dsw-alias-bg-layer-1,transparent)}
|
|
20279
20283
|
.odc-panel{display:grid;gap:14px}.odc-card{min-width:0;padding:15px;border:1px solid var(--dsw-alias-border-l4,transparent);border-radius:12px;background:var(--dsw-alias-bg-layer-1,transparent)}.odc-card>p{margin-top:6px}.odc-card-head,.odc-row{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.odc-card-head{margin-bottom:12px}
|
|
20280
20284
|
.odc-quota-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.odc-metric{display:grid;align-content:start;gap:5px;min-height:96px}.odc-metric-value{font-size:20px;font-weight:650;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.odc-metric-value.odc-metric-text{font-size:13px;font-weight:600;line-height:1.55}.odc-quota-grid+.odc-quota-grid{margin-top:10px}
|
|
20281
|
-
.odc-label,.odc-hint,.odc-meta{color:var(--dsw-alias-label-secondary,inherit);font-size:11px;line-height:1.6}.odc-meta{margin-top:10px!important}
|
|
20285
|
+
.odc-label,.odc-hint,.odc-meta{color:var(--dsw-alias-label-secondary,inherit);font-size:11px;line-height:1.6}.odc-meta{margin-top:10px!important}
|
|
20286
|
+
.odc-window{display:grid;gap:10px;margin-top:12px;padding:14px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,transparent);min-width:0}.odc-window-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.odc-window h4{margin:0;font-size:13px;font-weight:600}.odc-window-remaining{display:flex;align-items:baseline;gap:6px;font-variant-numeric:tabular-nums;white-space:nowrap}.odc-window-remaining strong{font-size:22px;line-height:1.2}.odc-window progress{display:block;width:100%;height:8px;accent-color:var(--dsw-alias-brand-primary,Highlight)}
|
|
20287
|
+
.odc-window-usage{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:0}.odc-window-usage>div{display:grid;gap:3px;min-width:0}.odc-window dt,.odc-quota-footer dt{color:var(--dsw-alias-label-secondary,inherit);font-size:11px}.odc-window dd,.odc-quota-footer dd{margin:0;min-width:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.odc-window-reset{display:grid;gap:3px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l4,transparent)}.odc-window-reset time{font-size:12px}.odc-window-details>summary{cursor:pointer;font-size:11px;color:var(--dsw-alias-label-secondary,inherit);min-height:32px;padding:6px 0}.odc-window-details dl{display:grid;gap:8px;margin:6px 0 0}.odc-window-details dl>div{display:grid;gap:3px}.odc-quota-footer{display:grid;gap:8px;margin:0;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l4,transparent)}.odc-quota-footer>div{display:grid;grid-template-columns:72px minmax(0,1fr);gap:10px}.odc-quota-footer dd{font-size:11px;color:var(--dsw-alias-label-secondary,inherit)}
|
|
20282
20288
|
.odc-button{display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:6px 12px;border:1px solid var(--dsw-alias-border-l3,transparent);border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-primary,inherit);font:inherit;font-size:12px;cursor:pointer}.odc-button:hover:not(:disabled){border-color:var(--dsw-alias-brand-primary,Highlight)}.odc-button-primary{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary,Highlight));color:var(--dsw-alias-label-primary-foreground,HighlightText);border-color:transparent}.odc-button-primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-brand-primary,Highlight))}.odc-button:disabled{opacity:.55;cursor:not-allowed}.odc-button-small{min-height:26px;padding:3px 9px;font-size:11px}.odc-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
20283
20289
|
.odc-notice{padding:9px 11px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);font-size:12px;line-height:1.6}.odc-notice[data-kind=error]{color:var(--dsw-alias-state-error-primary,inherit);color:color-mix(in srgb,var(--dsw-alias-state-error-primary,CanvasText) 85%,var(--dsw-alias-label-primary,CanvasText))}
|
|
20284
20290
|
.odc-model-groups{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:12px}.odc-model-list{display:grid;gap:6px;margin:10px 0 0;padding:0;list-style:none}.odc-model-item{padding:9px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);min-width:0}.odc-model-head{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;flex-wrap:wrap}.odc-model-switch{min-width:0;flex:1 1 190px}.odc-model-item strong,.odc-model-item code{display:block;overflow-wrap:anywhere}.odc-model-item strong{font-size:12px;font-weight:600}.odc-model-item code{margin-top:2px;color:var(--dsw-alias-label-secondary,inherit);font-size:11px}.odc-model-meta{margin-top:6px!important;color:var(--dsw-alias-label-secondary,inherit);font-size:11px;overflow-wrap:anywhere}.odc-model-count{color:var(--dsw-alias-label-secondary,inherit);font-size:11px;font-weight:400}.odc-chip{display:inline-flex;align-items:center;padding:1px 7px;border:1px solid var(--dsw-alias-border-l3,transparent);border-radius:999px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;line-height:1.6}
|
|
@@ -20471,19 +20477,49 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
|
|
|
20471
20477
|
React.Fragment,
|
|
20472
20478
|
null,
|
|
20473
20479
|
h("p", { className: "odc-metric-value" }, "\u2014"),
|
|
20474
|
-
h("p", { className: "odc-hint" }, "\
|
|
20475
|
-
) : quota.windows.map((window, index) =>
|
|
20476
|
-
|
|
20477
|
-
|
|
20478
|
-
h(
|
|
20479
|
-
"
|
|
20480
|
-
{ className: "odc-
|
|
20481
|
-
h(
|
|
20482
|
-
|
|
20483
|
-
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20480
|
+
h("p", { className: "odc-hint" }, "\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\u989D\u5EA6\u7A97\u53E3\u3002")
|
|
20481
|
+
) : quota.windows.map((window, index) => {
|
|
20482
|
+
const label = windowLabel(window.durationSeconds);
|
|
20483
|
+
const remainingPercent = Math.max(0, Math.min(100, 100 - window.percent));
|
|
20484
|
+
return h(
|
|
20485
|
+
"section",
|
|
20486
|
+
{ className: "odc-window", key: `${window.durationSeconds}-${index}`, "aria-label": label },
|
|
20487
|
+
h(
|
|
20488
|
+
"div",
|
|
20489
|
+
{ className: "odc-window-head" },
|
|
20490
|
+
h("h4", null, label),
|
|
20491
|
+
h(
|
|
20492
|
+
"div",
|
|
20493
|
+
{ className: "odc-window-remaining" },
|
|
20494
|
+
h("strong", null, `${remainingPercent.toFixed(1)}%`),
|
|
20495
|
+
h("span", { className: "odc-label" }, "\u5269\u4F59")
|
|
20496
|
+
)
|
|
20497
|
+
),
|
|
20498
|
+
h("progress", { max: 100, value: remainingPercent, "aria-label": `${label}\u5269\u4F59\u989D\u5EA6` }),
|
|
20499
|
+
h(
|
|
20500
|
+
"dl",
|
|
20501
|
+
{ className: "odc-window-usage", "aria-label": "\u7A97\u53E3\u7528\u91CF\u660E\u7EC6" },
|
|
20502
|
+
[{ label: "\u5DF2\u7528", value: window.used }, { label: "\u4E0A\u9650", value: window.limit }, { label: "\u5269\u4F59", value: window.remaining ?? "\u2014" }].map((item) => h("div", { key: item.label }, h("dt", null, item.label), h("dd", null, item.value)))
|
|
20503
|
+
),
|
|
20504
|
+
h(
|
|
20505
|
+
"div",
|
|
20506
|
+
{ className: "odc-window-reset" },
|
|
20507
|
+
h("span", { className: "odc-label" }, "\u4E0B\u6B21\u6062\u590D"),
|
|
20508
|
+
window.resetsAt === void 0 ? h("span", null, "\u2014") : h("time", { dateTime: window.resetsAt }, formatTime(window.resetsAt))
|
|
20509
|
+
),
|
|
20510
|
+
window.windowStart === void 0 && window.resetMode === void 0 ? null : h(
|
|
20511
|
+
"details",
|
|
20512
|
+
{ className: "odc-window-details" },
|
|
20513
|
+
h("summary", null, "\u7A97\u53E3\u8BE6\u60C5"),
|
|
20514
|
+
h(
|
|
20515
|
+
"dl",
|
|
20516
|
+
null,
|
|
20517
|
+
window.windowStart === void 0 ? null : h("div", null, h("dt", null, "\u7A97\u53E3\u5F00\u59CB"), h("dd", null, h("time", { dateTime: window.windowStart }, formatTime(window.windowStart)))),
|
|
20518
|
+
window.resetMode === void 0 ? null : h("div", null, h("dt", null, "\u91CD\u7F6E\u65B9\u5F0F"), h("dd", null, RESET_MODE_LABELS[window.resetMode] ?? window.resetMode))
|
|
20519
|
+
)
|
|
20520
|
+
)
|
|
20521
|
+
);
|
|
20522
|
+
})
|
|
20487
20523
|
),
|
|
20488
20524
|
h("div", { className: "odc-quota-grid" }, metrics.map((metric) => h(
|
|
20489
20525
|
"div",
|
|
@@ -20499,12 +20535,17 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
|
|
|
20499
20535
|
h("strong", { className: "odc-metric-value odc-metric-text" }, metric.value),
|
|
20500
20536
|
h("span", { className: "odc-hint" }, metric.hint)
|
|
20501
20537
|
))),
|
|
20502
|
-
h(
|
|
20538
|
+
h(
|
|
20539
|
+
"dl",
|
|
20540
|
+
{ className: "odc-quota-footer", "aria-label": "\u989D\u5EA6\u6570\u636E\u6765\u6E90\u4E0E\u66F4\u65B0\u65F6\u95F4" },
|
|
20541
|
+
h("div", null, h("dt", null, "\u6700\u8FD1\u66F4\u65B0"), h("dd", null, h("time", { dateTime: quota.updatedAt }, formatTime(quota.updatedAt)))),
|
|
20542
|
+
quota.source === void 0 ? null : h("div", null, h("dt", null, "\u6570\u636E\u6765\u6E90"), h("dd", null, SOURCE_LABELS[quota.source]))
|
|
20543
|
+
),
|
|
20503
20544
|
h(
|
|
20504
20545
|
"details",
|
|
20505
20546
|
{ className: "odc-model-details" },
|
|
20506
20547
|
h("summary", null, "\u5982\u4F55\u7406\u89E3\u8FD9\u4E9B\u989D\u5EA6\uFF1F"),
|
|
20507
|
-
h("p", { className: "odc-hint" }, "\u8D60\u9001\u7A97\u53E3\
|
|
20548
|
+
h("p", { className: "odc-hint" }, "\u8D60\u9001\u7A97\u53E3\u663E\u793A\u5468\u671F\u5185\u7684\u4F7F\u7528\u91CF\u3002\u5957\u9910\u4F59\u989D\u548C\u5145\u503C / \u8D60\u9001\u91D1\u989D\u662F\u94B1\u5305\u7684\u4E0D\u540C\u5206\u6C60\uFF0C\u603B\u989D\u5EA6\u662F\u94B1\u5305\u5408\u8BA1\u3002\u2014 \u8868\u793A\u6682\u65E0\u6570\u636E\u3002")
|
|
20508
20549
|
),
|
|
20509
20550
|
quota.note !== void 0 ? h("p", { className: "odc-notice", "data-kind": quota.state === "error" ? "error" : "status", role: quota.state === "error" ? "alert" : "status" }, quota.note) : null
|
|
20510
20551
|
);
|
|
@@ -20585,7 +20626,7 @@ function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalS
|
|
|
20585
20626
|
h(
|
|
20586
20627
|
"div",
|
|
20587
20628
|
{ className: "odc-card-head" },
|
|
20588
|
-
h("div", null, h("h3", null, "\u989D\u5EA6\u6982\u89C8"), h("p", { className: "odc-hint" }, "\u5957\u9910\
|
|
20629
|
+
h("div", null, h("h3", null, "\u989D\u5EA6\u6982\u89C8"), h("p", { className: "odc-hint" }, "\u67E5\u770B\u5957\u9910\u7528\u91CF\u3001\u8BA2\u9605\u4F59\u989D\u548C\u5145\u503C\u4F59\u989D\u3002")),
|
|
20589
20630
|
h("button", { className: "odc-button", type: "button", disabled: busy, onClick: onRefresh }, busy ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0\u989D\u5EA6")
|
|
20590
20631
|
),
|
|
20591
20632
|
h(QuotaView, { quota: status?.quota, nextAutoRefreshAt, refreshIntervalSeconds })
|
|
@@ -20859,7 +20900,7 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
|
|
|
20859
20900
|
saving.current = false;
|
|
20860
20901
|
}
|
|
20861
20902
|
};
|
|
20862
|
-
const source = status?.modelsSource === "openai" ? "
|
|
20903
|
+
const source = status?.modelsSource === "openai" ? "\u5F53\u524D\u7F51\u5173" : status?.modelsSource === "builtin" ? "\u5185\u7F6E\u76EE\u5F55" : "\u5C1A\u672A\u786E\u8BA4";
|
|
20863
20904
|
const updated = status?.modelsUpdatedAt === void 0 ? "" : ` \xB7 \u66F4\u65B0\u4E8E ${formatTime(status.modelsUpdatedAt)}`;
|
|
20864
20905
|
const models = status?.models ?? [];
|
|
20865
20906
|
return h(
|
|
@@ -20872,7 +20913,7 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
|
|
|
20872
20913
|
"div",
|
|
20873
20914
|
null,
|
|
20874
20915
|
h("h3", null, "\u53EF\u7528\u6A21\u578B"),
|
|
20875
|
-
h("p", { className: "odc-hint" }, "\
|
|
20916
|
+
h("p", { className: "odc-hint" }, "\u6309\u5206\u7EC4\u641C\u7D22\u6A21\u578B\uFF0C\u8BBE\u7F6E\u542F\u7528\u72B6\u6001\u4E0E\u9ED8\u8BA4\u53C2\u6570\u3002")
|
|
20876
20917
|
),
|
|
20877
20918
|
h(
|
|
20878
20919
|
"div",
|
|
@@ -20882,8 +20923,9 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
|
|
|
20882
20923
|
className: "odc-button",
|
|
20883
20924
|
type: "button",
|
|
20884
20925
|
disabled: refreshingModels || status === void 0 || status.apiKeyConfigured === false,
|
|
20885
|
-
onClick: onRefreshModels
|
|
20886
|
-
|
|
20926
|
+
onClick: onRefreshModels,
|
|
20927
|
+
title: "\u4ECE\u5F53\u524D\u914D\u7F6E\u7684\u7F51\u5173\u8BFB\u53D6\u53EF\u7528\u6A21\u578B\u76EE\u5F55"
|
|
20928
|
+
}, refreshingModels ? "\u6B63\u5728\u5237\u65B0\u6A21\u578B\u2026" : "\u5237\u65B0\u6A21\u578B\u76EE\u5F55")
|
|
20887
20929
|
)
|
|
20888
20930
|
),
|
|
20889
20931
|
status?.apiKeyConfigured === false ? h("p", { className: "odc-hint" }, "\u5237\u65B0\u6A21\u578B\u9700\u8981\u53EF\u7528\u7684 API Key\uFF1B\u4FDD\u5B58 Key \u540E\u91CD\u8BD5\u3002") : null,
|
|
@@ -20892,8 +20934,8 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
|
|
|
20892
20934
|
models.length === 0 ? h("p", { className: "odc-hint", role: "status" }, "\u6682\u65E0\u53EF\u7528\u6A21\u578B\uFF1B\u53EF\u5237\u65B0\u6A21\u578B\u5217\u8868\u540E\u91CD\u8BD5\u3002") : h(
|
|
20893
20935
|
"div",
|
|
20894
20936
|
{ className: "odc-model-groups" },
|
|
20895
|
-
h(ModelGroup, { title: "\u5957\u9910\u8D60\u9001
|
|
20896
|
-
h(ModelGroup, { title: "\u4ED8\u8D39
|
|
20937
|
+
h(ModelGroup, { title: "\u5957\u9910\u8D60\u9001\u6A21\u578B", group: "plan", models, settingsMap, authoritative, writable, pending, onCommit: commit }),
|
|
20938
|
+
h(ModelGroup, { title: "\u4ED8\u8D39\u6A21\u578B", group: "paid", models, settingsMap, authoritative, writable, pending, onCommit: commit })
|
|
20897
20939
|
)
|
|
20898
20940
|
);
|
|
20899
20941
|
}
|
|
@@ -20985,12 +21027,12 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
|
|
|
20985
21027
|
"section",
|
|
20986
21028
|
{ className: "odc-card" },
|
|
20987
21029
|
h("h3", null, "\u7A7A\u8F6E\u76D1\u63A7"),
|
|
20988
|
-
h("p", { className: "odc-hint" }, "\
|
|
21030
|
+
h("p", { className: "odc-hint" }, "\u68C0\u6D4B\u5957\u9910\u8D60\u9001\u6A21\u578B\u5728\u5DE5\u5177\u5BF9\u8BDD\u4E2D\u8FD4\u56DE\u7684\u7A7A\u56DE\u7B54\u3002"),
|
|
20989
21031
|
h("div", { style: { marginTop: 14 } }, h(Switch, {
|
|
20990
21032
|
checked: formSnapshot.value?.emptyTurnGuard ?? status?.config.emptyTurnGuard ?? true,
|
|
20991
21033
|
disabled: !writable || pendingField.includes("emptyTurnGuard"),
|
|
20992
21034
|
label: "\u542F\u7528\u7A7A\u8F6E\u76D1\u63A7",
|
|
20993
|
-
hint: `\
|
|
21035
|
+
hint: `\u5DF2\u68C0\u6D4B\u5230 ${status?.guardedTurns ?? "\u2014"} \u6B21\u7A7A\u56DE\u7B54\u3002\u81EA\u52A8\u91CD\u8BD5\u7531 DSH \u7684\u91CD\u8BD5\u8BBE\u7F6E\u63A7\u5236\uFF0C\u91CD\u8BD5\u53EF\u80FD\u989D\u5916\u6D88\u8017\u989D\u5EA6\u3002`,
|
|
20994
21036
|
onChange: (checked) => {
|
|
20995
21037
|
void setFormField("emptyTurnGuard", checked);
|
|
20996
21038
|
}
|
|
@@ -21000,7 +21042,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
|
|
|
21000
21042
|
"section",
|
|
21001
21043
|
{ className: "odc-card" },
|
|
21002
21044
|
h("h3", null, "\u63A8\u7406\u534F\u8BAE"),
|
|
21003
|
-
h("p", { className: "odc-hint" }, "\
|
|
21045
|
+
h("p", { className: "odc-hint" }, "\u9009\u62E9\u5F53\u524D\u7F51\u5173\u652F\u6301\u7684\u63A8\u7406\u534F\u8BAE\u3002\u6A21\u578B\u76EE\u5F55\u59CB\u7EC8\u4ECE\u8BE5\u7F51\u5173\u8BFB\u53D6\u3002"),
|
|
21004
21046
|
h(
|
|
21005
21047
|
"div",
|
|
21006
21048
|
{ className: "odc-field" },
|
|
@@ -21048,7 +21090,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
|
|
|
21048
21090
|
className: "odc-input",
|
|
21049
21091
|
type: "text",
|
|
21050
21092
|
value: apiKeyEnv,
|
|
21051
|
-
disabled: !writable,
|
|
21093
|
+
disabled: !writable || pendingField.includes("apiKeyEnv"),
|
|
21052
21094
|
autoCapitalize: "off",
|
|
21053
21095
|
spellCheck: false,
|
|
21054
21096
|
onChange: (event) => setApiKeyEnv(event.target.value)
|
|
@@ -21068,7 +21110,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
|
|
|
21068
21110
|
"section",
|
|
21069
21111
|
{ className: "odc-card" },
|
|
21070
21112
|
h("h3", null, "\u8BF7\u6C42\u65F6\u9650\u4E0E\u81EA\u52A8\u5237\u65B0"),
|
|
21071
|
-
h("p", { className: "odc-hint" }, "\
|
|
21113
|
+
h("p", { className: "odc-hint" }, "\u8F93\u5165\u6709\u6548\u8303\u56F4\u5185\u7684\u6574\u6570\uFF0C\u79BB\u5F00\u8F93\u5165\u6846\u540E\u4FDD\u5B58\u3002"),
|
|
21072
21114
|
h(NumberField, {
|
|
21073
21115
|
id: "odc-request-timeout",
|
|
21074
21116
|
label: "\u8BF7\u6C42\u603B\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",
|
|
@@ -21119,14 +21161,32 @@ function loginInFlight(state) {
|
|
|
21119
21161
|
var ACTIVATION_OPEN_LABELS = {
|
|
21120
21162
|
opened: "\u5DF2\u5728\u65B0\u7A97\u53E3\u6253\u5F00\u5B98\u65B9\u6388\u6743\u9875\uFF1B\u8BF7\u5728\u8BE5\u7A97\u53E3\u786E\u8BA4\u8BBE\u5907\u7801\u3002",
|
|
21121
21163
|
"no-link": "\u6388\u6743\u7801\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u7533\u8BF7\u3002",
|
|
21122
|
-
"invalid-url": "\u6388\u6743\u94FE\u63A5\
|
|
21164
|
+
"invalid-url": "\u6388\u6743\u94FE\u63A5\u65E0\u6548\uFF0C\u8BF7\u53D6\u6D88\u5E76\u91CD\u65B0\u5F00\u59CB\u767B\u5F55\u3002",
|
|
21123
21165
|
unavailable: "\u65E0\u6CD5\u542F\u52A8\u4E34\u65F6\u6D4F\u89C8\u5668\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u5B89\u88C5 Chrome\uFF1B\u4E5F\u53EF\u590D\u5236\u94FE\u63A5\u624B\u52A8\u6253\u5F00\u3002",
|
|
21124
21166
|
failed: "\u4E34\u65F6\u6D4F\u89C8\u5668\u7A97\u53E3\u672A\u80FD\u6253\u5F00\uFF0C\u8BF7\u590D\u5236\u94FE\u63A5\u624B\u52A8\u6253\u5F00\u3002"
|
|
21125
21167
|
};
|
|
21126
21168
|
function LoginApproval({ login, onOpen, opening, notice }) {
|
|
21169
|
+
const mounted = useMounted();
|
|
21170
|
+
const copyVersion = React.useRef(0);
|
|
21171
|
+
const [copyState, setCopyState] = React.useState("idle");
|
|
21172
|
+
React.useEffect(() => {
|
|
21173
|
+
copyVersion.current += 1;
|
|
21174
|
+
setCopyState("idle");
|
|
21175
|
+
}, [login?.jobId, login?.state, login?.activationUrl]);
|
|
21127
21176
|
if (login?.state !== "waiting" || login.userCode === void 0 || login.expiresAt === void 0) return null;
|
|
21128
21177
|
const url2 = validateActivationUrl(login.activationUrl, login.userCode);
|
|
21129
21178
|
if (url2 === null) return null;
|
|
21179
|
+
const copyLink = async () => {
|
|
21180
|
+
const version2 = ++copyVersion.current;
|
|
21181
|
+
setCopyState("copying");
|
|
21182
|
+
try {
|
|
21183
|
+
if (typeof navigator.clipboard?.writeText !== "function") throw new Error("clipboard-unavailable");
|
|
21184
|
+
await navigator.clipboard.writeText(url2);
|
|
21185
|
+
if (mounted.current && version2 === copyVersion.current) setCopyState("copied");
|
|
21186
|
+
} catch {
|
|
21187
|
+
if (mounted.current && version2 === copyVersion.current) setCopyState("manual");
|
|
21188
|
+
}
|
|
21189
|
+
};
|
|
21130
21190
|
return h(
|
|
21131
21191
|
"div",
|
|
21132
21192
|
{ className: "odc-readonly", "aria-label": "\u8BBE\u5907\u6388\u6743" },
|
|
@@ -21143,14 +21203,24 @@ function LoginApproval({ login, onOpen, opening, notice }) {
|
|
|
21143
21203
|
onOpen?.();
|
|
21144
21204
|
}
|
|
21145
21205
|
}, opening === true ? "\u6B63\u5728\u6253\u5F00\u2026" : "\u5728\u65B0\u7A97\u53E3\u6253\u5F00\u6388\u6743\u9875"),
|
|
21146
|
-
h("
|
|
21206
|
+
h("button", { className: "odc-button", type: "button", disabled: copyState === "copying", onClick: () => {
|
|
21207
|
+
void copyLink();
|
|
21208
|
+
} }, copyState === "copying" ? "\u6B63\u5728\u590D\u5236\u2026" : "\u590D\u5236\u6388\u6743\u94FE\u63A5"),
|
|
21209
|
+
h("a", { className: "odc-link", href: url2, target: "_blank", rel: "noreferrer noopener" }, "\u5B98\u65B9\u6388\u6743\u9875")
|
|
21147
21210
|
),
|
|
21211
|
+
copyState === "copied" ? h("p", { className: "odc-hint", role: "status" }, "\u94FE\u63A5\u5DF2\u590D\u5236\uFF0C\u53EF\u5728\u5E38\u7528\u6D4F\u89C8\u5668\u4E2D\u7C98\u8D34\u6253\u5F00\u3002") : null,
|
|
21212
|
+
copyState === "manual" ? h(
|
|
21213
|
+
"label",
|
|
21214
|
+
{ className: "odc-field" },
|
|
21215
|
+
h("span", null, "\u8BF7\u9009\u62E9\u5E76\u590D\u5236\u6388\u6743\u94FE\u63A5"),
|
|
21216
|
+
h("input", { className: "odc-input", type: "text", readOnly: true, value: url2, onFocus: (event) => event.target.select() })
|
|
21217
|
+
) : null,
|
|
21148
21218
|
notice ? h(NoticeView, { notice }) : null,
|
|
21149
21219
|
h("p", { className: "odc-hint" }, `\u6388\u6743\u7801\u6709\u6548\u81F3 ${formatTime(login.expiresAt)}\u3002\u5728\u6388\u6743\u7A97\u53E3\u786E\u8BA4\u540E\uFF0C\u8FD4\u56DE\u6B64\u9875\u67E5\u770B\u7ED3\u679C\u3002`),
|
|
21150
|
-
h("p", { className: "odc-hint" }, "\
|
|
21220
|
+
h("p", { className: "odc-hint" }, "\u4E34\u65F6 Chrome \u7A97\u53E3\u9700\u8981\u5355\u72EC\u767B\u5F55\uFF1B\u4E5F\u53EF\u590D\u5236\u94FE\u63A5\u5230\u5DF2\u767B\u5F55\u7684\u5E38\u7528\u6D4F\u89C8\u5668\u3002\u4EC5\u786E\u8BA4\u4F60\u672C\u4EBA\u53D1\u8D77\u7684\u6388\u6743\u3002")
|
|
21151
21221
|
);
|
|
21152
21222
|
}
|
|
21153
|
-
function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
21223
|
+
function Connection({ status, formSnapshot, setFormField, pendingField, caller, onLoginStatus, onStatus }) {
|
|
21154
21224
|
const mounted = useMounted();
|
|
21155
21225
|
const actionVersion = React.useRef(0);
|
|
21156
21226
|
const [busy, setBusy] = React.useState(false);
|
|
@@ -21185,12 +21255,12 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
|
21185
21255
|
try {
|
|
21186
21256
|
const next = await caller("startLogin", { expectedRevision: status.revision });
|
|
21187
21257
|
if (!mounted.current || version2 !== actionVersion.current) return;
|
|
21258
|
+
onLoginStatus(next);
|
|
21188
21259
|
setNotice(null);
|
|
21189
21260
|
setActivationNotice(null);
|
|
21190
|
-
await (next.state === "success" ? refreshAfterLogin() : loadStatus());
|
|
21191
21261
|
} catch {
|
|
21192
21262
|
autoOpenPending.current = false;
|
|
21193
|
-
if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\
|
|
21263
|
+
if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u767B\u5F55\u8BF7\u6C42\u6682\u672A\u786E\u8BA4\uFF0C\u8BF7\u91CD\u8BD5\u3002" });
|
|
21194
21264
|
} finally {
|
|
21195
21265
|
if (mounted.current && version2 === actionVersion.current) setBusy(false);
|
|
21196
21266
|
}
|
|
@@ -21200,10 +21270,11 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
|
21200
21270
|
const version2 = ++actionVersion.current;
|
|
21201
21271
|
setBusy(true);
|
|
21202
21272
|
try {
|
|
21203
|
-
await caller("cancelLogin", { jobId: login.jobId });
|
|
21273
|
+
const next = await caller("cancelLogin", { jobId: login.jobId });
|
|
21204
21274
|
if (!mounted.current || version2 !== actionVersion.current) return;
|
|
21205
|
-
|
|
21206
|
-
|
|
21275
|
+
autoOpenPending.current = false;
|
|
21276
|
+
onLoginStatus(next);
|
|
21277
|
+
setNotice({ kind: "status", text: next.message ?? LOGIN_LABELS[next.state] });
|
|
21207
21278
|
} catch {
|
|
21208
21279
|
if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u53D6\u6D88\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
|
|
21209
21280
|
} finally {
|
|
@@ -21220,15 +21291,15 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
|
21220
21291
|
setKeyBusy(true);
|
|
21221
21292
|
setNotice(null);
|
|
21222
21293
|
try {
|
|
21223
|
-
await caller("saveApiKey", { value: apiKey, expectedRevision: status.revision });
|
|
21294
|
+
const next = await caller("saveApiKey", { value: apiKey, expectedRevision: status.revision });
|
|
21224
21295
|
if (!mounted.current || version2 !== actionVersion.current) return;
|
|
21225
21296
|
setApiKey("");
|
|
21226
|
-
|
|
21227
|
-
|
|
21297
|
+
onStatus(next);
|
|
21298
|
+
setNotice({ kind: "status", text: next.apiKeySource === "reference" ? `API Key \u5DF2\u4FDD\u5B58\uFF1B\u5F53\u524D\u4ECD\u4F18\u5148\u4F7F\u7528\u73AF\u5883\u6216\u51ED\u636E\u5F15\u7528 ${next.config.apiKeyEnv}\u3002` : next.apiKeySource === "stored" ? "API Key \u5DF2\u4FDD\u5B58\u5E76\u7528\u4E8E\u5F53\u524D\u7F51\u5173\u3002" : "API Key \u5DF2\u4FDD\u5B58\u3002" });
|
|
21228
21299
|
} catch {
|
|
21229
21300
|
if (!mounted.current || version2 !== actionVersion.current) return;
|
|
21230
21301
|
setApiKey("");
|
|
21231
|
-
setNotice({ kind: "error", text: "
|
|
21302
|
+
setNotice({ kind: "error", text: "\u4FDD\u5B58\u7ED3\u679C\u6682\u672A\u786E\u8BA4\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
|
|
21232
21303
|
} finally {
|
|
21233
21304
|
if (mounted.current && version2 === actionVersion.current) setKeyBusy(false);
|
|
21234
21305
|
}
|
|
@@ -21251,15 +21322,16 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
|
21251
21322
|
}
|
|
21252
21323
|
};
|
|
21253
21324
|
React.useEffect(() => {
|
|
21254
|
-
if (!autoOpenPending.current || busy || keyBusy) return;
|
|
21325
|
+
if (!autoOpenPending.current || busy || keyBusy || opening || status === void 0) return;
|
|
21255
21326
|
if (state === "waiting") {
|
|
21256
21327
|
autoOpenPending.current = false;
|
|
21257
21328
|
void openActivation();
|
|
21258
21329
|
} else if (state === "error" || state === "cancelled" || state === "success") {
|
|
21259
21330
|
autoOpenPending.current = false;
|
|
21260
21331
|
}
|
|
21261
|
-
}, [state, login?.jobId, busy, keyBusy]);
|
|
21332
|
+
}, [state, login?.jobId, busy, keyBusy, opening, status]);
|
|
21262
21333
|
const desktopChecked = formSnapshot.value?.useDesktopCredential ?? status?.config.useDesktopCredential ?? true;
|
|
21334
|
+
const keySource = status?.apiKeySource === "reference" ? `\u73AF\u5883\u6216\u51ED\u636E\u5F15\u7528\uFF08${status.config.apiKeyEnv}\uFF09` : status?.apiKeySource === "stored" ? "\u5DF2\u4FDD\u5B58\u7684 API Key" : status?.apiKeySource === "device" ? "\u8BBE\u5907\u6388\u6743" : status?.apiKeyConfigured ? "\u5C1A\u672A\u786E\u8BA4" : "\u672A\u914D\u7F6E";
|
|
21263
21335
|
return h(
|
|
21264
21336
|
React.Fragment,
|
|
21265
21337
|
null,
|
|
@@ -21275,7 +21347,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
|
21275
21347
|
checked: desktopChecked,
|
|
21276
21348
|
disabled: formSnapshot.status !== "ready" || formSnapshot.value === void 0 || !formSnapshot.writable || pendingField.includes("useDesktopCredential"),
|
|
21277
21349
|
label: "\u4F18\u5148\u4F7F\u7528\u684C\u9762\u767B\u5F55\u6001",
|
|
21278
|
-
hint: "\
|
|
21350
|
+
hint: "\u4F18\u5148\u663E\u793A\u684C\u9762\u7AEF\u767B\u5F55\u8D26\u53F7\u7684\u989D\u5EA6\u3002",
|
|
21279
21351
|
onChange: (checked) => {
|
|
21280
21352
|
void setFormField("useDesktopCredential", checked);
|
|
21281
21353
|
}
|
|
@@ -21308,8 +21380,9 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
|
|
|
21308
21380
|
h(
|
|
21309
21381
|
"section",
|
|
21310
21382
|
{ className: "odc-card" },
|
|
21311
|
-
h("h3", null, "API Key
|
|
21312
|
-
h("p", { className: "odc-
|
|
21383
|
+
h("h3", null, "API Key"),
|
|
21384
|
+
h("p", { className: "odc-meta", "aria-label": "\u5F53\u524D\u751F\u6548\u7684\u63A8\u7406\u51ED\u636E\u6765\u6E90" }, `\u5F53\u524D\u751F\u6548\u6765\u6E90\uFF1A${keySource}`),
|
|
21385
|
+
h("p", { className: "odc-hint" }, status?.apiKeyConfigured === true ? "\u5F53\u524D\u7F51\u5173\u5DF2\u914D\u7F6E\u63A8\u7406\u51ED\u636E\u3002\u53EF\u5728\u6B64\u4FDD\u5B58\u63D2\u4EF6\u4E13\u7528\u7684 API Key\u3002" : "\u5F53\u524D\u7F51\u5173\u5C1A\u65E0\u63A8\u7406\u51ED\u636E\u3002\u53EF\u5B8C\u6210\u8BBE\u5907\u6388\u6743\u4EE5\u4F7F\u7528\u5B98\u65B9\u7F51\u5173\uFF0C\u6216\u4E3A\u5F53\u524D\u7F51\u5173\u5355\u72EC\u4FDD\u5B58 API Key\u3002"),
|
|
21313
21386
|
h(
|
|
21314
21387
|
"form",
|
|
21315
21388
|
{ onSubmit: (event) => {
|
|
@@ -21378,6 +21451,19 @@ function SettingsPage({ caller, form }) {
|
|
|
21378
21451
|
...acceptedFormSnapshot,
|
|
21379
21452
|
value: acceptedFormSnapshot.value === void 0 ? void 0 : { ...acceptedFormSnapshot.value, ...pendingValues }
|
|
21380
21453
|
}), [acceptedFormSnapshot, pendingValues]);
|
|
21454
|
+
const acceptLoginStatus = React.useCallback((login) => {
|
|
21455
|
+
statusVersion.current += 1;
|
|
21456
|
+
loginVersion.current += 1;
|
|
21457
|
+
setStatus((previous) => previous === void 0 ? previous : { ...previous, login });
|
|
21458
|
+
setError(void 0);
|
|
21459
|
+
}, []);
|
|
21460
|
+
const acceptStatus = React.useCallback((next) => {
|
|
21461
|
+
statusVersion.current += 1;
|
|
21462
|
+
loginVersion.current += 1;
|
|
21463
|
+
setStatus(next);
|
|
21464
|
+
setModelsNotice(null);
|
|
21465
|
+
setError(void 0);
|
|
21466
|
+
}, []);
|
|
21381
21467
|
const loadStatus = React.useCallback(async () => {
|
|
21382
21468
|
const version2 = ++statusVersion.current;
|
|
21383
21469
|
try {
|
|
@@ -21480,7 +21566,7 @@ function SettingsPage({ caller, form }) {
|
|
|
21480
21566
|
if (!mounted.current || version2 !== modelsVersion.current) return;
|
|
21481
21567
|
setStatus(next);
|
|
21482
21568
|
setError(void 0);
|
|
21483
|
-
setModelsNotice(next.modelsError === void 0 ? { kind: "status", text: `\u5DF2\u4ECE
|
|
21569
|
+
setModelsNotice(next.modelsError === void 0 ? { kind: "status", text: `\u5DF2\u4ECE\u5F53\u524D\u7F51\u5173\u5237\u65B0\u6A21\u578B\u76EE\u5F55\uFF0C\u5171 ${next.models.length} \u4E2A\u6A21\u578B\u3002` } : null);
|
|
21484
21570
|
} catch {
|
|
21485
21571
|
if (mounted.current && version2 === modelsVersion.current) setModelsNotice({ kind: "error", text: "\u6A21\u578B\u5237\u65B0\u672A\u5B8C\u6210\uFF0C\u8BF7\u68C0\u67E5\u51ED\u636E\u3001\u7F51\u5173\u4E0E\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002" });
|
|
21486
21572
|
} finally {
|
|
@@ -21501,10 +21587,7 @@ function SettingsPage({ caller, form }) {
|
|
|
21501
21587
|
const login = await caller("loginStatus");
|
|
21502
21588
|
if (stopped || !mounted.current || version2 !== loginVersion.current) return;
|
|
21503
21589
|
setStatus((previous) => previous === void 0 ? previous : { ...previous, login });
|
|
21504
|
-
if (!loginInFlight(login.state))
|
|
21505
|
-
if (login.state === "success") void refresh();
|
|
21506
|
-
else void loadStatus();
|
|
21507
|
-
}
|
|
21590
|
+
if (!loginInFlight(login.state) && login.state !== "success") void loadStatus();
|
|
21508
21591
|
} catch {
|
|
21509
21592
|
}
|
|
21510
21593
|
};
|
|
@@ -21518,6 +21601,11 @@ function SettingsPage({ caller, form }) {
|
|
|
21518
21601
|
loginVersion.current += 1;
|
|
21519
21602
|
};
|
|
21520
21603
|
}, [caller, loadStatus, loginActive, mounted, refresh]);
|
|
21604
|
+
React.useEffect(() => {
|
|
21605
|
+
if (loginState !== "success") return;
|
|
21606
|
+
void loadStatus();
|
|
21607
|
+
void refresh(true);
|
|
21608
|
+
}, [loginState, status?.login.jobId, loadStatus, refresh]);
|
|
21521
21609
|
const configuredSeconds = formSnapshot.value?.quotaRefreshSeconds ?? status?.config.quotaRefreshSeconds;
|
|
21522
21610
|
const refreshIntervalSeconds = configuredSeconds === void 0 ? DEFAULT_QUOTA_REFRESH_SECONDS : normaliseQuotaRefreshSeconds(configuredSeconds);
|
|
21523
21611
|
const quotaNextRefreshAt = status?.quota.nextRefreshAt;
|
|
@@ -21563,7 +21651,7 @@ function SettingsPage({ caller, form }) {
|
|
|
21563
21651
|
notice: modelsNotice
|
|
21564
21652
|
});
|
|
21565
21653
|
} else if (tab === "connection") {
|
|
21566
|
-
content = h(Connection, { status, formSnapshot, setFormField, pendingField, caller,
|
|
21654
|
+
content = h(Connection, { status, formSnapshot, setFormField, pendingField, caller, onLoginStatus: acceptLoginStatus, onStatus: acceptStatus });
|
|
21567
21655
|
} else {
|
|
21568
21656
|
content = h(Advanced, { status, formSnapshot, setFormField, pendingField });
|
|
21569
21657
|
}
|
|
@@ -21571,7 +21659,7 @@ function SettingsPage({ caller, form }) {
|
|
|
21571
21659
|
"div",
|
|
21572
21660
|
{ className: "odc-settings" },
|
|
21573
21661
|
h("h2", null, "OpenDesign CoRouter"),
|
|
21574
|
-
h("p", { className: "odc-intro" }, "\
|
|
21662
|
+
h("p", { className: "odc-intro" }, "\u67E5\u770B\u989D\u5EA6\uFF0C\u7BA1\u7406\u6A21\u578B\u3001\u8FDE\u63A5\u4E0E\u8BF7\u6C42\u8BBE\u7F6E\u3002"),
|
|
21575
21663
|
h("div", { className: "odc-tabs", role: "tablist", "aria-label": "CoRouter \u8BBE\u7F6E\u5206\u7C7B" }, TABS.map((item, index) => h("button", {
|
|
21576
21664
|
key: item.id,
|
|
21577
21665
|
ref: (node2) => {
|
package/lib/device-auth.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export interface DeviceTokens {
|
|
|
3
3
|
runtimeKey: string;
|
|
4
4
|
}
|
|
5
5
|
export declare const DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
|
|
6
|
-
export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.
|
|
6
|
+
export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.7";
|
|
7
7
|
export declare const DEVICE_REQUEST_TIMEOUT_MS = 20000;
|
|
8
8
|
/** One bounded launch step of the temporary activation window. */
|
|
9
9
|
export declare const DEVICE_OPEN_TIMEOUT_MS = 30000;
|
|
@@ -122,9 +122,9 @@ function amount(value, label, negative = false) {
|
|
|
122
122
|
if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
|
|
123
123
|
return value;
|
|
124
124
|
}
|
|
125
|
-
function positiveInteger(value, label, max) {
|
|
125
|
+
function positiveInteger(value, label, max, min = 1) {
|
|
126
126
|
const result = count(value, label);
|
|
127
|
-
if (result
|
|
127
|
+
if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
|
|
128
128
|
return result;
|
|
129
129
|
}
|
|
130
130
|
function parseEfforts(value) {
|
|
@@ -227,9 +227,9 @@ function parseStatusConfig(value) {
|
|
|
227
227
|
apiKeyEnv,
|
|
228
228
|
...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
|
|
229
229
|
...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
|
|
230
|
-
...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
|
|
231
|
-
...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
|
|
232
|
-
...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
|
|
230
|
+
...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
|
|
231
|
+
...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
|
|
232
|
+
...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
|
|
233
233
|
};
|
|
234
234
|
}
|
|
235
235
|
function parseStatus(value) {
|
|
@@ -242,9 +242,13 @@ function parseStatus(value) {
|
|
|
242
242
|
if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
|
|
243
243
|
ids.add(model.id);
|
|
244
244
|
}
|
|
245
|
+
const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
|
|
246
|
+
const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
|
|
247
|
+
if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
|
|
245
248
|
return {
|
|
246
249
|
revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
|
|
247
|
-
apiKeyConfigured
|
|
250
|
+
apiKeyConfigured,
|
|
251
|
+
...apiKeySource === void 0 ? {} : { apiKeySource },
|
|
248
252
|
...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
|
|
249
253
|
quota: parseQuotaSnapshot(value.quota),
|
|
250
254
|
login: parseLoginState(value.login),
|