dsh-better-codex-subagent
Agent 与会话 活跃维护

dsh-better-codex-subagent

ivwumupy/dsh-better-codex-subagent

可直接替换默认固定codex子代理提供者的即插即用组件,完整兼容原有调用逻辑,无需额外配置即可完成子代理服务切换,降低集成改造成本。

0
Stars 标星
0
Forks 分支
0
Watchers 关注
0
Open Issues
TypeScript
主要语言
None
开源协议
32 KB
仓库大小
1 个月前
最后推送
一键安装扩展 / 插件指令
dsh plugin --profile web add github:ivwumupy/dsh-better-codex-subagent
git clone https://github.com/ivwumupy/dsh-better-codex-subagent.git
git clone git@github.com:ivwumupy/dsh-better-codex-subagent.git
README.md main

dsh-better-codex-subagent

English | 中文

A drop-in replacement for the fixed codex subagent provider
(@deepseek-ai/dsh-subagent-codex)
that additionally mirrors the Codex app-server stream into a harness child
session. Every Codex run therefore renders as an ordinary one-shot subagent in
the session tree and Web UI: a discoverable child node under the delegating
session, with the delegated task, the assistant answers, and the tool
executions (commands and file changes) as a normal conversation transcript.

The provider registers under the same codex name, so the
tool-subagent-codex tool row (provider: codex) keeps working unchanged.
Loading this plugin together with @deepseek-ai/dsh-subagent-codex fails loud
on the duplicate provider name — compose one or the other.

Start and ownership

start(request) derives the child cwd from the parent Session, spawns the
fixed codex app-server --stdio command through dsh-subprocess, and performs
initialize → initialized → thread/start { cwd, ephemeral }. Only after
the app-server returns a thread matching the requested lifetime does the
provider create the projection child session, seed it (descriptor, turn start,
user task), and publish the run. A failure before publication closes the wire,
terminates the managed process tree, waits for it to exit, and rejects
start() — no orphan child session is left behind.

The published run's result contract is identical to the base provider: one
turn, the authoritative turn/completed terminal notification, and the
latest agentMessage with phase: "final_answer" (or the phase: null
compatibility fallback) as the returned answer. Local cancellation maps to
aborted, contextWindowExceeded to max-tokens, and any other remote
failure to error. dispose() is idempotent and reaches whole-tree
quiescence. The projection session stays in the store after the run settles
as a terminal, read-only one-shot child; the Web UI already renders one-shot
subagent conversations read-only.

Projection

The child session mirrors the app-server notification stream through a
stateful transcript:

App-server notification Projection-session events
item/agentMessage/delta accumulated per item id
item/completed (agentMessage, final_answer or null phase) assistant/message with the accumulated or completed text
item/started / item/completed (commandExecution) tool/call (exec_command with command/cwd) + tool/result (aggregatedOutput, else exit code, else status)
item/started / item/completed (fileChange) tool/call (fileChange with path/kind changes) + tool/result (path summary)
run settlement turn/end (completed / aborted / max-tokens / error)

The transcript is deliberately tolerant: unknown notification methods, item
kinds, and agent-message phases are ignored, so an app-server version that
introduces new item types cannot fail the run. Malformed payloads of known
kinds degrade to a skipped write. The base provider's fail-closed posture is
kept where it matters: unknown server requests (which demand an answer) and
mismatched thread/turn scoping in terminal notifications still fail the run.

Configuration

Key Default Meaning
env {} Explicit child environment layered over the subprocess seam's credential-scrubbed parent environment.
disposeGraceMs 3000 Positive finite grace in milliseconds, no greater than MAX_TIMER_DELAY_MS, between the shared process-tree owner's termination tiers.
ephemeral true Thread lifetime passed to thread/start. false persists the Codex session under CODEX_HOME/sessions for a later codex resume; true keeps the base provider's ephemeral contract.
- id: better-codex-subagent
  name: 'dsh-better-codex-subagent'
  config:
    env:
      OPENAI_API_KEY: !!js process.env.OPENAI_API_KEY
    ephemeral: false

- id: tool-subagent-codex
  name: '@deepseek-ai/dsh-tool-subagent'
  config:
    provider: codex
    toolName: subagent_codex
    maxDepth: provider-managed

Background execution

One-shot background execution works for the codex provider: the tool row
just needs enableRunInBackground unset or true (the default). The model
can then pass run_in_background: true, which starts the Codex run as a
background job that returns a job id immediately; job_output collects the
final answer and job_kill cancels. The projection session is the job's
child session, so the Web UI still renders the running and settled subagent
transcript. backgroundMode must stay one-shot (the default): the codex
provider has no prepareContinuable capability, and a continuable tool row
fails at mount.

Installation

The package is a dsh bundle: its manifest declares
dsh.bundle with a patch layer (cordis.patch.yml) that mounts the provider,
so dsh plugin installs it as a bundle into a profile. The package ships
prebuilt (lib/types/*.js ESM + declarations) plus the source and declares
its harness packages as peer dependencies, so it loads wherever the harness
packages are already present — a dsh profile, for example, resolves them from
the installed dsh runtime.

# From this package directory: build and produce the publishable tarball.
pnpm pack        # → dsh-better-codex-subagent-0.1.0.tgz

Install into a profile (dsh plugin forwards to pnpm and appends the bundle
to the profile's dsh.profile.bundles because of the dsh.bundle manifest):

dsh plugin --profile web add ./dsh-better-codex-subagent-0.1.0.tgz

Other distribution forms work the same way: dsh plugin --profile web add dsh-better-codex-subagent after publishing to npm, or
dsh plugin --profile web add github:you/deepseek-harness#<sha> from git — a
git install fetches sources only, so the package then needs a prepare
script (none is shipped yet) and an allowBuilds entry in the profile's
pnpm-workspace.yaml.

If the profile already mounts the base
@deepseek-ai/dsh-subagent-codex provider (for example a manually inserted
- id: subagent-codex row in the profile's cordis.patch.yml), remove that
row and its dependency before restarting — both packages register the codex
provider name and the duplicate fails loud:

dsh plugin --profile web remove @deepseek-ai/dsh-subagent-codex
# and delete the `- id: subagent-codex` insert row from
# ~/.dsh/profiles/web/cordis.patch.yml

The tool-subagent-codex tool row (provider: codex) in the standard-codex
agent preset needs no change. Then restart dsh web.

Product compatibility and evidence

The wire implements the same 0.147.0 app-server surface as the base provider
(adapted from its wire.ts), with the ephemeral lifetime parameterized and a
validated notification sink added. Development evidence is pinned to
@openai/codex@0.147.0; the npm package is a test-only dependency, and
deployments still supply codex on PATH. The keyless real-product test
boots the real app-server against a loopback Responses fixture and asserts
that the published run is discoverable through ctx.subagents.listChildren
and that its transcript carries the delegated task, the answer, and the
closing turn/end.

Known Limitations and Deferred Work

  • Message granularity is per completed item, not per delta — the
    item/agentMessage/delta stream is accumulated but written as one
    assistant/message on item/completed; the Web UI does not stream the
    answer live. Streaming assistant/chunk projection is deferred.
  • Tool projection covers commandExecution and fileChange items only —
    mcpToolCall, webSearch, collabToolCall, plan, and reasoning items
    are ignored; the transcript is the extension point for them.
  • No continuation — the child is a terminal one-shot projection session;
    follow-up messages, cold resume, and codex resume through the harness are
    out of scope (persisting the thread with ephemeral: false makes the Codex
    session resumable in the Codex CLI itself).
  • Host-managed product installation and account state — a missing or
    incompatible codex, configuration error, or authentication failure is
    surfaced as a startup or run error; the plugin provides no installer, login
    flow, or runtime version gate.
  • No wall-clock timeout or side-effect rollback — the caller cancels long
    work, and files or external systems changed before cancellation are not
    restored.