Introduction

In DeepSeek Harness (DSH), when a model invokes the ask_user_question tool, the loop remains suspended until a human answers in the Web UI. The question is only rendered when the browser is taking over (ui-user-questions). If the tab is closed, sent to the background, or the connection is interrupted, the question will never be rendered. At this point, the session state remains “in progress” with no timeout, and the only way to exit is to manually stop it, which displays a misleading ASK_ABORTED error. The dsh-ask-user-timeout plugin addresses this issue by providing a bounded lifecycle for this tool.

Plugin Overview

dsh-ask-user-timeout is a Guard plugin maintained by yeruizhi. It listens to the tools/execute extension point and sets a deadline for the ask_user_question tool. If the question is not rendered, the tool returns an ASK_TIMEOUT error instead of suspending indefinitely. The plugin does not change the tool’s schema, output shape, or semantics; it only terminates the suspension.

Installation

Use the official installation command to add the plugin:

dsh plugin --profile web add git+https://github.com/yeruizhi/dsh-ask-user-timeout.git

After installation, restart dsh web, then hard-refresh the browser to apply the wrapper. The plugin takes effect for ask_user_question invocations in sessions created after installation.

Configuration

The plugin controls the timeout via the timeoutMs configuration item, with a default value of 600000 (10 minutes).

Add the following configuration to ~/.dsh/profiles/web/cordis.patch.yml:

- insert:
    - id: ask-user-timeout
      name: 'dsh-ask-user-timeout'
      config:
        timeoutMs: 300000

How It Works

  1. It listens to the tools/execute extension point (the same as the official timeout-policy guard).
  2. It only wraps the tool named ask_user_question; other tools remain unchanged.
  3. During dispatch, it replaces exec.signal with a fused deadline and restores the upstream signal after execution completes.
  4. When the deadline is reached, it replaces the result with error.code = ASK_TIMEOUT, allowing the loop to continue.
  5. It does not change the tool’s schema, output shape, or semantics.

Scope and Notes

This is a Guard plugin intended to solve the “suspension” issue, not to fix Web UI rendering problems. If the question is not rendered and the user reopens the tab, the plugin will not renotify that question. The deeper issue is tracked in deepseek-ai/deepseek-harness discussion #2929.