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
6.2 KiB
description, kind
| description | kind |
|---|---|
| Input trigger pipeline for the Web GUI: / and @ detection under the caret, the grouped candidate menu, and pick routing to registered sources; for users and maintainers of slash commands and references. | package-reference |
@deepseek-ai/dsh-client-ui-input-trigger
English | 中文
Summary
This package powers the input trigger pipeline of the Web GUI: it detects / and @ typed under the caret, shows a grouped candidate menu, and routes a pick to the registered source. Sources register through ctx.inputTriggers — the / command source (ui-commands), the @ file and session reference sources (ui-reference), and any business package — and the conversation wiring drives the pipeline per session. Typing a trigger seeds every source registered for it; a chrome launcher can also open exactly one source over the current selection. The pipeline is presentation-only: picks produce command claims or reference inserts whose consequences belong to the consuming host and input packages.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Mount this plugin alongside ui-conversation; the menu then appears in the input overlay when the user types a trigger under the caret. Grouped candidates render under title rows; a pick routes to the source, and the consuming surface applies the result — a slash command opens its popup or executes, a reference inserts its inline token.
Keyboard and mouse
The composer surface keeps focus while the menu is open: rows pick on mousedown, the highlight rides aria-activedescendant, and a pointer press outside both the menu and the composer card dismisses it. Space and Enter adjudication polls the optional matchSpace/matchEnter hooks in registration order; the first non-undefined answer wins, and a source can refuse a submission it cannot consume whole. A candidate declaring drill: true carries a second verb beside the settling pick: its trailing chevron and the Tab key route the same row through onPick with action: 'drill' (every other path reports 'pick'), and Tab passes untouched on rows without the flag so native focus traversal survives. A source implementing the optional header hook additionally publishes crumbs above its group: the pipeline re-polls it on every hit with the live query and whether a drill, rather than typing, produced it, and a crumb pick routes back through onPick with action: 'drill'.
Understand the implementation
Implementation internals — click to expand
src/core/ is the pure core — trigger detection, menu reduction, and exact match, with zero React/DOM/cordis — while src/client/service.ts wires the core to the menu snapshot store, the per-hit candidate fetch (generation-gated, AbortSignal-superseded, failed sources dropping silently with a console record), and the pick paths. One InputTriggerController resolves per session scope (sessionOf); the conversation wiring layer drives track/arbitrate/onSpace/adjudicate on the controller. A source is warmed into every session controller it can reach; sources whose lexicon rolls change after warm implement subscribeLexicon and the controller re-polls on each notification. MenuView self-registers into conversation.input.overlay (list kind, session scope) and renders null while closed. The listbox role sits on its scrolling viewport rather than the bounded shell, because a breadcrumb header is not an option and a listbox may not carry one; crumbs ride their own snapshot store beside the menu store, so the frozen reducer stays unaware of them. The overlay SlotMap merge lives here because the dependency direction (ui-conversation → ui-input-trigger) admits no reverse type import.
Further Exploration
Read these pages when the trigger pipeline is not enough. They move from the pipeline to the sources that register into it and the shell that owns the input.
- ui-commands — registers the
/command source into this pipeline and owns the command popup shell. - ui-reference — registers the
@file and session reference sources. - ui-conversation — declares the input overlay slot and owns the composer and input machine.
- Web client architecture — how browser plugin rows load and register slots.
Model Experience
None, as the trigger pipeline is browser presentation only — picks produce command claims and reference inserts whose model-visible consequences are owned by the consuming host and input-machine packages.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
These limits define the current trigger pipeline. They are current package constraints, not a general menu comparison or a task backlog.
- Global source layer only — session-scope source registration (per-session shadowing) is designed but not enabled; the ledger tracks the trigger condition, a real per-session source need.
InputTriggerCandidate.iconrenders as text —MenuViewdrops the string into the icon slot verbatim; wiring to the design-system icon enum lands when that enum ships.- Overlay SlotMap merge home is split from slot ownership — the sole
conversation.input.overlaymerge lives here, while ui-conversation owns its anchor, children declaration, and lifecycle because the dependency direction is ui-conversation → ui-input-trigger.
Dev Note
Working context for maintainers — click to expand
None.