Cedar-OS provides TypeScript types and Zod schemas for agent responses, enabling type-safe handling of LLM outputs, structured responses, streaming events, and frontend tool execution.

Basic LLM Responses

The core response type contains the agent’s text response along with usage and metadata information: TypeScript Type:
interface LLMResponse {
	content: string;
	usage?: {
		promptTokens: number;
		completionTokens: number;
		totalTokens: number;
	};
	metadata?: Record<string, unknown>;
	// The object field contains structured output when using JSON Schema or Zod
	object?: StructuredResponseType | StructuredResponseType[];
}
Corresponding Zod Schema:
import { LLMResponseSchema } from 'cedar-os';

// Basic response schema (no structured output)
const BasicResponseSchema = LLMResponseSchema();

// With custom structured output schema
const TaskResponseSchema = LLMResponseSchema(
	z.object({
		taskId: z.string(),
		title: z.string(),
		completed: z.boolean(),
	})
);

// Usage example
const response = TaskResponseSchema.parse(agentResponse);
const taskId = response.object?.taskId; // ✅ Fully typed

Structured Responses

For agents that return structured data, Cedar provides flexible typing for custom response objects: TypeScript Types:
// Base structure for all response objects
interface BaseStructuredResponseType {
	type: string;
	content?: string;
}

// Create custom response types
type CustomStructuredResponseType<
	T extends string,
	P extends object = Record<string, never>
> = BaseStructuredResponseType & { type: T } & P;

// Example: Task creation response
type CreateTaskResponse = CustomStructuredResponseType<
	'create_task',
	{
		taskId: string;
		title: string;
		assignee?: string;
	}
>;
Corresponding Zod Schemas:
import {
	StructuredResponseSchema,
	BaseStructuredResponseSchema,
} from 'cedar-os';

// Generic structured response schema
const AnyStructuredResponse = BaseStructuredResponseSchema;

// Specific response type schema
const CreateTaskResponseSchema = StructuredResponseSchema('create_task').and(
	z.object({
		taskId: z.string(),
		title: z.string(),
		assignee: z.string().optional(),
	})
);

// Usage with LLMResponse
const TaskResponseSchema = LLMResponseSchema(CreateTaskResponseSchema);

Built-in Response Types

Cedar provides several built-in response types with corresponding TypeScript types and Zod schemas:

FrontendToolResponse

For executing registered frontend tools: TypeScript Type:
type FrontendToolResponse = CustomStructuredResponseType<
	'frontendTool',
	{
		toolName: string;
		args?: unknown;
	}
>;

// Example usage
type SendEmailToolResponse = CustomStructuredResponseType<
	'frontendTool',
	{
		toolName: 'sendEmail';
		args: {
			to: string;
			subject: string;
			body: string;
		};
	}
>;
Corresponding Zod Schema:
import { FrontendToolResponseSchema } from 'cedar-os';

// Basic frontend tool response validation
const response = FrontendToolResponseSchema.parse({
	type: 'frontendTool',
	toolName: 'sendEmail',
	args: {
		to: 'user@example.com',
		subject: 'Hello',
		body: 'This is a test email',
	},
});

// Create specific tool response schemas
const SendEmailToolSchema = FrontendToolResponseSchema.and(
	z.object({
		toolName: z.literal('sendEmail'),
		args: z.object({
			to: z.string().email(),
			subject: z.string(),
			body: z.string(),
		}),
	})
);

SetStateResponse

For executing state setter functions: TypeScript Type:
type SetStateResponse = CustomStructuredResponseType<
	'setState',
	{
		stateKey: string;
		setterKey: string;
		args?: unknown; // Single object parameter (v0.1.11+)
	}
>;

// Example usage
type AddTodoResponse = CustomStructuredResponseType<
	'setState',
	{
		stateKey: 'todos';
		setterKey: 'addTodo';
		args: {
			text: string;
			priority: 'low' | 'medium' | 'high';
		};
	}
>;
Corresponding Zod Schema:
import { SetStateResponseSchema } from 'cedar-os';

// Basic setState response validation
const response = SetStateResponseSchema.parse({
	type: 'setState',
	stateKey: 'todos',
	setterKey: 'addTodo',
	args: {
		text: 'Learn Cedar-OS',
		priority: 'high',
	},
});

// Create specific setter response schemas
const AddTodoResponseSchema = SetStateResponseSchema.and(
	z.object({
		stateKey: z.literal('todos'),
		setterKey: z.literal('addTodo'),
		args: z.object({
			text: z.string(),
			priority: z.enum(['low', 'medium', 'high']),
		}),
	})
);

MessageResponse

For adding custom messages to chat: TypeScript Type:
type MessageResponse = CustomStructuredResponseType<
	'message',
	{
		role?: 'user' | 'assistant' | 'bot';
		content: string;
	}
>;
Corresponding Zod Schema:
import { BackendMessageResponseSchema } from 'cedar-os';

const messageResponse = BackendMessageResponseSchema.parse({
	type: 'message',
	role: 'assistant',
	content: 'Task completed successfully!',
});

Streaming Responses

For real-time streaming, Cedar provides event-based typing: TypeScript Type:
type StreamEvent =
	| { type: 'chunk'; content: string }
	| {
			type: 'object';
			object: StructuredResponseType | StructuredResponseType[];
	  }
	| { type: 'done'; completedItems: (string | object)[] }
	| { type: 'error'; error: unknown };
Corresponding Zod Schema:
import { StreamEventSchema } from 'cedar-os';

// Validate streaming events
function handleStreamEvent(event: unknown) {
	const validatedEvent = StreamEventSchema.parse(event);

	switch (validatedEvent.type) {
		case 'chunk':
			console.log('Content:', validatedEvent.content); // ✅ string
			break;
		case 'object':
			console.log('Structured:', validatedEvent.object); // ✅ StructuredResponseType
			break;
		case 'done':
			console.log('Completed:', validatedEvent.completedItems); // ✅ (string | object)[]
			break;
		case 'error':
			console.error('Error:', validatedEvent.error); // ✅ unknown
			break;
	}
}

Voice Responses

For voice-enabled agents, Cedar extends the base response with audio-specific fields: TypeScript Type:
interface VoiceLLMResponse extends LLMResponse {
	transcription?: string;
	audioData?: string; // Base64 encoded audio
	audioUrl?: string;
	audioFormat?: string;
}
Corresponding Zod Schema:
import { VoiceLLMResponseSchema } from 'cedar-os';

// Basic voice response schema
const BasicVoiceResponseSchema = VoiceLLMResponseSchema();

// Voice response with structured output
const VoiceTaskResponseSchema = VoiceLLMResponseSchema(
	z.object({
		action: z.enum(['create', 'update', 'delete']),
		target: z.string(),
	})
);

// Usage example
const voiceResponse = VoiceTaskResponseSchema.parse(agentResponse);
const transcription = voiceResponse.transcription; // ✅ string | undefined
const action = voiceResponse.object?.action; // ✅ 'create' | 'update' | 'delete' | undefined

Next Steps

Now that you understand response typing, learn about: