Commit bae019e
fix(core): preserve guardrail validation with Anthropic schemas (#15739)
## Summary
Fix guardrail processors with Anthropic structured output by applying
the existing Anthropic schema compatibility layer when building AI SDK
v5 response formats.
Anthropic rejects JSON Schema numeric bounds like `minimum` and
`maximum` on structured output schemas. The guardrail processors still
define scores with strict Zod validation (`z.number().min(0).max(1)`),
but the provider-facing JSON Schema now strips unsupported numeric
bounds for Anthropic before the request is sent.
This preserves the previous local validation semantics for generated
output while avoiding Anthropic request failures that caused guardrails
to fail open.
## What changed
- Pass model info into core response-format schema generation so
Anthropic compatibility can run on direct AI SDK v5 structured output.
- Keep guardrail score/confidence schemas strict with Zod
`min(0).max(1)`.
- Remove the temporary manual score validation/clamping path.
- Add regression tests for Anthropic-compatible provider schemas and
preserved local Zod validation.
## Test plan
- `pnpm --filter ./packages/core exec vitest run
src/processors/processors/prompt-injection-detector.test.ts
src/processors/processors/pii-detector.test.ts
src/processors/processors/moderation.test.ts
src/stream/base/schema.test.ts`
- `pnpm --filter ./packages/schema-compat test --
provider-compats/anthropic.test.ts`
- `pnpm --filter ./packages/core check`
Note: `pnpm test:core:zod` and `pnpm --filter ./packages/core
typecheck:zod-compat` were requested by package instructions, but those
scripts are not present in the current root/core `package.json` files.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
The PR fixes guardrail processors to work properly with Anthropic AI
models while keeping their safety checks intact. Anthropic doesn't
accept certain validation constraints in schemas (like numeric ranges),
so the code now removes those from what's sent to Anthropic—but keeps
the strict validation on the backend to ensure guardrails still work
correctly.
---
## Overview
This PR ensures that guardrail processors (moderation, PII detection,
prompt-injection detection) remain locally strict while producing
Anthropic-compatible structured-output schemas for AI SDK v5. The core
issue is that Anthropic rejects JSON Schema numeric bounds
(`minimum`/`maximum`), so the fix applies an existing Anthropic schema
compatibility layer when building provider-facing response formats.
## Changes
### Schema Compatibility Layer
- Updated `getTransformedSchema` and `getResponseFormat` in
`packages/core/src/stream/base/schema.ts` to accept an optional `model`
parameter (`SchemaModelInfo`)
- When model info is provided, applies `AnthropicSchemaCompatLayer` to
strip numeric bounds from JSON schemas sent to Anthropic
- Preserves existing behavior when no model info is provided
- Added new exported type `SchemaModelInfo` to support passing model
context
### Response Format Generation
- Modified `packages/core/src/stream/aisdk/v5/execute.ts` to pass model
context (`provider`, `modelId`, `supportsStructuredOutputs: true`) into
`getResponseFormat`
- Enables provider-specific schema transformations based on model
capabilities
### Guardrail Validation Tests
- Added new tests for moderation, PII detection, and prompt-injection
detection verifying Anthropic schema compatibility
- Tests confirm that generated schemas for Anthropic exclude numeric
bounds (`minimum`/`maximum`) while still containing score/confidence
fields
- Added runtime validation tests simulating out-of-range values to
verify fail-open behavior with warning logs
- Tests confirm local Zod validation remains strict with numeric
constraints (`z.number().min(0).max(1)`)
### Schema Compatibility Validation
- Added unit test for `AnthropicSchemaCompatLayer` in
`packages/schema-compat/src/provider-compats/anthropic.test.ts`
verifying numeric bounds are stripped while Zod validation behavior is
preserved
## Impact
- Guardrail processors maintain strict local validation semantics
- Schemas sent to Anthropic are compatible with Anthropic's structured
output requirements
- Removed temporary manual score validation/clamping path
- Regression tests ensure both Anthropic compatibility and preserved
local validation work correctly
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>1 parent 480f137 commit bae019e
8 files changed
Lines changed: 262 additions & 7 deletions
File tree
- .changeset
- packages
- core/src
- processors/processors
- stream
- aisdk/v5
- base
- schema-compat/src/provider-compats
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
Lines changed: 50 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
700 | 701 | | |
701 | 702 | | |
702 | 703 | | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
703 | 753 | | |
Lines changed: 70 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
1139 | 1140 | | |
1140 | 1141 | | |
1141 | 1142 | | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
| 1187 | + | |
| 1188 | + | |
| 1189 | + | |
| 1190 | + | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
| 1194 | + | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
| 1198 | + | |
| 1199 | + | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
1142 | 1212 | | |
Lines changed: 47 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
723 | 723 | | |
724 | 724 | | |
725 | 725 | | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
726 | 773 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
90 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
91 | 99 | | |
92 | 100 | | |
93 | 101 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
22 | 50 | | |
23 | 51 | | |
24 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | | - | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
72 | | - | |
73 | | - | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
74 | 94 | | |
75 | 95 | | |
76 | 96 | | |
| |||
119 | 139 | | |
120 | 140 | | |
121 | 141 | | |
122 | | - | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
123 | 146 | | |
124 | 147 | | |
125 | 148 | | |
| |||
131 | 154 | | |
132 | 155 | | |
133 | 156 | | |
134 | | - | |
| 157 | + | |
135 | 158 | | |
136 | 159 | | |
137 | 160 | | |
| |||
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
| 3 | + | |
2 | 4 | | |
3 | 5 | | |
4 | 6 | | |
| |||
60 | 62 | | |
61 | 63 | | |
62 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
63 | 87 | | |
0 commit comments