Bläddra i källkod

test(snapshot): pin persistent tool schemas

Tianyi Cui 2 månader sedan
förälder
incheckning
38e4a7bf7f
1 ändrade filer med 22 tillägg och 0 borttagningar
  1. 22 0
      examples/jsonrpc-agent/tests/sdk.snapshot.ts

+ 22 - 0
examples/jsonrpc-agent/tests/sdk.snapshot.ts

@@ -57,6 +57,8 @@ interface SdkScenario {
   configs?: { live: string; replay: string }
   /** Cwd-relative files whose final contents are part of the scenario contract. */
   expectedFiles?: Readonly<Record<string, string>>
+  /** Assembled model-facing tool names and required argument keys. */
+  expectedTools?: Readonly<Record<string, readonly string[]>>
 }
 
 const SCENARIOS: SdkScenario[] = [
@@ -85,6 +87,7 @@ const SCENARIOS: SdkScenario[] = [
     children: 0,
     configs: { live: persistentToolsLiveConfig, replay: persistentToolsReplayConfig },
     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 {
   return {
     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(notifications.at(-1)?.method).toBe('session.finished')
       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) {
         expect(notifications.some(n => n.method === 'subagent.started')).toBe(true)
         expect(notifications.some(n => n.method === 'subagent.finished')).toBe(true)