diff --git a/.changeset/run-input-protocol-version.md b/.changeset/run-input-protocol-version.md new file mode 100644 index 0000000000..89d392b8b5 --- /dev/null +++ b/.changeset/run-input-protocol-version.md @@ -0,0 +1,6 @@ +--- +'@tanstack/ai': patch +'@tanstack/ai-client': patch +--- + +Connection adapters now send the AG-UI `protocolVersion` (`"1.0"`) in the `RunAgentInput` request body, as the AG-UI spec asks. `@tanstack/ai/client` re-exports `PROTOCOL_VERSION`. diff --git a/packages/ai-client/src/connection-adapters.ts b/packages/ai-client/src/connection-adapters.ts index 00d7b8551d..124c055cd7 100644 --- a/packages/ai-client/src/connection-adapters.ts +++ b/packages/ai-client/src/connection-adapters.ts @@ -1,5 +1,6 @@ import { EventType, + PROTOCOL_VERSION, getChunkRunId as getNormalizedChunkRunId, restoreInboundChunk, uiMessagesToWire, @@ -1416,6 +1417,7 @@ function buildRunAgentInputBody( return { threadId: runContext.threadId, runId: runContext.runId, + protocolVersion: PROTOCOL_VERSION, ...(runContext.parentRunId !== undefined && { parentRunId: runContext.parentRunId, }), diff --git a/packages/ai-client/tests/connection-adapters.test.ts b/packages/ai-client/tests/connection-adapters.test.ts index c70c077014..786d807f94 100644 --- a/packages/ai-client/tests/connection-adapters.test.ts +++ b/packages/ai-client/tests/connection-adapters.test.ts @@ -575,6 +575,31 @@ describe('connection-adapters', () => { expect(body.forwardedProps).toMatchObject({ key: 'value' }) }) + it('should send the AG-UI protocolVersion in the request body', async () => { + fetchMock.mockResolvedValue({ + ok: true, + body: { + getReader: () => ({ + read: vi.fn().mockResolvedValue({ done: true, value: undefined }), + releaseLock: vi.fn(), + }), + }, + } as any) + + const adapter = fetchServerSentEvents('/api/chat') + for await (const _ of adapter.connect( + [{ role: 'user', content: 'Hello' }], + undefined, + undefined, + RUN_CONTEXT, + )) { + // Consume + } + + const body = JSON.parse(fetchMock.mock.calls[0]?.[1]?.body as string) + expect(body.protocolVersion).toBe('1.0') + }) + it('should use custom fetchClient when provided', async () => { const customFetch = vi.fn() const mockReader = { diff --git a/packages/ai/src/client.ts b/packages/ai/src/client.ts index f1849d3224..c74ccd340d 100644 --- a/packages/ai/src/client.ts +++ b/packages/ai/src/client.ts @@ -157,7 +157,7 @@ export async function generationParamsFromRequest( return generationParamsFromBody(kind, body) } -export { EventType } from '@ag-ui/core' +export { EventType, PROTOCOL_VERSION } from '@ag-ui/core' export type { RunAgentInput } from '@ag-ui/core' export { diff --git a/testing/e2e/tests/ag-ui-compliance.spec.ts b/testing/e2e/tests/ag-ui-compliance.spec.ts index 5bb87f0a59..df3da51152 100644 --- a/testing/e2e/tests/ag-ui-compliance.spec.ts +++ b/testing/e2e/tests/ag-ui-compliance.spec.ts @@ -39,6 +39,8 @@ test.describe('AG-UI client-to-server compliance', () => { expect(body).toHaveProperty('tools') expect(body).toHaveProperty('context') expect(body).toHaveProperty('forwardedProps') + // AG-UI 1.0: the client states its protocol version in-band. + expect(body.protocolVersion).toBe('1.0') expect(Array.isArray(body.messages)).toBe(true) expect(Array.isArray(body.tools)).toBe(true) }