feat: add the worker-thread code runtime (dsh-code-runtime-worker)

The shipped backend of the code-execution seam, per the Code Mode RFC's
worker-thread section: one fresh Node worker per run, executing the
model's TypeScript after a host-side type-strip (wrapped in an
async-function shell so top-level return/await parse, sliced back out
position-preserved), bindings bridged over the message port under
hostile-peer rules (own-property name lookup, at-most-once replies,
post-settlement drops, null-prototype namespaces), logs streamed eagerly
with an in-band truncation marker, and two independent budgets — measured
event-loop busy time (computeMs) plus a never-pausing wall ceiling
(maxWallMs) — funneling into worker.terminate(). env: {} and execArgv: []
keep the isolate hermetic; disposal aborts in-flight runs and awaits
worker exits.

The worker entry loads unbuilt via Node's native type stripping
(src/worker.ts, erasable-only) and ships built as a sibling tsdown bundle
(lib/worker.js); tests/built-lib.e2e.ts pins the built load path under
plain node and joins the built-artifact smoke gate. Unit suites cover the
bootstrap in-process (fake port) and the runtime over real workers,
per-file 100%.
This commit is contained in:
Tianyi Cui
2026-07-08 11:00:06 +08:00
parent 15a3431913
commit 583704ac1d
26 changed files with 1486 additions and 9 deletions

View File

@@ -0,0 +1,328 @@
import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { WorkerCodeRuntime } from '@deepseek-ai/dsh-code-runtime-worker'
import type { Config } from '@deepseek-ai/dsh-code-runtime-worker'
import type { CodeRunResult } from '@deepseek-ai/dsh-code-runtime'
/**
* Integration suite over REAL worker threads (no mocks — workers are cheap
* and local, per docs/testing.md's real-over-mock policy). Each test builds
* a fresh context so budgets can be tuned per case.
*/
async function setup(config: Config = {}) {
const ctx = new Context()
await ctx.plugin(WorkerCodeRuntime, config)
const runtime = ctx.codeRuntime as WorkerCodeRuntime
return { ctx, runtime }
}
/** Convenience: one namespace `tools` with the given functions. */
function tools(functions: Record<string, (args: unknown) => Promise<unknown>>) {
return [{ global: 'tools', functions }]
}
describe('WorkerCodeRuntime — programs and bindings (real workers)', () => {
it('registers with the seam descriptors', async () => {
const { runtime } = await setup()
expect(runtime.language).toBe('typescript')
expect(runtime.isolation).toBe('worker-thread')
})
it('runs TypeScript (erasable syntax), captures console/stdout in order, returns the value', async () => {
const { runtime } = await setup()
const result = await runtime.run({
program: `
interface Point { x: number; y: number }
const p: Point = { x: 1, y: 2 } as Point;
console.log('point', p);
process.stdout.write('raw-out\\n');
console.warn('careful');
return p.x + p.y;
`,
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.value).toBe(3)
expect(result.logs.map(entry => [entry.source, entry.level ?? null])).toEqual([
['console', 'log'],
['stdout', null],
['console', 'warn'],
])
expect(result.logs[0]?.text).toBe('point { x: 1, y: 2 }')
})
it('bridges binding calls both ways and rejects the program-side call on a host rejection', async () => {
const { runtime } = await setup()
const calls: unknown[] = []
const result = await runtime.run({
program: `
const first = await tools.echo({ n: 1 });
let caught = '';
try { await tools.fail({}) } catch (error) { caught = error.message }
let caughtRaw = '';
try { await tools.failRaw({}) } catch (error) { caughtRaw = error.message }
return { first, caught, caughtRaw };
`,
bindings: tools({
echo: async (args) => { calls.push(args); return { echoed: args } },
fail: async () => { throw new Error('nope') },
// A non-Error throw: the host renders it, the program still catches.
failRaw: async () => { throw 'raw-nope' },
}),
})
expect(result.error).toBeUndefined()
expect(result.value).toEqual({ first: { echoed: { n: 1 } }, caught: 'nope', caughtRaw: 'raw-nope' })
expect(calls).toEqual([{ n: 1 }])
})
it('reports non-erasable syntax as an exception without spawning a worker', async () => {
const { runtime } = await setup()
const result = await runtime.run({ program: 'enum E { A }\nreturn 1', bindings: [] })
expect(result.error?.kind).toBe('exception')
expect(result.error?.message).toMatch(/enum|strip/i)
})
it('reports a runtime throw as an exception with the message', async () => {
const { runtime } = await setup()
const result = await runtime.run({ program: 'throw new Error("kaboom")', bindings: [] })
expect(result.error?.kind).toBe('exception')
expect(result.error?.message).toContain('kaboom')
})
it('gives the program an EMPTY environment', async () => {
const { runtime } = await setup()
const result = await runtime.run({ program: 'return JSON.stringify(process.env)', bindings: [] })
expect(result.value).toBe('{}')
})
it('replaces a non-cloneable return value with a string rendering', async () => {
const { runtime } = await setup()
const result = await runtime.run({ program: 'return { f: () => 1 }', bindings: [] })
expect(typeof result.value).toBe('string')
})
it('keeps logs streamed before a failure', async () => {
const { runtime } = await setup()
const result = await runtime.run({
program: 'console.log("before"); throw new Error("after-log")',
bindings: [],
})
expect(result.error?.kind).toBe('exception')
expect(result.logs.map(entry => entry.text)).toContain('before')
})
})
describe('WorkerCodeRuntime — budgets and containment (real workers)', () => {
it('ends a hot loop at the compute budget — including behind a pending decoy dispatch', async () => {
const { runtime } = await setup({ computeMs: 300, maxWallMs: 30_000 })
const result = await runtime.run({
// The decoy: fire a call at a never-resolving binding WITHOUT awaiting,
// then spin. Host-side pending-call bookkeeping would pause a naive
// budget here; measured busy time cannot be fooled.
program: 'void tools.slow({}); for (;;) {}',
bindings: tools({ slow: () => new Promise(() => {}) }),
})
expect(result.error?.kind).toBe('timeout')
expect(result.error?.message).toContain('compute budget')
}, 15_000)
it('does not charge time spent awaiting a slow binding against the compute budget', async () => {
const { runtime } = await setup({ computeMs: 250, maxWallMs: 30_000 })
const result = await runtime.run({
program: 'return await tools.slow({})',
bindings: tools({ slow: () => new Promise(resolve => setTimeout(() => { resolve('slow-done') }, 700)) }),
})
expect(result.error).toBeUndefined()
expect(result.value).toBe('slow-done')
}, 15_000)
it('ends an idle-forever run at the wall-clock ceiling', async () => {
const { runtime } = await setup({ computeMs: 30_000, maxWallMs: 400 })
const result = await runtime.run({
program: 'await tools.never({}); return 1',
bindings: tools({ never: () => new Promise(() => {}) }),
})
expect(result.error?.kind).toBe('timeout')
expect(result.error?.message).toContain('wall-clock ceiling')
}, 15_000)
it('reports an abort mid-run and stops the worker', async () => {
const { runtime } = await setup()
const controller = new AbortController()
setTimeout(() => { controller.abort('user-cancel') }, 150)
const result = await runtime.run({ program: 'for (;;) {}', bindings: [], signal: controller.signal })
expect(result.error).toEqual({ kind: 'abort', message: 'user-cancel' })
}, 15_000)
it('reports a pre-aborted signal without spawning', async () => {
const { runtime } = await setup()
const controller = new AbortController()
controller.abort('too-late')
const result = await runtime.run({ program: 'return 1', bindings: [], signal: controller.signal })
expect(result.error).toEqual({ kind: 'abort', message: 'too-late' })
})
it('drops a binding resolution that lands after the run settled', async () => {
const { runtime } = await setup()
const controller = new AbortController()
let replyDelivered!: Promise<void>
const result = await runtime.run({
program: 'void tools.late({}); for (;;) {}',
bindings: tools({
// Anchored on invocation: abort 100ms after the call reaches the
// host, resolve 400ms after — by then the run has settled, so the
// resolution's reply hits the post-settlement drop.
late: () => new Promise((resolve) => {
setTimeout(() => { controller.abort('cancel-now') }, 100)
replyDelivered = new Promise(done => setTimeout(() => { resolve('too-late'); done() }, 400))
}),
}),
signal: controller.signal,
})
expect(result.error).toEqual({ kind: 'abort', message: 'cancel-now' })
// Let the late resolution actually fire so its reply executes instead of
// being cancelled with the test.
await replyDelivered
}, 15_000)
it('contains an OOM under resourceLimits as worker-exit, host process healthy', async () => {
const { runtime } = await setup({ maxOldGenerationSizeMb: 32 })
const result = await runtime.run({
program: 'const hog = []; for (;;) hog.push(new Array(1e6).fill(1));',
bindings: [],
})
expect(result.error?.kind).toBe('worker-exit')
// And the host is fine: run something else.
const after = await runtime.run({ program: 'return "alive"', bindings: [] })
expect(after.value).toBe('alive')
}, 30_000)
it('truncates runaway log output at the byte budget with an in-band marker', async () => {
const { runtime } = await setup({ maxLogBytes: 300 })
const result = await runtime.run({
program: 'for (let i = 0; i < 1000; i++) console.log("spam line", i); return 1',
bindings: [],
})
expect(result.logs.at(-1)?.text).toContain('truncated at 300 bytes')
const total = result.logs.reduce((sum, entry) => sum + Buffer.byteLength(entry.text, 'utf8'), 0)
expect(total).toBeLessThan(1_000)
})
it('caps an oversized return value with a truncation marker', async () => {
const { runtime } = await setup({ maxValueBytes: 64 })
const result = await runtime.run({ program: 'return "y".repeat(10_000)', bindings: [] })
expect(result.value).toBe(`${'y'.repeat(64)}… [truncated]`)
})
it('captures pipe writes that bypass the patched write slot as stray logs, capped by the same budget', async () => {
const { runtime } = await setup({ maxLogBytes: 4 })
const result = await runtime.run({
// The bootstrap patches the stream instance's own `write`; going
// through the prototype's slot reaches the real pipe underneath, so
// the bytes arrive host-side as stray data. The pauses keep the two
// writes in separate pipe chunks and let them land before settlement.
program: `
const write = (text) => Object.getPrototypeOf(process.stdout).write.call(process.stdout, text);
write('abcd');
await new Promise(resolve => setTimeout(resolve, 150));
write('ef');
await new Promise(resolve => setTimeout(resolve, 100));
return 1;
`,
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.logs).toContainEqual({ source: 'stdout', text: 'abcd' })
expect(result.logs.map(entry => entry.text)).not.toContain('ef')
}, 15_000)
})
describe('WorkerCodeRuntime — hostile programs (real workers)', () => {
it('survives forged port traffic: unknown binding names, duplicate ids, junk shapes', async () => {
const { runtime } = await setup()
const result = await runtime.run({
program: `
const { parentPort } = await import('node:worker_threads');
parentPort.postMessage({ type: 'call', id: 7777, global: 'tools', name: 'missing', args: {} });
parentPort.postMessage({ type: 'call', id: 7777, global: 'tools', name: 'missing', args: {} });
parentPort.postMessage({ type: 'call', id: 7778, global: 'tools', name: 'constructor', args: {} });
parentPort.postMessage({ type: 'junk' });
return await tools.real({});
`,
bindings: tools({ real: async () => 'still-works' }),
})
expect(result.error).toBeUndefined()
expect(result.value).toBe('still-works')
})
it('answers a binding whose resolution cannot be cloned with a failure reply', async () => {
const { runtime } = await setup()
const result = await runtime.run({
program: 'try { await tools.bad({}) } catch (error) { return error.message }',
bindings: tools({ bad: async () => (() => 1) }),
})
expect(result.value).toContain('not structured-cloneable')
})
it('exposes binding names that collide with Object.prototype as ordinary functions', async () => {
const { runtime } = await setup()
const result = await runtime.run({
program: 'return [await tools["__proto__"]({}), await tools["constructor"]({}), typeof tools["hasOwnProperty"]]',
// Computed keys: a literal `'__proto__': …` entry would SET the record's
// prototype instead of declaring a binding of that name.
bindings: tools({ ['__proto__']: async () => 'proto-ok', ['constructor']: async () => 'ctor-ok' }),
})
expect(result.value).toEqual(['proto-ok', 'ctor-ok', 'undefined'])
})
})
describe('WorkerCodeRuntime — seam misuse and lifecycle', () => {
it('rejects invalid binding globals loudly (identifier, reserved word, duplicate, console)', async () => {
const { runtime } = await setup()
const cases: [string, RegExp][] = [
['not valid!', /not a usable identifier/],
['await', /not a usable identifier/],
['console', /duplicate binding global/],
]
for (const [global, message] of cases) {
await expect(runtime.run({ program: 'return 1', bindings: [{ global, functions: {} }] })).rejects.toThrow(message)
}
await expect(runtime.run({
program: 'return 1',
bindings: [{ global: 'tools', functions: {} }, { global: 'tools', functions: {} }],
})).rejects.toThrow(/duplicate binding global/)
})
it('rejects config values that are not positive numbers', async () => {
const ctx = new Context()
await expect(ctx.plugin(WorkerCodeRuntime, { computeMs: -1 })).rejects.toThrow(/positive number/)
})
it('keeps runs isolated: no state survives from one run to the next', async () => {
const { runtime } = await setup()
await runtime.run({ program: 'globalThis.leak = "value"; return 1', bindings: [] })
const second = await runtime.run({ program: 'return typeof globalThis.leak', bindings: [] })
expect(second.value).toBe('undefined')
})
it('disposal aborts in-flight runs, awaits worker exit, and rejects later runs', async () => {
const ctx = new Context()
const fiber = await ctx.plugin(WorkerCodeRuntime)
const runtime = ctx.codeRuntime as WorkerCodeRuntime
const inflight: Promise<CodeRunResult> = runtime.run({ program: 'for (;;) {}', bindings: [] })
// Give the worker a moment to actually start spinning.
await new Promise(resolve => setTimeout(resolve, 200))
await fiber.dispose()
const result = await inflight
expect(result.error).toEqual({ kind: 'abort', message: 'runtime disposed' })
await expect(runtime.run({ program: 'return 1', bindings: [] })).rejects.toThrow(/after disposal/)
}, 15_000)
it('removes ctx.codeRuntime when the providing fiber disposes (HMR safety)', async () => {
const ctx = new Context()
const fiber = await ctx.plugin(WorkerCodeRuntime)
expect(ctx.get('codeRuntime')).toBeInstanceOf(WorkerCodeRuntime)
await fiber.dispose()
expect(ctx.get('codeRuntime')).toBeUndefined()
})
})