dsh-provider-qoder 0.4.1 → 0.4.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.md +13 -22
- package/README_CN.md +13 -25
- package/lib/client.js +85 -120
- package/lib/index.d.ts +2 -44
- package/lib/index.js +85 -71
- package/package.json +19 -16
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-provider-qoder)
|
|
4
4
|
[](LICENSE)
|
|
5
|
+
[](https://github.com/mo-n/dsh-provider-qoder)
|
|
5
6
|
[](https://awesome-dsh-plugin.com)
|
|
6
7
|
|
|
7
8
|
English | [简体中文](./README_CN.md)
|
|
@@ -15,17 +16,18 @@ This project is a community adapter plugin and is not affiliated with Qoder or D
|
|
|
15
16
|
|
|
16
17
|
- Configure subscription access via Qoder Personal Access Token (PAT).
|
|
17
18
|
- Supports both Global (`global`) and China (`china`) services.
|
|
18
|
-
-
|
|
19
|
-
- Supports multimodality, search, and tool calls.
|
|
19
|
+
- Automatically fetches available models for your account, supports selecting enabled models, and displays pricing multipliers and reasoning effort options when reported by the service.
|
|
20
|
+
- Supports multimodality, web search, and tool calls.
|
|
20
21
|
- View account information, quota, and reset dates in Settings.
|
|
21
22
|
|
|
22
23
|
## Installation
|
|
23
24
|
|
|
24
25
|
### Prerequisites
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
- An active Qoder subscription and a PAT matching the selected service region.
|
|
28
|
+
- The DSH profile running the plugin must provide a managed credentials service; when configuring via the settings page, the credential storage must also be writable.
|
|
29
|
+
- Requirements: DSH `>=0.1.7-rc.2`.
|
|
27
30
|
|
|
28
|
-
This package supports DSH `>=0.1.7-rc.2 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0`, Cordis `>=4.0.4 <5`, and React `^18.2.0`.
|
|
29
31
|
### Install from npm
|
|
30
32
|
|
|
31
33
|
Run in your terminal:
|
|
@@ -47,27 +49,14 @@ Open DSH Web, navigate to **Settings → Models**, locate the **Qoder Credential
|
|
|
47
49
|
|
|
48
50
|
Select the region matching your account, enter your Qoder PAT into the input box labeled **API Key**, and click **Save**.
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
Once saved, the plugin automatically fetches the list of supported models for your account, making them immediately available in the DSH model picker.
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
2. Expand **Custom Settings** and click **Fetch Available Models**.
|
|
54
|
-
3. Select the models you want to enable (keep at least one), then click **Save**.
|
|
55
|
-
4. Select a Qoder model in the DSH model picker to start chatting.
|
|
54
|
+
### 2. View Account & Manage Models
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
The model picker refreshes Qoder metadata for enabled models when opened, with a five-minute cache after a successful fetch. When settings are writable, refreshed multipliers and capabilities are also synchronized to the saved catalog shown in **Custom Settings**, without enabling additional models. Failed refreshes retain the last known metadata.
|
|
56
|
+
Open **Settings → Qoder** to view account and quota details, configure the web search policy, and adjust enabled models:
|
|
60
57
|
|
|
61
58
|
<p align="center">
|
|
62
|
-
<img src="./assets/
|
|
63
|
-
</p>
|
|
64
|
-
|
|
65
|
-
### 3. View Account & Quota
|
|
66
|
-
|
|
67
|
-
Open **Settings → Qoder** to view account and quota details, and configure the web search policy as needed:
|
|
68
|
-
|
|
69
|
-
<p align="center">
|
|
70
|
-
<img src="./assets/account-quota.png" alt="Qoder account quota and search settings" width="650" />
|
|
59
|
+
<img src="./assets/account-quota.png" alt="Qoder account quota and model settings" width="650" />
|
|
71
60
|
</p>
|
|
72
61
|
|
|
73
62
|
## Upcoming Features
|
|
@@ -83,4 +72,6 @@ Open **Settings → Qoder** to view account and quota details, and configure the
|
|
|
83
72
|
|
|
84
73
|
Please report issues via [GitHub Issues](https://github.com/mo-n/dsh-provider-qoder/issues) with the plugin and DSH versions, selected service region, reproduction steps, and sanitized error messages. Do not submit PATs, short-lived tokens, or personal account information.
|
|
85
74
|
|
|
86
|
-
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
This project is licensed under the [MIT License](LICENSE).
|
package/README_CN.md
CHANGED
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
[](https://github.com/mo-n/dsh-provider-qoder)
|
|
6
6
|
[](https://awesome-dsh-plugin.com)
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
[English](./README.md) | 简体中文
|
|
10
9
|
|
|
11
|
-
在 DeepSeek Harness(DSH
|
|
10
|
+
在 DeepSeek Harness(DSH)中使用 Qoder 订阅,支持多模态、联网搜索和工具调用,可选择国际版或中国区 Qoder 服务。
|
|
12
11
|
|
|
13
12
|
插件负责认证和模型通信,工具执行、工作区操作及权限管理由 DSH 负责。
|
|
14
13
|
本项目是社区适配插件,与 Qoder、DeepSeek 官方均无关联。
|
|
@@ -17,7 +16,7 @@
|
|
|
17
16
|
|
|
18
17
|
- 通过 Qoder Personal Access Token(PAT,个人访问令牌)配置订阅访问。
|
|
19
18
|
- 支持国际版(`global`)和中国区(`china`)服务。
|
|
20
|
-
-
|
|
19
|
+
- 自动拉取账号可用模型,支持选择启用的模型,并在服务支持时显示价格倍率和推理强度选项。
|
|
21
20
|
- 支持多模态、搜索以及工具调用。
|
|
22
21
|
- 在设置中查看账号信息、额度和重置时间。
|
|
23
22
|
|
|
@@ -25,9 +24,9 @@
|
|
|
25
24
|
|
|
26
25
|
### 使用前提
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
- 拥有可用的 Qoder 订阅,以及与所选服务区域匹配的 PAT。
|
|
28
|
+
- 运行插件的 DSH profile 必须提供托管凭据服务;通过设置页面配置时,凭据存储还需可写。
|
|
29
|
+
- 环境要求:DSH `>=0.1.7-rc.2`。
|
|
31
30
|
|
|
32
31
|
### 从 npm 安装
|
|
33
32
|
|
|
@@ -50,31 +49,18 @@ dsh plugin --profile web add dsh-provider-qoder
|
|
|
50
49
|
|
|
51
50
|
选择与账号一致的区域,将 Qoder PAT 填入界面标为 **API 密钥** 的输入框,然后点击 **保存**。
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
1. 保存 PAT 和服务区域后,再次点击 **编辑**。
|
|
56
|
-
2. 展开 **自定义设置**,点击 **获取可用模型**。
|
|
57
|
-
3. 选择需要启用的模型,至少保留一个,然后点击 **保存**。
|
|
58
|
-
4. 在 DSH 的模型选择器中选择 Qoder 模型,开始对话。
|
|
52
|
+
保存后,插件会拉取账号支持的模型列表,即可在 DSH 模型选择器中选用。
|
|
59
53
|
|
|
60
|
-
|
|
54
|
+
### 2. 查看账号与设置模型
|
|
61
55
|
|
|
62
|
-
|
|
56
|
+
打开 **设置 → Qoder** 查看账号额度,并可切换联网搜索策略与调整启用的模型:
|
|
63
57
|
|
|
64
58
|
<p align="center">
|
|
65
|
-
<img src="./assets/
|
|
59
|
+
<img src="./assets/account-quota_CN.png" alt="Qoder 账号额度与模型设置" width="650" />
|
|
66
60
|
</p>
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
## 后续计划
|
|
69
63
|
|
|
70
|
-
打开 **设置 → Qoder** 查看账号额度,并可按需切换联网搜索策略:
|
|
71
|
-
|
|
72
|
-
<p align="center">
|
|
73
|
-
<img src="./assets/account-quota.png" alt="Qoder 账号额度与搜索设置" width="650" />
|
|
74
|
-
</p>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
## 后续计划功能
|
|
78
64
|
- [ ] 请求限流排队机制
|
|
79
65
|
- [ ] 接入 Qoder 的 Protobuf 协议
|
|
80
66
|
|
|
@@ -86,4 +72,6 @@ dsh plugin --profile web add dsh-provider-qoder
|
|
|
86
72
|
|
|
87
73
|
请通过 [GitHub Issues](https://github.com/mo-n/dsh-provider-qoder/issues) 提交问题,附上插件和 DSH 版本、所选服务区域、复现步骤及脱敏后的错误信息。不要提交 PAT、短期令牌或个人账号信息。
|
|
88
74
|
|
|
89
|
-
|
|
75
|
+
## 许可证
|
|
76
|
+
|
|
77
|
+
本项目基于 [MIT License](LICENSE) 开源。
|
package/lib/client.js
CHANGED
|
@@ -69,6 +69,29 @@ window.__ModuleLoader__.load({
|
|
|
69
69
|
tokenCount
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
+
/** Clone a model catalog entry, detaching any contextOptions object. */
|
|
73
|
+
function cloneCatalogModel(model) {
|
|
74
|
+
return {
|
|
75
|
+
...model,
|
|
76
|
+
...model.contextOptions !== void 0 ? { contextOptions: { ...model.contextOptions } } : {}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Carry subscriber context choices only while the refreshed catalog supports them. */
|
|
80
|
+
function mergeAdvertisedContext(remembered, advertised, updated) {
|
|
81
|
+
const merged = { ...updated };
|
|
82
|
+
delete merged.contextOptions;
|
|
83
|
+
delete merged.contextTier;
|
|
84
|
+
if (advertised.contextOptions !== void 0) merged.contextOptions = { ...advertised.contextOptions };
|
|
85
|
+
const tier = selectedContextTier({
|
|
86
|
+
contextTier: remembered.contextTier,
|
|
87
|
+
contextOptions: merged.contextOptions
|
|
88
|
+
});
|
|
89
|
+
if (tier !== void 0) {
|
|
90
|
+
merged.contextTier = tier.key;
|
|
91
|
+
merged.contextWindow = tier.tokenCount;
|
|
92
|
+
} else if (advertised.contextWindow !== void 0) merged.contextWindow = remembered.contextTier !== void 0 ? advertised.contextWindow : Math.min(remembered.contextWindow ?? advertised.contextWindow, advertised.contextWindow);
|
|
93
|
+
return merged;
|
|
94
|
+
}
|
|
72
95
|
const defaultMaxTokens = 32768;
|
|
73
96
|
const defaultModels = [
|
|
74
97
|
{
|
|
@@ -120,6 +143,31 @@ window.__ModuleLoader__.load({
|
|
|
120
143
|
}
|
|
121
144
|
];
|
|
122
145
|
//#endregion
|
|
146
|
+
//#region src/client/credential-operations.ts
|
|
147
|
+
function regionOf(value) {
|
|
148
|
+
if (typeof value !== "object" || value === null) return "global";
|
|
149
|
+
return value.region === "china" ? "china" : "global";
|
|
150
|
+
}
|
|
151
|
+
function modelsOf(section, region) {
|
|
152
|
+
const scoped = section?.modelsByRegion?.[region];
|
|
153
|
+
return Array.isArray(scoped) ? scoped : defaultModels.map((model) => ({ ...model }));
|
|
154
|
+
}
|
|
155
|
+
function reconcileQoderModels(known, discovered) {
|
|
156
|
+
const availableIds = new Set(discovered.map((model) => model.id));
|
|
157
|
+
const unavailable = known.filter((model) => !availableIds.has(model.id)).map(cloneCatalogModel);
|
|
158
|
+
const previous = new Map(known.map((model) => [model.id, model]));
|
|
159
|
+
const reconciled = discovered.map((model) => {
|
|
160
|
+
const remembered = previous.get(model.id);
|
|
161
|
+
if (remembered === void 0) return cloneCatalogModel(model);
|
|
162
|
+
return mergeAdvertisedContext(remembered, model, model);
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
catalog: [...reconciled, ...unavailable],
|
|
166
|
+
selected: reconciled,
|
|
167
|
+
unavailableIds: new Set(unavailable.map((model) => model.id))
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
123
171
|
//#region src/client/locales.ts
|
|
124
172
|
const zh = {
|
|
125
173
|
nav: "Qoder",
|
|
@@ -165,7 +213,6 @@ window.__ModuleLoader__.load({
|
|
|
165
213
|
contextTierDefaultSuffix: "(默认)",
|
|
166
214
|
contextTierHint: "选择该模型使用的上下文档位;更大的档位会同时提升 DSH 的上下文预算并改变 Qoder 请求使用的档位。",
|
|
167
215
|
contextSelectFailed: "上下文切换失败,请重试。",
|
|
168
|
-
contextDefaultFailed: "当前会话已切换,但新会话默认值保存失败。",
|
|
169
216
|
contextSelectTitle: "选择上下文大小",
|
|
170
217
|
contextSelectMenuHeader: "上下文容量",
|
|
171
218
|
accountTitle: "Qoder",
|
|
@@ -237,7 +284,6 @@ window.__ModuleLoader__.load({
|
|
|
237
284
|
contextTierDefaultSuffix: " (default)",
|
|
238
285
|
contextTierHint: "Select the context tier for this model. A larger tier raises the DSH context budget and changes the tier the Qoder request uses.",
|
|
239
286
|
contextSelectFailed: "Could not change the context window. Please retry.",
|
|
240
|
-
contextDefaultFailed: "Session updated, but the default for new sessions could not be saved.",
|
|
241
287
|
contextSelectTitle: "Select context window size",
|
|
242
288
|
contextSelectMenuHeader: "Context Capacity",
|
|
243
289
|
accountTitle: "Qoder",
|
|
@@ -316,49 +362,6 @@ window.__ModuleLoader__.load({
|
|
|
316
362
|
}
|
|
317
363
|
}
|
|
318
364
|
//#endregion
|
|
319
|
-
//#region src/client/credential-operations.ts
|
|
320
|
-
function reconcileQoderModels(known, discovered) {
|
|
321
|
-
const availableIds = new Set(discovered.map((model) => model.id));
|
|
322
|
-
const unavailable = known.filter((model) => !availableIds.has(model.id)).map((model) => ({
|
|
323
|
-
...model,
|
|
324
|
-
...model.contextOptions !== void 0 ? { contextOptions: { ...model.contextOptions } } : {}
|
|
325
|
-
}));
|
|
326
|
-
const previous = new Map(known.map((model) => [model.id, model]));
|
|
327
|
-
const reconciled = discovered.map((model) => {
|
|
328
|
-
const remembered = previous.get(model.id);
|
|
329
|
-
if (remembered === void 0) return {
|
|
330
|
-
...model,
|
|
331
|
-
...model.contextOptions !== void 0 ? { contextOptions: { ...model.contextOptions } } : {}
|
|
332
|
-
};
|
|
333
|
-
const carried = selectedContextTier({
|
|
334
|
-
contextTier: remembered.contextTier,
|
|
335
|
-
contextOptions: model.contextOptions ?? remembered.contextOptions
|
|
336
|
-
});
|
|
337
|
-
const options = model.contextOptions ?? remembered.contextOptions;
|
|
338
|
-
const clonedOptions = options !== void 0 ? { contextOptions: { ...options } } : {};
|
|
339
|
-
if (carried !== void 0) return {
|
|
340
|
-
...model,
|
|
341
|
-
...clonedOptions,
|
|
342
|
-
contextTier: carried.key,
|
|
343
|
-
contextWindow: carried.tokenCount
|
|
344
|
-
};
|
|
345
|
-
const budget = remembered.contextWindow;
|
|
346
|
-
return budget === void 0 || model.contextWindow === void 0 ? {
|
|
347
|
-
...model,
|
|
348
|
-
...clonedOptions
|
|
349
|
-
} : {
|
|
350
|
-
...model,
|
|
351
|
-
...clonedOptions,
|
|
352
|
-
contextWindow: Math.min(budget, model.contextWindow)
|
|
353
|
-
};
|
|
354
|
-
});
|
|
355
|
-
return {
|
|
356
|
-
catalog: [...reconciled, ...unavailable],
|
|
357
|
-
selected: reconciled,
|
|
358
|
-
unavailableIds: new Set(unavailable.map((model) => model.id))
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
//#endregion
|
|
362
365
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderCredentialCard.module.css.mjs
|
|
363
366
|
const css$1 = ".SRqrhW_credential{color:var(--dsw-alias-label-primary);border-radius:10px;margin-top:12px}.SRqrhW_credential p{margin:8px 0 0}.SRqrhW_credentialEditor{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);flex-direction:column;gap:12px;padding:12px 14px;display:flex}.SRqrhW_credentialRowHead{align-items:center;gap:10px;display:flex}.SRqrhW_credentialIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.SRqrhW_credentialName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.SRqrhW_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.SRqrhW_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.SRqrhW_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.SRqrhW_regionBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:500;line-height:16px;display:inline-flex}.SRqrhW_regionSelector{flex-direction:column;gap:8px;margin-bottom:14px;display:flex}.SRqrhW_regionGroup{gap:8px;display:flex}.SRqrhW_regionOption{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);user-select:none;border-radius:8px;align-items:center;gap:6px;padding:6px 12px;font-size:12px;line-height:18px;transition:all .12s;display:inline-flex}.SRqrhW_regionOption:hover:not(.SRqrhW_regionOptionDisabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.SRqrhW_credential button.SRqrhW_regionOptionActive{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-selected);color:var(--dsw-alias-brand-primary);font-weight:500}.SRqrhW_regionOptionDisabled{cursor:not-allowed;opacity:.5}.SRqrhW_editButton{box-sizing:border-box;font:inherit;background:0 0;margin-left:auto;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2)!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_editButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.SRqrhW_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;padding:14px 16px}.SRqrhW_customized{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);margin-top:12px;transition:all .12s;overflow:hidden}.SRqrhW_customizedSummary{box-sizing:border-box;border-radius:var(--dsw-radius-xl,12px);cursor:pointer;width:100%;color:var(--dsw-alias-label-primary);user-select:none;align-items:center;gap:8px;margin:0;padding:12px 14px;font-size:13px;font-weight:600;line-height:18px;list-style:none;transition:background .12s;display:flex}.SRqrhW_customizedSummary:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelSummaryBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:400;line-height:16px;display:inline-flex}.SRqrhW_customizedSummary::-webkit-details-marker{display:none}.SRqrhW_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary{border-bottom:.5px solid var(--dsw-alias-border-l2);border-bottom-right-radius:0;border-bottom-left-radius:0}.SRqrhW_customizedBody{padding:12px 14px 14px}.SRqrhW_modelCatalog{flex-direction:column;gap:10px;display:flex}.SRqrhW_modelList{flex-direction:column;gap:10px;max-height:360px;padding-right:4px;display:flex;overflow-y:auto}.SRqrhW_modelList::-webkit-scrollbar{width:4px}.SRqrhW_modelList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);border-radius:2px}.SRqrhW_modelCatalogHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.SRqrhW_modelCatalogHeadCompact{justify-content:flex-end;align-items:center;gap:12px;display:flex}.SRqrhW_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.SRqrhW_modelCatalogMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:2px 0 0!important}.SRqrhW_linkButton{box-sizing:border-box;font:inherit;background:0 0;font-size:12px;line-height:18px;border:none!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoice{border-radius:6px;flex-direction:column;gap:4px;padding:6px 8px;font-size:13px;display:flex}.SRqrhW_modelChoice:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoiceHead{cursor:pointer;grid-template-columns:auto minmax(0,1fr) auto auto auto;align-items:center;gap:8px;display:grid}.SRqrhW_modelTier{align-items:center;gap:8px;padding-left:24px;display:flex}.SRqrhW_modelTierLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}.SRqrhW_modelTierSelect{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);height:24px;color:inherit;font:inherit;cursor:pointer;border:0;border-radius:6px;padding:0 6px;font-size:12px}.SRqrhW_modelTierHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px;margin:0!important}.SRqrhW_modelChoiceName{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.SRqrhW_modelChoice code{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_modelRate{min-width:34px;color:var(--dsw-alias-brand-primary);text-align:right;font-size:12px;font-weight:600}.SRqrhW_modelUnavailable{cursor:not-allowed;opacity:.55}.SRqrhW_modelBadge{color:var(--dsw-alias-state-error-primary);font-size:11px}@media (prefers-reduced-motion:reduce){.SRqrhW_customizedSummary:before{transition:none}}.SRqrhW_head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:20px;display:flex}.SRqrhW_heading{margin:0;font-size:18px;font-weight:600}.SRqrhW_status{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_configured,.SRqrhW_success{color:var(--dsw-alias-state-success-primary)}.SRqrhW_label{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;display:block}.SRqrhW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:32px;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;margin-top:6px;padding:0 10px}.SRqrhW_input:focus{border-color:var(--dsw-alias-brand-primary)}.SRqrhW_input::placeholder{color:var(--dsw-alias-label-dimmed)}.SRqrhW_input:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_hint{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_actions{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.SRqrhW_credential button{cursor:pointer;height:32px;color:var(--dsw-alias-label-primary);border:1px solid #0000;border-radius:16px;padding:0 12px}.SRqrhW_credential button:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)!important}.SRqrhW_primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.SRqrhW_secondary{background:0 0;border-color:var(--dsw-alias-border-l2)!important}.SRqrhW_secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_danger{background:0 0;border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.SRqrhW_danger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.SRqrhW_error{color:var(--dsw-alias-state-error-primary);font-size:12px}.SRqrhW_success{font-size:12px}.SRqrhW_accountSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_accountHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_userInfo{align-items:center;gap:10px;min-width:0;display:flex}.SRqrhW_avatar{background:var(--dsw-alias-brand-primary);width:32px;height:32px;color:var(--dsw-alias-label-primary-foreground);text-transform:uppercase;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:flex}.SRqrhW_userDetails{flex-direction:column;gap:2px;min-width:0;display:flex}.SRqrhW_userName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;overflow:hidden}.SRqrhW_userEmail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.SRqrhW_refreshBtn{border:1px solid var(--dsw-alias-border-l2)!important;height:26px!important;color:var(--dsw-alias-label-secondary)!important;background:0 0!important;border-radius:13px!important;padding:0 8px!important;font-size:12px!important}.SRqrhW_refreshBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)!important}.SRqrhW_quotaBlock{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding-top:8px;display:flex}.SRqrhW_quotaHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_quotaLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.SRqrhW_quotaTop{justify-content:space-between;align-items:baseline;gap:8px;font-size:12px;display:flex}.SRqrhW_quotaTop strong{color:var(--dsw-alias-brand-primary);font-size:13px}.SRqrhW_quotaDescription{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0!important}.SRqrhW_quotaProgress{background:var(--dsw-alias-border-l3);width:100%;height:6px;accent-color:var(--dsw-alias-brand-primary);-webkit-appearance:none;appearance:none;border:0;border-radius:999px;overflow:hidden}.SRqrhW_quotaProgress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.SRqrhW_quotaProgress::-webkit-progress-value{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaProgress::-moz-progress-bar{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaMeta{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;gap:8px;font-size:11px;display:flex}.SRqrhW_accountLoadingText,.SRqrhW_accountEmptyText{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.SRqrhW_userNameRow{align-items:center;gap:8px;display:flex}.SRqrhW_planBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-brand-primary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.SRqrhW_orgTag{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_suspendedBanner{background:var(--dsw-alias-state-error-subtle,#ff4d4f1a);color:var(--dsw-alias-state-error-primary);border-radius:6px;align-items:center;gap:6px;margin-bottom:8px;padding:6px 10px;font-size:12px;display:flex}.SRqrhW_searchModeSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_searchModeHintText{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:12px;line-height:18px}";
|
|
364
367
|
const tagId$1 = "dsh-provider-qoder/QoderCredentialCard.module.css";
|
|
@@ -610,18 +613,6 @@ window.__ModuleLoader__.load({
|
|
|
610
613
|
minute: "2-digit"
|
|
611
614
|
});
|
|
612
615
|
}
|
|
613
|
-
function modelsOf$1(value, selectedRegion) {
|
|
614
|
-
if (typeof value !== "object" || value === null) return defaultModels.map((model) => ({ ...model }));
|
|
615
|
-
const section = value;
|
|
616
|
-
const region = selectedRegion ?? (section.region === "china" ? "china" : "global");
|
|
617
|
-
const scoped = section.modelsByRegion?.[region];
|
|
618
|
-
if (Array.isArray(scoped)) return scoped;
|
|
619
|
-
return defaultModels.map((model) => ({ ...model }));
|
|
620
|
-
}
|
|
621
|
-
function regionOf$1(value) {
|
|
622
|
-
if (typeof value !== "object" || value === null) return "global";
|
|
623
|
-
return value.region === "china" ? "china" : "global";
|
|
624
|
-
}
|
|
625
616
|
/**
|
|
626
617
|
* Settings card for the Qoder subscription: credential state, subscriber
|
|
627
618
|
* profile, and every quota block the provider reports.
|
|
@@ -928,8 +919,8 @@ window.__ModuleLoader__.load({
|
|
|
928
919
|
]
|
|
929
920
|
});
|
|
930
921
|
};
|
|
931
|
-
const currentRegion = regionOf
|
|
932
|
-
const currentModels = modelsOf
|
|
922
|
+
const currentRegion = regionOf(modelSnapshot.value);
|
|
923
|
+
const currentModels = modelsOf(modelSnapshot.value, currentRegion);
|
|
933
924
|
const canModifyModels = modelSnapshot.status === "ready" && modelSnapshot.writable;
|
|
934
925
|
const handleModelsChange = async (models) => {
|
|
935
926
|
if (!canModifyModels) return;
|
|
@@ -998,10 +989,6 @@ window.__ModuleLoader__.load({
|
|
|
998
989
|
}
|
|
999
990
|
//#endregion
|
|
1000
991
|
//#region src/client/QoderCredentialCard.tsx
|
|
1001
|
-
function regionOf(value) {
|
|
1002
|
-
if (typeof value !== "object" || value === null) return "global";
|
|
1003
|
-
return value.region === "china" ? "china" : "global";
|
|
1004
|
-
}
|
|
1005
992
|
function QoderCredentialCard({ operations, t }) {
|
|
1006
993
|
const [state, setState] = (0, react.useState)({ status: "loading" });
|
|
1007
994
|
const [editing, setEditing] = (0, react.useState)(false);
|
|
@@ -1240,39 +1227,20 @@ window.__ModuleLoader__.load({
|
|
|
1240
1227
|
"qoder-subscription"
|
|
1241
1228
|
].includes(provider ?? "");
|
|
1242
1229
|
}
|
|
1243
|
-
function modelsOf(section, region, _legacyRegion) {
|
|
1244
|
-
const scoped = section?.modelsByRegion?.[region];
|
|
1245
|
-
if (scoped !== void 0) return scoped;
|
|
1246
|
-
return defaultModels.map((model) => ({ ...model }));
|
|
1247
|
-
}
|
|
1248
1230
|
function historicalContextWindow(current, lastUsed, contextWindow) {
|
|
1249
1231
|
return current.provider === lastUsed?.provider && current.model === lastUsed?.model ? contextWindow : void 0;
|
|
1250
1232
|
}
|
|
1251
|
-
/**
|
|
1252
|
-
async function saveContextSelection(operations, sessionId, region, modelId, tierKey
|
|
1233
|
+
/** Composer selections belong to the current session; model defaults live in settings. */
|
|
1234
|
+
async function saveContextSelection(operations, sessionId, region, modelId, tierKey) {
|
|
1253
1235
|
try {
|
|
1254
|
-
|
|
1236
|
+
return await operations.setSessionTier?.(sessionId, modelId, tierKey, region) ? "saved" : "session-failed";
|
|
1255
1237
|
} catch {
|
|
1256
1238
|
return "session-failed";
|
|
1257
1239
|
}
|
|
1258
|
-
try {
|
|
1259
|
-
const models = modelsOf(operations.getModelSnapshot().value, region, legacyRegion);
|
|
1260
|
-
const model = models.find((candidate) => candidate.id === modelId);
|
|
1261
|
-
const tier = model && contextTiersOf(model).find((candidate) => candidate.key === tierKey);
|
|
1262
|
-
if (!tier) return "default-failed";
|
|
1263
|
-
const updated = models.map((candidate) => candidate.id === modelId ? {
|
|
1264
|
-
...candidate,
|
|
1265
|
-
contextTier: tierKey,
|
|
1266
|
-
contextWindow: tier.tokenCount
|
|
1267
|
-
} : candidate);
|
|
1268
|
-
return await operations.storeModels(region, updated) ? "saved" : "default-failed";
|
|
1269
|
-
} catch {
|
|
1270
|
-
return "default-failed";
|
|
1271
|
-
}
|
|
1272
1240
|
}
|
|
1273
1241
|
//#endregion
|
|
1274
1242
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderContextSelect.module.css.mjs
|
|
1275
|
-
const css = ".hiDrJa_root{align-items:center;display:inline-flex;position:relative}.hiDrJa_trigger{height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;user-select:none;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;transition:background .12s,color .12s;display:flex}.hiDrJa_trigger:hover,.hiDrJa_triggerActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.hiDrJa_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.hiDrJa_icon{color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;display:inline-flex}.hiDrJa_label{white-space:nowrap}.hiDrJa_chevron{color:var(--dsw-alias-label-caption);align-items:center;transition:transform .12s;display:inline-flex}.hiDrJa_chevronOpen{transform:rotate(180deg)}.hiDrJa_menu{z-index:1100;background:var(--dsw-
|
|
1243
|
+
const css = ".hiDrJa_root{align-items:center;display:inline-flex;position:relative}.hiDrJa_trigger{height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;user-select:none;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;transition:background .12s,color .12s;display:flex}.hiDrJa_trigger:hover,.hiDrJa_triggerActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.hiDrJa_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.hiDrJa_icon{color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;display:inline-flex}.hiDrJa_label{white-space:nowrap}.hiDrJa_chevron{color:var(--dsw-alias-label-caption);align-items:center;transition:transform .12s;display:inline-flex}.hiDrJa_chevronOpen{transform:rotate(180deg)}.hiDrJa_menu{z-index:1100;background:var(--dsw-menu-surface-fill);min-width:180px;backdrop-filter:var(--dsw-menu-backdrop-filter);border:1px solid var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;padding:4px;animation:.12s hiDrJa_fadeIn;display:flex;position:absolute;bottom:calc(100% + 8px);right:0}@keyframes hiDrJa_fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.hiDrJa_menuHeader{text-transform:uppercase;letter-spacing:.5px;color:var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-border-l1);margin-bottom:4px;padding:6px 10px 4px;font-size:11px;font-weight:600}.hiDrJa_option{box-sizing:border-box;width:100%;color:inherit;cursor:pointer;text-align:left;background:0 0;border:none;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;font-size:13px;line-height:20px;transition:background .1s;display:flex}.hiDrJa_option:hover{background:var(--dsw-alias-interactive-bg-hover)}.hiDrJa_optionSelected{color:var(--dsw-alias-state-brand);font-weight:600}.hiDrJa_optionInfo{align-items:center;gap:6px;display:flex}.hiDrJa_tag{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-caption);border-radius:4px;padding:1px 5px;font-size:11px;font-weight:500}.hiDrJa_check{color:var(--dsw-alias-state-brand);align-items:center;font-size:12px;display:inline-flex}.hiDrJa_error{color:var(--dsw-alias-label-primary);max-width:240px;font-size:12px}";
|
|
1276
1244
|
const tagId = "dsh-provider-qoder/QoderContextSelect.module.css";
|
|
1277
1245
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1278
1246
|
const tag = document.createElement("style");
|
|
@@ -1308,7 +1276,6 @@ window.__ModuleLoader__.load({
|
|
|
1308
1276
|
const [pending, setPending] = (0, react.useState)(false);
|
|
1309
1277
|
const [error, setError] = (0, react.useState)(null);
|
|
1310
1278
|
const saving = (0, react.useRef)(false);
|
|
1311
|
-
const legacyRegion = (0, react.useRef)(void 0);
|
|
1312
1279
|
const rootRef = (0, react.useRef)(null);
|
|
1313
1280
|
const directoryState = (0, react.useSyncExternalStore)((fn) => directory ? directory.subscribe(fn) : () => () => {}, () => directory ? directory.getSnapshot() : null);
|
|
1314
1281
|
const modelSnapshot = (0, react.useSyncExternalStore)((fn) => operations ? operations.subscribeModels(fn) : () => () => {}, () => operations ? operations.getModelSnapshot() : null);
|
|
@@ -1336,9 +1303,8 @@ window.__ModuleLoader__.load({
|
|
|
1336
1303
|
model: projectedCurrent.model
|
|
1337
1304
|
} : null);
|
|
1338
1305
|
if (!current) return null;
|
|
1339
|
-
const region = modelSnapshot?.value
|
|
1340
|
-
|
|
1341
|
-
const models = modelsOf(modelSnapshot?.value, region, legacyRegion.current ?? region);
|
|
1306
|
+
const region = regionOf(modelSnapshot?.value);
|
|
1307
|
+
const models = modelsOf(modelSnapshot?.value, region);
|
|
1342
1308
|
const currentModelId = current.model.includes("/") ? current.model.split("/")[1] : current.model;
|
|
1343
1309
|
const currentProviderId = current.provider ?? (current.model.includes("/") ? current.model.split("/")[0] : void 0);
|
|
1344
1310
|
const activeModel = models.find((m) => m.id === currentModelId || m.id === current.model);
|
|
@@ -1362,15 +1328,11 @@ window.__ModuleLoader__.load({
|
|
|
1362
1328
|
setPending(true);
|
|
1363
1329
|
setError(null);
|
|
1364
1330
|
try {
|
|
1365
|
-
|
|
1366
|
-
if (result !== "session-failed") setManualTiers((prev) => ({
|
|
1331
|
+
if (await saveContextSelection(operations, sessionId, region, activeModel.id, tierKey) === "saved") setManualTiers((prev) => ({
|
|
1367
1332
|
...prev,
|
|
1368
1333
|
[sessionKey]: tierKey
|
|
1369
1334
|
}));
|
|
1370
|
-
|
|
1371
|
-
key: sessionKey,
|
|
1372
|
-
message: result === "session-failed" ? "contextSelectFailed" : "contextDefaultFailed"
|
|
1373
|
-
});
|
|
1335
|
+
else setError({ key: sessionKey });
|
|
1374
1336
|
} finally {
|
|
1375
1337
|
saving.current = false;
|
|
1376
1338
|
setPending(false);
|
|
@@ -1425,7 +1387,7 @@ window.__ModuleLoader__.load({
|
|
|
1425
1387
|
error && error.key === sessionKey && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1426
1388
|
role: "alert",
|
|
1427
1389
|
className: QoderContextSelect_module_css_default.error,
|
|
1428
|
-
children: t ? t(
|
|
1390
|
+
children: t ? t("contextSelectFailed") : "contextSelectFailed"
|
|
1429
1391
|
}),
|
|
1430
1392
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1431
1393
|
className: QoderContextSelect_module_css_default.menu,
|
|
@@ -1634,10 +1596,7 @@ window.__ModuleLoader__.load({
|
|
|
1634
1596
|
storeModels: async (region, models) => {
|
|
1635
1597
|
try {
|
|
1636
1598
|
const current = modelScope.getSnapshot().value;
|
|
1637
|
-
const clonedModels = models.map(
|
|
1638
|
-
...m,
|
|
1639
|
-
...m.contextOptions !== void 0 ? { contextOptions: { ...m.contextOptions } } : {}
|
|
1640
|
-
}));
|
|
1599
|
+
const clonedModels = models.map(cloneCatalogModel);
|
|
1641
1600
|
return await modelScope.set("modelsByRegion", {
|
|
1642
1601
|
...current?.modelsByRegion,
|
|
1643
1602
|
[region]: clonedModels
|
|
@@ -1709,25 +1668,31 @@ window.__ModuleLoader__.load({
|
|
|
1709
1668
|
activeLocale
|
|
1710
1669
|
})
|
|
1711
1670
|
}, QoderCredentialCard));
|
|
1712
|
-
ctx.
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1671
|
+
ctx.inject([
|
|
1672
|
+
"modelDirectories",
|
|
1673
|
+
"sessions",
|
|
1674
|
+
"remote.session"
|
|
1675
|
+
], (scope) => {
|
|
1676
|
+
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
1677
|
+
name: "conversation.input.right",
|
|
1678
|
+
id: "qoder-context-select",
|
|
1679
|
+
order: 10,
|
|
1680
|
+
inject: (sessionId) => {
|
|
1681
|
+
let directory = void 0;
|
|
1682
|
+
try {
|
|
1683
|
+
const modelDirectories = scope.get("modelDirectories");
|
|
1684
|
+
directory = sessionId && modelDirectories ? modelDirectories.directoryFor(sessionId)?.store : void 0;
|
|
1685
|
+
} catch {}
|
|
1686
|
+
return {
|
|
1687
|
+
sessionId,
|
|
1688
|
+
directory,
|
|
1689
|
+
operations,
|
|
1690
|
+
t,
|
|
1691
|
+
activeLocale
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
}, QoderContextSelect));
|
|
1695
|
+
});
|
|
1731
1696
|
}
|
|
1732
1697
|
//#endregion
|
|
1733
1698
|
exports.apply = apply;
|
package/lib/index.d.ts
CHANGED
|
@@ -155,46 +155,6 @@ interface QoderAccountInfo {
|
|
|
155
155
|
updatedAt: string;
|
|
156
156
|
}
|
|
157
157
|
//#endregion
|
|
158
|
-
//#region src/qoder/transport/logging.d.ts
|
|
159
|
-
/** Bounded, redacted diagnostics internal to the Qoder transport. */
|
|
160
|
-
interface QoderLogger {
|
|
161
|
-
debug?(message: string, ...details: unknown[]): void;
|
|
162
|
-
warn?(message: string, ...details: unknown[]): void;
|
|
163
|
-
error?(message: string, ...details: unknown[]): void;
|
|
164
|
-
}
|
|
165
|
-
//#endregion
|
|
166
|
-
//#region src/qoder/transport/wire/cosy.d.ts
|
|
167
|
-
interface CosyCredentials {
|
|
168
|
-
userID: string;
|
|
169
|
-
authToken: string;
|
|
170
|
-
name: string;
|
|
171
|
-
email: string;
|
|
172
|
-
machineID?: string;
|
|
173
|
-
}
|
|
174
|
-
//#endregion
|
|
175
|
-
//#region src/qoder/transport/search.d.ts
|
|
176
|
-
interface QoderSearchClientOptions {
|
|
177
|
-
fetch?: typeof fetch;
|
|
178
|
-
region?: QoderRegion;
|
|
179
|
-
logger?: QoderLogger;
|
|
180
|
-
timeoutMs?: number;
|
|
181
|
-
resolveCredentials: (signal?: AbortSignal) => Promise<CosyCredentials>;
|
|
182
|
-
refreshCredentials?: (signal?: AbortSignal) => Promise<CosyCredentials>;
|
|
183
|
-
now?: () => number;
|
|
184
|
-
}
|
|
185
|
-
declare class QoderSearchClient {
|
|
186
|
-
private readonly fetchImpl;
|
|
187
|
-
private readonly region;
|
|
188
|
-
private readonly logger?;
|
|
189
|
-
private readonly timeoutMs;
|
|
190
|
-
private readonly resolveCredentials;
|
|
191
|
-
private readonly refreshCredentials?;
|
|
192
|
-
private readonly now;
|
|
193
|
-
constructor(options: QoderSearchClientOptions);
|
|
194
|
-
search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
|
|
195
|
-
private attempt;
|
|
196
|
-
}
|
|
197
|
-
//#endregion
|
|
198
158
|
//#region src/qoder/transport/index.d.ts
|
|
199
159
|
interface QoderTransport {
|
|
200
160
|
stream(options: GenerateOptions, model?: QoderCatalogModel): AsyncIterable<StreamChunk>;
|
|
@@ -210,16 +170,14 @@ interface QoderTransport {
|
|
|
210
170
|
declare const QODER_SEARCH_PROVIDER_ID = "qoder";
|
|
211
171
|
interface QoderSearchProviderOptions {
|
|
212
172
|
ctx: Context;
|
|
213
|
-
resolveTransport
|
|
214
|
-
searchClient?: QoderSearchClient;
|
|
173
|
+
resolveTransport: () => QoderTransport;
|
|
215
174
|
getWebSearchMode: () => QoderWebSearchMode;
|
|
216
175
|
fallbackProvider?: WebSearchProvider;
|
|
217
176
|
}
|
|
218
177
|
declare class QoderSearchProvider implements WebSearchProvider {
|
|
219
178
|
readonly id = "qoder";
|
|
220
179
|
private readonly ctx;
|
|
221
|
-
private readonly resolveTransport
|
|
222
|
-
private readonly searchClient?;
|
|
180
|
+
private readonly resolveTransport;
|
|
223
181
|
private readonly getWebSearchMode;
|
|
224
182
|
private readonly fallbackProvider?;
|
|
225
183
|
constructor(options: QoderSearchProviderOptions);
|
package/lib/index.js
CHANGED
|
@@ -32,6 +32,9 @@ const reasoningEffortOrder = /* @__PURE__ */ new Map([
|
|
|
32
32
|
function positiveNumber(value) {
|
|
33
33
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
34
34
|
}
|
|
35
|
+
function nonNegativeNumber(value) {
|
|
36
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
37
|
+
}
|
|
35
38
|
function contextOptionsOf(value) {
|
|
36
39
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
37
40
|
const options = {};
|
|
@@ -42,8 +45,8 @@ function contextOptionsOf(value) {
|
|
|
42
45
|
const isDefault = typeof entry.is_default === "boolean" ? entry.is_default : void 0;
|
|
43
46
|
if (tokenCount === void 0) continue;
|
|
44
47
|
options[key] = {
|
|
45
|
-
|
|
46
|
-
...isDefault
|
|
48
|
+
tokenCount,
|
|
49
|
+
...isDefault !== void 0 ? { isDefault } : {}
|
|
47
50
|
};
|
|
48
51
|
}
|
|
49
52
|
if (Object.keys(options).length === 0) return void 0;
|
|
@@ -96,9 +99,9 @@ function normalizeQoderModels(payload, onConflict) {
|
|
|
96
99
|
const contextWindow = (defaultOptions.length === 1 ? defaultOptions[0].tokenCount : void 0) ?? positiveNumber(raw.max_input_tokens) ?? 18e4;
|
|
97
100
|
const maxContextWindow = Math.max(positiveNumber(raw.max_input_tokens) ?? 0, contextWindow, ...Object.values(contextOptions ?? {}).map((option) => option.tokenCount ?? 0));
|
|
98
101
|
const isReasoning = thinkingDefault(raw.thinking_config, raw.is_reasoning === true, onConflict);
|
|
99
|
-
const priceFactor =
|
|
100
|
-
const rawOriginalPrice =
|
|
101
|
-
const promotionPrice = typeof raw.promotion === "object" && raw.promotion !== null && raw.promotion.active === true
|
|
102
|
+
const priceFactor = nonNegativeNumber(raw.price_factor) ?? nonNegativeNumber(raw.priceFactor);
|
|
103
|
+
const rawOriginalPrice = nonNegativeNumber(raw.original_price_factor) ?? nonNegativeNumber(raw.originPriceFactor);
|
|
104
|
+
const promotionPrice = typeof raw.promotion === "object" && raw.promotion !== null && raw.promotion.active === true ? nonNegativeNumber(raw.promotion.before_promotion_price_factor) : void 0;
|
|
102
105
|
const originalPriceFactor = rawOriginalPrice ?? promotionPrice;
|
|
103
106
|
const isFree = raw.is_free === true || raw.isFree === true || Array.isArray(raw.tags) && raw.tags.includes("limited_time_free") || priceFactor === 0;
|
|
104
107
|
const reasoning = reasoningEffortsOf(raw.thinking_config);
|
|
@@ -187,28 +190,40 @@ function selectedContextTier(model) {
|
|
|
187
190
|
function effectiveContextWindow(model) {
|
|
188
191
|
return selectedContextTier(model)?.tokenCount ?? model.contextWindow;
|
|
189
192
|
}
|
|
193
|
+
/** Clone a model catalog entry, detaching any contextOptions object. */
|
|
194
|
+
function cloneCatalogModel(model) {
|
|
195
|
+
return {
|
|
196
|
+
...model,
|
|
197
|
+
...model.contextOptions !== void 0 ? { contextOptions: { ...model.contextOptions } } : {}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/** Carry subscriber context choices only while the refreshed catalog supports them. */
|
|
201
|
+
function mergeAdvertisedContext(remembered, advertised, updated) {
|
|
202
|
+
const merged = { ...updated };
|
|
203
|
+
delete merged.contextOptions;
|
|
204
|
+
delete merged.contextTier;
|
|
205
|
+
if (advertised.contextOptions !== void 0) merged.contextOptions = { ...advertised.contextOptions };
|
|
206
|
+
const tier = selectedContextTier({
|
|
207
|
+
contextTier: remembered.contextTier,
|
|
208
|
+
contextOptions: merged.contextOptions
|
|
209
|
+
});
|
|
210
|
+
if (tier !== void 0) {
|
|
211
|
+
merged.contextTier = tier.key;
|
|
212
|
+
merged.contextWindow = tier.tokenCount;
|
|
213
|
+
} else if (advertised.contextWindow !== void 0) merged.contextWindow = remembered.contextTier !== void 0 ? advertised.contextWindow : Math.min(remembered.contextWindow ?? advertised.contextWindow, advertised.contextWindow);
|
|
214
|
+
return merged;
|
|
215
|
+
}
|
|
190
216
|
function mergeQoderDiscoveryMetadata(configured, discovered) {
|
|
191
217
|
const catalog = new Map(discovered.map((model) => [model.id, model]));
|
|
192
218
|
return configured.map((model) => {
|
|
193
219
|
const advertised = catalog.get(model.id);
|
|
194
|
-
if (advertised === void 0) return
|
|
195
|
-
...model,
|
|
196
|
-
...model.contextOptions !== void 0 ? { contextOptions: { ...model.contextOptions } } : {}
|
|
197
|
-
};
|
|
220
|
+
if (advertised === void 0) return cloneCatalogModel(model);
|
|
198
221
|
const merged = { ...model };
|
|
199
|
-
for (const key of discoveredMetadataKeys)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const tier = selectedContextTier(merged);
|
|
205
|
-
if (tier !== void 0) {
|
|
206
|
-
merged.contextWindow = tier.tokenCount;
|
|
207
|
-
return merged;
|
|
208
|
-
}
|
|
209
|
-
delete merged.contextTier;
|
|
210
|
-
if (advertised.contextWindow !== void 0) merged.contextWindow = Math.min(model.contextWindow ?? advertised.contextWindow, advertised.contextWindow);
|
|
211
|
-
return merged;
|
|
222
|
+
for (const key of discoveredMetadataKeys) if (key !== "contextOptions") {
|
|
223
|
+
delete merged[key];
|
|
224
|
+
if (advertised[key] !== void 0) Object.assign(merged, { [key]: advertised[key] });
|
|
225
|
+
}
|
|
226
|
+
return mergeAdvertisedContext(model, advertised, merged);
|
|
212
227
|
});
|
|
213
228
|
}
|
|
214
229
|
function hasSameQoderDiscoveryMetadata(left, right) {
|
|
@@ -3233,11 +3248,7 @@ var QoderAdapter = class extends LlmAdapter {
|
|
|
3233
3248
|
const base = this.effectiveModels().find((candidate) => candidate.id === modelId);
|
|
3234
3249
|
if (base === void 0) return void 0;
|
|
3235
3250
|
if (sessionId) {
|
|
3236
|
-
const manualTierKey = this.
|
|
3237
|
-
this.region(),
|
|
3238
|
-
sessionId,
|
|
3239
|
-
modelId
|
|
3240
|
-
]));
|
|
3251
|
+
const manualTierKey = this.getSessionTier(sessionId, modelId);
|
|
3241
3252
|
const reqCtx = this.sessions?.get(sessionId)?.requestContext?.();
|
|
3242
3253
|
const tier = resolveContextTier(base, manualTierKey, !this.historyRegionChanged && reqCtx?.provider === this.providerId && reqCtx.model === modelId ? reqCtx.contextWindow : void 0);
|
|
3243
3254
|
if (tier) return {
|
|
@@ -3283,8 +3294,7 @@ var QoderAdapter = class extends LlmAdapter {
|
|
|
3283
3294
|
*/
|
|
3284
3295
|
publishDiscoveredModels(transport, models) {
|
|
3285
3296
|
try {
|
|
3286
|
-
|
|
3287
|
-
if (pending !== void 0 && pending !== null && typeof pending.catch === "function") pending.catch(() => {});
|
|
3297
|
+
Promise.resolve(this.onModelsDiscovered?.(transport, models)).catch(() => {});
|
|
3288
3298
|
} catch {}
|
|
3289
3299
|
}
|
|
3290
3300
|
effectiveModels() {
|
|
@@ -3360,17 +3370,23 @@ var QoderAdapter = class extends LlmAdapter {
|
|
|
3360
3370
|
* @module dsh-provider-qoder/dsh/search-provider
|
|
3361
3371
|
*/
|
|
3362
3372
|
const QODER_SEARCH_PROVIDER_ID = "qoder";
|
|
3373
|
+
function initiatingModelProvider(ctx) {
|
|
3374
|
+
const agent = (ctx.get("agents") ?? ctx.agents)?.currentInitiator?.();
|
|
3375
|
+
const defaultModelService = ctx.get("agentDefaultModel");
|
|
3376
|
+
return agent?.options?.provider ?? defaultModelService?.get?.()?.provider;
|
|
3377
|
+
}
|
|
3378
|
+
function shouldUseQoderSearch(mode, provider) {
|
|
3379
|
+
return mode === "always" || mode === "auto" && provider === "dsh-provider-qoder";
|
|
3380
|
+
}
|
|
3363
3381
|
var QoderSearchProvider = class {
|
|
3364
3382
|
id = QODER_SEARCH_PROVIDER_ID;
|
|
3365
3383
|
ctx;
|
|
3366
3384
|
resolveTransport;
|
|
3367
|
-
searchClient;
|
|
3368
3385
|
getWebSearchMode;
|
|
3369
3386
|
fallbackProvider;
|
|
3370
3387
|
constructor(options) {
|
|
3371
3388
|
this.ctx = options.ctx;
|
|
3372
3389
|
this.resolveTransport = options.resolveTransport;
|
|
3373
|
-
this.searchClient = options.searchClient;
|
|
3374
3390
|
this.getWebSearchMode = options.getWebSearchMode;
|
|
3375
3391
|
this.fallbackProvider = options.fallbackProvider;
|
|
3376
3392
|
}
|
|
@@ -3380,13 +3396,15 @@ var QoderSearchProvider = class {
|
|
|
3380
3396
|
async search(request, signal) {
|
|
3381
3397
|
const mode = this.getWebSearchMode();
|
|
3382
3398
|
if (mode === "disabled") throw new WebError("Qoder web search is disabled in settings.", "WEB_PROVIDER_UNAVAILABLE");
|
|
3383
|
-
const
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3399
|
+
const providerRoute = initiatingModelProvider(this.ctx);
|
|
3400
|
+
if (shouldUseQoderSearch(mode, providerRoute)) {
|
|
3401
|
+
const result = await this.resolveTransport().searchWeb(request, signal);
|
|
3402
|
+
if (request.maxResults === void 0 || result.sources.length <= request.maxResults) return result;
|
|
3403
|
+
return {
|
|
3404
|
+
...result,
|
|
3405
|
+
sources: result.sources.slice(0, request.maxResults),
|
|
3406
|
+
truncated: true
|
|
3407
|
+
};
|
|
3390
3408
|
}
|
|
3391
3409
|
const fallback = this.resolveFallback();
|
|
3392
3410
|
if (fallback && fallback.available()) return fallback.search(request, signal);
|
|
@@ -3554,6 +3572,26 @@ function publicError(code, message, details = { issues: [] }) {
|
|
|
3554
3572
|
}
|
|
3555
3573
|
};
|
|
3556
3574
|
}
|
|
3575
|
+
async function executeRpc(operation, task, signal, logger) {
|
|
3576
|
+
try {
|
|
3577
|
+
return {
|
|
3578
|
+
ok: true,
|
|
3579
|
+
value: await task()
|
|
3580
|
+
};
|
|
3581
|
+
} catch (error) {
|
|
3582
|
+
if (signal.aborted || error instanceof QoderLlmError && error.code === "ABORTED") {
|
|
3583
|
+
logger?.debug?.(`[Qoder RPC] ${operation} was aborted`);
|
|
3584
|
+
return publicError("ABORTED", "Request aborted");
|
|
3585
|
+
}
|
|
3586
|
+
let code = "INTERNAL";
|
|
3587
|
+
if (error instanceof QoderLlmError) if (error.code === "MISSING_CREDENTIAL" || error.code === "NO_CREDENTIALS") code = "NO_CREDENTIALS";
|
|
3588
|
+
else if (error.code === "AUTH") code = "UNAUTHENTICATED";
|
|
3589
|
+
else if (error.code === "TIMEOUT") code = "TIMEOUT";
|
|
3590
|
+
else code = "UPSTREAM_ERROR";
|
|
3591
|
+
logger?.error?.(`[Qoder RPC] Failed to ${operation}`, logError(error));
|
|
3592
|
+
return publicError(code, error instanceof Error ? error.message : `Failed to ${operation}`);
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3557
3595
|
function apply(ctx, input = {}) {
|
|
3558
3596
|
const config = readConfig(input);
|
|
3559
3597
|
const logger = ctx.logger;
|
|
@@ -3699,27 +3737,7 @@ function apply(ctx, input = {}) {
|
|
|
3699
3737
|
const handler = async (endpoint, payload, signal) => {
|
|
3700
3738
|
if (!isQoderRpcEndpoint(endpoint)) return publicError("UNKNOWN_ENDPOINT", `Unknown endpoint: ${endpoint}`);
|
|
3701
3739
|
if (signal.aborted) return publicError("ABORTED", "Request aborted");
|
|
3702
|
-
|
|
3703
|
-
try {
|
|
3704
|
-
return {
|
|
3705
|
-
ok: true,
|
|
3706
|
-
value: await task()
|
|
3707
|
-
};
|
|
3708
|
-
} catch (error) {
|
|
3709
|
-
if (signal.aborted || error instanceof QoderLlmError && error.code === "ABORTED") {
|
|
3710
|
-
logger?.debug?.(`[Qoder RPC] ${operation} was aborted`);
|
|
3711
|
-
return publicError("ABORTED", "Request aborted");
|
|
3712
|
-
}
|
|
3713
|
-
let code = "INTERNAL";
|
|
3714
|
-
if (error instanceof QoderLlmError) if (error.code === "MISSING_CREDENTIAL" || error.code === "NO_CREDENTIALS") code = "NO_CREDENTIALS";
|
|
3715
|
-
else if (error.code === "AUTH") code = "UNAUTHENTICATED";
|
|
3716
|
-
else if (error.code === "TIMEOUT") code = "TIMEOUT";
|
|
3717
|
-
else code = "UPSTREAM_ERROR";
|
|
3718
|
-
logger?.error?.(`[Qoder RPC] Failed to ${operation}`, logError(error));
|
|
3719
|
-
return publicError(code, error instanceof Error ? error.message : `Failed to ${operation}`);
|
|
3720
|
-
}
|
|
3721
|
-
};
|
|
3722
|
-
if (endpoint === "models") return await executeRpc("discover Qoder models", () => discoverModels(signal));
|
|
3740
|
+
if (endpoint === "models") return await executeRpc("discover Qoder models", () => discoverModels(signal), signal, logger);
|
|
3723
3741
|
if (endpoint === "sessionTier") {
|
|
3724
3742
|
const data = payload;
|
|
3725
3743
|
if (typeof data?.sessionId === "string" && typeof data?.modelId === "string" && typeof data?.tierKey === "string" && (data.region === "global" || data.region === "china")) {
|
|
@@ -3727,7 +3745,7 @@ function apply(ctx, input = {}) {
|
|
|
3727
3745
|
return await executeRpc("select session context tier", async () => {
|
|
3728
3746
|
adapter.setSessionTier(sessionId, modelId, tierKey, region);
|
|
3729
3747
|
return { success: true };
|
|
3730
|
-
});
|
|
3748
|
+
}, signal, logger);
|
|
3731
3749
|
}
|
|
3732
3750
|
return publicError("INTERNAL", "Invalid sessionTier payload");
|
|
3733
3751
|
}
|
|
@@ -3736,7 +3754,7 @@ function apply(ctx, input = {}) {
|
|
|
3736
3754
|
const outcome = await executeRpc("load Qoder account", () => activeTransport.readAccount({
|
|
3737
3755
|
force,
|
|
3738
3756
|
signal
|
|
3739
|
-
}));
|
|
3757
|
+
}), signal, logger);
|
|
3740
3758
|
if (outcome.ok) logger?.debug?.("[Qoder RPC] Subscriber account resolved");
|
|
3741
3759
|
return outcome;
|
|
3742
3760
|
};
|
|
@@ -3753,19 +3771,15 @@ function apply(ctx, input = {}) {
|
|
|
3753
3771
|
});
|
|
3754
3772
|
webCtx.web.registerSearchProvider(searchProvider);
|
|
3755
3773
|
if (typeof webCtx.web.search === "function") {
|
|
3756
|
-
const originalSearch = webCtx.web.search
|
|
3774
|
+
const originalSearch = webCtx.web.search;
|
|
3757
3775
|
webCtx.effect(() => {
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
const agent = (ctx.get("agents") ?? ctx.agents)?.currentInitiator?.();
|
|
3762
|
-
const defaultModelService = ctx.get("agentDefaultModel");
|
|
3763
|
-
const isQoderActive = (agent?.options?.provider ?? defaultModelService?.get?.()?.provider) === providerQoder;
|
|
3764
|
-
if (mode === "always" || isQoderActive) return searchProvider.search(request, signal);
|
|
3765
|
-
return originalSearch(request, signal);
|
|
3776
|
+
const routedSearch = async (request, signal) => {
|
|
3777
|
+
if (shouldUseQoderSearch(resolveConfig().webSearchMode ?? "auto", initiatingModelProvider(ctx))) return searchProvider.search(request, signal);
|
|
3778
|
+
return originalSearch.call(webCtx.web, request, signal);
|
|
3766
3779
|
};
|
|
3780
|
+
webCtx.web.search = routedSearch;
|
|
3767
3781
|
return () => {
|
|
3768
|
-
webCtx.web.search = originalSearch;
|
|
3782
|
+
if (webCtx.web.search === routedSearch) webCtx.web.search = originalSearch;
|
|
3769
3783
|
};
|
|
3770
3784
|
}, "provider-qoder: transparent web search router");
|
|
3771
3785
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-provider-qoder",
|
|
3
3
|
"description": "Global Qoder subscription adapter for the DeepSeek Harness LLM seam",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"qoder"
|
|
19
19
|
],
|
|
20
20
|
"type": "module",
|
|
21
|
+
"engines": {
|
|
22
|
+
"dsh": ">=0.1.7-rc.2",
|
|
23
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
24
|
+
},
|
|
21
25
|
"scripts": {
|
|
22
26
|
"dev": "tsdown --config tsdown.config.mjs --watch",
|
|
23
27
|
"typecheck": "tsc --noEmit",
|
|
@@ -65,23 +69,21 @@
|
|
|
65
69
|
},
|
|
66
70
|
"license": "MIT",
|
|
67
71
|
"peerDependencies": {
|
|
68
|
-
"@deepseek-ai/cordis": ">=4.0.4
|
|
69
|
-
"@deepseek-ai/dsh-api-remotes": ">=0.1.7-rc.2
|
|
70
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.2
|
|
71
|
-
"@deepseek-ai/dsh-client-connection": ">=0.1.7-rc.2
|
|
72
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.2
|
|
73
|
-
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.7-rc.2
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.2
|
|
75
|
-
"@deepseek-ai/dsh-credentials": ">=0.1.7-rc.2
|
|
76
|
-
"@deepseek-ai/dsh-invariants": ">=0.1.7-rc.2
|
|
77
|
-
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.2
|
|
78
|
-
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.2
|
|
79
|
-
"@deepseek-ai/dsh-web": ">=0.1.7-rc.2
|
|
72
|
+
"@deepseek-ai/cordis": ">=4.0.4",
|
|
73
|
+
"@deepseek-ai/dsh-api-remotes": ">=0.1.7-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.2",
|
|
75
|
+
"@deepseek-ai/dsh-client-connection": ">=0.1.7-rc.2",
|
|
76
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.2",
|
|
77
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.7-rc.2",
|
|
78
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.2",
|
|
79
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.7-rc.2",
|
|
80
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.7-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.2",
|
|
82
|
+
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.2",
|
|
83
|
+
"@deepseek-ai/dsh-web": ">=0.1.7-rc.2",
|
|
84
|
+
"@deepseek-ai/schemastery": "~3.18.4",
|
|
80
85
|
"react": "^18.2.0"
|
|
81
86
|
},
|
|
82
|
-
"dependencies": {
|
|
83
|
-
"@deepseek-ai/schemastery": "3.18.4"
|
|
84
|
-
},
|
|
85
87
|
"devDependencies": {
|
|
86
88
|
"@deepseek-ai/cordis": "4.0.4",
|
|
87
89
|
"@deepseek-ai/cordis-plugin-loader": "1.0.5",
|
|
@@ -101,6 +103,7 @@
|
|
|
101
103
|
"@deepseek-ai/dsh-session": "0.1.7-rc.2",
|
|
102
104
|
"@deepseek-ai/dsh-settings": "0.1.7-rc.2",
|
|
103
105
|
"@deepseek-ai/dsh-web": "0.1.7-rc.2",
|
|
106
|
+
"@deepseek-ai/schemastery": "3.18.4",
|
|
104
107
|
"@types/node": "24.3.0",
|
|
105
108
|
"@types/react": "18.3.1",
|
|
106
109
|
"lightningcss": "^1.33.0",
|