fix(subagent-claude-code): tighten provider evidence
This commit is contained in:
@@ -99,7 +99,7 @@ export async function startMessagesFixture(
|
||||
request.on('data', (chunk: Buffer) => { chunks.push(chunk) })
|
||||
request.on('end', () => {
|
||||
const path = request.url ?? ''
|
||||
if (!path.startsWith('/v1/messages')) {
|
||||
if (path !== '/v1/messages' && !path.startsWith('/v1/messages?')) {
|
||||
response.writeHead(404, { 'content-type': 'application/json' })
|
||||
response.end(JSON.stringify({
|
||||
type: 'error',
|
||||
|
||||
@@ -10,6 +10,11 @@ import { tmpdir } from 'node:os'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { promisify } from 'node:util'
|
||||
import type {
|
||||
Query,
|
||||
SDKMessage,
|
||||
SDKSystemMessage,
|
||||
} from '@anthropic-ai/claude-agent-sdk'
|
||||
import { Context } from 'cordis'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
@@ -23,6 +28,39 @@ import {
|
||||
type MessagesFixture,
|
||||
} from './messages-fixture.ts'
|
||||
|
||||
const observedSdkMessages = vi.hoisted((): SDKMessage[] => [])
|
||||
|
||||
vi.mock('@anthropic-ai/claude-agent-sdk', async (importOriginal) => {
|
||||
const actual = await importOriginal<
|
||||
typeof import('@anthropic-ai/claude-agent-sdk')
|
||||
>()
|
||||
return {
|
||||
...actual,
|
||||
query(options: Parameters<typeof actual.query>[0]): Query {
|
||||
const query = actual.query(options)
|
||||
// Observe the real SDK stream without replacing its protocol or CLI.
|
||||
return new Proxy(query, {
|
||||
get(target, property) {
|
||||
if (property === Symbol.asyncIterator) {
|
||||
return async function* (): AsyncGenerator<SDKMessage, void> {
|
||||
for await (const message of target) {
|
||||
observedSdkMessages.push(message)
|
||||
yield message
|
||||
}
|
||||
}
|
||||
}
|
||||
const value: unknown = Reflect.get(target, property, target)
|
||||
if (typeof value === 'function') {
|
||||
const method = value as (...args: unknown[]) => unknown
|
||||
return method.bind(target)
|
||||
}
|
||||
return value
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const execFileAsync = promisify(execFile)
|
||||
const sdkRoot = dirname(fileURLToPath(
|
||||
import.meta.resolve('@anthropic-ai/claude-agent-sdk'),
|
||||
@@ -54,6 +92,7 @@ afterEach(async () => {
|
||||
for (const root of roots.splice(0)) {
|
||||
rmSync(root, { recursive: true, force: true })
|
||||
}
|
||||
observedSdkMessages.length = 0
|
||||
})
|
||||
|
||||
interface RealHarness {
|
||||
@@ -168,10 +207,16 @@ describe('real Claude Agent SDK 0.3.220 and Claude Code 2.1.220', {
|
||||
})
|
||||
await run.dispose()
|
||||
|
||||
const initMessage = observedSdkMessages.find(
|
||||
(message): message is SDKSystemMessage =>
|
||||
message.type === 'system' && message.subtype === 'init',
|
||||
)
|
||||
expect(initMessage?.claude_code_version).toBe('2.1.220')
|
||||
|
||||
expect(fixture.requests).toHaveLength(1)
|
||||
const recorded = fixture.requests[0]!
|
||||
expect(recorded.method).toBe('POST')
|
||||
expect(recorded.path).toMatch(/^\/v1\/messages(?:\\?|$)/)
|
||||
expect(recorded.path).toMatch(/^\/v1\/messages(?:\?.*)?$/)
|
||||
expect(recorded.headers['x-api-key']).toBe(fakeKey)
|
||||
expect(recorded.body.model).toBe(settingsModel)
|
||||
expect(Array.isArray(recorded.body.messages)).toBe(true)
|
||||
|
||||
@@ -341,6 +341,17 @@ describe('task admission and package contracts', () => {
|
||||
disposeGraceMs: 29,
|
||||
})
|
||||
|
||||
await expect(ctx.subagents.start('claude-code', {
|
||||
...request(),
|
||||
parent: {
|
||||
id: 'parent-without-cwd',
|
||||
session: { header: {} },
|
||||
} as unknown as Agent,
|
||||
})).rejects.toThrow(
|
||||
'subagent-claude-code: no working directory for the child — delegate from a parent session that has one',
|
||||
)
|
||||
expect(queryMock).not.toHaveBeenCalled()
|
||||
|
||||
const run = await ctx.subagents.start('claude-code', request())
|
||||
child.settle({ exitCode: 9, signal: null })
|
||||
child.stdout.end()
|
||||
|
||||
Reference in New Issue
Block a user