workflow: rename dsh-workflow-vm to dsh-workflow-workerthread

Pure mechanical rename now that the package's internals are the
worker-thread engine: directory, package name, spec/e2e filenames,
module tags and logger prefixes, tsconfig/knip/run-gates/AGENTS.md
references, example cordis.yml plugin ids, doc links; catalogs
regenerated and the lockfile refreshed.
This commit is contained in:
imccyu
2026-07-09 19:06:55 +08:00
parent d5c65e2b4c
commit 0d11a3afc7
43 changed files with 59 additions and 59 deletions

View File

@@ -5,7 +5,7 @@ The workflow seam: a model-written JavaScript orchestration script that fans out
| Package | Role | ctx key |
|---|---|---|
| `workflow/` | Abstract workflow seam: service base class + run vocabulary + `workflow/*` events | `ctx.workflows` |
| `workflow-vm/` | `node:worker_threads` engine: one worker per run; the script's vm context lives inside the worker, `agent()` bridges to `ctx.subagents` over the message port | (provides `ctx.workflows`) |
| `workflow-workerthread/` | `node:worker_threads` engine: one worker per run; the script's vm context lives inside the worker, `agent()` bridges to `ctx.subagents` over the message port | (provides `ctx.workflows`) |
| `tool-workflow/` | Model-facing `workflow` tool over `ctx.workflows` | (registers on `ctx.tools`) |
The interface lives at `workflow/workflow/`. The engine's `agent()` hook rides the [subagent seam](../subagent/README.md) (any registered provider; the shipped examples use `spawn`), and `agent({ schema })` rides the structured-output support the in-process backends implement. The worker thread isolates the SCRIPT — the host never blocks on it, and a cancelled run's post-grace termination is real — but it is NOT a security boundary; an isolated-vm/separate-process engine (actual sandboxing) swaps in behind the same interface if that ever matters.

View File

@@ -40,7 +40,7 @@
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-workflow": "workspace:^",
"@deepseek-ai/dsh-workflow-vm": "workspace:^",
"@deepseek-ai/dsh-workflow-workerthread": "workspace:^",
"cordis": "^4.0.0-rc.6"
}
}

View File

@@ -10,7 +10,7 @@ import { WorkflowRunId, WorkflowService } from '@deepseek-ai/dsh-workflow'
import type { WorkflowResult, WorkflowRun, WorkflowStartRequest } from '@deepseek-ai/dsh-workflow'
import { CallId } from '@deepseek-ai/dsh-llm'
import SubagentService from '@deepseek-ai/dsh-subagent'
import WorkerWorkflowEngine from '@deepseek-ai/dsh-workflow-vm'
import WorkerWorkflowEngine from '@deepseek-ai/dsh-workflow-workerthread'
import * as toolWorkflow from '../src/index.ts'
/** A controllable engine standing in behind ctx.workflows (the tool's only seam). */

View File

@@ -1,4 +1,4 @@
# @deepseek-ai/dsh-workflow-vm
# @deepseek-ai/dsh-workflow-workerthread
The [`WorkflowService`](../workflow/README.md) implementation, on **`node:worker_threads`**: each run gets its OWN worker thread (one run = one worker, no pooling — a run is heavyweight, so the ~tens-of-ms thread spin-up is noise), the script executes in a vm context INSIDE that worker with the workflow hooks injected, and every `agent()` call bridges back over the message port to [`ctx.subagents`](../../subagent/README.md) on the host. Child agents are I/O-bound LLM loops and stay on the host event loop; the thread isolates the SCRIPT, the only part that can spin synchronously.

View File

@@ -1,5 +1,5 @@
{
"name": "@deepseek-ai/dsh-workflow-vm",
"name": "@deepseek-ai/dsh-workflow-workerthread",
"description": "worker-thread workflow engine: executes model-written orchestration scripts off the host event loop, bridging agent() calls back to ctx.subagents",
"version": "0.0.1",
"private": true,

View File

@@ -22,7 +22,7 @@
* still queued worker-side for a concurrency slot are unknowable then; the
* worker's own count rides the result message on every graceful path.
*
* @module @deepseek-ai/dsh-workflow-vm/host
* @module @deepseek-ai/dsh-workflow-workerthread/host
*/
import { fileURLToPath } from 'node:url'
@@ -190,7 +190,7 @@ export class WorkerRun implements WorkflowRun {
// data, so serialization cannot fail); there is nothing left to
// deliver to — log and move on.
/* v8 ignore next -- postMessage teardown race (a throw between exit and its event): not constructible in-process */
this.ctx.logger.warn(`workflow-vm: postMessage failed: ${renderThrown(error)}`)
this.ctx.logger.warn(`workflow-workerthread: postMessage failed: ${renderThrown(error)}`)
}
}
@@ -293,7 +293,7 @@ export class WorkerRun implements WorkflowRun {
// The subagent seam's dispose() is not supposed to reject; a backend
// that does anyway must not wedge the script's finally (which awaits
// the ack) — ack and move on.
this.ctx.logger.warn(`workflow-vm: child dispose failed: ${renderThrown(error)}`)
this.ctx.logger.warn(`workflow-workerthread: child dispose failed: ${renderThrown(error)}`)
this.finishChild(callId)
this.post(HostToWorkerType.ChildDisposed, { callId })
},
@@ -322,7 +322,7 @@ export class WorkerRun implements WorkflowRun {
void run.dispose().then(
() => { this.finishChild(callId) },
(error: unknown) => {
this.ctx.logger.warn(`workflow-vm: child dispose failed during reap: ${renderThrown(error)}`)
this.ctx.logger.warn(`workflow-workerthread: child dispose failed during reap: ${renderThrown(error)}`)
this.finishChild(callId)
},
)

View File

@@ -36,7 +36,7 @@
* Plugin export shape: a default-exported {@link WorkflowService} subclass
* (the class-based service form, like `dsh-bash-local`).
*
* @module @deepseek-ai/dsh-workflow-vm
* @module @deepseek-ai/dsh-workflow-workerthread
*/
import { randomUUID } from 'node:crypto'

View File

@@ -14,7 +14,7 @@
* result not the source is the contract: it must materialize to plain
* JSON data and pass the shape validation).
*
* @module @deepseek-ai/dsh-workflow-vm/meta
* @module @deepseek-ai/dsh-workflow-workerthread/meta
*/
import * as vm from 'node:vm'

View File

@@ -13,7 +13,7 @@
* `post(type, payload)` whose payload parameter is looked up from the map,
* so a tag/payload mismatch is a compile error at the call site.
*
* @module @deepseek-ai/dsh-workflow-vm/protocol
* @module @deepseek-ai/dsh-workflow-workerthread/protocol
*/
import type { WorkflowAgentEndInfo, WorkflowAgentInfo, WorkflowResult } from '@deepseek-ai/dsh-workflow'

View File

@@ -27,7 +27,7 @@
* thrown by a hook is built OUTSIDE the script's vm context, so an in-script
* `instanceof Error` check is false; read `name`/`code`/`message` instead.
*
* @module @deepseek-ai/dsh-workflow-vm/realm
* @module @deepseek-ai/dsh-workflow-workerthread/realm
*/
/** Thrown by {@link materializeFromRealm}; the caller wraps it into the right `WorkflowError` code. */

View File

@@ -33,7 +33,7 @@
* the settles-within-grace guarantee by force-settling `cancelled` and
* terminating the worker the real kill an in-process engine could not have.
*
* @module @deepseek-ai/dsh-workflow-vm/runtime
* @module @deepseek-ai/dsh-workflow-workerthread/runtime
*/
import * as vm from 'node:vm'

View File

@@ -14,7 +14,7 @@
* A `cancel` arriving instead of `go` still releases the gate: `drive()`
* sees the cancelled state and settles without running the body.
*
* @module @deepseek-ai/dsh-workflow-vm/session
* @module @deepseek-ai/dsh-workflow-workerthread/session
*/
import type { MessagePort } from 'node:worker_threads'

View File

@@ -6,7 +6,7 @@
* JSON data by construction, so the structured-clone hop never meets a value
* it cannot carry. Types only, per the package convention.
*
* @module @deepseek-ai/dsh-workflow-vm/types
* @module @deepseek-ai/dsh-workflow-workerthread/types
*/
import type { ContentBlock } from '@deepseek-ai/dsh-llm'

View File

@@ -6,7 +6,7 @@
* coverage); loading this module on the main thread throws via
* `requireParentPort`, which is how the suite covers the file itself.
*
* @module @deepseek-ai/dsh-workflow-vm/worker
* @module @deepseek-ai/dsh-workflow-workerthread/worker
*/
import { parentPort, workerData } from 'node:worker_threads'

View File

@@ -28,7 +28,7 @@ describe.skipIf(!existsSync(builtIndex) || !existsSync(builtWorker))('built work
await writeFile(driver, `
import { Context } from 'cordis'
import SubagentService from '@deepseek-ai/dsh-subagent'
import WorkerWorkflowEngine from '@deepseek-ai/dsh-workflow-vm'
import WorkerWorkflowEngine from '@deepseek-ai/dsh-workflow-workerthread'
const ctx = new Context()
await ctx.plugin(SubagentService)

View File

@@ -41,7 +41,7 @@ async function setup(script: Script) {
return { ctx, parent, adapter }
}
describe('dsh-workflow-vm over the real in-process stack', () => {
describe('dsh-workflow-workerthread over the real in-process stack', () => {
it('runs a two-stage workflow: a plain child, then a schema child through the structured runtime', async () => {
const { ctx, parent } = await setup([
textResponse('the file list is a.ts'),

View File

@@ -119,7 +119,7 @@ async function run(ctx: Context, parent: Agent, source: string, args?: unknown):
}
}
describe('dsh-workflow-vm', () => {
describe('dsh-workflow-workerthread', () => {
describe('script execution over a real worker thread', () => {
it('runs a script end-to-end: agent() text results, phases, log, args, return value, events', async () => {
const { ctx, parent, provider } = await setup({ reply: (_request, index) => text(`answer-${index}`) })

View File

@@ -1,6 +1,6 @@
# @deepseek-ai/dsh-workflow
The **workflow seam** (`ctx.workflows`): an abstract service defining WHAT a workflow engine does — execute a model-written orchestration script that fans out subagents — without saying HOW. The bash-shaped third of the [workflow family](../README.md): implementations subclass `WorkflowService` and register as the `workflows` service (one per context); [`dsh-workflow-vm`](../workflow-vm/README.md) (one worker thread per run) is the implementation, and [`dsh-tool-workflow`](../tool-workflow/README.md) is the model-facing consumer.
The **workflow seam** (`ctx.workflows`): an abstract service defining WHAT a workflow engine does — execute a model-written orchestration script that fans out subagents — without saying HOW. The bash-shaped third of the [workflow family](../README.md): implementations subclass `WorkflowService` and register as the `workflows` service (one per context); [`dsh-workflow-workerthread`](../workflow-workerthread/README.md) (one worker thread per run) is the implementation, and [`dsh-tool-workflow`](../tool-workflow/README.md) is the model-facing consumer.
## Service: `WorkflowService` (abstract)

View File

@@ -4,7 +4,7 @@
* that fans out subagents — without saying HOW. Implementations subclass
* {@link WorkflowService} and register as the `workflows` service (one
* implementation per context, cordis' standard duplicate-service behavior);
* the implementation is `@deepseek-ai/dsh-workflow-vm`, which runs each
* the implementation is `@deepseek-ai/dsh-workflow-workerthread`, which runs each
* script in its own worker thread. Hardened engines (an isolated-vm or
* separate-process sandbox) swap in without touching the model-facing tool
* that consumes them (`@deepseek-ai/dsh-tool-workflow`).