| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- /**
- * Fixed Codex one-shot subagent provider. Every accepted run starts a fresh
- * official `codex app-server --stdio` process in the delegating Session's
- * workspace and publishes only after an ephemeral thread exists.
- *
- * @module @deepseek-ai/dsh-subagent-codex
- */
- import type { Context } from '@deepseek-ai/cordis'
- import z from '@deepseek-ai/schemastery'
- import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
- import {
- assertPositiveFinite,
- NO_START_CAPABILITIES,
- resolveChildCwd,
- type ResolvedSubagentStartRequest,
- type SubagentCapabilities,
- type SubagentProvider,
- } from '@deepseek-ai/dsh-subagent'
- import {
- DEFAULT_DISPOSE_GRACE_MS,
- startCodexRun,
- type CodexRunSpec,
- } from './run.ts'
- export const name = 'subagent-codex'
- export const inject = ['subagents', 'subprocess']
- /** Deployment-owned environment and process-release bound. */
- export interface Config {
- /**
- * Explicit environment entries layered over the subprocess seam's
- * credential-scrubbed parent environment.
- */
- env?: Record<string, string>
- /** Grace in milliseconds for app-server process-tree termination. */
- disposeGraceMs?: number
- }
- export const Config: z<Config> = z.object({
- env: z.dict(z.string()).default({}),
- disposeGraceMs: z.number().default(DEFAULT_DISPOSE_GRACE_MS),
- })
- type ResolvedConfig = Required<Config>
- class CodexProvider implements SubagentProvider {
- readonly name = 'codex'
- readonly capabilities: SubagentCapabilities = NO_START_CAPABILITIES
- readonly inheritsParentContext = false
- constructor(
- private readonly ctx: Context,
- private readonly config: ResolvedConfig,
- ) {}
- start(request: ResolvedSubagentStartRequest) {
- const parentCwd = request.parent.session.header.cwd
- if (parentCwd === undefined) {
- throw new Error(
- 'subagent-codex: no working directory for the child — delegate from a parent session that has one',
- )
- }
- const spec: CodexRunSpec = {
- cwd: resolveChildCwd(
- 'subagent-codex',
- undefined,
- parentCwd,
- ),
- env: this.config.env,
- disposeGraceMs: this.config.disposeGraceMs,
- spawn: spawnSpec => this.ctx.subprocess.spawn(spawnSpec),
- onError: (error, stopReason) => {
- this.ctx.logger.warn(
- `subagent-codex: child run failed (${stopReason}): ${error.message}`,
- )
- },
- }
- return startCodexRun(request, spec)
- }
- }
- /**
- * Register the fixed `codex` provider.
- * @param ctx - context carrying shared subagent and subprocess services.
- * @param config - explicit child environment and disposal grace.
- */
- export function apply(ctx: Context, config: Config): void {
- const resolved = config as ResolvedConfig
- assertPositiveFinite(
- 'subagent-codex',
- 'disposeGraceMs',
- resolved.disposeGraceMs,
- )
- if (resolved.disposeGraceMs > MAX_TIMER_DELAY_MS) {
- throw new Error(
- `subagent-codex: disposeGraceMs must be no greater than ${MAX_TIMER_DELAY_MS}`,
- )
- }
- ctx.subagents.registerProvider(new CodexProvider(ctx, resolved))
- }
|