dsh-model-headers 0.2.0 → 0.2.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/lib/client.js +4 -4
- package/lib/index.js +42 -29
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 设置页 section「模型请求头」:
|
|
5
5
|
* - 规则卡片列表(双列):启停开关 / 模型通配符 / 头摘要 / 编辑 / 删除(二次确认)
|
|
6
6
|
* - 添加·编辑弹框:模型下拉(combobox:点选 settings.yaml 现有模型 / 推导通配符 / 手输任意)+ 头键值行(值可插入 ${sessionId} 变量)
|
|
7
|
-
* - 通信:
|
|
7
|
+
* - 通信:dsh v0.1.5 的 /api 通道 POST /api/model-headers/*,信封 {ok, value | error{message}}
|
|
8
8
|
* - 挂载点:settings.section 槽位(order 100,排在「技能与MCP」之后)。
|
|
9
9
|
*/
|
|
10
10
|
window.__ModuleLoader__.load({
|
|
@@ -17,13 +17,13 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
|
|
18
18
|
const INJECT = ["slots", "connection"];
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
const
|
|
20
|
+
/** dsh v0.1.5:浏览器侧统一走 /api 通道,endpoint 带插件前缀。 */
|
|
21
|
+
const RPC_PREFIX = "model-headers";
|
|
22
22
|
|
|
23
23
|
let hostCtx = null;
|
|
24
24
|
|
|
25
25
|
async function callApi(endpoint, body = {}) {
|
|
26
|
-
const result = await hostCtx.connection.rpc.call(
|
|
26
|
+
const result = await hostCtx.connection.rpc.call("/api", `${RPC_PREFIX}/${endpoint}`, body);
|
|
27
27
|
if (result.ok) return result.value;
|
|
28
28
|
throw new Error(result.error?.message || `rpc ${endpoint} failed`);
|
|
29
29
|
}
|
package/lib/index.js
CHANGED
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* dsh 原生请求头(x-client-request-id / session_id)在此之前已就位,作为
|
|
17
17
|
* sessionId 取值来源。
|
|
18
18
|
*
|
|
19
|
-
* 管理:
|
|
20
|
-
*
|
|
19
|
+
* 管理:dsh v0.1.5 传输模型下注册精确 POST 路由 /api/model-headers/*,
|
|
20
|
+
* 配置文件 fs.watch 热加载。每次实际注入追加一行到
|
|
21
|
+
* ~/.dsh/model-headers.log 供核验(>5MB 截断)。
|
|
21
22
|
*/
|
|
22
23
|
|
|
23
24
|
import { watch as fsWatch } from 'node:fs'
|
|
@@ -27,6 +28,8 @@ import path from 'node:path'
|
|
|
27
28
|
import { randomUUID } from 'node:crypto'
|
|
28
29
|
|
|
29
30
|
export const name = 'dsh-model-headers'
|
|
31
|
+
// 保持空 inject:静态声明只影响自身 fiber 启动门槛,headless 无 webServer 会让
|
|
32
|
+
// 插件永不装配(自愈/热加载失效)。RPC 的服务等待改用 apply 内 ctx.inject 回调。
|
|
30
33
|
export const inject = []
|
|
31
34
|
export { ensureCacheRetention, listConfiguredModels }
|
|
32
35
|
|
|
@@ -35,7 +38,7 @@ const CONFIG_FILE = () => path.join(DSH_HOME(), 'model-headers.json')
|
|
|
35
38
|
const LOG_FILE = () => path.join(DSH_HOME(), 'model-headers.log')
|
|
36
39
|
const SETTINGS_FILE = () => path.join(DSH_HOME(), 'settings.yaml')
|
|
37
40
|
const LOG_MAX_BYTES = 5 * 1024 * 1024
|
|
38
|
-
const
|
|
41
|
+
const RPC_PREFIX = 'model-headers' // 挂在 /api/<prefix>/<endpoint> 下的精确 POST 路由
|
|
39
42
|
const GUARD = Symbol.for('dsh.model-headers.installed')
|
|
40
43
|
|
|
41
44
|
const e2str = (e) => String(e?.message || e).slice(0, 160)
|
|
@@ -415,35 +418,45 @@ export function apply(ctx) {
|
|
|
415
418
|
await loadRules()
|
|
416
419
|
await ensureCacheRetention()
|
|
417
420
|
await watchConfig()
|
|
418
|
-
console.log(`[dsh-model-headers] host ready: ${rules.length} rule(s)
|
|
421
|
+
console.log(`[dsh-model-headers] host ready: ${rules.length} rule(s)`)
|
|
419
422
|
})()
|
|
420
423
|
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
424
|
+
// ---- RPC(dsh v0.1.5 新传输模型)----
|
|
425
|
+
// 浏览器侧固定 POST /api/<endpoint>;插件用 connection.fetch.register
|
|
426
|
+
// 注册精确 POST 路由(fetchRoutes 优先于网关 interceptor)。register 内部
|
|
427
|
+
// 经 owner.webServer.register 落路由,故回调 fiber 链上需同时有
|
|
428
|
+
// connection 与 webServer。信封:client-request {rpcId,method,payload} →
|
|
429
|
+
// server-response {rpcId,result:{ok,value|error}}。
|
|
430
|
+
const okResponse = (rpcId, result) => new Response(
|
|
431
|
+
JSON.stringify({ type: 'server-response', rpcId, result }),
|
|
432
|
+
{ status: 200, headers: { 'content-type': 'application/json' } },
|
|
433
|
+
)
|
|
434
|
+
// fetch.register 内部为 owner.effect(() => owner.webServer.register(route)),
|
|
435
|
+
// 解析的是本回调 fiber 作用域链上的 webServer——只 inject connection 会抛
|
|
436
|
+
// "cannot get property webServer without inject"。web profile 两者就绪即注册;
|
|
437
|
+
// headless 无 webServer 时回调静默等待(无需 HTTP 路由),插件本体仍正常装配。
|
|
438
|
+
ctx.inject(['connection', 'webServer'], (svc) => {
|
|
439
|
+
for (const [name, action] of Object.entries(endpoints)) {
|
|
440
|
+
const path = `/api/${RPC_PREFIX}/${name}`
|
|
441
|
+
svc.connection.fetch.register({
|
|
442
|
+
path,
|
|
443
|
+
methods: ['POST'],
|
|
444
|
+
requestBody: 'buffered',
|
|
445
|
+
fetch: async (request) => {
|
|
446
|
+
let rpcId = ''
|
|
447
|
+
try {
|
|
448
|
+
const msg = await request.json()
|
|
449
|
+
rpcId = typeof msg?.rpcId === 'string' ? msg.rpcId : ''
|
|
450
|
+
const value = await action.run(msg?.payload ?? {})
|
|
451
|
+
return okResponse(rpcId, rpcOk(value))
|
|
452
|
+
} catch (e) {
|
|
453
|
+
return okResponse(rpcId, rpcFail(e2str(e)))
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
})
|
|
435
457
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const action = endpoints[endpoint]
|
|
439
|
-
if (action === undefined) return rpcFail(`unknown endpoint "${endpoint}"`)
|
|
440
|
-
return rpcOk(await action.run(payload ?? {}))
|
|
441
|
-
} catch (e) {
|
|
442
|
-
return rpcFail(e2str(e))
|
|
443
|
-
}
|
|
444
|
-
}, { authority: 'loopback' })
|
|
445
|
-
console.log(`[dsh-model-headers] rpc '${RPC_CHANNEL}' ready`)
|
|
446
|
-
})()
|
|
458
|
+
console.log(`[dsh-model-headers] rpc routes ready under /api/${RPC_PREFIX} (${Object.keys(endpoints).length} endpoints)`)
|
|
459
|
+
})
|
|
447
460
|
|
|
448
461
|
// 文件监听随插件卸载关闭;fetch 钩子恢复原状(配合热重载)。
|
|
449
462
|
ctx.effect(() => () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-model-headers",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Per-model custom request headers: inject headers into LLM requests matched by model-name wildcard; values support fixed strings and the ${sessionId} variable. Managed from a settings-page UI.",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"homepage": "https://github.com/LvanLa/deepseek-harness-ex/tree/master/plugins/dsh-model-headers",
|