Repository navigation
Description
Summary
Provide a supported, explicit path from a JSON-compatible wire schema to typed runtime values, while preserving an accurate schema in the language model prompt.
Examples include:
- An ISO timestamp string becoming a
Date. - An array of
[string, number]entries becoming aMap<string, number>. - An array of strings becoming a
Set<string>.
JSON does not natively represent these runtime objects. Adding their declarations to the TypeScript validator would not, by itself, convert JSON values into instances.
Existing support and a reproducible gap
This is not a claim that TypeChat has no conversion extension points. Custom validators can already return validated/converted results, and the Zod validator returns safeParse output. The existing validateInstance callback also permits additional validation, although its signature uses the same type for input and output.
However, an explicit Zod date transform currently loses its input type when TypeChat generates the prompt schema:
import { z } from "zod";
import { createZodJsonValidator } from "typechat/zod";
const Event = z.object({
dateTime: z.iso.datetime().transform(value => new Date(value))
});
const validator = createZodJsonValidator({ Event }, "Event");
console.log(validator.getSchemaText());
const result = validator.validate({
dateTime: "2022-08-20T08:30:00.000Z"
});
if (result.success) {
console.log(result.data.dateTime instanceof Date); // true
}The generated prompt schema is:
interface Event {
dateTime: any;
}Runtime conversion succeeds and "not-a-date" is correctly rejected, but the model no longer sees the string input constraint. The prompt schema should describe the JSON input (string, with appropriate format guidance), while the validated result should retain the runtime output type (Date).
This follows from the current Zod schema emitter: transform/pipeline types fall through to any.
Proposed direction
Build on the existing validator and Zod integration rather than introduce a redundant parsing hook:
- Keep the wire schema JSON-compatible and make conversion explicitly opt-in.
- Preserve input-schema information for transformations/pipelines instead of emitting
anyor describing a runtime object as if it were a JSON value. - Maintain accurate input/output typing so an application can receive a
Date,Map, orSetwithout unsafe assertions. - For TypeScript-backed schemas, validate the JSON representation first and then explicitly convert it; do not treat an ISO string as already being a
Date. - Document whether existing extension points are sufficient and add API surface only if necessary.
Automatic date-string detection, arbitrary class hydration, constructor evaluation, and serialization of promises or weak collections are not part of this request.
Acceptance criteria
- The date-transform reproduction emits a string-based input schema while returning a correctly typed, valid
Date. - Documented examples demonstrate explicit date, map, and set wire representations and conversions, including collection duplicate-handling behavior.
- Invalid formats/conversion failures produce meaningful validation errors; they must not silently succeed or return an invalid date.
- Tests cover the full translation/repair path with a stubbed model, including conversion failures and
attemptRepair: false. - Existing JSON-only translation behavior remains unchanged unless conversion is explicitly requested.
- Documentation explains the boundary between wire types and runtime types, the order of validation/conversion, and any limitations.
Verification and related work
The reproduction, successful date conversion, and invalid-date rejection were verified offline on Node.js 24.13.0 against a freshly built checkout at e767d883f7ddbb64fc8497ef9c19407128c4b30a on 2026-10-12.
Related historical report: #107. That report's TypeScript Date error still reproduces, but restoring standard-library declarations alone would not address JSON-to-runtime conversion.
Companion feature: #452 covers missing declarations for JSON-compatible standard-library types. The two requests address separate concerns and can be worked on independently.
Activity
robgruen commentedon Nov 4, 2026
/typechat propose
github-actions commentedon Nov 4, 2026
Work proposal P1
Proposal for community discussion, not accepted work or permission to build.
Recommendation
The existing validator contract provides the needed conversion boundary, so I recommend building on PR 467 by huong8373tt-beep instead of introducing a parsing hook. A wire schema describes the JSON sent by the model; a runtime type describes the converted value returned to the application. The inspected Zod validator already returns safeParse's transformed data; its prompt emitter loses the input type. PR 467 addresses that defect for pipelines, which chain validation and conversion steps, and checks grouping in the generated types. It remains unmerged and subject to human review.
For Zod, use explicit input schemas and transforms, with date-format guidance in field descriptions. For TypeScript schemas, document a typed custom validator that delegates JSON validation to createTypeScriptJsonValidator before constructing runtime fields, then returns the converted object through TypeChatJsonValidator. Keeping conversion inside validate lets reported failures use the existing repair path, which gives the model one chance to correct an invalid response. validateInstance remains additional validation of the converted object. This avoids changing public signatures or treating strings as existing Date instances.
For the examples, I propose UTC ISO timestamp strings for Date fields, arrays of string/number pairs for Map fields, and string arrays for Set fields. Use native collection rules: the last value for a repeated map key wins, repeated set values collapse, and first-insertion order is retained. This avoids a core-wide uniqueness policy, but can discard duplicate entries; applications needing uniqueness should validate it before construction. The merged helper-type contribution in PR 461 by idhanth remains separate and should not be redone.
Two details still need confirmation before these terms can be finalized. Are native duplicate rules acceptable for the examples, or must duplicates fail validation? Does the conversion-failure requirement cover expected invalid-data failures reported through Result or Zod validation issues, rather than arbitrary exceptions thrown by application code? I recommend explicitly reporting expected failures with useful messages while preserving the existing propagation of unexpected exceptions.
Changes since the previous proposal
Direction and readiness
The approved GOALS.md policy supports this through G1 for application-defined schemas, G2 for accurate schemas and explicit validation failures, G3 for compatible interfaces, G4 for composable integrations without new platform dependencies, and G5 for documentation and deterministic regressions. Keeping conversions explicit and application-owned respects N2 and N4. No project-direction exception, vendor lock-in, or agent-platform capability is proposed.
The conversation records no choice of collection duplicate rules or clarification of whether conversion failures include arbitrary thrown exceptions. The proposal recommends concrete defaults, but both questions remain open. PR 467 is existing, unmerged work with a human changes-requested review; its contribution should be preserved and reviewed rather than treated as accepted or duplicated.
Goal
Allow applications to opt into accurately prompted, type-safe conversion of JSON object fields to Date, Map, and Set through existing validator interfaces, with explicit errors and unchanged default JSON behavior.
Scope
Non-goals
Acceptance criteria
Open questions
Evidence limits and assumptions
Related contributions: #467, #461.
Not eligible for acceptance yet. Discuss the remaining questions and request
/typechat proposeagain.Proposal run | Approved scope policy
robgruen commentedon Nov 6, 2026
/typechat reply
github-actions commentedon Nov 6, 2026
Your example separates the two things correctly: the wire schema describes the JSON a model can send, while the result type describes the converted value your application receives. Since P1, PR 467 by huong8373tt-beep has merged. In the inspected source, the date transform now emits a string field while successful validation returns the transformed, Date-typed value. Timestamp-format guidance is not emitted automatically; put it on the transformed field's description.
I would keep the remaining work on the existing validator path rather than add a parsing hook. Zod transformations already support explicit conversions. With a TypeScript schema, a custom TypeChatJsonValidator can delegate JSON checking to createTypeScriptJsonValidator, then construct the runtime object. validateInstance runs afterward and uses the same input and output type, so it is not the right boundary for introducing a different result type. PR 461 by idhanth supplies JSON-compatible helper declarations, not Date, Map, or Set conversion.
Reporting expected conversion failures as validation errors lets the current translator include their messages in its single repair attempt; attemptRepair: false returns the first failure without another model completion. Unexpected exceptions from application transforms currently propagate instead. The remaining request concerns explicit date, map, and set examples, documentation, and translation/repair coverage, rather than a second implementation of the merged schema fix.
Two choices from P1 still need your confirmation. For the examples, are native collection rules acceptable: the last value for a repeated map key wins, repeated set values collapse, and first-insertion order is retained? Can conversion failures mean expected invalid-data failures returned through Result or Zod validation issues, while unexpected thrown exceptions continue to propagate? I recommend those defaults to preserve existing behavior, with stricter duplicate rejection left to explicit application validation.
Related contributions: #467, #461, #272.
Automated response requested by the project owner. This does not accept work or authorize implementation.
robgruen commentedon Nov 10, 2026
For this I think we want to select the default behavior to do what most people want but allow for alternate behaviors (like fail on duplicate keys, repeated set values, etc.). That could be a validator configuration option.
- Can the conversion-failure requirement cover invalid-data failures explicitly returned through Result or Zod validation issues, while preserving propagation of unexpected thrown exceptions? I recommend this existing contract rather than automatically catching arbitrary transform exceptions.
Agreed. Catching and covering is never good unless the caller explicitly wants this behavior. That said, should we offer it? I'm not convinced we need to.
robgruen commentedon Nov 10, 2026
/typechat reply
github-actions commentedon Nov 10, 2026
I recommend native Map and Set behavior as the default for the explicit conversion examples: the last value for a repeated map key wins, repeated set values collapse, and first-insertion order is retained. That matches JavaScript's collection conventions, although it can discard input entries. Applications requiring uniqueness should be able to select duplicate rejection instead. These choices would apply only to explicitly requested conversions, not ordinary JSON-only validation.
I would make that choice configurable on the example's conversion validator first, rather than add a blanket option to TypeChat's core factories. The inspected factories do not have a duplicate-policy parameter, but the existing interfaces provide the necessary boundary. With Zod, check the original arrays before transforming them. With a TypeScript schema, a custom TypeChatJsonValidator can delegate JSON-shape validation to createTypeScriptJsonValidator, then check duplicates and construct the runtime values. Checking before construction matters: validateInstance runs afterward, when Map or Set construction has already discarded duplicates.
I would not add a catch-exceptions option now. Expected input problems should become validation failures, while unexpected exceptions continue to propagate, as you agreed. The inspected translator can include a returned validation error in its single repair attempt; setting attemptRepair to false disables that attempt. It does not catch exceptions thrown by validators or transforms. If a converter has a known, recoverable exception, application code can translate that specific case into a validation error. A generic catch risks treating programming bugs as input the model should repair.
PR 467 by huong8373tt-beep already supplies the merged transform input-schema fix, and idhanth's merged PR 461 remains the separate helper-type contribution. I would build the remaining examples, documentation, and translation/repair coverage on that work, without a new parsing hook. Would native defaults and a configurable example validator satisfy your request, or do you need duplicate policy exposed as a reusable public library option?
Related contributions: #467, #461, #272.
Automated response requested by the project owner. This does not accept work or authorize implementation.
robgruen commentedon Nov 10, 2026
Good call!
Should we write an example validator that has this that people can use? That should lower the barrier to entry by providing the code but not including it in the core library.
For the exception I agree...the repair attempt could inadvertently change data content to make the validation pass which could then have unintended consequences.
:) Just read your last sentence (have been typing while reading). Yes, examples not repair hook and native defaults.
robgruen commentedon Nov 10, 2026
/typechat reply
github-actions commentedon Nov 10, 2026
Yes. A copyable example validator is the right fit, rather than a new core option or parsing hook. The current TypeChatJsonValidator contract can return converted, typed values. For a TypeScript schema, the example can validate the JSON representation with createTypeScriptJsonValidator, then check formats and duplicates before constructing Date, Map, and Set fields. A companion Zod example can use input schemas followed by transforms. The model prompt should describe those JSON inputs, not the runtime objects.
I recommend ISO timestamp strings, arrays of string-and-number pairs, and string arrays as the three input forms. Use native collection defaults: the last value for a repeated map key wins, repeated set values collapse, and first-insertion order is retained. Put opt-in duplicate rejection on the example validator, not on the core factories. Check duplicates in the original arrays; validateInstance runs after conversion, when collection construction has already discarded them.
I agree with keeping unexpected exceptions out of repair. Expected input problems should return validation errors, while unexpected exceptions continue to propagate. One important distinction is that returned validation errors still enter the translator's existing single repair attempt by default. The documentation should explain that a repair can change content and show attemptRepair set to false when the application must not ask the model to revise rejected data. No new catch-exceptions option or repair hook is needed.
The merged contributions provide the foundation: huong8373tt-beep's PR 467 preserves Zod transform input schemas, and idhanth's PR 461 adds JSON-compatible helper declarations without runtime conversion. I would keep the remaining work focused on reusable examples, clear input/output typing and format guidance, and deterministic coverage of duplicate rejection, conversion failures, repair, and disabled repair.
Related contributions: #467, #461, #272.
Automated response requested by the project owner. This does not accept work or authorize implementation.
robgruen commentedon Nov 10, 2026
/typechat propose
github-actions commentedon Nov 10, 2026
Work proposal P2
Proposal for community discussion, not accepted work or permission to build.
Recommendation
I recommend completing this with a copyable, configurable validator example and a companion Zod example, rather than a new core option or parsing hook. The wire schema describes the JSON a model can send; the result type describes the converted values the application receives. Your follow-up favors keeping this reusable code outside the core, with native collection defaults and an alternative that rejects duplicates.
The prompt-schema fix no longer needs implementation: huong8373tt-beep's merged PR 467 emits the input side of supported Zod transforms and pipelines, while safeParse returns the transformed values. The inspected date example therefore has a string input and a Date result. Format guidance still belongs in a field description. For the TypeScript version, compose TypeChatJsonValidator with createTypeScriptJsonValidator to check the JSON representation before constructing runtime fields. Preserve the underlying schema check before model requests and compiler cleanup. idhanth's merged PR 461 remains the separate helper-type contribution, not runtime conversion. mmoskal's draft PR 272 concerns structured-output schema access and is not needed for this approach.
For these synchronous, object-shaped examples, I recommend UTC ISO timestamp strings, arrays of string and number pairs for Map fields, and string arrays for Set fields. By default, the last value for a repeated map key wins, repeated set values collapse, and first-insertion order is retained. Allow duplicate rejection to be selected independently for each collection on the example validator only. Check the original arrays before construction, because validateInstance runs after conversion, when duplicates have already been discarded. Native defaults match JavaScript conventions but can lose entries; rejection makes that tradeoff explicit without imposing it on every application.
Expected input problems should return useful validation errors through TypeChat's success-or-error Result type or Zod validation issues; unexpected exceptions should continue to propagate. I would not add a catch-exceptions option or repair hook. Returned validation failures still enter the translator's existing single repair attempt by default, and that attempt can change content. The documentation and examples should demonstrate attemptRepair set to false when the application must not ask the model to revise rejected data. This preserves current behavior while making the data-integrity choice visible.
Changes since the previous proposal
Direction and readiness
The frozen approved GOALS.md policy supports application-defined input schemas through G1, accurate schemas and explicit failures through G2, compatible validator composition through G3, dependency-light integration through G4, and examples with deterministic regressions through G5. Keeping conversions explicit and application-owned respects N2 and N4. This proposal adds no agent-platform capability, vendor dependency, or additional language implementation and requires no project-direction exception.
The owner's frozen follow-up resolves P1's duplicate-policy and exception questions by favoring examples outside the core, native defaults with alternate duplicate behavior, and no repair hook. The existing interfaces support that approach, PR 467 is merged, and the separately inspected draft PR 272 is not a competing conversion implementation or a dependency. The proposed remaining work has observable criteria and no blocking questions. This is a recommendation for an explicit human decision on these terms, not acceptance or authorization to implement.
Goal
Let applications copy explicit, configurable JSON-to-runtime conversion examples that preserve accurate prompt schemas and typed Date, Map, and Set results through existing TypeChat validators, without changing core APIs or ordinary JSON-only behavior.
Scope
Non-goals
Acceptance criteria
Evidence limits and assumptions
Related contributions: #467, #461, #272.
The owner may accept these exact terms with
/typechat accept P2. Acceptance does not start a build.Proposal run | Approved scope policy
robgruen commentedon Nov 11, 2026
/typechat accept
robgruen commentedon Nov 12, 2026
/typechat build