Skip to main content
Glama

omp-dsh-workers

test

Ejecuta trabajadores de DeepSeek Harness (DSH) desde tu sesión de oh-my-pi. oh-my-pi (OMP) es un agente de codificación de terminal; DeepSeek Harness (dsh) es el runtime de agente de DeepSeek. La sesión se convierte en el director: reparte encargos con dsh_spawn, cada trabajador se ejecuta como una sesión persistente dsh --profile headless, y las preguntas y resultados de los trabajadores vuelven como mensajes nativos retransmitidos por un script.

Experimental v0.1: las interfaces están congeladas en docs/contracts/, pero nada de esto ha pasado aún por un ciclo de publicación pública.

Por qué

El harness de OMP es caro por tarea, y un subagente nativo paga ese coste en cada trabajo. Aquí se paga una sola vez a nivel del director; el trabajo se ejecuta en DSH, rápido y frugal en tokens, con solo un script entre ellos: cero tokens de modelo por tarea. DSH hace que las ejecuciones sean persistentes (--resume sobre un id de sesión real). Cuando no necesitas DSH, los subagentes nativos siguen siendo la opción correcta.

Related MCP server: dsh-crew

Cómo funciona

Dos niveles de modelo, deliberadamente separados:

Nivel

Quién

El modelo proviene de

1

Director — tu sesión principal de OMP en modo /dvibe

el modelo de tu sesión de OMP

2

Ejecutor DSH — un proceso headless de DSH por ejecución

model de dsh_spawn, si no el rol @dsh, si no el modelo de tu sesión, si no el predeterminado de DSH

Así que @dsh nombra el modelo heredado del ejecutor cuando dsh_spawn no tiene model — el vigilante es código, no un modelo.

flowchart TD
    D["Director<br/>main OMP session, /dvibe on"]
    B["dsh-bridge<br/>argv spawn · run registry · steer channel"]
    X["DSH headless run<br/>+ resume plugin"]
    L["relay.ts<br/>script representative, in-process"]
    D -->|"dsh_spawn — brief, label, model"| B
    B -->|"dsh --profile headless [--resume]"| X
    X -->|"Envelope v1 (last stdout line)"| B
    B -->|"pollRun, 1s"| L
    L -->|"⟨label⟩ question / result / failure (followUp)"| D
    D -->|"dsh_answer — resumes the session"| B
    D -.->|"steering: dsh_list → dsh_send / dsh_wait by runId"| B
    D -.->|"dsh_kill by runId"| B

El director lanza con dsh_spawn, responde con dsh_answer, dirige con dsh_send, espera con dsh_wait y cancela con dsh_kill; dsh_list resuelve una etiqueta a un runId.

Componentes

Ruta

Qué es

extensions/dsh-task/

La extensión de OMP: dsh_task, dsh_spawn, dsh_answer, dsh_wait, dsh_kill, dsh_send, dsh_list, el script de retransmisión (relay.ts), /dvibe, un vigilante de procesos huérfanos.

tools/dsh-bridge/

bridge-core: lanzamiento en su propio grupo de procesos separado, registro de ejecuciones, Envelope v1, canal de dirección, arrendamiento de propietario y recolección. Node ≥ 22, JavaScript ESM simple, sin dependencias y sin paso de compilación.

plugins/dsh-headless-resume/

Plugin de Cordis en el perfil headless de DSH: añade --resume, imprime Envelope v1, ejecuta la verificación previa del modelo, lee el canal de dirección.

scripts/

Instalación: enlaces simbólicos al directorio OMP activo, el parche del perfil de DSH, el enlazado de dependencias del plugin.

Requisitos

  • oh-my-pi v18 — verificado con 18.0.3 / 18.0.4; @oh-my-pi/* fijado en ^18.0.4.

  • DSH ≥ 0.1.1-rc.2 en PATH, con el perfil headless presente.

  • bun para los scripts de prueba; Node ≥ 22 para bridge-core.

  • Un proveedor de modelos configurado en tus ajustes de DSH; la extensión es neutral respecto al proveedor: pasa una cadena <provider>/<model>[:<effort>] a DSH.

DSH está en fase de candidato a versión final. El plugin de reanudación se adjunta por id de entrada, por lo que una versión que renombre esos ids hace que el parche deje de aplicarse silenciosamente. Tras cada actualización de DSH vuelve a ejecutar dsh --profile headless --help: si --resume ya no aparece, el plugin no está montado; docs/dsh-update-checklist.md contiene la lista de verificación completa.

Instalación

El repositorio es la fuente de verdad; los directorios activos solo reciben enlaces simbólicos que apuntan a él.

1. Enlaza la extensión en OMP.

scripts/install-omp-links.sh [--dry-run] [--uninstall] [--omp-dir DIR]

Crea un enlace simbólico extensions/dsh-task bajo $OMP_DIR (por defecto $HOME/.omp/agent). Idempotente: un enlace con el mismo origen se deja como está, uno que apunte a otro lugar se reorienta, y un archivo real en el destino aborta el script. --uninstall elimina solo los enlaces que apuntan aquí.

2. Monta el plugin de reanudación en el perfil headless de DSH.

scripts/install-resume-plugin.sh              # install
scripts/install-resume-plugin.sh --uninstall  # remove

Hace una copia de seguridad antes de cada cambio; requiere dsh en PATH y ${DSH_HOME:-$HOME/.dsh}/profiles/headless. Después:

  • Enlaza simbólicamente @deepseek-ai y commander desde $DSH_MODULES a node_modules del plugin.

  • Añade el plugin: dsh plugin --profile headless add link:<plugin dir>, tras hacer una copia de seguridad de package.json.

  • Añade un bloque cordis.patch.yml que desactiva headless-startup / headless-runner e inserta headless-resume-startup / headless-resume-runner.

  • Verifica: éxito solo cuando dsh --profile headless --help menciona --resume.

3. (solo pruebas) scripts/link-plugin-deps.sh enlaza las dependencias por su cuenta; bun run test:resume lo invoca.

Uso

Modo director

  • /dvibe conmuta el modo director; /dvibe on / /dvibe off son explícitos. El modelo también puede cambiarlo mediante la herramienta dvibe (action: "on" | "off"), que permanece en el conjunto de herramientas reducido.

  • Mientras está activo, el conjunto de herramientas se reduce a read, todo, dsh_spawn, dsh_answer, dsh_send, dsh_wait, dsh_list, dsh_kill, dvibe, más una directiva de director añadida al mensaje del sistema. La herramienta dvibe devuelve esa directiva en su resultado: el modelo la llama después de que se haya ejecutado before_agent_start, por lo que el mensaje del turno no puede llevar las reglas.

  • Los encargos van a dsh_spawn tal cual. Las preguntas de los trabajadores llegan como mensajes ⟨label⟩ desde relay.ts, respondidas con dsh_answer; los resultados llegan de la misma manera.

  • La entrega es al menos una vez: un evento se vuelve a anunciar cada 120 s hasta que un message_start coincidente demuestre que el followUp entró en el contexto del turno; máximo 3 intentos por evento. Un need_input entregado permanece vigilado hasta dsh_answer.

  • ¿Has terminado de repartir trabajo? Termina el turno: los eventos llegan como mensajes por sí solos.

  • dsh_wait es la alternativa síncrona, solo cuando el siguiente paso se bloquea en esa ejecución concreta y no queda nada que repartir; un envelope leído de esta manera nunca llega dos veces.

  • Al hacer /dvibe off, al apagar o al cambiar de sesión dentro del proceso, se restaura el conjunto de herramientas anterior.

Encargos, modelos, reanudación

  • Asigna a cada tarea una label corta y, opcionalmente, un model, ambos como parámetros de dsh_spawn; la etiqueta localiza la ejecución más tarde en dsh_list, dsh_answer, dsh_send.

  • La notación de modelo es <provider>/<model>[:<effort>]; niveles de esfuerzo: off, minimal, low, medium, high, xhigh, max. El sufijo tras el último : cuenta como esfuerzo solo si es uno de ellos; si no, los dos puntos pertenecen al nombre del modelo. Sin espacios en blanco ni caracteres de control; proveedor/modelo ≤ 200 caracteres cada uno, especificación ≤ 512; una especificación mal formada falla antes de lanzar: error [invalid_model].

  • Sin model, la ejecución hereda el rol @dsh de OMP (modelRoles.dsh), recurre al modelo de tu sesión y luego al predeterminado de DSH.

  • Reanudación: pasa resumeFromRunId; el bridge busca su sessionId. No pongas un runId en resumeSessionId: son identificadores distintos, obtendrás resume_not_found.

  • La reanudación funciona una vez que la ejecución ha dejado un envelope en disco; sin uno, dsh_spawn lanza has no session to resume — tanto para una ejecución aún en curso como para una que ya no está (terminada antes de tiempo, caída al inicio, barrida). Comprueba cuál es antes de reaccionar: un nuevo encargo para una ejecución que sigue trabajando duplica el trabajo.

  • La sobrescritura del modelo no es persistente: una reanudación sin model recalcula el modelo. dsh_answer no tiene ningún parámetro model; para continuar con otro modelo usa dsh_spawn con resumeFromRunId y un model explícito.

Lo que ve el director

Las tarjetas de herramientas se muestran para los humanos, por separado del texto que recibe el modelo: ▶ dsh spawn → <label>, ✓ started <label> (<runId8>) · pid …, luego ⏳ still running con las últimas líneas de salida o ✓ completed · model: … · session: … más las primeras líneas de resultado. Mientras haya ejecuciones en seguimiento, un panel dsh runs se sitúa sobre el editor y el pie muestra dsh: N running · M done. La salida de texto de las herramientas no cambia: sigue siendo el contrato.

Herramientas

Herramienta

Parámetros

Texto que recibe el llamador

dsh_spawn

task, label?, model?, timeoutMs?, resumeFromRunId?, resumeSessionId?

started <runId> (pid <pid>), más label=… y model=… cuando se proporcionan

dsh_answer

runId / label (al menos uno; con ambos, runId selecciona la ejecución objetivo, label nombra la nueva ejecución), más answer

answered <oldRunId> -> <newRunId>

dsh_wait

runId, waitMs? (por defecto 30000; 0 = una sola comprobación)

el resultado de la ejecución, o still running: <runId>, o wait cancelled for <runId>; run still active

dsh_send

runId, text

sent to <runId> / pending: … / NOT delivered: run ended before reading; message lost

dsh_kill

runId

kill <runId>: killed (…) o kill <runId>: not killed (…)

dsh_list

no active runs, o una línea por ejecución

dsh_task

task, model?, timeoutMs?, resumeFromRunId?, resumeSessionId?

el resultado de la ejecución (bloqueante, de un solo uso)

Que dsh_wait agote el tiempo es normal: la ejecución sigue viva y se puede volver a esperar; abortar una espera nunca detiene la ejecución. pending de dsh_send significa que la escritura llegó al canal y la ejecución seguía viva al volver a comprobarlo — no es una entrega confirmada; espera en lugar de reenviar. dsh_task no deja ningún envelope, por lo que su ejecución no se puede continuar; las cadenas pasan por dsh_spawn.

Líneas en las que el director puede confiar

Estas líneas van a la salida de texto de la herramienta, no solo a details, para que un director que lea texto plano pueda verificar el ejecutor, la continuidad y los códigos de error:

model: <provider>/<model>[:<effort>]
session: <sessionId>
error [<code>]: <message>

# and one line per run from dsh_list:
<runId> state=<state> label=<label|-> model=<spec|default> started=<ISO-8601>

Códigos de error

Cada fallo devuelve un turno de error explícito con un código de envelope, nunca un éxito parcial.

Código de Envelope

Significado

spawn_failed

El binario de DSH no se inició.

nonzero_exit

La ejecución terminó con un código de salida de error.

timeout

La ejecución no terminó dentro de su plazo.

killed

La ejecución fue cancelada.

malformed_output

DSH no devolvió un Envelope v1 válido.

resume_not_found

No existe tal sesión para reanudar.

resume_corrupt

La sesión persistida está corrupta o no es compatible.

resume_busy

La sesión ya está activa, o su preparación persistida está reservada.

owner_gone

Nadie renovó la concesión de la ejecución; el watchdog la reclamó.

deadline_exceeded

La ejecución superó su plazo y fue recolectada.

model_not_found

El proveedor/modelo no está en el catálogo de DSH.

invalid_model

El modelo existe, pero el esfuerzo o los metadatos no le corresponden.

Valores predeterminados: plazo de ejecución 30 min; concesión del propietario 5 min, renovada por cada ventana de dsh_wait.

Pruebas

bun run test          # unit + integration + bridge = 370 tests, no installed DSH needed
bun run test:resume   # resume plugin — needs an installed DSH

Recuentos verificados en este árbol: 195 unit + 11 integration + 164 bridge = 370 pruebas, que pasan sin un DSH instalado. Unit simula bridge-core; integration y bridge se ejecutan contra un binario dsh falso inyectado a través de DSH_BINARY. CI ejecuta las mismas tres suites con un HOME limpio, después de typecheck, lint, format:check (tsc estricto, Biome). test:resume importa @deepseek-ai/* en tiempo de ejecución — DSH debe estar instalado.

Limitaciones

  • Los huérfanos se barren, no se previenen. Las ejecuciones de DSH sobreviven a la sesión de OMP; el barrido ocurre al cargar y cada 30 s. En un session_shutdown limpio, la extensión mata sus propias ejecuciones (SIGTERM síncrono, SIGKILL de mejor esfuerzo) sin limpiar el registro.

  • Sin recuperación de fallos en vuelo: una muerte a mitad de turno no se restaura; solo se puede reanudar la sesión de DSH.

  • La compactación al reanudar lee la cabecera de la ejecución anterior hasta que se escribe la primera cabecera de nueva solicitud.

  • model en el envelope es de mejor esfuerzo: última configuración de solicitud preparada, no prueba de envío.

  • La anulación del modelo es por ejecución, no se hereda a través de resumeFromRunId.

  • Las métricas de Hub no ven los tokens de DSH.

Estado, historial, licencia

Experimental v0.1 (0.1.0). Los contratos de interfaz se encuentran en docs/contracts/; docs/dsh-update-checklist.md cubre las actualizaciones de DSH. Todo lo que un usuario o un modelo lee está en inglés; los comentarios en el código y los nombres de pruebas están en ruso. MIT License.

Related MCP Connectors

Related MCP Servers