English | 中文
Trigger-independent session feedback plus human-facing /feedback capture. The package exports recordFeedback(session, text), which appends one log-only feedback/record event. Its plugin registers one global command through ctx.commands, so every composed command adapter discovers it; the shipped Web client executes it without a model turn.
| Input | Result |
|---|---|
/feedback <text> |
Append feedback/record and acknowledge with Feedback recorded for session {sessionId} followed by User: {userId}. |
/feedback |
Return a direct usage error. Whitespace-only input is treated as empty. |
Surrounding whitespace is discarded, but feedback is otherwise unparsed: no truncation, case folding, or control words. Text that looks like another command, such as /feedback /plan felt slow, is feedback content. Repeated commands each produce their own event; nothing is replaced or merged.
recordFeedback(session, text) is the command-independent write path. It rejects empty normalized text and appends feedback/record { text }; a different UI, hook, or host integration can call it without constructing a slash command. The /feedback handler uses that producer and starts no model work. The optional dsh-session-telemetry-otel consumer observes the event without changing its capture contract.
The feedback text appears in exactly one durable payload: feedback/record. dsh-commands still appends its generic command/run / command/done pairing, but this definition sets recordInput: false, so command/run omits args; the paired command/done carries only the outcome. All three events are log-only and absent from the ordered surface, deriveMessages(), and model requests. These appends start persistence's ordinary eager drain, but neither producer forces session/flush, so acknowledgement means the feedback is in the log, not that it has reached disk. The acknowledgement identifies both the receiving session and the shared anonymous user; the first accepted feedback for a harness home can create $DSH_HOME/.userid. Rejected empty input leaves only the command pairing settled as kind: 'error', with no feedback/record and no user-id lookup.
The event is authoritative rather than the command record because feedback may arrive through a trigger other than /feedback. Keeping the payload out of command/run avoids two records carrying the same text.
The producer injects only commands. A custom app mounts the registry plus this plugin:
- id: commands
name: '@deepseek-ai/dsh-commands'
- id: command-feedback
name: '@deepseek-ai/dsh-command-feedback'
The shipped dsh base mounts this command unconditionally; it has no configuration and no dependency on the persisted-goal stack. The Web client exposes it through the command adapter. Headless mode, ACP automation, and JSON-RPC do not provide a command adapter, so they do not expose it.
/feedback captureNothing. The slash input, feedback/record, and the acknowledgement are absent from model requests. The feedback event and registry lifecycle records are log-only and carry no surfaceOp, so they never reach the ordered surface, deriveMessages(), or a system prompt. Recording feedback during a turn does not change that turn's remaining requests.
Zero direct token effect. Neither an accepted entry nor a usage error adds model tokens, in the recording turn or any later one.
Independent of the model request path. Recording appends to the session log only, leaving an already-reusable request prefix untouched. Nothing this package contributes can invalidate cache reuse.
feedback/record.ctx.sessions.flush(session)./feedback is unavailable there.