feat(core)!: extract zod from @ag-ui/core, ship @ag-ui/core/schemas subpath#1637
Open
AlemTuzlak wants to merge 37 commits into
Open
feat(core)!: extract zod from @ag-ui/core, ship @ag-ui/core/schemas subpath#1637AlemTuzlak wants to merge 37 commits into
AlemTuzlak wants to merge 37 commits into
Conversation
…ests - Reject array inputs in defaultEventValidator (typeof [] === 'object' footgun) - Treat empty issues[] as success in fromStandardSchema (Standard Schema compliance) - Add tests for fromStandardSchema and array rejection
zod's .min(1) is a runtime-only check; it does not produce a non-empty tuple type at the inference level. The static type was too narrow. Adds direct equality assertions for both RunFinishedSuccessOutcome and RunFinishedInterruptOutcome to catch any future regression.
Replace schema.parse()-based factory helpers with plain object construction. Inline the three coercion behaviors previously supplied by Zod schemas: - TEXT_MESSAGE_START: role defaults to "assistant" when omitted - ACTIVITY_SNAPSHOT: replace defaults to true when omitted - RUN_FINISHED: outcome:null/undefined normalized to field omission Add explicit guard in createRunFinishedInterruptEvent to throw on empty interrupts array, preserving the .min(1) validation previously done by Zod.
…ument strip limitation
…interface BREAKING CHANGE: `@ag-ui/core` no longer exports any `*Schema` constants. zod is no longer used to define types. Consumers using runtime validation should use the `AgentValidator` interface or write their own schemas with the validation library of their choice.
…erance Replaces coverage from the deleted backwards-compatibility.test.ts: the protocol contract is that AG-UI events tolerate unknown future fields, and the new validator must continue to accept them.
The package no longer uses zod for type definitions, schema validation, or any other purpose. Consumers needing runtime schema validation should plug in their own AgentValidator implementation.
@ag-ui/core no longer exports *Schema constants. Three external consumers (adk-middleware, TypeScript SDK README, and core README example) now use type-only imports or locally-defined validation instead.
…r architecture The Event Schemas section described the deleted zod schemas. Replace with guidance for defaultEventValidator + Standard Schema customization. Also tighten the multimodal example to use import type for UserMessage.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Python Preview PackagesVersion
Install with uvAdd the TestPyPI index to your [[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
explicit = trueThen install the packages you need: # Core SDK
uv add 'ag-ui-protocol==0.0.0.dev1778088798' --index testpypi
# Integrations (each already depends on the matching ag-ui-protocol preview)
uv add 'ag-ui-langgraph==0.0.0.dev1778088798' --index testpypi
uv add 'ag-ui-crewai==0.0.0.dev1778088798' --index testpypi
# NOTE: ag-ui-agent-spec depends on pyagentspec (git-only, not on PyPI).
# You will need to install pyagentspec separately from its git repo.
uv add 'ag-ui-agent-spec==0.0.0.dev1778088798' --index testpypi
uv add 'ag_ui_adk==0.0.0.dev1778088798' --index testpypi
uv add 'ag_ui_strands==0.0.0.dev1778088798' --index testpypiInstall with pippip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
ag-ui-protocol==0.0.0.dev1778088798
Commit: dabd28b |
The *-static.ts files were a migration scaffold used to prove static types matched z.infer types via expectTypeOf assertions. After zod was removed, the scaffolding became dead-end indirection. Move the type definitions directly into types.ts / events.ts / capabilities.ts where they belong and delete the static files.
…tValidator - Schemas come back at a new opt-in subpath; zod becomes an optional peer dependency so consumers control the version (the original v3/v4 conflict fix). - defaultEventValidator removed; @ag-ui/client and @ag-ui/proto default to zodValidator from the subpath, preserving prior runtime-validation behavior. - adk-middleware reverts its local validator and imports AgentCapabilitiesSchema from @ag-ui/core/schemas. - BinaryInputContent runtime check rewritten as .refine() (loses precise error path; boolean check unchanged). - CHANGELOG and docs updated to reflect the actual final architecture.
- zodValidator uses Standard Schema (zod 3.24+); the peer range was too permissive (3.22.4 would crash at import). - Add types conditions to exports map so node16/nodenext module resolution can locate .d.ts files for both entries.
…ubpath The 8 schema test files deleted in 908f9d5 were exercising real protocol-validation behavior, not just zod mechanics. Now that the schemas live at the @ag-ui/core/schemas subpath, the tests can come back with their imports redirected. types-static.test.ts is renamed and reframed as an equality check between the hand-written types and z.infer<typeof XxxSchema>, providing drift protection against future schema/type divergence.
Rewrite schemas.ts to use zod API that's stable across both majors: - z.nativeEnum(EventType) -> z.enum([...EventType values as tuple...]) - z.record(X) -> z.record(z.string(), X) (two-arg form is required in zod 4) Existing tests continue to pass against the resolved zod version. Standard Schema works in both zod 3.24+ and zod 4, so zodValidator (built via fromStandardSchema(EventSchemas)) is unchanged.
The AgentValidator/fromStandardSchema/zodValidator abstraction was introduced to make runtime validation pluggable. With both internal consumers (transformHttpEventStream and the protobuf encoder/decoder) reverted to calling EventSchemas.parse directly, the abstraction has no in-tree users and earns no public-API complexity. Removed entirely. @ag-ui/client and @ag-ui/proto now import EventSchemas from @ag-ui/core/schemas and declare zod as a regular dependency. @ag-ui/core's main entry stays type-only with no runtime deps.
Adds a journey-format migration guide at sdk/js/core/migration-0-1-0 documenting the schemas-to-subpath move, plus an automated jscodeshift codemod that splits combined imports and redirects every *Schema import to @ag-ui/core/schemas. Cross-links the migration guide from the existing core overview and events pages.
The previous code called .at(0).node which returns a Collection, not a path. Use .paths()[0].node instead. Verified against the input fixture: output matches expected; running twice is a no-op (idempotent). Also updated the expected fixture to reflect actual jscodeshift output (header comments attached to a removed node are dropped; multiline formatting for the merged import). Updated test.ts to use execFileSync subprocess with os.tmpdir() for cross-platform compatibility.
…e resolution
Problem 1 – @ag-ui/core/schemas module not found in consumers using legacy
moduleResolution: add `types` conditions to the exports map in package.json and
bump moduleResolution from node to bundler in the four affected tsconfigs
(sdks/typescript, packages/core, packages/client, integrations/adk-middleware).
Problem 2 – schema-type-equality.test.ts compile errors caused by three TypeScript
limitations:
- BaseEventSchema uses z.enum([...]) with plain string literals, inferring a string
union instead of the EventType enum type. Assertions use `AsObject<HandWrittenEvent>`
(interface→mapped-type conversion) + reverse toExtend<_ISchema>() to work around
TypeScript's interface/index-signature restriction.
- Events with required z.any() fields (StateSnapshotEvent.snapshot, RawEvent.event,
CustomEvent.value, RunStartedEvent nested RunAgentInput) have those fields inferred
as optional by zod 3's addQuestionMarks. Same AsObject + reverse-toExtend pattern.
- BaseEventSchema.passthrough() adds [x: string]: unknown to all inferred event
types; forward toExtend<HandWrittenEvent>() fails for events where the above quirks
also apply.
Also fix backwards-compatibility.test.ts discriminated-union access (toolCalls requires
role narrowing) and add a type cast in adk-middleware index.ts to bridge the z.any()
optionality gap in AgentCapabilities parsing.
- codemod test.ts: select npx.cmd on Windows so the smoke test runs - codemod transform: preserve import-type semantics when moving schema specifiers (don't force schemas subpath to load at runtime) - codemod transform: warn on namespace imports of @ag-ui/core that cannot be automatically rewritten - codemod README: move 'Aliased imports' out of 'Known limitations' (it's correct behavior, not a limitation) - client / proto / adk-middleware package.json: add types condition to exports map so node16/nodenext consumers resolve .d.ts files
- Dedup by (imported, local) pair so 'Foo' and 'Foo as Bar' both survive. - When the existing @ag-ui/core/schemas declaration is type-only, don't merge value specs into it (and vice versa) — emit separate declarations to keep value imports loadable at runtime. - Fixtures: add cases for double-aliased import and pre-existing type-only schemas declaration; reflect the corrected behavior.
…stness Node 24 + Windows: execFileSync no longer performs PATHEXT resolution for .cmd shims, so the platform-conditional 'npx.cmd' fix from a prior commit fails with EINVAL. Switching to shell:true with the literal 'npx' delegates resolution to the shell on every platform. Args are static literals so shell injection is not a concern. Also use mkdtempSync per invocation so concurrent runs don't race on a shared temp file.
- Tsconfig moduleResolution bumps were tangential to the zod migration. Revert them. Add typesVersions to @ag-ui/core's package.json so the schemas subpath types still resolve under legacy moduleResolution. - Move codemods from sdks/typescript/codemods/ to repo root codemods/ for discoverability. Update the migration-guide npx invocation URL to point at the new path.
Earlier commits removed @standard-schema/spec from @ag-ui/core's package.json when the validator was dropped, but did not regenerate the lockfile. CI uses --frozen-lockfile and fails install.
The previous z.infer<typeof BaseEventSchema> type included a [k: string]: unknown index signature inherited from .passthrough(), which silently accepted arbitrary extra fields like 'threadId' on downstream event constructors. The hand-written BaseEvent was closed, breaking integrations (notably claude-agent-sdk) that relied on this type-level passthrough. Restore the index signature so inferred and hand-written types match exactly and the runtime passthrough behavior is reflected at the type level. Also add `as XxxEvent` type assertions to event-factories.ts to work around a TypeScript limitation where object spread of Omit<T, K> types with index signatures does not preserve named property requirements in the inferred object literal type.
…with zod inference - Tool.parameters, RunAgentInput.state, RunAgentInput.forwardedProps: made optional in the hand-written types to match what zod's addQuestionMarks produces from z.any() fields. Schema-type-equality can now use stricter assertions. - adk-middleware: dropped 'as AgentCapabilities' cast that was working around the previous drift. - backwards-compatibility test: dropped role-narrowing pattern in favor of the simpler direct-access form (vitest doesn't strict-typecheck).
@ag-ui/a2a-middleware
@ag-ui/a2ui-middleware
@ag-ui/event-throttle-middleware
@ag-ui/mcp-apps-middleware
@ag-ui/middleware-starter
@ag-ui/a2a
@ag-ui/adk
@ag-ui/ag2
@ag-ui/agno
@ag-ui/aws-strands
@ag-ui/claude-agent-sdk
@ag-ui/crewai
@ag-ui/langchain
@ag-ui/langgraph
@ag-ui/langroid
@ag-ui/llamaindex
@ag-ui/mastra
@ag-ui/pydantic-ai
@ag-ui/server-starter
@ag-ui/server-starter-all-features
@ag-ui/vercel-ai-sdk
create-ag-ui-app
@ag-ui/client
@ag-ui/core
@ag-ui/encoder
@ag-ui/proto
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@ag-ui/coreno longer depends on zod. Upstream consumers were repeatedly hitting v3/v4 dual-installation conflicts because core pinned zod 3.x as a hard runtime dep. This PR:*Schemaexports to a new opt-in subpath:@ag-ui/core/schemas.^3.24.0 || ^4.0.0— consumers pick exactly one zod version.@ag-ui/coreentry type-only (TypeScript types +EventTypeenum +AGUIError+ event factories). Zero runtime dependencies.@ag-ui/clientand@ag-ui/protoimportEventSchemasfrom@ag-ui/core/schemasand callEventSchemas.parse(...)directly, preserving prior runtime-validation behavior with no caller changes.@ag-ui/coreto0.1.0with a CHANGELOG entry.Migration tooling
docs/sdk/js/core/migration-0-1-0.mdx(journey format with decision tree, before/after diffs, FAQ).codemods/0.1.0-schemas-to-subpath.ts(repo root). Splits combined imports, redirects every*Schemaimport to the subpath, preservesimport typesemantics + per-specifier type modifiers, dedupes by(imported, local)so aliased duplicates survive, warns on namespace imports, idempotent. Run via:Breaking change
@ag-ui/coreno longer exports any*Schemaconstants from its main entry. The two existing internal consumers (adk-middleware, README example) have been migrated.Tool.parameters,RunAgentInput.state, andRunAgentInput.forwardedPropsare now optional (?: any) to match what zod'saddQuestionMarksinfers fromz.any()fields. Non-breaking widening (extra| undefinedallowed).Test plan
pnpm -C sdks/typescript/packages/core test— 182/182pnpm -C sdks/typescript/packages/proto test— 92/92pnpm -C sdks/typescript/packages/client test— 482/483 (1 pre-existing Windows-only ESM-loader failure onesm-interop.test.ts, unrelated)pnpm -C integrations/adk-middleware/typescript test— 8/8pnpm -C sdks/typescript build— clean across@ag-ui/core,@ag-ui/client,@ag-ui/proto,@ag-ui/encoder,@ag-ui/adk,@ag-ui/claude-agent-sdknode codemods/test.ts)Notable internal changes
BaseEventinterface gains[k: string]: unknownto match the runtime.passthrough()semantics that the priorz.infertypes provided. This restores compatibility with consumers (notablyclaude-agent-sdk) that pass extra fields likethreadIdon event constructors.BinaryInputContentSchemaruntime check moved fromsuperRefineto.refine()to work cleanly across both zod 3 and zod 4 majors.