refactor(subagent-subprocess): shared provider skeleton for out-of-process backends
The duplication gate flagged three ACP/SDK clones; the shared halves move into dsh-subagent-subprocess as provider.ts: NO_START_CAPABILITIES (frozen all-false advertisement), assertPositiveFinite (prefix-parameterized timing validation), settleRunResult (never-reject result settlement with contained onError sink and listener hygiene), and subprocessRunHandle (idempotent dispose publication). Both backends now compose these; the previously unreachable cancelled-rejection branch is directly unit-tested at the library level instead of v8-ignored in each backend. knip learns the subagent-sdk workspace (e2e entry outside vitest unit includes).
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
import type { Context } from 'cordis'
|
||||
import z from 'schemastery'
|
||||
import type { SubagentCapabilities, SubagentProvider, SubagentStartRequest } from '@deepseek-ai/dsh-subagent'
|
||||
import { resolveChildCwd, validateConfiguredCwd } from '@deepseek-ai/dsh-subagent-subprocess'
|
||||
import { assertPositiveFinite, NO_START_CAPABILITIES, resolveChildCwd, validateConfiguredCwd } from '@deepseek-ai/dsh-subagent-subprocess'
|
||||
import {
|
||||
DEFAULT_DISPOSE_EOF_GRACE_MS,
|
||||
DEFAULT_DISPOSE_GRACE_MS,
|
||||
@@ -79,13 +79,6 @@ export const Config: z<Config> = z.object({
|
||||
disposeGraceMs: z.number().default(DEFAULT_DISPOSE_GRACE_MS),
|
||||
})
|
||||
|
||||
/** A timing bound must be a positive finite number (it bounds a teardown wait). */
|
||||
function assertPositiveFinite(name: string, value: number): void {
|
||||
if (!Number.isFinite(value) || value <= 0) {
|
||||
throw new Error(`subagent-sdk: ${name} must be a positive finite number`)
|
||||
}
|
||||
}
|
||||
|
||||
/** The shape after schemastery applied the defaults (cwd has none). */
|
||||
type ResolvedConfig = Required<Omit<Config, 'cwd'>> & Pick<Config, 'cwd'>
|
||||
|
||||
@@ -95,7 +88,7 @@ type ResolvedConfig = Required<Omit<Config, 'cwd'>> & Pick<Config, 'cwd'>
|
||||
* service rejects a request needing any of them before `start` runs).
|
||||
*/
|
||||
class SdkProvider implements SubagentProvider {
|
||||
readonly capabilities: SubagentCapabilities = { outputSchema: false, depthLimit: false, toolFilter: false, persona: false }
|
||||
readonly capabilities: SubagentCapabilities = NO_START_CAPABILITIES
|
||||
// Context contract: an out-of-process SDK child starts fresh — no parent conversation crosses the process boundary.
|
||||
readonly inheritsParentContext = false
|
||||
|
||||
@@ -125,9 +118,9 @@ class SdkProvider implements SubagentProvider {
|
||||
export function apply(ctx: Context, config: Config): void {
|
||||
// schemastery (Config) has already filled every defaulted field.
|
||||
const resolved = config as ResolvedConfig
|
||||
assertPositiveFinite('shutdownTimeoutMs', resolved.shutdownTimeoutMs)
|
||||
assertPositiveFinite('disposeEofGraceMs', resolved.disposeEofGraceMs)
|
||||
assertPositiveFinite('disposeGraceMs', resolved.disposeGraceMs)
|
||||
assertPositiveFinite('subagent-sdk', 'shutdownTimeoutMs', resolved.shutdownTimeoutMs)
|
||||
assertPositiveFinite('subagent-sdk', 'disposeEofGraceMs', resolved.disposeEofGraceMs)
|
||||
assertPositiveFinite('subagent-sdk', 'disposeGraceMs', resolved.disposeGraceMs)
|
||||
// Interpret a relative configured cwd against the harness launch directory
|
||||
// ONCE, at load, and fail a misconfigured directory here — not per start.
|
||||
const configuredCwd = validateConfiguredCwd('subagent-sdk', resolved.cwd)
|
||||
|
||||
Reference in New Issue
Block a user