dsh-runnpu 0.1.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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +16 -0
  3. package/compute-mode/preset/agent.cordis.yml +368 -0
  4. package/compute-mode/preset/preset.yml +3 -0
  5. package/compute-mode/preset/skills/runnpu/SKILL.md +233 -0
  6. package/compute-mode/preset/skills/runnpu/VENDOR.txt +11 -0
  7. package/compute-mode/preset/skills/runnpu/examples/01-dev-environment.sh +26 -0
  8. package/compute-mode/preset/skills/runnpu/examples/02-training-job.sh +26 -0
  9. package/compute-mode/preset/skills/runnpu/examples/03-inference-service.sh +24 -0
  10. package/compute-mode/preset/skills/runnpu/examples/04-fractional-vnpu.sh +14 -0
  11. package/compute-mode/preset/skills/runnpu/examples/05-troubleshoot.sh +17 -0
  12. package/compute-mode/preset/skills/runnpu/references/admin.md +60 -0
  13. package/compute-mode/preset/skills/runnpu/references/data-sources.md +35 -0
  14. package/compute-mode/preset/skills/runnpu/references/templates-assets.md +61 -0
  15. package/compute-mode/preset/skills/runnpu/references/training-runs.md +56 -0
  16. package/compute-mode/preset/skills/runnpu/references/troubleshooting.md +75 -0
  17. package/compute-mode/preset/skills/runnpu/references/workload-types.md +47 -0
  18. package/cordis.patch.yml +80 -0
  19. package/dist/chunk-JLZMOSQC.mjs +1 -0
  20. package/dist/chunk-JUBIWGKW.mjs +4 -0
  21. package/dist/chunk-JZXLCA2E.mjs +1 -0
  22. package/dist/chunk-KQOFBYGE.mjs +9 -0
  23. package/dist/chunk-XMZG2NP7.mjs +2 -0
  24. package/dist/chunk-XQPU3AJN.mjs +1 -0
  25. package/dist/chunk-YKASEMP3.mjs +1 -0
  26. package/dist/chunk-YPL4VUYF.mjs +4 -0
  27. package/dist/compute-node.mjs +1 -0
  28. package/dist/compute-tools.mjs +41 -0
  29. package/dist/connectors.mjs +3 -0
  30. package/dist/dsh-runnpu.mjs +43 -0
  31. package/dist/json.mjs +1 -0
  32. package/dist/pins.mjs +1 -0
  33. package/dist/series.mjs +1 -0
  34. package/dist/training-node.mjs +2 -0
  35. package/dist/training-tools.mjs +30 -0
  36. package/dist/ui-host.mjs +1 -0
  37. package/lib/client.js +189 -0
  38. package/package.json +78 -0
  39. package/training-mode/preset/agent.cordis.yml +343 -0
  40. package/training-mode/preset/preset.yml +3 -0
  41. package/training-mode/preset/skills/runnpu/SKILL.md +233 -0
  42. package/training-mode/preset/skills/runnpu/VENDOR.txt +11 -0
  43. package/training-mode/preset/skills/runnpu/examples/01-dev-environment.sh +26 -0
  44. package/training-mode/preset/skills/runnpu/examples/02-training-job.sh +26 -0
  45. package/training-mode/preset/skills/runnpu/examples/03-inference-service.sh +24 -0
  46. package/training-mode/preset/skills/runnpu/examples/04-fractional-vnpu.sh +14 -0
  47. package/training-mode/preset/skills/runnpu/examples/05-troubleshoot.sh +17 -0
  48. package/training-mode/preset/skills/runnpu/references/admin.md +60 -0
  49. package/training-mode/preset/skills/runnpu/references/data-sources.md +35 -0
  50. package/training-mode/preset/skills/runnpu/references/templates-assets.md +61 -0
  51. package/training-mode/preset/skills/runnpu/references/training-runs.md +56 -0
  52. package/training-mode/preset/skills/runnpu/references/troubleshooting.md +75 -0
  53. package/training-mode/preset/skills/runnpu/references/workload-types.md +47 -0
  54. package/training-mode/preset/skills/swanlab-skill/LICENSE +21 -0
  55. package/training-mode/preset/skills/swanlab-skill/SKILL.md +163 -0
  56. package/training-mode/preset/skills/swanlab-skill/VENDOR.txt +9 -0
  57. package/training-mode/preset/skills/swanlab-skill/references/ANALYSIS_GUIDE.md +83 -0
  58. package/training-mode/preset/skills/swanlab-skill/references/CLI_REFERENCE.md +510 -0
  59. package/training-mode/preset/skills/swanlab-skill/references/SDK_QUICKSTART.md +341 -0
  60. package/training-mode/preset/skills/swanlab-skill/references/SWANLAB_CONCEPTS.md +523 -0
  61. package/training-mode/preset/skills/swanlab-skill/scripts/plot_metrics.py +353 -0
  62. package/training-mode/preset/skills/swanlab-skill/scripts/runs_benchmark.py +550 -0
  63. package/training-mode/preset/skills/training-research/SKILL.md +33 -0
  64. package/training-mode/preset/skills/training-research/references/pipeline.md +45 -0
  65. package/training-mode/preset/skills/training-research/references/research.md +76 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EM-GeekLab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # dsh-runnpu
2
+
3
+ DeepSeek Harness (dsh) 插件:在 RunNPU 昇腾 NPU 集群上提供「算力管理」与「训练」两个 agent 模式。
4
+
5
+ ```bash
6
+ cd ~/.dsh/profiles/web
7
+ pnpm add dsh-runnpu
8
+ npx dsh-runnpu install all --profile web --with-cli
9
+ pnpm install
10
+ ```
11
+
12
+ 然后重启 dsh,新建会话时选择模式。`npx dsh-runnpu doctor` 检查配套的 runnpu / swanlab CLI。
13
+
14
+ 配套 runnpu CLI 版本:v0.1.1(发布仓 https://github.com/EM-GeekLab/run-npu-skill )。
15
+
16
+ 本包只含构建产物;使用与安装说明见 https://github.com/EM-GeekLab/run-npu-harness 。
@@ -0,0 +1,368 @@
1
+ # The `compute` agent preset — 算力管理模式.
2
+ #
3
+ # Derived from the shipped `standard` preset. Two deliberate differences:
4
+ # 1. the persona is a cluster operator, not a coding agent;
5
+ # 2. `skill-filesystem` also scans this preset's own `skills/` tree, so the
6
+ # RunNPU skill ships WITH the mode.
7
+ #
8
+ # The UI half of this mode (right-hand cluster panel, pinned charts, the login
9
+ # form) is NOT here: it lives in the `dsh-runnpu` bundle on the host
10
+ # plane, and keys off this preset's id through the session's `agentPreset`
11
+ # projection. A preset decides what the AGENT can do; the bundle decides what
12
+ # the WINDOW looks like.
13
+
14
+ # ── identity ────────────────────────────────────────────────────────────────
15
+
16
+ # The preset's own persona, shadowing the deployment default for this agent.
17
+ # `{{model}}` and `{{cwd}}` resolve from the agent's own route and workspace.
18
+ - id: persona
19
+ name: '@deepseek-ai/dsh-persona'
20
+ config:
21
+ # dsh ≥ 0.1.5 reads `prefix` (+ optional `suffix`); older harnesses read `text`.
22
+ # Both point at the same block, so one preset serves both.
23
+ prefix: &persona >-
24
+ You are a compute-platform engineer operating a RunNPU Ascend NPU cluster
25
+ through the DeepSeek Harness, powered by the {{model}} model.
26
+
27
+ Answer questions about cluster state, capacity, quota, queueing and
28
+ workload health using the `runnpu` skill — always read it before acting.
29
+ Read-only commands you may run directly.
30
+
31
+ For per-project questions there are two levels, and picking the wrong
32
+ one is the usual mistake. `cluster_usage` gives the CLUSTER-WIDE roll-up
33
+ per project — quota, held, running, held-minus-running. But quota and
34
+ storage are actually accounted PER POOL, and that detail only exists in
35
+ `cluster_chart` with query `projects` and source `usage` / `storage` /
36
+ `queues`: one row per project per pool, with a signed `over_guarantee`
37
+ (positive = borrowing capacity that can be preempted, negative = paying
38
+ for a guarantee nobody is using) and storage `used_pct`. When someone
39
+ asks which project is over, which is wasting, whose disk is filling up,
40
+ or why a project's queue is not admitting, that is where the answer is —
41
+ and it is a table they can pin.
42
+
43
+ For "who is holding the cards", "how much quota is used" and "what is
44
+ wrong right now", prefer `cluster_usage` and `cluster_anomalies` over
45
+ assembling the answer from several CLI calls: those numbers are computed
46
+ deterministically, so they do not need checking, and the anomaly rules
47
+ catch things nobody thought to ask about. Report the EVIDENCE each
48
+ finding fired on, not just its verdict. When capacity is the question,
49
+ start from `cluster_usage` — held-minus-running is usually the real
50
+ answer, not the free-card count.
51
+
52
+ To STOP, START or DELETE a workload, use the `cluster_workload_action`
53
+ tool — never the shell. The tool routes the decision through the
54
+ harness's approval prompt, so the user approves the exact structured
55
+ action that then runs, and it records the operation either way. A shell
56
+ command asks in prose and executes something the user never saw. If the
57
+ user declines, do not rephrase and ask again. This is no longer only a
58
+ rule you are asked to follow: `runnpu workload delete|stop|start` typed
59
+ into the shell is REFUSED by a guard before it runs, so reaching for the
60
+ shell costs a turn and changes nothing. The read-only subcommands —
61
+ `list`, `logs`, `events`, `endpoints`, `get`, `exec`, `port-forward` —
62
+ are untouched; keep using them freely.
63
+
64
+ To change a project's QUOTA, use `cluster_quota_set` rather than `runnpu
65
+ project quota set`. The CLI replaces the whole quota block, so changing
66
+ one pool there means retyping every pool that is to survive, and a pool
67
+ left out is a pool set to nothing. The tool reads the current quota,
68
+ applies only the fields you name, and writes once — so name ONLY what
69
+ changes. What the user sees in the approval prompt is a DIFF ("保底 2 →
70
+ 4 卡"), so restate that same diff in your own words before you call:
71
+ somebody can only agree to a change they can recognise. To take capacity
72
+ away, set the pool's numbers to 0 — do not try to remove the pool, and do
73
+ not fall back to the CLI when the tool refuses something.
74
+
75
+ Everything else that changes the platform — creating workloads,
76
+ membership, users — still goes through the CLI, and there you must
77
+ restate the parameters and get explicit agreement before running
78
+ anything. Creating a workload is allowed through the shell and is also
79
+ RECORDED: the operation log keeps the project, name, type, template and
80
+ image of what you created — never the command line itself — so "who built
81
+ this" is answerable later without env values ending up in a log file.
82
+
83
+ Quantities carry units and accounting basis: quota is in CARDS, internal
84
+ accounting uses card-equivalents (100 cores = 1 card). A `null` metric or
85
+ `metrics.available=false` means the data source is NOT WIRED UP — say so;
86
+ never report it as zero. Refer to a workload as `<project-slug>/<name>`.
87
+
88
+ This session runs with a right-hand cluster panel. `cluster_chart`
89
+ renders a query as a line chart, a bar chart or a TABLE, and every one of
90
+ them can be pinned. Pick by the shape of the question: "how did it
91
+ change" is a line, "who has the most" is a bar, "which ones, with their
92
+ numbers" is a table. Do NOT hand-write a markdown table of cluster data —
93
+ it cannot be pinned, it goes stale the moment you send it, and you are
94
+ retyping numbers you already have. Produce the view and tell the user
95
+ they can pin it; a pinned view keeps its query and refreshes itself, so
96
+ it is worth more than anything pasted into the conversation. Ignore the
97
+ workspace directory: this mode is about the cluster, not about code.
98
+
99
+ For a PERIODIC report, use `cluster_report` — never re-derive the digest
100
+ from `cluster_usage` each time. It reports what CHANGED since the last
101
+ report, which is the only thing worth delivering on a schedule: a digest
102
+ that repeats the same findings every morning gets skipped, including the
103
+ morning a new one appears. Calling it advances the baseline, so use
104
+ `preview` when merely demonstrating it.
105
+
106
+ Schedule the report with `schedule_create`, and tell the user its three
107
+ real limits BEFORE they rely on it, because none of them is obvious and
108
+ each one looks like a bug later: (1) delivery is SESSION-LOCAL — the
109
+ report arrives as a message in THIS conversation, never as mail or a
110
+ notification, and while the session is closed it simply waits, overdue,
111
+ until the session is resumed; (2) the interval is fixed-rate from the
112
+ moment you create it, so "every day" means 24h from now, not 09:00 —
113
+ state the wall-clock time the first one will land and let the user
114
+ re-anchor if they wanted a different hour; (3) a session that was already
115
+ running before reminders were mounted has no `schedule_create` at all.
116
+
117
+ Finish each answer by calling `cluster_followups` with the two to four
118
+ questions THIS answer actually raises — name the workload, node or
119
+ project you just found something about, or the decision now waiting on
120
+ the user. They appear as one-click buttons above the composer. Skip the
121
+ call when nothing genuinely follows; an empty row beats four questions
122
+ nobody wants.
123
+ text: *persona
124
+ - id: agent-instructions
125
+ name: '@deepseek-ai/dsh-agent-instructions'
126
+ config:
127
+ maxBytes: 65536
128
+
129
+ # ── shell ───────────────────────────────────────────────────────────────────
130
+
131
+ # `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
132
+ # publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
133
+ # the criterion for host-plane ownership — injection resolves before any session
134
+ # exists, so there is no agent to key by. Behind a preset realm those variables
135
+ # never reached the model's shell at all. Both shell tools consume the host
136
+ # registry from here; their executors (`bash-sandbox`/`pwsh-sandbox`) are
137
+ # host-plane too.
138
+ - id: tool-bash
139
+ name: '@deepseek-ai/dsh-tool-bash'
140
+ disabled: !!js process.platform === 'win32'
141
+
142
+ - id: tool-pwsh
143
+ name: '@deepseek-ai/dsh-tool-pwsh'
144
+ disabled: !!js process.platform !== 'win32'
145
+
146
+ # ── filesystem ──────────────────────────────────────────────────────────────
147
+
148
+ # Both register into the host `tools` registry and provide nothing, so
149
+ # they need no realm. The `fs` service and its policy stay in the host.
150
+ - id: tool-fs
151
+ name: '@deepseek-ai/dsh-tool-fs'
152
+
153
+ - id: tool-fs-search
154
+ name: '@deepseek-ai/dsh-tool-fs-search'
155
+ config:
156
+ sampleOverCapGlobResults: false
157
+
158
+ # ── background jobs ────────────────────────────────────────────────────────
159
+
160
+ # Only the model-facing controls. The task REGISTRY stays on the host plane:
161
+ # its producers sit outside any realm this file could put it in — `tool-bash`
162
+ # above resolves it with `ctx.get`, and an entry-local realm here is invisible
163
+ # to every sibling row, so `run_in_background` would answer "background jobs
164
+ # unavailable" while these controls sat in the catalog. The registry is keyed by
165
+ # owning agent anyway, so one host instance serves every session. What a preset
166
+ # chooses is whether its agent can collect and stop background work at all.
167
+ - id: tool-jobs
168
+ name: '@deepseek-ai/dsh-tool-jobs'
169
+
170
+ # ── skills ──────────────────────────────────────────────────────────────────
171
+
172
+ # The skill REGISTRY lives in the host composition and is layered per scope:
173
+ # these rows register into THIS preset's layer of it, so they need no realm.
174
+ # `skill-filesystem` contributes local-root discovery for agents on this preset, and
175
+ # `tool-skill` gives them the catalog and loader; the merged catalog also
176
+ # carries whatever the deployment registered globally (repository plugins).
177
+ - id: skill-filesystem
178
+ name: '@deepseek-ai/dsh-skill-filesystem'
179
+ config:
180
+ # Rank 300 `custom`: scanned after project roots, before user roots.
181
+ # These directories ship WITH the preset, so the mode carries its own
182
+ # skills instead of depending on what the machine happens to have.
183
+ # `__DSH_PRESET_ROOT__` is substituted with the machine's real preset root
184
+ # by scripts/install-presets.mjs at copy time — an absolute path baked at
185
+ # authoring time only works on the author's machine.
186
+ customSkillDirs:
187
+ - __DSH_PRESET_ROOT__/compute/skills
188
+
189
+ - id: tool-skill
190
+ name: '@deepseek-ai/dsh-tool-skill'
191
+
192
+ # ── goals ───────────────────────────────────────────────────────────────────
193
+
194
+ # Only the model-facing tool. The goal SERVICE, its session driver, and the
195
+ # `/goal` command stay on the host plane: the Gateway serves the goal domain as
196
+ # Remote endpoints whose receiver comes from a generated descriptor, so it
197
+ # resolves `goals` on the host and an entry-local realm here would hide it. The
198
+ # registry is keyed by session anyway, so one host instance serves every
199
+ # session. What a preset chooses is whether its agent can call the goal tool.
200
+ - id: tool-goal
201
+ name: '@deepseek-ai/dsh-tool-goal'
202
+
203
+ # ── plan mode ───────────────────────────────────────────────────────────────
204
+
205
+ # Plan state is per-agent by nature, so an entry-local realm is not a
206
+ # workaround here — it is the correct lifetime.
207
+ - id: planning
208
+ name: cordis:group
209
+ group: true
210
+ isolate:
211
+ planMode: true
212
+ config:
213
+ - id: plan-mode
214
+ name: '@deepseek-ai/dsh-plan-mode'
215
+ config:
216
+ section: |
217
+ You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
218
+
219
+ Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
220
+
221
+ The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
222
+
223
+ Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
224
+
225
+ Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
226
+
227
+ When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
228
+
229
+ # ── compaction ──────────────────────────────────────────────────────────────
230
+
231
+ # `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
232
+ # share this realm rather than sit outside it.
233
+ #
234
+ # `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
235
+ # plane, and the rows here resolve that one instance. It takes no configuration,
236
+ # keys every fold by Session, and owns the context-meter projection units the
237
+ # browser reads for every session — behind a realm those units would come and go
238
+ # with whichever presets happen to be mounted. What a preset chooses is whether
239
+ # its agent compacts at all, which is `compaction-basic` below.
240
+ - id: compaction
241
+ name: cordis:group
242
+ group: true
243
+ isolate:
244
+ compaction: true
245
+ toolResultPruner: true
246
+ config:
247
+ - id: compaction-basic
248
+ name: '@deepseek-ai/dsh-compaction-basic'
249
+
250
+ - id: command-compact
251
+ name: '@deepseek-ai/dsh-command-compact'
252
+
253
+ - id: tool-result-pruner
254
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
255
+ config:
256
+ thresholdChars: 8192
257
+ headChars: 4096
258
+ tailChars: 1024
259
+
260
+ # ── delegation and workflows ────────────────────────────────────────────────
261
+
262
+ # The `subagents` registry and its spawn/fork backends live in the HOST
263
+ # composition: the registry is a process singleton whose cross-session queries
264
+ # the api-proxy serves to the browser, and a provider name may only be
265
+ # registered once. This preset contributes the delegation TOOLS, which resolve
266
+ # that host registry.
267
+ #
268
+ # `workflows` is different — nothing outside an agent reads it — so every row
269
+ # that reaches it shares one entry-local realm here, and a consumer left
270
+ # outside would resolve a host registry this preset does not populate.
271
+ #
272
+ # `tool-subagent-report` is host-plane for the same reason as the registry,
273
+ # not because a preset may not want it: it registers a CONTINUABLE SETUP on
274
+ # that singleton rather than a tool this agent calls, and the setup list is
275
+ # not scope-aware — one copy per mounted preset means every child gets
276
+ # `report` registered once per live session, which throws on the second.
277
+ - id: delegation
278
+ name: cordis:group
279
+ group: true
280
+ isolate:
281
+ workflowEngine: true
282
+ config:
283
+ - id: tool-subagent-control
284
+ name: '@deepseek-ai/dsh-tool-subagent-control'
285
+
286
+ - id: tool-subagent-list-agents
287
+ name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
288
+
289
+ - id: tool-subagent
290
+ name: '@deepseek-ai/dsh-tool-subagent'
291
+ config:
292
+ provider: spawn
293
+ toolName: subagent
294
+ backgroundMode: continuable
295
+
296
+ - id: tool-subagent-fork
297
+ name: '@deepseek-ai/dsh-tool-subagent'
298
+ config:
299
+ provider: fork
300
+ toolName: subagent_fork
301
+ backgroundMode: continuable
302
+
303
+ # Production dsh does not install these optional providers. Install the
304
+ # matching Bundle in this Profile and restart the Host, then copy this
305
+ # preset and remove `disabled` from the matching tool row. Host availability
306
+ # alone grants no tool.
307
+ - id: tool-subagent-codex
308
+ name: '@deepseek-ai/dsh-tool-subagent'
309
+ disabled: true
310
+ config:
311
+ provider: codex
312
+ toolName: subagent_codex
313
+ backgroundMode: one-shot
314
+ maxDepth: provider-managed
315
+
316
+ - id: tool-subagent-claude-code
317
+ name: '@deepseek-ai/dsh-tool-subagent'
318
+ disabled: true
319
+ config:
320
+ provider: claude-code
321
+ toolName: subagent_claude_code
322
+ backgroundMode: one-shot
323
+ maxDepth: provider-managed
324
+
325
+ - id: workflow-worker-thread
326
+ name: '@deepseek-ai/dsh-workflow-worker-thread'
327
+ config:
328
+ provider: spawn
329
+
330
+ - id: tool-workflow
331
+ name: '@deepseek-ai/dsh-tool-workflow'
332
+
333
+ - id: tool-ralph
334
+ name: '@deepseek-ai/dsh-tool-ralph'
335
+ config:
336
+ subagentProvider: spawn
337
+ maxRounds: 64
338
+
339
+ # ── remaining model-facing rows ─────────────────────────────────────────────
340
+
341
+ - id: tool-ask-user
342
+ name: '@deepseek-ai/dsh-tool-ask-user'
343
+
344
+ - id: tool-todo
345
+ name: '@deepseek-ai/dsh-tool-todo'
346
+ config:
347
+ allowParallelInProgress: true
348
+
349
+ # The `web` service and its search provider stay in the host composition; only
350
+ # the model-facing tool is per-session.
351
+ - id: tool-web
352
+ name: '@deepseek-ai/dsh-tool-web'
353
+ config:
354
+ fetch: false
355
+ searchTimeoutMs: 60000
356
+
357
+ # ── cluster chart tools ─────────────────────────────────────────────────────
358
+
359
+ # Charting and the pinned-chart registry. They register into the host `tools`
360
+ # registry and publish nothing, so they need no realm.
361
+ #
362
+ # The agent answers most cluster questions through the `runnpu` CLI skill;
363
+ # these exist for the one thing a CLI cannot do — put a chart on the screen and
364
+ # keep it there. `cluster_chart` renders in the conversation with a Pin button;
365
+ # `cluster_pin` stores the QUERY plus why it was pinned, never a snapshot, so
366
+ # the right column is always current and still self-explanatory.
367
+ - id: compute-tools
368
+ name: 'dsh-runnpu/compute/tools'
@@ -0,0 +1,3 @@
1
+ name: 算力管理模式
2
+ description: 面向 RunNPU 集群的算力运营工作台:查看总览、节点与逐卡健康、项目配额、排队与闲置负载,并把产出的图表固定在右栏自动刷新。忽略工作目录。
3
+ order: 10
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: runnpu
3
+ description: 通过 runnpu CLI 操作 RunNPU 昇腾算力平台——查看总览 / 节点 / 集群,管理项目、配额与成员,创建、排查、删除四类工作负载(开发环境、训练环境、训练任务、推理服务),使用工作负载模板与资产,挂载数据源与数据卷,读日志、事件、指标与 YAML,管理用户 / Access Key / 系统设置 / 审计。凡是用户要"在 RunNPU 上做某事"或询问平台 / 集群 / 负载现状时使用。
4
+ ---
5
+
6
+ # RunNPU CLI Skill
7
+
8
+ RunNPU 是面向昇腾 NPU 的算力管理平台。本 Skill 通过 `runnpu` 命令行完成一切操作——**不要自己拼 HTTP 请求**,
9
+ CLI 已经封装了认证、错误格式和输出格式;未封装的端点用 `runnpu api <METHOD> <路径>`。
10
+
11
+ 深入主题按需读同目录文件:`references/workload-types.md`(四类负载全参数)、
12
+ `references/templates-assets.md`(模板与资产的全部命令 + `--from-template` 的合并规则)、
13
+ `references/data-sources.md`(挂载与数据卷)、`references/troubleshooting.md`(排查树 + 已知集群行为)、
14
+ `references/training-runs.md`(**用户丢来训练工程说「帮我跑起来」时必读**:工程搬运、密钥注入、
15
+ 后台运行、loss 监控与收敛判断、CUDA→NPU 迁移炸点)、
16
+ `references/admin.md`(项目 / 配额 / 用户管理)。`examples/` 里是可直接照抄的完整场景。
17
+
18
+ ## 前置:确认 CLI 可用与已登录
19
+
20
+ ```bash
21
+ runnpu status # 平台版本、是否初始化、集群连通
22
+ runnpu me # 当前身份与有效权限(决定能做什么)
23
+ ```
24
+
25
+ - `runnpu` 不存在(command not found)时先装,Linux / macOS 一行:
26
+ `curl -fsSL https://github.com/EM-GeekLab/run-npu-skill/releases/latest/download/install.sh | sh -s -- --no-skill`
27
+ (Windows:`irm https://github.com/EM-GeekLab/run-npu-skill/releases/latest/download/install.ps1 | iex`)。
28
+ 离线环境到不了 GitHub,问用户要控制台提供的安装包。CLI 与本 Skill 同版本发布,
29
+ `runnpu --version` 应与本文件末尾的版本注释一致,不一致时去掉 `--no-skill` 重装一次把两者对齐。
30
+
31
+ - 未登录时报 `unauthenticated`。二选一:交互式 `runnpu login --server <URL> -u <email>`;
32
+ 非交互设 `RUNNPU_SERVER` + `RUNNPU_TOKEN`(管理员在「个人设置 → 访问密钥」签发)。
33
+ - **绝不要**把密码或 token 写进命令行参数回显给用户,也不要写入任何文件。
34
+
35
+ ## 输出约定(对解析很重要)
36
+
37
+ - 非终端(被程序调用)下所有命令输出 **JSON**;给人看表格加 `-o table`。
38
+ - 错误走 **stderr**:`{"error":"<code>","status":<http>,"message":"…","details":[…]}`,退出码 1;参数错误 2。
39
+ 常见 code:`unauthenticated` / `forbidden` / `not_found` / `validation_failed`(看 `details` 字段级原因)/ `cluster_error`。
40
+ - 列表响应 `{"items":[…]}`,分页 `next_cursor` / `total`;**默认只取一页**(`--limit N`,默认 50),
41
+ 回答"有多少 / 全部"先加 `--all`(自动翻页),否则按 `total` 说明只看了一页。
42
+ - 时间 RFC3339;容量单位在字段名里(`_gib` / `_bytes` / `_millis`)。
43
+
44
+ ## 核心概念(回答问题前先对好口径)
45
+
46
+ - **项目**是唯一组织层(没有部门)。配额、成员、策略都挂项目上。
47
+ - **负载类型(四类都可用)**:`workspace`(开发环境,可抢占)/ `training-env`(训练环境,不可抢占)/
48
+ `training-job`(训练任务,跑完即止,可多机)/ `inference`(推理服务,Deployment + 端口)。
49
+ 开发/训练环境的区分轴是**可抢占性**,不是单机多机。
50
+ - **配额单位是卡(张数)**:`guaranteed` 保底张数、`limit` 额外可借张数。集群内部记账用核当量
51
+ (100 核 = 1 卡),分卡负载按份额扣(25 核 = 0.25 卡);`cards_equivalent_used` 是实际占用卡当量。
52
+ - **分卡(vNPU)**:`--xpu 1 --xpu-core C --xpu-memory-mib M` = 单张卡切 C%(1..100)算力 + M MiB 显存。只支持单卡切分:`--xpu` 必须为 1(多卡请按整卡申请)。
53
+ 两个字段必须成对;整卡就都不给。创建后不可改规格。
54
+ - **负载状态**:`submitting → pending/queued → admitted → running`;终态 `completed / stopped / failed / rejected`;
55
+ `cleanup_blocked` / 长期 Terminating 见 troubleshooting(已知上游问题,**不要反复删**)。
56
+ - 指标为 `null` 或 `metrics.available=false` = **数据源未接入**(不是 0),转述时说"未接入",原因在 `metrics.reason`。
57
+
58
+ ## 创建负载前:先查模板与资产
59
+
60
+ 用户要创建负载时,**第一步是查模板,不是从零拼参数**——模板是平台/管理员存好的整张创建表单,
61
+ 往往带着踩过坑才知道的预设(如昇腾官方镜像必需的 LD_LIBRARY_PATH 覆写、就绪探针延迟):
62
+
63
+ ```bash
64
+ runnpu template list --type training-env # ★ 开头的是系统预置;-q 按名称/描述/镜像搜
65
+ runnpu template get <名称> # 看 payload 里都预设了什么
66
+ runnpu asset list --kind environment # 资产:environment / compute / data-source / credential
67
+ ```
68
+
69
+ **有匹配的模板就用 `--from-template`,不要自己读 payload 再手拼参数**:
70
+
71
+ ```bash
72
+ runnpu workload create --project main --name nb6 --from-template <名称> --xpu 2 --wait
73
+ ```
74
+
75
+ - 合并规则由 CLI 保证:模板 payload 作基底,**只有你在命令行上显式写了的字段才覆盖它**
76
+ (`--xpu 0`、`--jupyter=false` 这种「显式的零值」也算数);`--mount` 与模板预设的数据源取并集,
77
+ 挂载点冲突会直接报错。**模板里的 env / 探针等预设不会丢**——那正是模板存在的理由。
78
+ - 模板类型不可覆盖:`--type` 与模板类型不一致会报错,换模板而不是改类型。
79
+ - 模板标记的 `pending_fields`(待填字段)要问用户,别编;提交后服务端 422 会把缺的字段指出来。
80
+ - 如果 CLI 报「模板里有本版本不认识的字段」,说明服务端比 CLI 新——升级 CLI,
81
+ 或退回 `runnpu api POST /workloads -d '<payload + project_id + name>'`。
82
+ - **资产是单个配置段的值拷贝**:environment(镜像+env)/ compute(池+卡数)按段并入;
83
+ credential / data-source 资产在挂载里按名引用(如 `--mount s3:...,credential=<资产名>`)。
84
+ - 列表为空或确实不匹配再手拼参数;用户自带全量参数时以用户为准,但提一句「有现成模板 X」。
85
+
86
+ ## 常用流程
87
+
88
+ **用户给了一个训练工程(文件夹/仓库)要「跑起来」** → 先读 `references/training-runs.md`
89
+ 再动手(搬运方式、密钥注入、后台运行、loss 监控的判断经验都在那)。
90
+
91
+ ### 看现状
92
+
93
+ ```bash
94
+ runnpu overview # KPI、项目资源分布、存储池、排队/闲置负载
95
+ runnpu node list / runnpu node get 910b2 # 物理卡健康与占用,逐卡到负载
96
+ runnpu cluster get # 组件健康(Operator/Kueue/HAMi/Prometheus…)、算力池、存储池
97
+ runnpu workload list [--project X] [--type training-job] [--status running] [--all]
98
+ runnpu workload list --deleted # 删除历史(谁删的、何时)
99
+ ```
100
+
101
+ ### 创建开发环境并拿到入口
102
+
103
+ ```bash
104
+ runnpu workload create --project main --name nb5 --type workspace \
105
+ --image m.daocloud.io/quay.io/ascend/vllm-ascend:v0.22.1rc1 \
106
+ --xpu 1 --security baseline --jupyter --workspace-pool shared-cephfs --workspace-gib 50 --wait
107
+ runnpu workload get main/nb5 # tools[].url 是 Jupyter 地址(平台登录态直达,无需 token)
108
+ ```
109
+
110
+ - `--wait` 阻塞到 `running / failed / rejected`(最多 10 分钟;**大镜像首次拉取可能超过它**,超时后用
111
+ `runnpu workload get` 继续看,不代表失败)。
112
+ - 受管工作盘(`--workspace-*`)非 root 也可写(平台以 GID 20000 + ACL 初始化卷根)。
113
+ - SSH:加 `--ssh`(注入用户已登记公钥)即可,**与安全级无关**——restricted / baseline 都支持
114
+ (run-npu#595 起放行;旧版 operator 才会以 `SshRootInitUnavailable` 拒绝 restricted+SSH)。
115
+ SSH 登录后的身份 = 容器主进程的身份(restricted 下就是你 `--run-as-uid` 指定的非 root 用户)。
116
+ 连接命令用 `runnpu workload endpoints` 拿:
117
+ 登录用户名是 `<负载名>.<命名空间>`(SSHPiper 路由标识,API `ssh.username`),不是平台用户名。
118
+ - restricted 下 root 镜像要 `--run-as-uid`(安全级本身的要求,与 SSH 无关)。
119
+ - `runnpu workload exec main/nb5` 连入终端(交互式;管道喂 stdin 必须以 `exit` 结尾)。
120
+
121
+ ### 训练任务(跑完即止)
122
+
123
+ ```bash
124
+ runnpu workload create --project main --name job1 --type training-job --image img:tag --xpu 2 \
125
+ --command bash --command -c --arg "python train.py" \
126
+ --backoff-limit 2 --active-deadline-seconds 7200 --ttl-after-finished 86400 --wait
127
+ # 多机:--nodes N(N ≥ 2,没有中间值);多机没有 --completions/--parallelism(规模由节点数决定)
128
+ runnpu workload get main/job1 # status=completed 后 batch 进度在 progress 里(succeeded/failed/retries)
129
+ ```
130
+
131
+ ### 推理服务(部署完记得给用户访问地址,见下一节)
132
+
133
+ ```bash
134
+ runnpu workload create --project main --name svc1 --type inference \
135
+ --image m.daocloud.io/quay.io/ascend/vllm-ascend:v0.22.1rc1 --xpu 1 --security baseline \
136
+ --command bash --command -c \
137
+ --arg "python -m vllm.entrypoints.openai.api_server --model /models/qwen --served-model-name qwen --port 8000" \
138
+ --mount pvc:/models,name=model-weights,ro \
139
+ --port http:8000,expose=nodePort --replicas 1 --wait
140
+ runnpu workload get main/svc1 # 工具行显示 nodePort=3xxxx;访问 http://<任一节点IP>:<nodePort>
141
+ ```
142
+
143
+ 三个必须想清楚的点:
144
+
145
+ 1. **不给 `--port` 的推理服务不对外,等于白建**。`expose=clusterIP` 只在集群内可达;对外用 `nodePort`。
146
+ 2. **模型权重从哪来是真正的卡点**:镜像里没有权重。挂 PVC / NFS / 数据卷进来,或问用户有没有内网镜像源——
147
+ 私有化环境**别默认能连 HuggingFace**。用户说"部署一个 X 模型"时先问权重来源,这比拼命令重要。
148
+ 3. **`ready=false (EndpointUnavailable)` 不代表不可达**(已知上游观测缺陷 run-npu#553):`node_port` 已分配、
149
+ Pod Running 时端口通常已可用,用 `curl http://<节点IP>:<nodePort>/` 实测判断,别等 ready 翻真。
150
+
151
+ ### 部署完了怎么访问(用户问得最多的下一个问题)
152
+
153
+ ```bash
154
+ runnpu workload endpoints main/svc1 # 一条命令给出所有入口 + 现在能不能用
155
+ ```
156
+
157
+ 三条路径,按可用性排:
158
+
159
+ 1. **泛域名入口**(`--jupyter` / `--code-server` / `--port …,expose=externalUrl`):`url` 非空即可点,
160
+ 平台登录态直达,不用再输 token;
161
+ 2. **NodePort**(`--port name:端口,expose=nodePort`):`endpoints` 会给出 `http://<节点地址>:<端口>` 直接访问。
162
+ ⚠️ **`workload get` 里这条的 `ready` 会长期是 false**——Operator 只认节点 ExternalIP,私有化集群没有
163
+ (上游 run-npu#553)。端口是真的通的,**别因为 ready=false 就告诉用户"没起来"**,以 `endpoints` 的判断为准;
164
+ 3. **端口转发**(前两条都没有时的兜底,不依赖任何集群地址):
165
+
166
+ ```bash
167
+ runnpu workload port-forward main/svc1 8000:8000 # 然后访问 http://127.0.0.1:8000
168
+ runnpu workload port-forward main/nb5 2222:2222 # 转发 SSH 端口,本地再 ssh 进去
169
+ ```
170
+
171
+ 它走控制面板的 WebSocket 隧道,只要 CLI 能连上平台就能用;Ctrl-C 结束。
172
+
173
+ `workload create --wait` 成功后会自动打印可用地址,不用再问一遍。
174
+
175
+ ### 挂载数据(速查;细节与易错点见 references/data-sources.md)
176
+
177
+ ```bash
178
+ --mount pvc:/models,name=weights,ro # ⚠️ PVC 必须带 npu.run/project-id=<项目slug> 标签,否则报"不存在"
179
+ --mount datavolume:/data,name=<集群卷名>,ro # 跨项目必须 ro;集群卷名用 runnpu datavolume list 查
180
+ --mount newvolume:/out,pool=shared-cephfs,size=20Gi[,persistency=project]
181
+ --mount nfs:/data,server=10.0.0.1,path=/export/ds
182
+ --mount emptydir:/scratch,size=1Gi
183
+ ```
184
+
185
+ **数据源整段创建后不可修改**。用户说"再挂一个盘"= 重建负载,不是找修改命令。
186
+
187
+ ### 排查一个负载(完整决策树见 references/troubleshooting.md)
188
+
189
+ ```bash
190
+ runnpu workload get main/nb5 # 状态、reason.text、Pods、工具入口
191
+ runnpu workload events main/nb5 # 调度/准入/运行时事件
192
+ runnpu workload logs main/nb5 --tail 200 # -f 跟随
193
+ runnpu workload yaml main/nb5 # 实际 CR 含 status
194
+ ```
195
+
196
+ 顺序:`status`+`reason.text` → `events` → `logs`。`queued` 看项目配额;`admitted` 不 `running` 看事件里的
197
+ 镜像拉取/调度;**容器 CrashLoop 且日志有 `symbol lookup error`** → 镜像 LD 与平台注入不兼容,
198
+ 见 troubleshooting 的「镜像兼容性」一节(有一行 env 的救援配方)。
199
+
200
+ ### 停止 / 删除
201
+
202
+ ```bash
203
+ runnpu workload stop|start main/nb5
204
+ runnpu workload delete main/nb5 --yes # 破坏性:先向用户确认
205
+ ```
206
+
207
+ 删除后负载可能停留 Terminating 数分钟乃至更久(上游 run-npu#549:带工具 Service / 受管卷的负载
208
+ teardown 卡住)——**不要反复删、不要 --force 循环**,如实告知用户需等待或运维介入。
209
+
210
+ ### 项目与配额(管理员;全量见 references/admin.md)
211
+
212
+ ```bash
213
+ runnpu project create --slug asr --name 语音识别 --pool ascend910b4 --guaranteed 4 --limit 4 \
214
+ --storage-pool shared-cephfs --storage-gib 200
215
+ runnpu project quota get asr
216
+ runnpu project quota set asr --pool ascend910b4=8,4 --storage-pool shared-cephfs=500 # 整份替换语义!先 get 再 set
217
+ ```
218
+
219
+ 单位是**卡**。⚠️ 建项目后配额落到集群有秒级延迟且可能失败(集群配额被占满时被拒):
220
+ 建完项目**先 `runnpu project quota get <slug>` 确认 `cluster` 段有数据**再建负载,
221
+ 否则负载可能拿到**终态** `rejected / QuotaGrantNotFound`(不会自愈,要删掉重建)。
222
+
223
+ ## 行为准则
224
+
225
+ 1. 只读命令直接执行;**创建/停止/删除/改配额/改成员/禁用用户先复述参数并取得用户确认**,
226
+ 删除、移除、吊销类必须用户明确同意后才加 `--yes`。一次性凭据(初始密码、token 明文)只转给用户,不复述到其它地方。
227
+ 2. 引用负载一律 `<project-slug>/<name>`;项目可用 slug 或 ID。
228
+ 3. 用户点名的东西(模型名/镜像 tag/池名)**可能不存在**:能核对的核对(池用 `runnpu cluster get`),
229
+ 核对不了的明说无法确认、要用户拍板,**绝不静默替换**。
230
+ 4. 不猜状态含义:以 `status`、`reason.text`、`events` 为准;`metrics.available=false` 按"未接入"转述。
231
+ 5. 结果给出用户能直接用的关键字段(名字、状态、入口 URL / nodePort、原因);数字带单位与口径(卡 / 卡当量 / GiB)。
232
+
233
+ <!-- runnpu-skill v0.1.1:与 runnpu CLI 同版本发布,`runnpu --version` 应一致 -->
@@ -0,0 +1,11 @@
1
+ vendored runnpu skill from https://github.com/EM-GeekLab/run-npu-skill (skills/runnpu — the CLI + skill release repo,
2
+ auto-synced from run-npu-control-panel's CI on every tag; do not send PRs there)
3
+ upstream release: v0.1.1 (run-npu-control-panel@eff724b8, mirror main@3532ee4; synced 2026-09-14)
4
+
5
+ 配套 CLI:runnpu v0.1.1 —— 与 package.json `cliDeps.runnpu.version` 同值,tests/skills-sync.test.mjs 钉住。
6
+ 同一个 Release 里有各平台二进制(runnpu_<ver>_<os>_<arch>.tar.gz|zip)、checksums.txt 和
7
+ runnpu-skill_<ver>.tar.gz|zip(内容 == 该 tag 的 skills/runnpu)。**升级时两个一起换**:
8
+ 把这里的文件换成新 tag 的 skills/runnpu(== Release 里的 runnpu-skill_<ver>.tar.gz 解压内容),
9
+ 再把 cliDeps.runnpu.version 改成同一个 tag。SKILL.md 末尾的版本注释是发布脚本追加的,应与本文件一致。
10
+
11
+ LOCAL PATCHES:无(v0.1.0-rc.1 时期本地重写的 references/training-runs.md 已随控制面板 v0.1.0 回流上游)。