Merge commit 'a9cc0fddb40be295c43cb2badb4cbcb2b032556c' into codex/product-providers-pr2-claude-code

# Conflicts:
#	.agents/notes/proposed/feature/2026-08-04-claude-code-and-codex-subagent-backends.i18n.yaml
#	.agents/notes/proposed/feature/2026-08-04-claude-code-and-codex-subagent-backends.md
#	.agents/notes/proposed/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md
#	docs/core-data-structures/subprocess.i18n.yaml
#	packages/subprocess/subprocess/README.i18n.yaml
This commit is contained in:
pku-xht
2026-08-05 04:41:27 +08:00
34 changed files with 140 additions and 171 deletions

View File

@@ -83,18 +83,17 @@ function complete(
/**
* Start a loopback-only Anthropic Messages SSE fixture.
* @param script - one behavior per Messages request.
* @param behavior - the single response behavior for this fixture.
* @returns the bound server and its recorded requests.
*/
export async function startMessagesFixture(
script: readonly MessagesBehavior[],
behavior: MessagesBehavior,
): Promise<MessagesFixture> {
const requests: RecordedMessagesRequest[] = []
let requestStartedResolve!: () => void
const requestStarted = new Promise<void>((resolve) => {
requestStartedResolve = resolve
})
let behaviorIndex = 0
const server = createServer((request, response) => {
const chunks: Buffer[] = []
request.on('data', (chunk: Buffer) => { chunks.push(chunk) })
@@ -117,18 +116,6 @@ export async function startMessagesFixture(
body,
})
requestStartedResolve()
const behavior = script[behaviorIndex++]
if (behavior === undefined) {
response.writeHead(500, { 'content-type': 'application/json' })
response.end(JSON.stringify({
type: 'error',
error: {
type: 'api_error',
message: 'Messages fixture script was exhausted',
},
}))
return
}
if (behavior.kind === 'complete') {
complete(response, body, behavior.text)
}

View File

@@ -64,7 +64,7 @@ interface RealHarness {
readonly env: Record<string, string>
}
async function realHarness(script: readonly MessagesBehavior[]): Promise<{
async function realHarness(behavior: MessagesBehavior): Promise<{
readonly harness: RealHarness
readonly fixture: MessagesFixture
}> {
@@ -80,7 +80,7 @@ async function realHarness(script: readonly MessagesBehavior[]): Promise<{
join(claudeConfig, 'settings.json'),
`${JSON.stringify({ model: settingsModel }, null, 2)}\n`,
)
const fixture = await startMessagesFixture(script)
const fixture = await startMessagesFixture(behavior)
fixtures.push(fixture)
const env = {
ANTHROPIC_API_KEY: fakeKey,
@@ -149,9 +149,10 @@ describe('real Claude Agent SDK 0.3.220 and Claude Code 2.1.220', {
it('inherits host settings and sends the exact task and fake key to local Messages', async () => {
const sentinel = 'REAL_CLAUDE_CODE_SENTINEL_2_1_220'
const task = 'Return the fixture sentinel exactly.'
const { harness, fixture } = await realHarness([
{ kind: 'complete', text: sentinel },
])
const { harness, fixture } = await realHarness({
kind: 'complete',
text: sentinel,
})
expect(sdkPackage.version).toBe('0.3.220')
expect(sdkPackage.claudeCodeVersion).toBe('2.1.220')
expect(sdkPackage.optionalDependencies[platformPackage]).toBe('0.3.220')
@@ -191,7 +192,7 @@ describe('real Claude Agent SDK 0.3.220 and Claude Code 2.1.220', {
})
it('maps a real CLI process failure to error', async () => {
const { harness, fixture } = await realHarness([{ kind: 'hold' }])
const { harness, fixture } = await realHarness({ kind: 'hold' })
const run = await startRequest(harness, 'Exercise the failure path.')
await fixture.requestStarted
expect(harness.handles).toHaveLength(1)
@@ -207,7 +208,7 @@ describe('real Claude Agent SDK 0.3.220 and Claude Code 2.1.220', {
})
it('settles cancellation and leaves the real SDK-spawned CLI tree quiescent', async () => {
const { harness, fixture } = await realHarness([{ kind: 'hold' }])
const { harness, fixture } = await realHarness({ kind: 'hold' })
const controller = new AbortController()
const run = await startRequest(
harness,

View File

@@ -27,6 +27,7 @@ import type {
SubprocessSpawnSpec,
} from '@deepseek-ai/dsh-subprocess'
import LocalSubprocessService from '@deepseek-ai/dsh-subprocess-local'
import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
import * as claudeCode from '../src/index.ts'
import * as invariant from '../src/invariant.ts'
import {
@@ -74,8 +75,6 @@ async function nextTask(): Promise<void> {
interface FakeChildOptions {
readonly pid?: number
readonly stdin?: PassThrough | undefined
readonly stdout?: PassThrough | undefined
readonly exitOnTerminate?: boolean
readonly waitForExitError?: Error
readonly doneError?: Error
@@ -145,8 +144,8 @@ function fakeChild(options: FakeChildOptions = {}): FakeChild {
})
const handle: SubprocessHandle = {
pid: options.pid ?? 1234,
stdin: options.stdin === undefined ? stdin : options.stdin,
stdout: options.stdout === undefined ? stdout : options.stdout,
stdin,
stdout,
stderr: undefined,
collected: {},
done,
@@ -232,7 +231,6 @@ function sdkSpawnOptions(
interface FakeRun {
readonly child: FakeChild
readonly query: Query
readonly close: ReturnType<typeof vi.fn>
readonly spawnSpecs: SubprocessSpawnSpec[]
readonly options: Options[]
@@ -262,7 +260,7 @@ function fakeRun(
params.options.spawnClaudeCodeProcess!(sdkSpawnOptions())
return query
})
return { child, query, close, spawnSpecs, options, spec }
return { child, close, spawnSpecs, options, spec }
}
beforeEach(() => {
@@ -318,6 +316,11 @@ describe('task admission and package contracts', () => {
await expect(ctx.plugin(claudeCode, { disposeGraceMs }))
.rejects.toThrow('disposeGraceMs must be a positive finite number')
}
await expect(ctx.plugin(claudeCode, {
disposeGraceMs: MAX_TIMER_DELAY_MS + 1,
})).rejects.toThrow(
`disposeGraceMs must be no greater than ${MAX_TIMER_DELAY_MS}`,
)
await ctx.fiber.dispose()
})