test(snapshot): pin persistent tool schemas
This commit is contained in:
@@ -57,6 +57,8 @@ interface SdkScenario {
|
|||||||
configs?: { live: string; replay: string }
|
configs?: { live: string; replay: string }
|
||||||
/** Cwd-relative files whose final contents are part of the scenario contract. */
|
/** Cwd-relative files whose final contents are part of the scenario contract. */
|
||||||
expectedFiles?: Readonly<Record<string, string>>
|
expectedFiles?: Readonly<Record<string, string>>
|
||||||
|
/** Assembled model-facing tool names and required argument keys. */
|
||||||
|
expectedTools?: Readonly<Record<string, readonly string[]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCENARIOS: SdkScenario[] = [
|
const SCENARIOS: SdkScenario[] = [
|
||||||
@@ -85,6 +87,7 @@ const SCENARIOS: SdkScenario[] = [
|
|||||||
children: 0,
|
children: 0,
|
||||||
configs: { live: persistentToolsLiveConfig, replay: persistentToolsReplayConfig },
|
configs: { live: persistentToolsLiveConfig, replay: persistentToolsReplayConfig },
|
||||||
expectedFiles: { 'note.txt': 'beta\n' },
|
expectedFiles: { 'note.txt': 'beta\n' },
|
||||||
|
expectedTools: { bash: ['command'], str_replace_editor: ['command', 'path'] },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -112,6 +115,20 @@ async function persistedLogs(sessionsRoot: string): Promise<PersistedLog[]> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LoggedRequestHeader {
|
||||||
|
type?: string
|
||||||
|
data?: { header?: { tools?: Array<{ name: string; parameters: { required?: string[] } }> } }
|
||||||
|
}
|
||||||
|
|
||||||
|
function assembledToolRequirements(log: PersistedLog): Record<string, string[]> {
|
||||||
|
const event = log.content.trimEnd().split('\n')
|
||||||
|
.map(line => JSON.parse(line) as LoggedRequestHeader)
|
||||||
|
.find(candidate => candidate.type === 'request/header')
|
||||||
|
const tools = event?.data?.header?.tools
|
||||||
|
if (tools === undefined) throw new Error('session log has no request/header tools')
|
||||||
|
return Object.fromEntries(tools.map(tool => [tool.name, tool.parameters.required ?? []]))
|
||||||
|
}
|
||||||
|
|
||||||
function contextOf(logs: readonly { content: string; header: Record<string, unknown> }[], cwd: string): NormalizeContext {
|
function contextOf(logs: readonly { content: string; header: Record<string, unknown> }[], cwd: string): NormalizeContext {
|
||||||
return {
|
return {
|
||||||
sessionIds: logs.flatMap(log => typeof log.header.id === 'string' ? [log.header.id] : []),
|
sessionIds: logs.flatMap(log => typeof log.header.id === 'string' ? [log.header.id] : []),
|
||||||
@@ -337,6 +354,11 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => {
|
|||||||
expect(result.status).toBe('ok')
|
expect(result.status).toBe('ok')
|
||||||
expect(notifications.at(-1)?.method).toBe('session.finished')
|
expect(notifications.at(-1)?.method).toBe('session.finished')
|
||||||
expect(observedFiles).toEqual(scenario.expectedFiles ?? {})
|
expect(observedFiles).toEqual(scenario.expectedFiles ?? {})
|
||||||
|
if (scenario.expectedTools !== undefined) {
|
||||||
|
const parent = ordered[0]
|
||||||
|
if (parent === undefined) throw new Error(`${scenario.name} has no parent session log`)
|
||||||
|
expect(assembledToolRequirements(parent)).toEqual(scenario.expectedTools)
|
||||||
|
}
|
||||||
if (scenario.children > 0) {
|
if (scenario.children > 0) {
|
||||||
expect(notifications.some(n => n.method === 'subagent.started')).toBe(true)
|
expect(notifications.some(n => n.method === 'subagent.started')).toBe(true)
|
||||||
expect(notifications.some(n => n.method === 'subagent.finished')).toBe(true)
|
expect(notifications.some(n => n.method === 'subagent.finished')).toBe(true)
|
||||||
|
|||||||
Reference in New Issue
Block a user