dsh-agentone 0.5.29 → 0.5.31
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 +6 -0
- package/lib/index.js +4 -0
- package/lib/language.js +71 -0
- package/lib/model.js +25 -9
- package/lib/store.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -36,6 +36,11 @@ lark-cli / ccpg-cli 状态探测。
|
|
|
36
36
|
ccpg 走公司 `auto-install.sh`,口径与平台 cli-deployd 一致);
|
|
37
37
|
已装未授权时「去授权」发起官方 Device Flow(授权链接 + ASCII 二维码 +
|
|
38
38
|
验证码 + 自动轮询确认,设备码仅存插件进程内存)。
|
|
39
|
+
- **全局中文回复默认**:插件启动时在 `$DSH_HOME/AGENTS.md` 注入受标记
|
|
40
|
+
管理的「默认始终使用中文回复」指令块(dsh 官方 agent-instructions 机制,
|
|
41
|
+
每个会话基线加载,project 级指令优先);幂等不重复注入,用户已有语言
|
|
42
|
+
偏好或删除标记块后不再介入(本机只做一次决策,记录于
|
|
43
|
+
`$DSH_HOME/agentone/language-default.json`)。
|
|
39
44
|
- **首启引导**:dsh 首次启动弹出飞书登录引导(order -50,早于官方
|
|
40
45
|
「添加 API Key」),登录一次即跳过官方密钥引导;暗色主题适配。
|
|
41
46
|
|
|
@@ -104,6 +109,7 @@ lib/
|
|
|
104
109
|
page.js 状态页与授权完成页的 HTML/CSS/JS 模板(纯静态)
|
|
105
110
|
http.js 平台请求统一通道(超时、错误码透传)
|
|
106
111
|
auth.js 登录流、令牌轮换/吊销、能力面/套餐 API
|
|
112
|
+
language.js 全局中文回复默认($DSH_HOME/AGENTS.md 受标记管理注入)
|
|
107
113
|
model.js 平台模型 → settings.yaml / .credentials.yaml
|
|
108
114
|
skill.js 技能下载/解包/卸载(zip 穿越清洗、原子落盘)
|
|
109
115
|
store.js 凭据持久化(0600;损坏自动移开)
|
package/lib/index.js
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
import { applyPlatformModel, removePlatformModel } from './model.js';
|
|
32
32
|
import { installPlatformSkill, listPlatformSkills, removePlatformSkill } from './skill.js';
|
|
33
33
|
import { applyPlatformSkillhub, removePlatformSkillhub } from './skillhub.js';
|
|
34
|
+
import { ensureLanguageDefault } from './language.js';
|
|
34
35
|
import { beginCliAuth, cliAuthQrcode, completeCliAuth, parseCliAuthBeginOutput } from './cliauth.mjs';
|
|
35
36
|
import { platformFetch } from './http.js';
|
|
36
37
|
import { donePageHtml, statusPageHtml } from './page.js';
|
|
@@ -1508,6 +1509,9 @@ export function apply(ctx, config) {
|
|
|
1508
1509
|
ensureBuiltinPlugins(config, log).catch((error) => {
|
|
1509
1510
|
log.warn(`[dsh-agentone] builtin plugin check failed: ${error?.message || error}`);
|
|
1510
1511
|
});
|
|
1512
|
+
ensureLanguageDefault(config, log).catch((error) => {
|
|
1513
|
+
log.warn(`[dsh-agentone] language default check failed: ${error?.message || error}`);
|
|
1514
|
+
});
|
|
1511
1515
|
(async () => {
|
|
1512
1516
|
const credentials = await ensureFreshToken(config, log);
|
|
1513
1517
|
if (!credentials) return;
|
package/lib/language.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// 全局中文回复默认(#423):在 $DSH_HOME/AGENTS.md 注入受标记管理的指令块。
|
|
2
|
+
//
|
|
3
|
+
// dsh 没有原生「回复语言」设置(locale.preference 只是 UI 字典语言,不进
|
|
4
|
+
// 模型请求);官方全局指令机制是 agent-instructions 插件把 $DSH_HOME/AGENTS.md
|
|
5
|
+
// 作为用户全局基线注入每个会话,project 级 AGENTS.md/CLAUDE.md 更具体、优先
|
|
6
|
+
// 更高——天然满足「全局默认中文、更具体指令可覆盖」。
|
|
7
|
+
//
|
|
8
|
+
// 永不覆盖用户,本机只做一次决策(flag 落 storeDir/language-default.json):
|
|
9
|
+
// 标记块已存在 → no-op
|
|
10
|
+
// flag 已写但标记块被用户删除 → no-op(不与用户拉锯)
|
|
11
|
+
// 既有内容含语言偏好关键词 → 记 skipped,no-op
|
|
12
|
+
// 其余(含文件不存在) → 追加/创建标记块,记 applied
|
|
13
|
+
// 任何失败只记日志,绝不阻断启动。
|
|
14
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
15
|
+
import { dirname, join } from 'node:path';
|
|
16
|
+
|
|
17
|
+
import { resolveDshHome, storeDir } from './store.js';
|
|
18
|
+
|
|
19
|
+
const MARKER_BEGIN = '<!-- dsh-agentone:language-default begin -->';
|
|
20
|
+
const MARKER_END = '<!-- dsh-agentone:language-default end -->';
|
|
21
|
+
/** 用户显式语言偏好的宽松信号:命中即假定用户自管语言,插件不介入。 */
|
|
22
|
+
const LANGUAGE_HINT = /中文|汉语|英文|英语|Chinese|English|language|语言|respond in|reply in/i;
|
|
23
|
+
|
|
24
|
+
function languageBlock() {
|
|
25
|
+
return [
|
|
26
|
+
MARKER_BEGIN,
|
|
27
|
+
'- 默认始终使用中文回复(dsh-agentone 注入;删除本块并重启 dsh 即取消)。',
|
|
28
|
+
MARKER_END,
|
|
29
|
+
].join('\n');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function writeAtomic(path, text) {
|
|
33
|
+
await mkdir(dirname(path), { recursive: true });
|
|
34
|
+
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
35
|
+
await writeFile(tmp, text, 'utf8');
|
|
36
|
+
await rename(tmp, path);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 确保全局中文回复默认就位。幂等;返回决策结果供测试与日志核对。
|
|
41
|
+
*/
|
|
42
|
+
export async function ensureLanguageDefault(config, log = console) {
|
|
43
|
+
const agentsPath = join(resolveDshHome(), 'AGENTS.md');
|
|
44
|
+
const flagPath = join(storeDir(config), 'language-default.json');
|
|
45
|
+
let content = '';
|
|
46
|
+
try {
|
|
47
|
+
content = await readFile(agentsPath, 'utf8');
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
50
|
+
}
|
|
51
|
+
if (content.includes(MARKER_BEGIN)) return 'present';
|
|
52
|
+
try {
|
|
53
|
+
await readFile(flagPath, 'utf8');
|
|
54
|
+
// 决策已做过而标记块不在了:用户主动删除,尊重之。
|
|
55
|
+
return 'user-removed';
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
58
|
+
}
|
|
59
|
+
if (content.trim() && LANGUAGE_HINT.test(content)) {
|
|
60
|
+
await writeAtomic(flagPath, `${JSON.stringify({ status: 'skipped-user-pref' }, null, 2)}\n`);
|
|
61
|
+
log.info('[dsh-agentone] AGENTS.md 已有语言偏好,跳过中文默认注入');
|
|
62
|
+
return 'skipped-user-pref';
|
|
63
|
+
}
|
|
64
|
+
const next = content.trim()
|
|
65
|
+
? `${content.replace(/\s+$/, '')}\n\n${languageBlock()}\n`
|
|
66
|
+
: `${languageBlock()}\n`;
|
|
67
|
+
await writeAtomic(agentsPath, next);
|
|
68
|
+
await writeAtomic(flagPath, `${JSON.stringify({ status: 'applied' }, null, 2)}\n`);
|
|
69
|
+
log.info('[dsh-agentone] 已注入全局中文回复默认(AGENTS.md)');
|
|
70
|
+
return 'applied';
|
|
71
|
+
}
|
package/lib/model.js
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
// settings.yaml llm-pi-ai.providers.platform + agent-default-model
|
|
6
6
|
// .credentials.yaml refs.AGENTONE_API_KEY(dsh 凭据库,owner-only,watch 热加载)
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
8
|
+
// 密钥形态:平台 /api/plugin/v1/models 下发 direct(Token Hub base_url + 该用户
|
|
9
|
+
// 自己的 Token Hub 用户级 key),dsh 直连 Token Hub,运行时流量不过境平台(平台
|
|
10
|
+
// 部署国外时避免跨境转发延迟);计量/配额由 Token Hub 按用户令牌口径执行。
|
|
11
|
+
// 旧版平台不下发 direct 时回退为 30 天插件令牌 + 平台 /api/plugin/v1 代理。
|
|
10
12
|
import { readFile, rename, writeFile } from 'node:fs/promises';
|
|
11
13
|
import { join } from 'node:path';
|
|
12
14
|
import { parse, stringify } from 'yaml';
|
|
@@ -77,8 +79,13 @@ function parseYamlObject(text) {
|
|
|
77
79
|
return {};
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
/** 合并出 settings.yaml 文本:覆盖 platform provider 与 agent-default-model。
|
|
81
|
-
|
|
82
|
+
/** 合并出 settings.yaml 文本:覆盖 platform provider 与 agent-default-model。
|
|
83
|
+
* direct(直连 Token Hub)时写 compat.supportsDeveloperRole=false:pi-ai 对
|
|
84
|
+
* reasoning 模型默认把系统提示发成 developer 角色(自定义域名不在它的
|
|
85
|
+
* 非标准名单里),GLM 上游只认 system 会 400;false 保持 system。该配置键
|
|
86
|
+
* 需要 dsh-llm-pi-ai ≥ 0.1.0-rc.8,代理模式不写(网关侧有同样的归一化)。
|
|
87
|
+
*/
|
|
88
|
+
export function buildSettingsYaml(existingText, { baseUrl, models, defaultModel, direct = false }) {
|
|
82
89
|
const settings = parseYamlObject(existingText);
|
|
83
90
|
const existing = settings['llm-pi-ai'];
|
|
84
91
|
const llmPiAi =
|
|
@@ -90,6 +97,7 @@ export function buildSettingsYaml(existingText, { baseUrl, models, defaultModel
|
|
|
90
97
|
apiKeyEnv: CREDENTIAL_REF,
|
|
91
98
|
api: 'openai-completions',
|
|
92
99
|
baseURL: baseUrl,
|
|
100
|
+
...(direct ? { compat: { supportsDeveloperRole: false } } : {}),
|
|
93
101
|
reasoning: 'high',
|
|
94
102
|
models: models
|
|
95
103
|
.map((item) => platformModelEntry(item))
|
|
@@ -151,7 +159,11 @@ export async function fetchPlatformModels(platformUrl, accessToken) {
|
|
|
151
159
|
.filter(Boolean)
|
|
152
160
|
: [];
|
|
153
161
|
if (models.length === 0) throw new Error('平台返回的可用模型列表为空');
|
|
154
|
-
|
|
162
|
+
const direct =
|
|
163
|
+
data.direct && typeof data.direct.base_url === 'string' && typeof data.direct.api_key === 'string'
|
|
164
|
+
? { baseUrl: data.direct.base_url.replace(/\/+$/, ''), apiKey: data.direct.api_key }
|
|
165
|
+
: null;
|
|
166
|
+
return { models, defaultModel: data.default_model || (models[0]?.id ?? models[0]), direct };
|
|
155
167
|
}
|
|
156
168
|
|
|
157
169
|
async function writeFileAtomic(path, text, mode) {
|
|
@@ -172,11 +184,15 @@ function tmpName(path) {
|
|
|
172
184
|
export async function applyPlatformModel(config) {
|
|
173
185
|
const credentials = await loadCredentials(config);
|
|
174
186
|
if (!credentials) throw new Error('尚未登录平台');
|
|
175
|
-
const
|
|
176
|
-
const { models, defaultModel } = await fetchPlatformModels(
|
|
187
|
+
const { models, defaultModel, direct } = await fetchPlatformModels(
|
|
177
188
|
credentials.platform_url || config.platformUrl,
|
|
178
189
|
credentials.access_token,
|
|
179
190
|
);
|
|
191
|
+
// 平台下发 direct 时 dsh 直连 Token Hub;否则回退平台代理(旧版平台)。
|
|
192
|
+
const baseUrl = direct
|
|
193
|
+
? direct.baseUrl
|
|
194
|
+
: `${String(credentials.platform_url || config.platformUrl).replace(/\/+$/, '')}/api/plugin/v1`;
|
|
195
|
+
const providerKey = direct ? direct.apiKey : credentials.access_token;
|
|
180
196
|
const home = resolveDshHome(config);
|
|
181
197
|
const settingsPath = join(home, 'settings.yaml');
|
|
182
198
|
const credentialsPath = join(home, '.credentials.yaml');
|
|
@@ -184,10 +200,10 @@ export async function applyPlatformModel(config) {
|
|
|
184
200
|
readFile(settingsPath, 'utf8').catch(() => ''),
|
|
185
201
|
readFile(credentialsPath, 'utf8').catch(() => ''),
|
|
186
202
|
]);
|
|
187
|
-
await writeFileAtomic(credentialsPath, buildCredentialsYaml(existingCredentials,
|
|
203
|
+
await writeFileAtomic(credentialsPath, buildCredentialsYaml(existingCredentials, providerKey), 0o600);
|
|
188
204
|
await writeFileAtomic(
|
|
189
205
|
settingsPath,
|
|
190
|
-
buildSettingsYaml(existingSettings, { baseUrl, models, defaultModel }),
|
|
206
|
+
buildSettingsYaml(existingSettings, { baseUrl, models, defaultModel, direct: direct !== null }),
|
|
191
207
|
);
|
|
192
208
|
return { models, defaultModel };
|
|
193
209
|
}
|
package/lib/store.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-agentone",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "AgentOne
|
|
3
|
+
"version": "0.5.31",
|
|
4
|
+
"description": "AgentOne 平台集成插件:飞书登录、平台模型(直连 Token Hub 不过境平台、同步失败自愈重试)、SkillHub 技能(升级检测一键升级、装后即时刷新、套餐技能自动同步)、套餐申请、插件管理与自助升级、lark-cli / ccpg-cli 探测与一键安装(请求超时与错误码透传、令牌轮换 single-flight、凭据损坏容错与并发安全写入、状态页 UX 增强、全局中文回复默认(AGENTS.md 受标记管理、永不覆盖用户设置))",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"smoke": "node scripts/env-matrix-smoke.mjs"
|