// src/types/graph.test.ts import type { StructuredOutputConfig, StructuredOutputMode, AgentInputs, BaseGraphState, } from './graph'; import type { BaseMessage } from '@langchain/core/messages'; /** * Type-level tests to ensure StructuredOutputConfig interface is correctly defined. * These tests don't run at runtime but will fail at compile time if types are wrong. */ describe('StructuredOutputConfig type', () => { describe('type compatibility', () => { it('should accept minimal configuration', () => { const config: StructuredOutputConfig = { schema: { type: 'object' }, }; expect(config.schema).toBeDefined(); }); it('should accept full configuration', () => { const config: StructuredOutputConfig = { schema: { type: 'object', properties: { name: { type: 'string' }, value: { type: 'number' }, }, required: ['name'], }, name: 'TestSchema', description: 'A test schema for structured output', mode: 'auto', strict: true, handleErrors: true, maxRetries: 3, includeRaw: false, }; expect(config.schema).toBeDefined(); expect(config.name).toBe('TestSchema'); expect(config.description).toBe('A test schema for structured output'); expect(config.mode).toBe('auto'); expect(config.strict).toBe(true); expect(config.handleErrors).toBe(true); expect(config.maxRetries).toBe(3); expect(config.includeRaw).toBe(false); }); it('should accept all valid mode values', () => { const modes: StructuredOutputMode[] = ['auto', 'tool', 'provider']; for (const mode of modes) { const config: StructuredOutputConfig = { schema: { type: 'string' }, mode, }; expect(config.mode).toBe(mode); } }); it('should make all fields except schema optional', () => { const minimalConfig: StructuredOutputConfig = { schema: { type: 'boolean' }, }; // These should all be undefined for minimal config expect(minimalConfig.name).toBeUndefined(); expect(minimalConfig.description).toBeUndefined(); expect(minimalConfig.mode).toBeUndefined(); expect(minimalConfig.strict).toBeUndefined(); expect(minimalConfig.handleErrors).toBeUndefined(); expect(minimalConfig.maxRetries).toBeUndefined(); expect(minimalConfig.includeRaw).toBeUndefined(); }); }); describe('schema property types', () => { it('should accept object schema', () => { const config: StructuredOutputConfig = { schema: { type: 'object', properties: { nested: { type: 'object', properties: { value: { type: 'string' }, }, }, }, }, }; expect(config.schema.type).toBe('object'); }); it('should accept array schema', () => { const config: StructuredOutputConfig = { schema: { type: 'array', items: { type: 'object', properties: { id: { type: 'number' }, }, }, }, }; expect(config.schema.type).toBe('array'); }); it('should accept schema with enum', () => { const config: StructuredOutputConfig = { schema: { type: 'string', enum: ['option1', 'option2', 'option3'], }, }; expect(config.schema.enum).toEqual(['option1', 'option2', 'option3']); }); it('should accept schema with $ref', () => { const config: StructuredOutputConfig = { schema: { $schema: 'http://json-schema.org/draft-07/schema#', definitions: { Address: { type: 'object', properties: { street: { type: 'string' }, city: { type: 'string' }, }, }, }, type: 'object', properties: { address: { $ref: '#/definitions/Address' }, }, }, }; expect(config.schema.$schema).toBeDefined(); }); }); }); describe('AgentInputs with structuredOutput', () => { it('should accept structuredOutput as optional field', () => { const inputsWithout: Partial = { agentId: 'agent-1', provider: 'openai' as AgentInputs['provider'], }; expect(inputsWithout.structuredOutput).toBeUndefined(); const inputsWith: Partial = { agentId: 'agent-2', provider: 'anthropic' as AgentInputs['provider'], structuredOutput: { schema: { type: 'object' }, }, }; expect(inputsWith.structuredOutput).toBeDefined(); }); }); describe('BaseGraphState with structuredResponse', () => { it('should support structuredResponse field', () => { const state: Partial = { messages: [], structuredResponse: { result: 'success', data: [1, 2, 3] }, }; expect(state.structuredResponse).toEqual({ result: 'success', data: [1, 2, 3], }); }); it('should allow structuredResponse to be undefined', () => { const state: Partial = { messages: [], }; expect(state.structuredResponse).toBeUndefined(); }); }); describe('AgentInputs with summarizeCallback', () => { it('should accept summarizeCallback as optional field', () => { const inputsWithout: Partial = { agentId: 'agent-1', provider: 'openai' as AgentInputs['provider'], }; expect(inputsWithout.summarizeCallback).toBeUndefined(); const inputsWith: Partial = { agentId: 'agent-2', provider: 'anthropic' as AgentInputs['provider'], summarizeCallback: async (_messages: BaseMessage[]) => 'summary', }; expect(inputsWith.summarizeCallback).toBeDefined(); }); it('should accept a valid callback function type', () => { const mockCallback = async (messages: BaseMessage[]): Promise => { if (messages.length === 0) { return undefined; } return `Summary of ${messages.length} messages`; }; const inputs: Partial = { agentId: 'agent-summarize', provider: 'openai' as AgentInputs['provider'], summarizeCallback: mockCallback, }; expect(inputs.summarizeCallback).toBe(mockCallback); }); });