跳过主要内容
Z

dsh-whale-waker

ztan4706/dsh-whale-waker

给 DSH 工作区按目标定时唤醒:每个目标可设间隔、安静时段、每日上限和提示词;每次唤醒会等它自己那一轮结束并记下结果,没跑完的那一轮不会算作完成。

安装

dsh plugin --profile web add github:ztan4706/dsh-whale-waker

README

Whale Waker

Scheduled wake-ups for the residents of a workspace. Each target — a "whale" — gets its own interval, quiet hours, daily cap, prompt and deny-list. Every wake-up reuses the same session, gathers what changed since last time, and sends one short prompt.

  • Package: dsh-whale-waker
  • Version: 0.4.1
  • License: MIT
  • Author: Bao · E-1021

Why: an agent that only exists while you type is a tool. An agent that wakes on its own, reads what changed, and decides to do one small thing — that is closer to a resident. This plugin is the clock for that.


Install

dsh plugin --profile <your-profile> add dsh-whale-waker

From a local checkout:

git clone https://github.com/ztan4706/dsh-whale-waker.git
dsh plugin --profile <profile> add link:/absolute/path/dsh-whale-waker

Or install the directory through plugin_manager's install_bundle in the app. Restart DSH afterwards — plugin modules are cached by URL.

The settings page shows up in Settings → Whale Waker right after that.

Configure

Settings live in dsh-whale-waker.json:

  • $DSH_PROFILE_DIR/dsh-whale-waker.json by default,
  • or config.configPath from the row config.

The page edits the file for you; the scheduler re-reads it when the mtime changes (checked every five minutes).

{
  "targets": [
    {
      "id": "echo",
      "name": "Echo",
      "workspace": "D:\\rooms\\echo",
      "provider": "",
      "model": "",
      "enabled": true,
      "intervalMinutes": 95,
      "minGapMinutes": 45,
      "startHour": 9,
      "endHour": 23,
      "maxPerDay": 6,
      "prompt": "(Scheduled wake-up.)\n\n{material}\n\nMove one thing forward, or answer \"nothing this round\"."
    }
  ]
}
FieldMeaning
idTarget name; also the session id (walk-<id>) and the log tag.
workspaceThe room this whale lives in. Files changed here become material. Required: empty means no wake-up happens (no-workspace).
provider / modelOptional. Empty means "use this DSH's default model", so the plugin does not assume a vendor. A provider this host does not serve is logged and skipped as provider-not-configured instead of failing inside agent creation.
ollamaBaseEndpoint used only to pre-warm an ollama* provider. Default http://127.0.0.1:11434, 15 s timeout, and a failure never blocks the wake-up.
intervalMinutesHow often it may wake on its own (5–2880).
minGapMinutesMinimum gap between two wake-ups (0–1440).
startHour / endHourQuiet hours: outside this window nothing fires (0–24).
maxPerDayHard daily cap (0–48). 0 means never wake on its own.
dryRunCollect material and log it, but do not open a session.
watchExtra directories whose fresh files are listed as material.
stateSectionHeading in STATE.md whose bullets are quoted (default ## In progress).
denyToolsTool names removed from that whale's wake session (e.g. another agent's private tools).
activeWindowMinutesAfter a human actually talks in that workspace, the timer stays quiet this long (default 10; 0 disables). Manual wake-ups ignore it.
promptTemplate; {material} is replaced.
nameDisplay name used in the session title (defaults to id).
sessionTitleTitle template for the wake session; {name} is replaced (default Wake · {name}).

State (last wake, today's count) is persisted to dsh-whale-waker-state.json next to the config, so restarting DSH does not re-fire everybody.

Language

The settings page follows the DSH locale by default, and can be switched per plugin without touching the rest of the UI:

{ "ui": { "language": "zh-TW" } }

Supported values: auto (follow DSH), en, zh-CN, zh-TW. The selector sits near the top of the page; the choice is written to the same config file.

While you are talking to it

A wake-up never joins your live chat: it opens (or resumes) its own session, walk-<id>, in that workspace. So the honest answer to "would it start walking while I am mid-conversation?" is yes, unless something stops it.

So something stops it. The plugin watches agent/inbox/claimed for messages a human actually typed (its own injected prompts and walk-* sessions are ignored). If the workspace saw one within activeWindowMinutes (default 10), the timer wake is skipped and logged as user-active. The next tick, five minutes later, tries again.

What this does not do:

  • It does not interrupt a wake-up already running.
  • It does not persist: after a restart the activity map is empty until the next message. minGapMinutes is the backstop for that window.
  • It does not block manual wake-ups (wake_whale, or the page's "Wake once") — those are explicit intent and pass force.

Workspace path

The address under each target is editable: type a folder and press Apply. The host validates it (absolute, existing, a directory), stores the canonical spelling, and — when no workspace owns that folder — creates one titled after the last folder segment. That is what puts the wake session in its own sidebar group instead of "Ungrouped"; a typo is rejected with the reason instead of being saved.

Changing the path also changes the session id (walk-<id>-<workspace fingerprint>), so the next wake opens a fresh session in the new room; the old one is left as history.

Restart notice

The plugin compares the version on disk with the version the running process loaded. When they differ — the usual case right after an upgrade — the page shows a banner:

The package on disk is v0.0.2, but this process is still running v0.0.1. Restart DSH to load the new code.

That is deliberate: DSH caches plugin modules by URL, so "installed" and "running" can disagree, and silently pretending otherwise wastes an afternoon. Any plugin that changes something a restart is required for should say so, in the UI and in the log, instead of leaving the user to guess.

Tool

wake_whale — wake one target for a single turn.

  • wake_whale({}) lists targets, their next-eligible state and today's count.
  • wake_whale({ id: "echo", reason: "..." }) wakes that target once, bypassing the schedule but still respecting "already running".

What a wake-up does

  1. Collects material: files changed in the workspace since the last wake, plus watch directories, plus the stateSection bullets of STATE.md.
  2. Mounts an agent preset so the session has real tools (without one, a wake session cannot even read its own STATE.md).
  3. Reuses walk-<id>-<workspace fingerprint> — created the first time, resumed afterwards. The fingerprint changes with the workspace path, so a moved room gets a fresh session instead of resuming one that still points at the old path.
  4. Attaches that session to the workspace group that matches its cwd.
  5. Sends the prompt and waits for the turn to actually end (claim → turn/end). The session stays alive afterwards, so the conversation remains visible in that workspace.
  6. Names the session from sessionTitle (default Wake · {name}), because the automatic titler ignores prompts that a plugin injects and would otherwise leave it "Untitled" in the sidebar.

Everything is logged to dsh-whale-waker.log next to the config, including the material that was handed over — so "why did it say that" is answerable afterwards.

Limits (honest)

  • The scheduler checks every five minutes, so a wake can drift by up to five minutes.
  • Wake sessions run with the provider/model you configure; a slow local model can take a while to warm up (the plugin pre-warms Ollama, 3-minute timeout).
  • Only one wake per target at a time.
  • No UI to add targets — edit the JSON (or the page fields of existing targets).

License

MIT · Bao · E-1021

相关插件