@tanstack/ai
Version:
Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.
118 lines (103 loc) • 3.62 kB
text/typescript
import { describe, expect, it } from 'vitest'
import {
mergeMetadata,
tanstackMetadata,
withTanstackMetadata,
} from './merge-metadata'
describe('mergeMetadata', () => {
it('deep-merges tanstack and last-write-wins sibling keys', () => {
const merged = mergeMetadata(
{ author: 'dana', tanstack: { model: 'gpt-5.5' } },
{ tanstack: { createdAt: '2026-08-20T00:00:00.000Z' } },
)
expect(merged).toEqual({
author: 'dana',
tanstack: {
model: 'gpt-5.5',
createdAt: '2026-08-20T00:00:00.000Z',
},
})
})
it('last write wins for overlapping tanstack keys', () => {
const merged = mergeMetadata(
{ tanstack: { model: 'gpt-5.5', finishReason: 'stop' } },
{ tanstack: { model: 'claude' } },
)
expect(merged).toEqual({
tanstack: { model: 'claude', finishReason: 'stop' },
})
})
it('keeps a null value under a key', () => {
expect(mergeMetadata({ author: 'dana' }, { author: null })).toEqual({
author: null,
})
})
it('treats incoming null as absent', () => {
expect(mergeMetadata({ author: 'dana' }, null)).toEqual({ author: 'dana' })
})
it('treats incoming undefined as absent', () => {
expect(mergeMetadata({ author: 'dana' }, undefined)).toEqual({
author: 'dana',
})
})
it('returns incoming when current is missing', () => {
expect(mergeMetadata(undefined, { author: 'dana' })).toEqual({
author: 'dana',
})
})
})
describe('tanstackMetadata', () => {
it('reads metadata.tanstack when it is an object', () => {
expect(
tanstackMetadata({ metadata: { tanstack: { model: 'gpt-5.5' } } }),
).toEqual({ model: 'gpt-5.5' })
})
it('returns undefined when tanstack is missing or not an object', () => {
expect(tanstackMetadata({})).toBeUndefined()
expect(tanstackMetadata({ metadata: { tanstack: 'nope' } })).toBeUndefined()
expect(tanstackMetadata({ metadata: { tanstack: [] } })).toBeUndefined()
})
it('returns undefined when nested metadata is null', () => {
expect(tanstackMetadata({ metadata: null })).toBeUndefined()
})
it('reads tanstack from a raw record', () => {
expect(tanstackMetadata({ tanstack: { model: 'gpt-5.5' } })).toEqual({
model: 'gpt-5.5',
})
})
})
describe('withTanstackMetadata', () => {
it('writes metadata.tanstack and does not set the reserved ag-ui key', () => {
const next = withTanstackMetadata(
{ type: 'RUN_STARTED' },
{ model: 'gpt-5.5' },
)
expect(next.metadata).toEqual({ tanstack: { model: 'gpt-5.5' } })
expect(next.metadata).not.toHaveProperty('ag-ui')
})
it('merges new tanstack keys into existing metadata without dropping user keys', () => {
const next = withTanstackMetadata(
{ metadata: { author: 'dana', tanstack: { model: 'gpt-5.5' } } },
{ finishReason: 'stop' },
)
expect(next.metadata).toEqual({
author: 'dana',
tanstack: { model: 'gpt-5.5', finishReason: 'stop' },
})
})
it('last write wins for overlapping tanstack keys', () => {
const next = withTanstackMetadata(
{ metadata: { tanstack: { model: 'gpt-5.5' } } },
{ model: 'claude' },
)
expect(next.metadata).toEqual({ tanstack: { model: 'claude' } })
})
it('treats null metadata as absent and still writes tanstack', () => {
expect(() =>
withTanstackMetadata({ metadata: null }, { model: 'gpt-5.5' }),
).not.toThrow()
expect(
withTanstackMetadata({ metadata: null }, { model: 'gpt-5.5' }).metadata,
).toEqual({ tanstack: { model: 'gpt-5.5' } })
})
})