@openplan/dsh-fuse 0.1.0 → 0.1.1
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 +2 -2
- package/dist/harness.js +49 -0
- package/package.json +62 -62
package/README.md
CHANGED
|
@@ -15,12 +15,12 @@ O pacote declara `dsh.bundle`, que é o que faz `dsh plugin add` ativar a
|
|
|
15
15
|
camada. Sem essa declaração o pnpm instalaria uma biblioteca inerte.
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
# npm — a forma canônica de instalação (publicado
|
|
18
|
+
# npm — a forma canônica de instalação (publicado)
|
|
19
19
|
dsh plugin --profile <perfil> add @openplan/dsh-fuse
|
|
20
20
|
|
|
21
21
|
# tarball (sem depender de registry)
|
|
22
22
|
pnpm pack # gera openplan-dsh-fuse-<versão>.tgz
|
|
23
|
-
dsh plugin --profile <perfil> add ./openplan-dsh-fuse
|
|
23
|
+
dsh plugin --profile <perfil> add ./openplan-dsh-fuse-<versão>.tgz
|
|
24
24
|
|
|
25
25
|
# direto do git (exige allowlist de build do pnpm >= 10 — veja a doc do harness)
|
|
26
26
|
dsh plugin --profile <perfil> add github:<org>/<repo>#<sha>
|
package/dist/harness.js
CHANGED
|
@@ -98,6 +98,45 @@ export function apply(ctx, config) {
|
|
|
98
98
|
const logger = ctx.logger;
|
|
99
99
|
const tokenMeter = () => ctx.get?.("tokenMeter") ?? undefined;
|
|
100
100
|
const llm = () => ctx.get?.("llm") ?? undefined;
|
|
101
|
+
/**
|
|
102
|
+
* In-session cut notices: when the fuse blocks a step, the harness ends the
|
|
103
|
+
* turn as `{ kind: "blocked" }` with no visible explanation — the user is
|
|
104
|
+
* told nothing. The harness's own convention for "something just happened"
|
|
105
|
+
* is a plugin-producer `notice`-form user message (`agent.inject`), which
|
|
106
|
+
* the client conversation renders as a collapsed one-line row expandable to
|
|
107
|
+
* the full text. One notice per (rule, window) per process: a budget that
|
|
108
|
+
* stays tripped must not restate itself on every blocked step, and a new
|
|
109
|
+
* window that re-trips it should announce that again.
|
|
110
|
+
*/
|
|
111
|
+
const cutNotices = new Set();
|
|
112
|
+
function notifyCut(agent, input) {
|
|
113
|
+
const window = windowStart(new Date(), "day");
|
|
114
|
+
const key = `${input.rule}\u0000${window}`;
|
|
115
|
+
if (cutNotices.has(key))
|
|
116
|
+
return;
|
|
117
|
+
cutNotices.add(key);
|
|
118
|
+
try {
|
|
119
|
+
agent.inject({
|
|
120
|
+
id: crypto.randomUUID(),
|
|
121
|
+
role: "user",
|
|
122
|
+
content: [{ type: "text", text: input.detail }],
|
|
123
|
+
source: {
|
|
124
|
+
kind: "plugin",
|
|
125
|
+
plugin: "@openplan/dsh-fuse",
|
|
126
|
+
form: "notice",
|
|
127
|
+
summary: input.summary,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
// A notice must never break the reject path — the cut already landed
|
|
133
|
+
// in the store; the UI alert is best-effort.
|
|
134
|
+
logger.warn("[dsh] cut notice not delivered", {
|
|
135
|
+
rule: input.rule,
|
|
136
|
+
error: String(error),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
101
140
|
/**
|
|
102
141
|
* Documented load-time rule: *"A plugin should also reject schema-valid
|
|
103
142
|
* config that names an unavailable resource or provider as soon as it can
|
|
@@ -532,6 +571,11 @@ export function apply(ctx, config) {
|
|
|
532
571
|
resetAt: remoteBlock.resetAt,
|
|
533
572
|
project,
|
|
534
573
|
});
|
|
574
|
+
notifyCut(payload.agent, {
|
|
575
|
+
rule: remoteBlock.rule,
|
|
576
|
+
summary: "fuse: chamadas bloqueadas (orçamento do painel)",
|
|
577
|
+
detail: `O painel central cortou as chamadas deste escopo (regra: ${remoteBlock.rule}). O bloqueio vale até ${remoteBlock.resetAt} — o fuse local segue ativo e nenhum token é gasto enquanto isso.`,
|
|
578
|
+
});
|
|
535
579
|
return { kind: "reject" };
|
|
536
580
|
}
|
|
537
581
|
const estimatedCostUsd = estimateStepCostUsd(payload.agent, payload.messages, model, provider);
|
|
@@ -565,6 +609,11 @@ export function apply(ctx, config) {
|
|
|
565
609
|
rule: decision.rule,
|
|
566
610
|
project,
|
|
567
611
|
});
|
|
612
|
+
notifyCut(payload.agent, {
|
|
613
|
+
rule: decision.rule ?? "unknown",
|
|
614
|
+
summary: "fuse: chamada cortada — orçamento atingido",
|
|
615
|
+
detail: `O fuse bloqueou a chamada antes de gastar tokens (regra: ${decision.rule ?? "unknown"}). Ajuste o budget em cordis.patch.yml ou use a ferramenta dsh_budget_status para ver o status; o limite reseta no fim da janela.`,
|
|
616
|
+
});
|
|
568
617
|
return { kind: "reject" };
|
|
569
618
|
}
|
|
570
619
|
return next();
|
package/package.json
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
2
|
+
"name": "@openplan/dsh-fuse",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Cost policy for the DeepSeek Harness: per-call metering plus a local fuse that enforces budget, model and reasoning-effort limits before any token is spent.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"private": false,
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"cordis.patch.yml",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"dsh",
|
|
29
|
+
"dsh-plugin",
|
|
30
|
+
"llm",
|
|
31
|
+
"budget",
|
|
32
|
+
"cost",
|
|
33
|
+
"enforcement",
|
|
34
|
+
"cordis"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -p tsconfig.build.json",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"prepublishOnly": "pnpm build"
|
|
41
|
+
},
|
|
42
|
+
"dsh": {
|
|
43
|
+
"bundle": {
|
|
44
|
+
"patch": "./cordis.patch.yml"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@deepseek-ai/schemastery": "3.18.2",
|
|
49
|
+
"@libsql/client": "^0.17.4"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@deepseek-ai/cordis": "4.0.1"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
56
|
+
"@deepseek-ai/dsh-agent": "0.1.1-rc.2",
|
|
57
|
+
"@deepseek-ai/dsh-llm": "0.1.1-rc.2",
|
|
58
|
+
"@deepseek-ai/dsh-session": "0.1.1-rc.2",
|
|
59
|
+
"@deepseek-ai/dsh-tools": "0.1.1-rc.2",
|
|
60
|
+
"@types/node": "^22.0.0",
|
|
61
|
+
"typescript": "^5.9.0",
|
|
62
|
+
"vitest": "^3.1.0"
|
|
63
|
+
}
|
|
64
64
|
}
|