Skip to content

Conversation

@EurFelux
Copy link
Collaborator

@EurFelux EurFelux commented Feb 10, 2026

What this PR does

Before this PR:
Message block types (MessageBlock, ToolMessageBlock, CitationMessageBlock, etc.) were defined as plain TypeScript interfaces and enums. Model-related types (ModelPricing, ModelType, Model, etc.) used manual interface definitions. Enum values like MessageBlockType, MessageBlockStatus, and WebSearchSource were TypeScript enums.

After this PR:

  • All message block types are defined as Zod schemas with types inferred via z.infer<>
  • TypeScript enums are replaced with const objects + Zod schemas (e.g., MESSAGE_BLOCK_TYPE, MESSAGE_BLOCK_STATUS, WEB_SEARCH_SOURCE)
  • Supporting types (Serializable, SerializedError, FileMetadata, KnowledgeReference, tool types, etc.) are also migrated to Zod schemas
  • any types in metadata fields are narrowed to unknown
  • MessageBlock is now a Zod discriminated union on the type field

Part of #12846 — this PR completes the Zod schema migration for Message, MessageBlock (all discriminated union variants), and related types. Runtime validation (safeParse() at DB boundaries) will follow in subsequent PRs.

Why we need it and why it was done in this way

This is foundational work for adding runtime type validation as described in #12846. By defining types as Zod schemas first (without changing runtime behavior), we establish the schema definitions that can later be used for .parse() / .safeParse() validation at system boundaries (e.g., sessionMessageRepository.serializeMessage()).

The following tradeoffs were made:

  • @ts-ignore comments are added in a few places where existing untyped data flows (e.g., toolResponse.response) don't yet match the stricter schema types. These are marked with FIXME for follow-up work.
  • metadata fields use z.record(z.string(), z.unknown()) rather than a fully typed schema — this matches the previous any behavior while being slightly stricter. Further narrowing to Serializable is planned as follow-up.

The following alternatives were considered:

  • Migrating types and adding runtime validation simultaneously — rejected to keep the PR focused and reviewable.
  • Using io-ts or typia instead of Zod — Zod was chosen for its ecosystem adoption, ergonomic API, and existing usage in the codebase.

Breaking changes

None. This PR is a pure type-level refactoring with no runtime behavior changes. All enum values are preserved as const object equivalents.

Special notes for your reviewer

  • This is a type-only refactoring — no runtime behavior changes.
  • The @ts-ignore FIXME comments are intentional markers for follow-up work (runtime validation layer).
  • 71 files changed, but changes are mechanical: interface → Zod schema, enum → const object, import path updates.
  • Serializable type now has a custom Zod schema with unit tests (serialize.test.ts).

Checklist

  • PR: The PR description is expressive enough and will help future contributors
  • Code: Write code that humans can understand and Keep it simple
  • Refactor: You have left the code cleaner than you found it (Boy Scout Rule)
  • Upgrade: Impact of this change on upgrade flows was considered and addressed if required
  • Documentation: Not required (internal type changes only)

Release note

NONE

🤖 Generated with Claude Code

EurFelux and others added 30 commits February 11, 2026 00:44
- Replace manual type definition with Zod schema using z.lazy()
- Add SerializableSchema export for runtime validation
- Add assertSerializable() and tryParseSerializable() helpers
- Fix error.ts to use safeSerialize() for response field
- Remove FIXME comment about TS2589 recursion

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Circular references cause JSON.stringify to throw, so returning true
was misleading. Now correctly returns false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@EurFelux EurFelux requested a review from 0xfullex as a code owner February 10, 2026 20:03
@EurFelux EurFelux marked this pull request as draft February 10, 2026 20:03
Break circular dependency: file.ts → @types (index.ts) → knowledge.ts → file.ts
by moving objectKeys, objectEntries, objectEntriesStrict, objectValues, strip,
AtLeast, RequireSome, NotUndefined, NotNull to a dedicated typeUtils.ts module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant