Files
deepseek-harness/packages/client/ui-skill
Yichen Jiang 97e0299f74 feat(web): trim @ mention rows and cut their discovery cost
Session candidates labelled from projection checkpoints instead of a full
log fold per keystroke, with the uncheckpointed remainder folded once and
memoized while its log stays cold. The file index keeps answering while an
invalidated traversal rebuilds behind the caret, and its default exclusions
now cover build outputs so deep sources stay reachable.

Rows carry only what distinguishes them: a file names its parent directory,
a session names its workspace only when that workspace is not the current
one, and a drilled listing names none because its new breadcrumb does.

Resolves #3180
Related to #3154
2026-08-27 11:42:06 +08:00
..

description, kind
description kind
Web skill references and the dedicated skill tool row for the dsh web client: the /-triggered skill source and the skill call card. package-reference

@deepseek-ai/dsh-client-ui-skill

English | 中文

Summary

dsh-client-ui-skill lets users invoke skills by typing /name in the composer: the suggestion menu offers user-invocable skills from the skill.list RPC, and a pick lands the literal /name text that the host then loads as the skill's instructions. Loading is deterministic: the host's pre-step boundary (dsh-tool-skill) recognizes the whitespace-bounded /name token in the sent message and injects the rendered <skill_content> for every entry point, so a menu pick, a hand-typed token, and a TUI/ACP prompt all load the skill the same way. Settled skill calls render in the conversation as an expandable Instructions card, derived only from the frozen call/result slice.

Table of Contents


Use this package

Type / in the composer and pick a skill from the suggestions, or type /name directly; the sent message carries the literal text, and the host loads the skill the same way for a menu pick or a hand-typed token. A name shared with a host command still resolves to the command — adjudication claims the line client-side before it ever becomes a prompt.

What the source offers

Ordinary-session candidates come from the skill.list RPC; the host serves every user-invocable skill, and a modelInvocable: false entry (a disable-model-invocation skill, whose only entry point is this path) wears the user-only marker as a description prefix in the active language. Results filter by startsWith(query). A failed skill.list is logged and folded into a silent menu-group drop — the menu shows only pending/ready states.

The skill tool row

A collapsed row renders the skill glyph, Skill title, and requested skill name; running calls carry the transcript shimmer, failures replace the name with the first error line, and interrupted calls use the warning state. A settled row expands into a bounded Instructions card containing the exact durable tool output, with the standard trajectory Inspect affordance when available. The row derives its name, lifecycle, and body only from the frozen call/result slice supplied by ui-tool, never from the current catalog, so replay stays stable when installed skills or their descriptions change.


Understand the implementation

Implementation internals — click to expand

The source implements no adjudication hooks and no reference codec: the pick lands literal text and the prompt ships the same literal, so determinism lives host-side (slash pipeline note).

Candidate flow

Catalogs cache per ordinary session with a single-flight fetch; the scope-birth warm hook prewarms the session's entry, the forwarded agent-preset/selected owner event drops that one session's entry (the catalog belongs to the preset, and a blank session may switch after the warm), and connection/reset clears everything. Catalog-addressed continuable children resolve no skill candidates locally because the existing skill RPC requires an attached session; viewing their persisted history must not activate them. The list RPC rides the plugin's root-context connection captured at registration; draft chip visuals derive from the lexicon scan.

Registration

The /client exports are the plugin body (apply/inject) only; the source object is internal to the registration effect. The tool row registers the skill wire name in ui-tool's keyed tool.call.toolview slot.


Further Exploration

These pages cover the input machinery, the tool row host, and the host-side skill tool.


Model Experience

User-explicit skill invocation

What the model sees

The user's message reaches the model verbatim, /name literal included. The host's pre-step boundary (dsh-tool-skill) then appends the canonical <skill_content> block — the same renderSkillContent output the skill tool returns — as injected instructions context at the end of that step's injections, closest to the model's answer. Loading is deterministic: the model receives the full body without being asked to call the skill tool, and the catalog tells it not to re-load an inline-injected skill.

Token effect

One invocation adds the rendered skill body to that turn as injected context — the same cost as the model loading the skill through the tool, paid unconditionally instead of at the model's discretion. Menu browsing and the candidate fetch add zero model tokens.

KV Cache effect

Append-only: the injected message lands after the reusable history prefix. This package never edits earlier request tokens.

Known Limitations and Deferred Work

These limits define where the reference and the row fall back to generic behavior; they are current package constraints.

  • Result-only history pages use the generic row — keyed dispatch needs the paired call in the runtime window; pagination that leaves the call outside has no tool identity. This client presentation feature does not extend the history wire contract to recover it.
  • Text is the truth — the reference is plain draft text; a hand-typed identical token is the same reference, and the host gesture boundary judges the sent text, not the menu interaction. Chip visuals derive from the lexicon scan; no occurrence identity, position tracking, or structured reference payload exists on the prompt wire.
  • A menu opened before the prewarm settles shows no skill candidates for that keystroke; the next keystroke re-polls the settled cache.

Dev Note

Working context for maintainers — click to expand

None.