Files
deepseek-harness/packages/client/ui-task
Chinesezjc b462d5fd69 Merge remote-tracking branch 'origin/master' into feat/web-message-feedback-ui
Adapt to two contract changes master introduced:

- The generated Remote face now wraps every business result in
  RemoteResult, folding carrier failures into an ok:false branch instead
  of rejecting. The controller reads that envelope at its three call
  sites and maps a carrier failure onto the same settled shape the
  controls already render; three specs cover the new branch.
- Client packages split their tsconfig into host and client halves, and
  the host aggregate now compiles any test not named *.client.spec.*.
  Rename this package's specs to the client convention and drop the
  ../connection project reference, which pointed at a solution file that
  no longer carries the client sources.

Keep master's mount loop with its rollback-on-failure in api-remotes and
add messageFeedbackRemote to it.
2026-08-12 10:43:23 +08:00
..
2026-08-11 22:52:39 +08:00

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

English | 中文

Web background-task feature owner: contributes one entry to conversation.session.header.actions listing the ctx.tasks records this session can see. The data arrives entirely through the tasksBySession list mirror that dsh-client-runtime folds from session/tasks frames, so this package issues no RPC and holds no state beyond popover visibility.

The trigger renders only when the session has at least one task, so an ordinary conversation never grows a control for a capability it is not using. Its badge counts running plus stopping and is omitted at zero, leaving a session that holds only finished tasks a quiet entry point into its history rather than one advertising a count of nothing. The popover is a flat list: live rows first by startedAt ascending, then settled rows by finishedAt descending, with a same-millisecond tie broken on start order so the host's map iteration never decides it. A row shows the producer kind, the label, a status marker, the producer's detail in place of the generic status word once it has one, and an elapsed duration. That duration advances once per second while the row is live and freezes at finishedAt; the clock runs only while an open list holds something that moves. A settled row missing finishedAt reads as zero rather than as a negative figure, and a duration past an hour stays in hours rather than growing a day vocabulary no producer currently reaches.

Settled rows stay visible and de-emphasized until the registry drops them at owner disposal. They are in the snapshot, a failed task's detail is the only place its failure is legible, and filtering them out here is work the output and cancellation phases would undo. A running one-shot background subagent therefore appears both here and in the subagent catalog: the catalog navigates into the child's transcript, while this list is the only handle a future cancellation can attach to.

Escape closes the list and returns focus to the trigger, as does a pointer press outside it. The last task disappearing closes the list before the control unmounts, so focus never vanishes from a removed node. Styling uses tokens only; copy goes through the package's own task locale namespace. The behavior is specified by the Web background-task display Agent Note.

Model Experience

None, as this package renders host-computed registry state for a human and touches no prompt, message, schema, stream, or tool result. The model's own view of the same tasks stays with dsh-tool-tasks.

KV Cache effect

None; the package never assembles or sends provider requests.

Known Limitations and Deferred Work

  • Rows are read-only — a task's streamed output and a human-initiated cancellation are separate phases. Cancellation additionally owes a model-facing decision the seam does not answer today: kill() marks terminal delivery reported, so an interrupt written against the current contract would leave the model believing its task is still running.
  • The list is not the registry's own set — it shows what one session can see through the wire view, so a task owned by another session never appears here, and a process restart empties the list while the transcript keeps the run_in_background cards that started those tasks. An unowned task (one started without a live Agent) is the opposite case: it reaches every session's list, matching what list(caller) reports to every caller.