@vllm-sr/dsh 0.4.1 → 0.5.0
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 +62 -15
- package/package.json +2 -2
- package/src/client.js +13 -5
- package/src/index.js +232 -76
- package/src/keys.js +40 -3
- package/src/questions.js +31 -0
- package/src/shield.js +116 -40
- package/src/spans.js +216 -0
- package/web/client.js +150 -15
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ agent orders, is the work really done, which team should get each of these 230 t
|
|
|
11
11
|
- **System One**, the decision model, decides: `vllm-sr/d3-ultra`. It answers typed questions (choice, yes/no, score,
|
|
12
12
|
box) with probabilities, from one forward pass per question instead of generated text.
|
|
13
13
|
|
|
14
|
-
Both
|
|
15
|
-
|
|
14
|
+
Both take a free [System Duo](https://app.vllm-sr.ai) key, which the plugin gets for you: System One answers at `https://app.vllm-sr.ai/v1/systemone`,
|
|
15
|
+
and `vllm-sr/auto` at `https://app.vllm-sr.ai/v1/chat/completions`.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
@@ -26,9 +26,10 @@ The first line installs DeepSeek Harness (0.2.1-rc.5 or a later 0.2 release, on
|
|
|
26
26
|
`dsh plugin` uses to install plugins; without pnpm, `dsh plugin add` stops with "pnpm was not found". On a machine
|
|
27
27
|
with git, the package can also come straight from GitHub: `dsh plugin --profile web add github:Xunzhuo/dsh-system-one-plugin`.
|
|
28
28
|
|
|
29
|
-
On its first start the plugin gets
|
|
30
|
-
|
|
31
|
-
by you only). A
|
|
29
|
+
On its first start the plugin gets a free System Duo key, with the same small proof of work the site's "Get your API
|
|
30
|
+
key" button runs in the browser, and saves it in DeepSeek Harness's credential store and in `~/.dsh/.env` (readable
|
|
31
|
+
by you only). A line under your first request says so: "Free API key created for app.vllm-sr.ai, saved in
|
|
32
|
+
~/.dsh/.env", or why the site refused one. `vllm-sr/auto` becomes the default model; choose another model
|
|
32
33
|
in the app and System One keeps working beside it.
|
|
33
34
|
|
|
34
35
|
Headless:
|
|
@@ -56,6 +57,22 @@ of your profile patch stay as they are.
|
|
|
56
57
|
| Done-check | `agent/turn-stopping` | complete?, checked?, waiting for you? | an unfinished turn goes back once or twice to finish and verify |
|
|
57
58
|
| Tool | `system_one` | any rubric the LLM writes, over a file of items or images | one result row per item (JSONL or CSV) and a summary |
|
|
58
59
|
|
|
60
|
+
### Span answers (vllm-sr/vela3-turbo)
|
|
61
|
+
|
|
62
|
+
`vllm-sr/vela3-turbo` also answers span questions: which words of a text carry a label, with code-point offsets and a
|
|
63
|
+
probability each. Once the Decision API lists `span` for it (`spans: auto`, the default), four reflexes point at words
|
|
64
|
+
instead of whole passages:
|
|
65
|
+
|
|
66
|
+
- **Shield**: in a passage it flagged, the sentences that give orders go, and the text around them stays. The passage
|
|
67
|
+
is scored again without them, and a cut that leaves an injection behind falls back to removing lines.
|
|
68
|
+
- **Guard**: a call it flags names the shell command that does the damage, in its card and its question.
|
|
69
|
+
- **Done-check**: words of the final answer that nothing the turn read supports (preset `halu`) are marked, and
|
|
70
|
+
System Two goes back to re-verify just those.
|
|
71
|
+
- **Privacy** (`privacy: true`, off by default): personal data in tool results (preset `pii`, 17 labels) becomes its
|
|
72
|
+
label, as `[EMAIL_ADDRESS]`, before System Two reads it: the nine sensitive labels by default (names, e-mail and
|
|
73
|
+
street addresses, phone, card, bank and ID numbers, IP addresses), while dates, organizations and places pass. A
|
|
74
|
+
small card shows what was masked, by label only.
|
|
75
|
+
|
|
59
76
|
## See it in the Web UI
|
|
60
77
|
|
|
61
78
|
In `dsh web`, System One shows up in the conversation itself, where it acted, marked with an ember **System One**
|
|
@@ -70,11 +87,16 @@ badge that carries the decision's latency:
|
|
|
70
87
|
- **Done-check**: a card after the answer: done, waiting on you, or sent back to finish.
|
|
71
88
|
- **`system_one` tool**: its row shows the batch: items, questions, each question's answer distribution and the
|
|
72
89
|
results file.
|
|
90
|
+
- **Free key**: a **System Duo** line under your first request when the plugin created a key, or could not.
|
|
91
|
+
- **Spans** (vllm-sr/vela3-turbo): the words a span answer marked, in the card that used them: removed injections
|
|
92
|
+
struck through, a command's dangerous part, unsupported claims of the answer underlined, and masked personal data as
|
|
93
|
+
label chips in a **Privacy** card.
|
|
73
94
|
|
|
74
95
|
Routine checks (an allowed call, a clean result) are one line and fold with the turn's work. Cards stay visible when
|
|
75
96
|
the work folds, so a finished turn still shows what System One decided. Parallel calls in one step share one line or
|
|
76
97
|
card, and every decision pops in with a short animation the first time it appears (none with reduced motion). Each
|
|
77
|
-
element shows the Decision API's own answer: the probabilities, the model and the
|
|
98
|
+
element shows the Decision API's own answer: the probabilities, the model (in bold, as `vllm-sr/d3-ultra`) and the
|
|
99
|
+
measured latency.
|
|
78
100
|
|
|
79
101
|
Set `systemOneUi` to `compact` for one line per decision, or to `off` to hide them.
|
|
80
102
|
|
|
@@ -85,21 +107,26 @@ attributes that say what it shows:
|
|
|
85
107
|
|
|
86
108
|
| Attribute | Values |
|
|
87
109
|
| --- | --- |
|
|
88
|
-
| `data-system-one` | `card`, `compact` (one line)
|
|
89
|
-
| `data-system-one-reflex` | `triage`, `guard`, `shield`, `done` or `
|
|
90
|
-
| `data-system-one-verdict` | triage `brief`; guard `allow`, `ask` or `deny`; shield `clean`, `removed` or `flagged`; done-check `stop` or `continue`; tool `running` or `done`; `error` when System One did not answer |
|
|
110
|
+
| `data-system-one` | `card`, `compact` (one line), `tool` (the `system_one` row) or `notice` (the free-key line) |
|
|
111
|
+
| `data-system-one-reflex` | `triage`, `guard`, `shield`, `privacy`, `done`, `tool` or `key` |
|
|
112
|
+
| `data-system-one-verdict` | triage `brief`; guard `allow`, `ask` or `deny`; shield `clean`, `removed` or `flagged`; privacy `masked`; done-check `stop` or `continue`; tool `running` or `done`; key `created` or `failed`; `error` when System One did not answer |
|
|
91
113
|
| `data-system-one-outcome` | guard, once you answer its approval: `allowed`, `rejected`, `cancelled` or `failed` |
|
|
92
|
-
| `data-system-one-why` | done-check: `complete`, `waiting`, `unfinished` or `
|
|
114
|
+
| `data-system-one-why` | done-check: `complete`, `waiting`, `unfinished`, `unchecked` or `unsupported` |
|
|
93
115
|
| `data-system-one-tone` | its colour: `ok` (green), `info` (ember), `warn` (amber), `bad` (red) or `muted` |
|
|
94
116
|
| `data-system-one-count` | how many decisions it holds (a batch: how many items) |
|
|
95
117
|
| `data-system-one-turn`, `data-system-one-step` | where it acted (the step for guard and shield) |
|
|
118
|
+
| `data-system-one-model` | the model that answered, as `vllm-sr/d3-ultra` |
|
|
119
|
+
| `data-system-one-span-model`, `data-system-one-spans` | the span model that marked words, as `vllm-sr/vela3-turbo`, and how many |
|
|
96
120
|
|
|
97
121
|
Inside a root, `data-system-one-part` marks `badge` (the ember **System One** pill), `latency`, `reflex`, `summary`,
|
|
98
122
|
`model`, `head`, `toggle` (the button of a one-line element), `rows`, `verdict`, `outcome`, `subject`, `facts`,
|
|
99
|
-
`note` and `more`,
|
|
100
|
-
`
|
|
101
|
-
`
|
|
102
|
-
`data-system-one-
|
|
123
|
+
`note` and `more`, in the batch row also `stack`, `legend`, `failed`, `results` and `raw`, and in the free-key line
|
|
124
|
+
`badge` (the **System Duo** pill), `summary` and `links`. Span answers add `excerpts`, each `excerpt`, every marked
|
|
125
|
+
`span` (with `data-system-one-span-label` and `data-system-one-probability`) and, in a Privacy card, the `labels`. Each
|
|
126
|
+
number is a `data-system-one-fact`: `kind`, `effort`, `unclear` and `risky` (triage), `risk`, `leaks` and `on-task`
|
|
127
|
+
(guard), `passages`, `injection` and `spans` (shield), `masked` (privacy), `complete`, `checked`, `waiting` and
|
|
128
|
+
`unsupported` (done-check). Decision rows carry `data-system-one-decision` and `data-system-one-call`, batch questions
|
|
129
|
+
`data-system-one-question`. For example:
|
|
103
130
|
|
|
104
131
|
| Element | Selector |
|
|
105
132
|
| --- | --- |
|
|
@@ -113,11 +140,17 @@ Inside a root, `data-system-one-part` marks `badge` (the ember **System One** pi
|
|
|
113
140
|
| The ember badge, and its latency | `[data-system-one-part="badge"]`, `[data-system-one-part="latency"]` |
|
|
114
141
|
| "Dangerous", and "You rejected it" | `[data-system-one-fact="risk"]`, `[data-system-one-part="outcome"]` |
|
|
115
142
|
| The reason | `[data-system-one-part="note"]` |
|
|
143
|
+
| The model's name (bold) | `[data-system-one-part="model"]` |
|
|
144
|
+
| Free key created | `[data-system-one="notice"][data-system-one-verdict="created"]` |
|
|
145
|
+
| The words a span answer marked | `[data-system-one-part="span"]` (`[data-system-one-span-label="INJECTION"]`, `"DANGEROUS"`, `"unsupported"`, a PII label) |
|
|
146
|
+
| Privacy card | `[data-system-one-reflex="privacy"][data-system-one-verdict="masked"]` |
|
|
147
|
+
| Done-check that sent claims back | `[data-system-one-reflex="done"][data-system-one-why="unsupported"]` |
|
|
116
148
|
|
|
117
149
|
## Your data
|
|
118
150
|
|
|
119
151
|
System One sends what it decides about: the user's request (clipped), each tool call it reviews, the passages of tool
|
|
120
|
-
results it screens, the end of the turn
|
|
152
|
+
results it screens, the end of the turn (with what the turn read, for the done-check's span answer), and the items
|
|
153
|
+
given to the `system_one` tool. With `privacy: true`, the results of `privacyTools` go to System One whole. System Two receives the
|
|
121
154
|
conversation as any LLM provider does. System Duo logs requests to improve the services and to train models; read its
|
|
122
155
|
[terms](https://app.vllm-sr.ai/terms) and [privacy](https://app.vllm-sr.ai/privacy) pages before you use it with
|
|
123
156
|
private code or data. Each reflex can be turned off.
|
|
@@ -151,11 +184,25 @@ Every field has a default. Set any of them on the `system-one` row of a profile
|
|
|
151
184
|
tool: true
|
|
152
185
|
trace: ~/.dsh/system-one/trace.jsonl # or off
|
|
153
186
|
systemOneUi: card # how Chat shows System One: card, compact (one line each) or off
|
|
187
|
+
spans: auto # span answers: auto (once spanModel lists span), on or off
|
|
188
|
+
spanModel: vllm-sr/vela3-turbo
|
|
189
|
+
shieldSpans: true # remove injected words, not lines
|
|
190
|
+
guardSpans: true # name the dangerous part of a flagged call
|
|
191
|
+
doneHalu: true # send unsupported claims back
|
|
192
|
+
doneHaluAt: 0.6 # the lowest probability of an unsupported word that counts
|
|
193
|
+
privacy: false # mask personal data before System Two reads it
|
|
194
|
+
privacyAt: 0.5 # the lowest probability of a personal-data span that is masked
|
|
195
|
+
privacyLabels: [PERSON, EMAIL_ADDRESS, PHONE_NUMBER, STREET_ADDRESS, CREDIT_CARD, IBAN_CODE, US_SSN, US_DRIVER_LICENSE, IP_ADDRESS]
|
|
196
|
+
privacyTools: [web_fetch, bash, read]
|
|
154
197
|
```
|
|
155
198
|
|
|
156
199
|
`systemOneUi` applies to decisions made after a restart with the new value; decisions already in a session keep the
|
|
157
200
|
form they were recorded with. The tool's custom row is drawn for the default `toolName`, `system_one`.
|
|
158
201
|
|
|
202
|
+
With `privacy: true`, System Two sees `[LABEL]` placeholders instead of personal data in the results of
|
|
203
|
+
`privacyTools`, so it cannot copy a real value into a file it writes from what it read; it is told to ask you
|
|
204
|
+
instead. Span records keep labels and offsets of personal data, never the data itself.
|
|
205
|
+
|
|
159
206
|
The key comes from the credential reference `VLLM_SR_API_KEY` (`llmKeyEnv`), which both systems use. A separate
|
|
160
207
|
System One key in `DECISION_API_KEY` (`apiKeyEnv`), as plugin 0.2 kept it, still wins for System One; a 0.2 key for
|
|
161
208
|
`vllm-sr/auto` keeps working too.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vllm-sr/dsh",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "System Duo for DeepSeek Harness. Thinking, fast and slow: System One decision models guard, shield, triage and check your agent around System Two (vllm-sr/auto), with
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "System Duo for DeepSeek Harness. Thinking, fast and slow: System One decision models guard, shield, triage and check your agent around System Two (vllm-sr/auto), with a free app.vllm-sr.ai key.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
7
7
|
"dsh",
|
package/src/client.js
CHANGED
|
@@ -156,8 +156,8 @@ export function createDecisionClient(options) {
|
|
|
156
156
|
* @param {AbortSignal} [request.signal]
|
|
157
157
|
* @param {number} [request.timeoutMs] - per-call deadline (default: the client's)
|
|
158
158
|
* @param {number} [request.retries] - per-call retries (default: the client's)
|
|
159
|
-
* @returns {Promise<{answers: object[], ms: number, model: string, inputTokens: number, requestId?: string}>}
|
|
160
|
-
* answers in input order
|
|
159
|
+
* @returns {Promise<{answers: object[], spans: object[], thresholds: object[], ms: number, model: string, inputTokens: number, requestId?: string}>}
|
|
160
|
+
* answers, span answers and the thresholds applied, in input order
|
|
161
161
|
*/
|
|
162
162
|
async function ask({ model, questions, inputs, signal, timeoutMs: callTimeoutMs, retries: callRetries }) {
|
|
163
163
|
if (inputs.length === 0 || inputs.length > ITEMS_PER_REQUEST) {
|
|
@@ -176,10 +176,10 @@ export function createDecisionClient(options) {
|
|
|
176
176
|
const started = performance.now()
|
|
177
177
|
try {
|
|
178
178
|
const { json, requestId } = await post('/v1/decisions', body, signal, { timeoutMs: callTimeoutMs, retries: callRetries })
|
|
179
|
-
const
|
|
179
|
+
const each = field => [json[field] ?? {}, ...rest.map((_, index) => json.states?.[`i${index + 1}`]?.[field] ?? {})]
|
|
180
180
|
let inputTokens = json.usage?.input_tokens ?? 0
|
|
181
181
|
for (const entry of Object.values(json.states ?? {})) inputTokens += entry.usage?.input_tokens ?? 0
|
|
182
|
-
return { answers, ms: performance.now() - started, model: json.model ?? model, inputTokens, requestId }
|
|
182
|
+
return { answers: each('answers'), spans: each('spans'), thresholds: each('thresholds'), ms: performance.now() - started, model: json.model ?? model, inputTokens, requestId }
|
|
183
183
|
} finally {
|
|
184
184
|
release()
|
|
185
185
|
}
|
|
@@ -190,7 +190,15 @@ export function createDecisionClient(options) {
|
|
|
190
190
|
send('/api/info', 'GET', undefined, {}, AbortSignal.timeout(timeoutMs)).catch(() => {})
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
/** The published models' cards (no key needed): `[{id, question_types, presets}]`. */
|
|
194
|
+
async function models(signal) {
|
|
195
|
+
const response = await send('/v1/systemone/models', 'GET', undefined, { accept: 'application/json' }, signal ?? AbortSignal.timeout(timeoutMs))
|
|
196
|
+
if (response.status !== 200) throw new DecisionError(`Decision API ${response.status} listing models`, response.status)
|
|
197
|
+
const cards = JSON.parse(response.text)?.data
|
|
198
|
+
return Array.isArray(cards) ? cards : []
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return { ask, warm, models, hasKey: async () => Boolean(await apiKey()), close: () => agent.destroy() }
|
|
194
202
|
}
|
|
195
203
|
|
|
196
204
|
/** Probability that a noul answer is yes, or undefined when the question failed. */
|