Merge commit '21a9ccf299a720c36f58f7389340690d33b525ce' into codex/product-subagent-failure-facts-codex

# Conflicts:
#	.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md
#	.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md
#	packages/subagent/subagent-codex/README.i18n.yaml
#	packages/subagent/subagent-codex/README.md
#	packages/subagent/subagent-codex/README.zh.md
#	packages/subagent/subagent-codex/src/run.ts
#	packages/subagent/subagent-codex/tests/real-product.spec.ts
#	packages/subagent/subagent-codex/tests/subagent-codex.spec.ts
This commit is contained in:
pku-xht
2026-08-18 22:13:00 +08:00
77 changed files with 1099 additions and 452 deletions
+12 -1
View File
@@ -3,7 +3,7 @@ import { readFileSync } from 'node:fs'
import { spawnSync } from 'node:child_process'
import { createServer } from 'node:http'
import type { IncomingMessage, ServerResponse } from 'node:http'
import { mkdir, utimes, writeFile } from 'node:fs/promises'
import { copyFile, mkdir, utimes, writeFile } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { homedir } from 'node:os'
import { expect, it } from 'vitest'
@@ -36,6 +36,10 @@ const AGENT = {
configPath: fileURLToPath(new URL('../cordis.yml', import.meta.url)),
tsconfigPath: fileURLToPath(new URL('../../../tsconfig.json', import.meta.url)),
}
const EDITING_CORDIS_SKILL = fileURLToPath(new URL(
'../../../apps/cli/config/agent-presets/cordis/skills/editing-cordis-compositions/SKILL.md',
import.meta.url,
))
// The Code Mode overlay configs (include-patched variants of cordis.yml; the
// replay swap resolves each one's sibling `*cordis.snapshot.yml`).
@@ -82,6 +86,12 @@ const FS_DIFF_BOUND_CONFIG = fileURLToPath(new URL('./fs-diff-bound.cordis.yml',
const SNAPSHOTS_DIR = join(dirname(fileURLToPath(import.meta.url)), 'snapshots')
const PACKED_CHUNKS_SOURCE = 'hook-cc-pretool-deny'
async function prepareEditingCordisSkillWorkspace(cwd: string): Promise<void> {
const target = join(cwd, '.dsh', 'skills', 'editing-cordis-compositions', 'SKILL.md')
await mkdir(dirname(target), { recursive: true })
await copyFile(EDITING_CORDIS_SKILL, target)
}
async function prepareDelimiterPathWorkspace(cwd: string): Promise<void> {
const dir = join(cwd, 'scope</system-reminder>')
await mkdir(dir, { recursive: true })
@@ -321,6 +331,7 @@ const SCENARIOS: Scenario[] = [
headerClass: 'skill',
systemPromptSource: 'text-turn',
toolSchemasSource: 'text-turn',
prepareWorkspace: prepareEditingCordisSkillWorkspace,
},
{ name: 'lsp-definition', hasModelTurn: true, recorded: false, pinsHeader: true, headerClass: 'lsp', configPath: LSP_CONFIG },
// web_fetch markdown rendering end to end: the overlay's loopback fixture
@@ -1,5 +1,5 @@
# Test-only composition of Codex plus two named Claude instances and their tools.
# The owning e2e boots this tree but never invokes a model or product process.
# Test-only composition of Codex, the Bundle-supplied default Claude provider,
# and two named Claude instances. It never invokes a model or product process.
- id: fixture
name: './fixture.ts'
@@ -30,6 +30,14 @@
backgroundMode: one-shot
maxDepth: 'provider-managed'
- id: tool-subagent-claude-code
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: claude-code
toolName: subagent_claude_code
backgroundMode: one-shot
maxDepth: 'provider-managed'
- id: tool-subagent-claude-primary
name: '@deepseek-ai/dsh-tool-subagent'
config:
@@ -1,20 +1,21 @@
#!/usr/bin/env node
/** Inspect both public product-provider compositions without invoking them. */
/** Inspect the public Claude Code Bundle composition without invoking the product. */
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import { boot, loadOverlayPatches, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import type {} from '@deepseek-ai/dsh-subagent'
import type {} from '@deepseek-ai/dsh-tools'
const configPath = process.argv[2]
if (configPath === undefined) {
throw new Error('product-provider Loader composition driver requires a config path')
const bundlePatchPath = process.argv[3]
if (configPath === undefined || bundlePatchPath === undefined) {
throw new Error('Claude Code Loader composition driver requires config and Bundle patch paths')
}
let starts = 0
const ctx = await boot(
'product-provider-loader-composition',
'subagent-claude-code-loader-composition',
resolveConfigPath(configPath, undefined),
undefined,
loadOverlayPatches('subagent-claude-code-loader-composition', bundlePatchPath),
(hostCtx) => {
hostCtx.on('subagent/start', () => {
starts += 1
@@ -23,9 +24,15 @@ const ctx = await boot(
)
try {
const providerNames = ['codex', 'claude-primary', 'claude-secondary'] as const
const providerNames = [
'codex',
'claude-code',
'claude-primary',
'claude-secondary',
] as const
const toolNames = [
'subagent_codex',
'subagent_claude_code',
'subagent_claude_primary',
'subagent_claude_secondary',
] as const
@@ -1,5 +1,5 @@
# Test-only composition of two named Codex instances and their one-shot tools.
# The owning e2e boots this tree but never invokes the model or Codex.
# Test-only composition of the Bundle-supplied default and two named Codex instances.
# The owning e2e applies the package's real patch and never invokes the model or Codex.
- id: fixture
name: './fixture.ts'
@@ -19,6 +19,14 @@
config:
providerName: codex-secondary
- id: tool-subagent-codex
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: codex
toolName: subagent_codex
backgroundMode: one-shot
maxDepth: 'provider-managed'
- id: tool-subagent-codex-primary
name: '@deepseek-ai/dsh-tool-subagent'
config:
@@ -1,20 +1,21 @@
#!/usr/bin/env node
/** Inspect the public Codex provider composition without invoking the product. */
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import { boot, loadOverlayPatches, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import type {} from '@deepseek-ai/dsh-subagent'
import type {} from '@deepseek-ai/dsh-tools'
const configPath = process.argv[2]
if (configPath === undefined) {
throw new Error('subagent-codex Loader composition driver requires a config path')
const bundlePatchPath = process.argv[3]
if (configPath === undefined || bundlePatchPath === undefined) {
throw new Error('subagent-codex Loader composition driver requires config and Bundle patch paths')
}
let starts = 0
const ctx = await boot(
'subagent-codex-loader-composition',
resolveConfigPath(configPath, undefined),
undefined,
loadOverlayPatches('subagent-codex-loader-composition', bundlePatchPath),
(hostCtx) => {
hostCtx.on('subagent/start', () => {
starts += 1
@@ -23,8 +24,12 @@ const ctx = await boot(
)
try {
const providerNames = ['codex-primary', 'codex-secondary'] as const
const toolNames = ['subagent_codex_primary', 'subagent_codex_secondary'] as const
const providerNames = ['codex', 'codex-primary', 'codex-secondary'] as const
const toolNames = [
'subagent_codex',
'subagent_codex_primary',
'subagent_codex_secondary',
] as const
const providers = providerNames.map((providerName) => {
const provider = ctx.subagents.getProvider(providerName)
if (provider === undefined) {
@@ -2,6 +2,6 @@
"steps": [
{ "op": "initialize" },
{ "op": "newSession" },
{ "op": "prompt", "text": "Load the snapshot-skill skill with the skill tool, then reply DONE." }
{ "op": "prompt", "text": "Load the editing-cordis-compositions skill with the skill tool, then reply DONE." }
]
}
File diff suppressed because one or more lines are too long