engsys 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/core/agents/aaron.md +152 -0
- package/core/agents/bert.md +115 -0
- package/core/agents/isabelle.md +136 -0
- package/core/agents/jody.md +150 -0
- package/core/agents/leith.md +111 -0
- package/core/agents/marcelo.md +282 -0
- package/core/agents/melvin.md +101 -0
- package/core/agents/nyx.md +152 -0
- package/core/agents/otto.md +168 -0
- package/core/agents/patricia.md +283 -0
- package/core/commands/design-audit-local.md +155 -0
- package/core/commands/design-audit.md +235 -0
- package/core/commands/design-critique.md +96 -0
- package/core/commands/file-issue.md +22 -0
- package/core/commands/generate-project.md +45 -0
- package/core/commands/implement-issue.md +37 -0
- package/core/commands/implement-project.md +40 -0
- package/core/commands/naturalize.md +61 -0
- package/core/commands/pre-push.md +29 -0
- package/core/commands/prep-review-collect.md +130 -0
- package/core/commands/prep-review-finalize.md +121 -0
- package/core/commands/prep-review-publish.md +113 -0
- package/core/commands/prep-review.md +65 -0
- package/core/commands/project-closeout.md +25 -0
- package/core/skills/agentic-eval/SKILL.md +195 -0
- package/core/skills/chrome-devtools/SKILL.md +97 -0
- package/core/skills/code-review/SKILL.md +26 -0
- package/core/skills/gh-cli/SKILL.md +2202 -0
- package/core/skills/git-commit/SKILL.md +124 -0
- package/core/skills/git-workflow-agents/SKILL.md +462 -0
- package/core/skills/git-workflow-agents/reference.md +220 -0
- package/core/skills/github-actions/SKILL.md +190 -0
- package/core/skills/github-issues/SKILL.md +154 -0
- package/core/skills/llm-structured-outputs/SKILL.md +323 -0
- package/core/skills/llm-structured-outputs/references/provider-details.md +392 -0
- package/core/skills/pre-push/SKILL.md +115 -0
- package/core/skills/refactor/SKILL.md +645 -0
- package/core/skills/web-design-reviewer/SKILL.md +371 -0
- package/core/skills/webapp-testing/SKILL.md +127 -0
- package/core/skills/webapp-testing/test-helper.js +56 -0
- package/core/templates/CLAUDE.md.tmpl +98 -0
- package/core/templates/adr-template.md +67 -0
- package/core/templates/gh-issue-templates/bug.md +39 -0
- package/core/templates/gh-issue-templates/content.md +42 -0
- package/core/templates/gh-issue-templates/enhancement.md +36 -0
- package/core/templates/gh-issue-templates/feature.md +39 -0
- package/core/templates/gh-issue-templates/infrastructure.md +41 -0
- package/core/templates/post-edit-reminders.sh.tmpl +19 -0
- package/core/templates/settings.json.tmpl +90 -0
- package/core/templates/settings.local.json.tmpl +3 -0
- package/core/workflows/agent-implementation-workflow.md +346 -0
- package/core/workflows/generate-project.md +258 -0
- package/core/workflows/implement-project-workflow.md +190 -0
- package/core/workflows/issue-tracking.md +89 -0
- package/core/workflows/project-closeout-ceremony.md +77 -0
- package/core/workflows/review-workflow.md +266 -0
- package/engsys.config.example.yaml +46 -0
- package/install +202 -0
- package/lessons-library/README.md +80 -0
- package/lessons-library/async-callbacks-verify-liveness.md +15 -0
- package/lessons-library/change-isnt-done-until-every-surface-updated.md +15 -0
- package/lessons-library/claim-then-act-for-irreversible-ops.md +16 -0
- package/lessons-library/co-commit-entangled-work.md +15 -0
- package/lessons-library/dependabot-triage-playbook.md +17 -0
- package/lessons-library/deploy-by-digest-and-verify-the-running-revision.md +15 -0
- package/lessons-library/enforce-your-guarantee-at-your-boundary.md +16 -0
- package/lessons-library/gate-changes-on-measurement-not-vibes.md +15 -0
- package/lessons-library/iac-first-no-console-changes.md +15 -0
- package/lessons-library/independent-objective-review-gate.md +15 -0
- package/lessons-library/keep-an-immutable-source-of-truth.md +15 -0
- package/lessons-library/long-agent-runs-checkpoint-not-poll.md +15 -0
- package/lessons-library/model-identity-with-stable-ids-and-provenance.md +15 -0
- package/lessons-library/operator-choices-are-first-class.md +15 -0
- package/lessons-library/prefer-tool-enforced-structured-output.md +15 -0
- package/lessons-library/prove-causation-before-acting.md +15 -0
- package/lessons-library/re-read-state-before-acting.md +14 -0
- package/lessons-library/read-layer-tolerates-unbackfilled-rows.md +15 -0
- package/lessons-library/shell-safety-pipefail-and-validate-before-teardown.md +14 -0
- package/lessons-library/shift-correctness-left-and-distrust-false-greens.md +15 -0
- package/lessons-library/stray-control-bytes-hide-changes.md +14 -0
- package/lessons-library/tests-can-assert-the-bug.md +15 -0
- package/lessons-library/verify-ground-truth-not-reports.md +15 -0
- package/lessons-library/worktrees-need-bootstrap-from-origin-main.md +15 -0
- package/lib/commands.js +356 -0
- package/lib/generate-team-avatars.mjs +251 -0
- package/lib/manifest.js +155 -0
- package/lib/render.js +135 -0
- package/lib/selftest.js +90 -0
- package/lib/util.js +89 -0
- package/lib/yaml.js +156 -0
- package/optional-agents/gary.md +86 -0
- package/optional-agents/jos.md +136 -0
- package/optional-agents/sandy.md +101 -0
- package/optional-agents/steve.md +161 -0
- package/package.json +43 -0
- package/stacks/cloud/aws/claude.fragment.md +17 -0
- package/stacks/cloud/aws/settings.fragment.json +39 -0
- package/stacks/cloud/aws/skills/aws-deployment-preflight/SKILL.md +165 -0
- package/stacks/cloud/aws/skills/cloud-architecture-aws/SKILL.md +265 -0
- package/stacks/cloud/azure/claude.fragment.md +17 -0
- package/stacks/cloud/azure/settings.fragment.json +45 -0
- package/stacks/cloud/azure/skills/azure-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/azure/skills/cloud-architecture-azure/SKILL.md +211 -0
- package/stacks/cloud/cloudflare/claude.fragment.md +21 -0
- package/stacks/cloud/cloudflare/settings.fragment.json +31 -0
- package/stacks/cloud/cloudflare/skills/cloud-architecture-cloudflare/SKILL.md +294 -0
- package/stacks/cloud/cloudflare/skills/cloudflare-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/gcp/claude.fragment.md +17 -0
- package/stacks/cloud/gcp/settings.fragment.json +40 -0
- package/stacks/cloud/gcp/skills/cloud-architecture-gcp/SKILL.md +208 -0
- package/stacks/cloud/gcp/skills/gcp-deployment-preflight/SKILL.md +137 -0
- package/stacks/db/mongo/skills/mongo-conventions/SKILL.md +96 -0
- package/stacks/db/prisma/claude.fragment.md +49 -0
- package/stacks/db/prisma/skills/docker-database-package-copy/SKILL.md +44 -0
- package/stacks/db/prisma/skills/prisma-conventions/SKILL.md +37 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/SKILL.md +184 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/official-links.md +53 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/SKILL.md +197 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/official-links.md +45 -0
- package/stacks/iac/bicep/claude.fragment.md +14 -0
- package/stacks/iac/bicep/settings.fragment.json +20 -0
- package/stacks/iac/bicep/skills/iac-bicep/SKILL.md +113 -0
- package/stacks/iac/cdk/claude.fragment.md +14 -0
- package/stacks/iac/cdk/settings.fragment.json +23 -0
- package/stacks/iac/cdk/skills/iac-cdk/SKILL.md +104 -0
- package/stacks/iac/terraform/claude.fragment.md +13 -0
- package/stacks/iac/terraform/settings.fragment.json +25 -0
- package/stacks/iac/terraform/skills/iac-terraform/SKILL.md +93 -0
- package/stacks/iac/terraform/skills/terraform-conventions/SKILL.md +87 -0
- package/stacks/lang/kotlin/skills/android-testing/SKILL.md +263 -0
- package/stacks/lang/kotlin/skills/jetpack-compose/SKILL.md +264 -0
- package/stacks/lang/kotlin/skills/kotlin-coroutines/SKILL.md +329 -0
- package/stacks/lang/python/skills/python-conventions/SKILL.md +61 -0
- package/stacks/lang/shell/skills/shell-scripting/SKILL.md +110 -0
- package/stacks/lang/swift/skills/swift-concurrency/SKILL.md +423 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/approachable-concurrency.md +80 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/concurrency-patterns.md +233 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/swiftui-concurrency.md +187 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/synchronization-primitives.md +341 -0
- package/stacks/lang/swift/skills/swift-testing/SKILL.md +497 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-advanced.md +106 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-patterns.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/SKILL.md +334 -0
- package/stacks/lang/swift/skills/swiftdata/references/core-data-coexistence.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-advanced.md +975 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-queries.md +675 -0
- package/stacks/lang/swift/skills/swiftui-patterns/SKILL.md +371 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/architecture-patterns.md +486 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/deprecated-migration.md +1097 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/design-polish.md +780 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/platform-and-sharing.md +696 -0
- package/stacks/lang/typescript/skills/typescript-conventions/SKILL.md +91 -0
- package/stacks/platform/android/claude.fragment.md +40 -0
- package/stacks/platform/android/hooks/pre-push-gradle.sh +70 -0
- package/stacks/platform/android/settings.fragment.json +13 -0
- package/stacks/platform/android/skills/android-build-conventions/SKILL.md +247 -0
- package/stacks/platform/ios/claude.fragment.md +24 -0
- package/stacks/platform/ios/hooks/pre-push-xcodebuild.sh +82 -0
- package/stacks/platform/ios/settings.fragment.json +21 -0
- package/stacks/platform/ios/skills/xcodebuildmcp-simulator-logs/SKILL.md +76 -0
- package/stacks/platform/web/skills/frontend-testing/SKILL.md +246 -0
- package/stacks/platform/web/skills/react-conventions/SKILL.md +261 -0
- package/stacks/platform/web/skills/web-platform-conventions/SKILL.md +55 -0
- package/stacks/tooling/issue-tracker-github/claude.fragment.md +10 -0
- package/stacks/tooling/issue-tracker-github/settings.fragment.json +24 -0
- package/stacks/tooling/issue-tracker-github/skills/issue-tracker-github/SKILL.md +278 -0
- package/stacks/tooling/issue-tracker-linear/claude.fragment.md +17 -0
- package/stacks/tooling/issue-tracker-linear/settings.fragment.json +9 -0
- package/stacks/tooling/issue-tracker-linear/skills/issue-tracker-linear/SKILL.md +183 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: llm-structured-outputs
|
|
3
|
+
description: "Cross-provider reference for LLM structured outputs with Claude 4.6, GPT-5.3, Gemini 3.1 Pro, and Grok 4. Use when implementing json_schema constrained decoding, writing Zod schemas for LLM APIs, building multi-provider abstractions, or debugging schema compliance failures."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# LLM Structured Outputs
|
|
7
|
+
|
|
8
|
+
Cross-provider reference for schema-constrained JSON decoding with all major frontier LLM APIs. Last updated: February 23, 2026.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
- Implementing structured LLM outputs with any major provider
|
|
13
|
+
- Choosing the right API field for `json_schema` per vendor
|
|
14
|
+
- Writing Zod schemas and converting them to JSON Schema for API requests
|
|
15
|
+
- Building provider-agnostic LLM abstraction layers
|
|
16
|
+
- Debugging parse failures or schema non-compliance
|
|
17
|
+
- Migrating off `zod-to-json-schema` (deprecated Nov 2025)
|
|
18
|
+
- Handling edge cases: truncation, refusals, cache invalidation
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Core Concept
|
|
23
|
+
|
|
24
|
+
All four providers support **constrained decoding**: you send a JSON Schema and the model is constrained at the token level to produce compliant JSON. This is mathematical, not probabilistic.
|
|
25
|
+
|
|
26
|
+
| Provider | API Field | Type Value |
|
|
27
|
+
| --------------------------------- | ------------------------------------- | ------------------- |
|
|
28
|
+
| Anthropic Claude 4.6 | `output_config.format` | `"json_schema"` |
|
|
29
|
+
| OpenAI GPT-5.3 (Responses API) | `text.format` | `"json_schema"` |
|
|
30
|
+
| OpenAI GPT-5.3 (Chat Completions) | `response_format` | `"json_schema"` |
|
|
31
|
+
| Gemini 3.1 Pro | `generationConfig.responseJsonSchema` | N/A (schema object) |
|
|
32
|
+
| xAI Grok 4 | `response_format` | `"json_schema"` |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Per-Vendor API Patterns
|
|
37
|
+
|
|
38
|
+
### Anthropic Claude 4.6 (GA — no beta header needed)
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const response = await anthropic.messages.create({
|
|
42
|
+
model: "claude-opus-4-6", // or 'claude-sonnet-4-6'
|
|
43
|
+
max_tokens: 4096,
|
|
44
|
+
messages: [{ role: "user", content: prompt }],
|
|
45
|
+
output_config: {
|
|
46
|
+
format: {
|
|
47
|
+
type: "json_schema",
|
|
48
|
+
schema: jsonSchema,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const parsed = JSON.parse(response.content[0].text);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Key facts:
|
|
56
|
+
|
|
57
|
+
- GA since Feb 4, 2026 — **no** `anthropic-beta` header required
|
|
58
|
+
- `output_config.format` replaces deprecated `output_format`
|
|
59
|
+
- Assistant prefilling (`role: "assistant"` in messages) removed — returns 400
|
|
60
|
+
- Optional fields via `"type": ["string", "null"]` unions
|
|
61
|
+
- **NOT supported:** `anyOf`, `oneOf`, `allOf`, `pattern`, min/max constraints, recursive schemas
|
|
62
|
+
|
|
63
|
+
### OpenAI GPT-5.3
|
|
64
|
+
|
|
65
|
+
**Responses API** (recommended):
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const response = await openai.responses.create({
|
|
69
|
+
model: "gpt-5.3",
|
|
70
|
+
input: prompt,
|
|
71
|
+
text: {
|
|
72
|
+
format: {
|
|
73
|
+
type: "json_schema",
|
|
74
|
+
json_schema: { name: "result", strict: true, schema: jsonSchema },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Chat Completions API** (legacy):
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const response = await openai.chat.completions.create({
|
|
84
|
+
model: "gpt-5.3",
|
|
85
|
+
messages: [{ role: "user", content: prompt }],
|
|
86
|
+
response_format: {
|
|
87
|
+
type: "json_schema",
|
|
88
|
+
json_schema: { name: "result", strict: true, schema: jsonSchema },
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
> **Warning:** `gpt-5.3-chat-latest` does **not** support `json_schema`. Use `gpt-5.3` or `gpt-5.3-pro`.
|
|
94
|
+
|
|
95
|
+
- **Supported:** `anyOf`, `pattern`, `minimum`/`maximum`, `enum`
|
|
96
|
+
- **NOT supported:** `oneOf`, `allOf`, recursive schemas
|
|
97
|
+
- `additionalProperties: false` and all fields `required` (or `null`-unioned) are mandatory
|
|
98
|
+
|
|
99
|
+
### Gemini 3.1 Pro
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { GoogleGenAI } from "@google/genai";
|
|
103
|
+
const ai = new GoogleGenAI({ apiKey: GEMINI_API_KEY });
|
|
104
|
+
|
|
105
|
+
const response = await ai.models.generateContent({
|
|
106
|
+
model: "gemini-3.1-pro-preview",
|
|
107
|
+
contents: prompt,
|
|
108
|
+
config: {
|
|
109
|
+
responseMimeType: "application/json",
|
|
110
|
+
responseJsonSchema: jsonSchema,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
const parsed = JSON.parse(response.text);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- **Broadest schema support** of all four providers
|
|
117
|
+
- Supports `anyOf`, `$ref` (recursive), `prefixItems`, `minimum`/`maximum`, `pattern`
|
|
118
|
+
- **NOT supported:** `allOf`, `oneOf`, `not`, `if`/`then`/`else`
|
|
119
|
+
- Enum-only mode: `responseMimeType: 'text/x.enum'`
|
|
120
|
+
- Always strict (implicit constrained decoding)
|
|
121
|
+
|
|
122
|
+
### xAI Grok 4
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import OpenAI from "openai";
|
|
126
|
+
const client = new OpenAI({
|
|
127
|
+
apiKey: process.env.XAI_API_KEY,
|
|
128
|
+
baseURL: "https://api.x.ai/v1",
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const response = await client.chat.completions.create({
|
|
132
|
+
model: "grok-4-1-fast-reasoning", // recommended for production
|
|
133
|
+
messages: [{ role: "user", content: prompt }],
|
|
134
|
+
response_format: {
|
|
135
|
+
type: "json_schema",
|
|
136
|
+
json_schema: { name: "result", strict: true, schema: jsonSchema },
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
const parsed = JSON.parse(response.choices[0].message.content);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- OpenAI SDK works directly (same API shape)
|
|
143
|
+
- **NOT supported / unreliable:** min/max constraints, `pattern`, `allOf` — validate downstream
|
|
144
|
+
- Prefer `grok-4-1-fast-reasoning` over `grok-4-0709` (known strict mode empty-response bug)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Cross-Provider Feature Matrix
|
|
149
|
+
|
|
150
|
+
| Feature | Claude 4.6 | GPT-5.3 | Gemini 3.1 Pro | Grok 4 |
|
|
151
|
+
| ----------------------------- | :-----------: | :------: | :------------: | :-----------: |
|
|
152
|
+
| `anyOf` | ❌ | ✅ | ✅ | ⚠️ unreliable |
|
|
153
|
+
| `$ref` (recursive) | internal only | limited | ✅ | ❌ |
|
|
154
|
+
| `pattern` | ❌ | ✅ | ✅ | ❌ |
|
|
155
|
+
| min/max constraints | ❌ | ✅ | ✅ | ❌ |
|
|
156
|
+
| `additionalProperties: false` | required | required | supported | supported |
|
|
157
|
+
| Constrained decoding status | GA | GA | GA | GA |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Safe Cross-Provider Schema Subset
|
|
162
|
+
|
|
163
|
+
Use this when schemas must work across **all four** providers:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
{
|
|
167
|
+
type: 'object',
|
|
168
|
+
properties: {
|
|
169
|
+
name: { type: 'string' },
|
|
170
|
+
count: { type: 'integer' },
|
|
171
|
+
score: { type: 'number' },
|
|
172
|
+
active: { type: 'boolean' },
|
|
173
|
+
status: { type: 'string', enum: ['pending', 'done', 'failed'] },
|
|
174
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
175
|
+
nested: {
|
|
176
|
+
type: 'object',
|
|
177
|
+
properties: { value: { type: 'string' } },
|
|
178
|
+
required: ['value'],
|
|
179
|
+
additionalProperties: false
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
required: ['name', 'count', 'score', 'active', 'status', 'tags', 'nested'],
|
|
183
|
+
additionalProperties: false
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Avoid in cross-provider schemas:** `anyOf`, `oneOf`, `allOf`, `$ref`, `pattern`, min/max, `prefixItems`, `const`, `not`.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Zod 4 Integration (Native JSON Schema)
|
|
192
|
+
|
|
193
|
+
`zod-to-json-schema` is **deprecated as of November 2025**. Use Zod 4's built-in `z.toJSONSchema()`:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { z } from "zod";
|
|
197
|
+
|
|
198
|
+
const MySchema = z
|
|
199
|
+
.object({
|
|
200
|
+
title: z.string(),
|
|
201
|
+
score: z.number(),
|
|
202
|
+
tags: z.array(z.string()),
|
|
203
|
+
status: z.enum(["active", "archived"]),
|
|
204
|
+
})
|
|
205
|
+
.strict();
|
|
206
|
+
|
|
207
|
+
// Native Zod 4 — no external dependency
|
|
208
|
+
const jsonSchema = z.toJSONSchema(MySchema);
|
|
209
|
+
|
|
210
|
+
// Optional: target specific draft
|
|
211
|
+
z.toJSONSchema(MySchema, { target: "draft-07" });
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Zod SDK Helpers
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// OpenAI Responses API
|
|
218
|
+
import { zodTextFormat } from "openai/helpers/zod";
|
|
219
|
+
text: {
|
|
220
|
+
format: zodTextFormat(MySchema, "result");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// OpenAI Chat Completions / Grok
|
|
224
|
+
import { zodResponseFormat } from "openai/helpers/zod";
|
|
225
|
+
response_format: zodResponseFormat(MySchema, "result");
|
|
226
|
+
|
|
227
|
+
// Anthropic SDK parse helper
|
|
228
|
+
const response = await anthropic.messages.parse({
|
|
229
|
+
model: "claude-sonnet-4-6",
|
|
230
|
+
max_tokens: 4096,
|
|
231
|
+
messages: [{ role: "user", content: prompt }],
|
|
232
|
+
output_format: MySchema, // SDK converts automatically
|
|
233
|
+
});
|
|
234
|
+
const result = response.parsed_output;
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Multi-Provider Abstraction Pattern
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import { z } from "zod";
|
|
243
|
+
|
|
244
|
+
const MySchema = z
|
|
245
|
+
.object({
|
|
246
|
+
/* fields */
|
|
247
|
+
})
|
|
248
|
+
.strict();
|
|
249
|
+
const jsonSchema = z.toJSONSchema(MySchema);
|
|
250
|
+
|
|
251
|
+
// Anthropic
|
|
252
|
+
const anthropicBody = {
|
|
253
|
+
output_config: { format: { type: "json_schema", schema: jsonSchema } },
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// OpenAI (Responses API)
|
|
257
|
+
const openaiBody = {
|
|
258
|
+
text: {
|
|
259
|
+
format: {
|
|
260
|
+
type: "json_schema",
|
|
261
|
+
json_schema: { name: "result", strict: true, schema: jsonSchema },
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// OpenAI (Chat Completions) / Grok
|
|
267
|
+
const openaiChatBody = {
|
|
268
|
+
response_format: {
|
|
269
|
+
type: "json_schema",
|
|
270
|
+
json_schema: { name: "result", strict: true, schema: jsonSchema },
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// Gemini
|
|
275
|
+
const geminiConfig = {
|
|
276
|
+
responseMimeType: "application/json",
|
|
277
|
+
responseJsonSchema: jsonSchema,
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Always validate output regardless of provider
|
|
281
|
+
function parseAndValidate<T>(raw: string, schema: z.ZodType<T>): T {
|
|
282
|
+
const json = JSON.parse(raw);
|
|
283
|
+
return schema.parse(json); // throws ZodError on mismatch
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Edge Cases & Troubleshooting
|
|
290
|
+
|
|
291
|
+
| Issue | Cause | Fix |
|
|
292
|
+
| ------------------------------- | ------------------------------------------------------- | -------------------------------------------- |
|
|
293
|
+
| Anthropic returns 400 | Assistant prefilling used | Remove `role: "assistant"` from messages |
|
|
294
|
+
| Anthropic ignores schema | Using `output_format` instead of `output_config.format` | Update parameter name |
|
|
295
|
+
| GPT-5.3 rejects `json_schema` | Using `gpt-5.3-chat-latest` | Switch to `gpt-5.3` or `gpt-5.3-pro` |
|
|
296
|
+
| Grok returns empty response | `grok-4-0709` + complex `strict: true` schema | Switch to `grok-4-1-fast-reasoning` |
|
|
297
|
+
| JSON incomplete / truncated | `stop_reason: "max_tokens"` | Increase `max_tokens` or simplify prompt |
|
|
298
|
+
| Refusal / no output | Safety system triggered | Check `stop_reason`, add context or rephrase |
|
|
299
|
+
| Prompt cache miss | `output_config.format` changed | Keep schema constant across turns |
|
|
300
|
+
| Zod import error `toJSONSchema` | Zod v3 still installed | Upgrade to Zod 4 (`zod@^4`) |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Best Practices
|
|
305
|
+
|
|
306
|
+
1. **Always use constrained decoding** — never rely on prompt-only JSON formatting
|
|
307
|
+
2. **Define schemas in Zod, derive JSON Schema** via `z.toJSONSchema()` — single source of truth
|
|
308
|
+
3. **Always validate outputs** through `schema.parse()` even with constrained decoding
|
|
309
|
+
4. **Handle truncation**: check `stop_reason === "max_tokens"` before parsing
|
|
310
|
+
5. **Keep schemas flat and explicit** for cross-provider reliability
|
|
311
|
+
6. **Use `additionalProperties: false`** and list all fields in `required` on every object
|
|
312
|
+
7. **Implement a retry/repair loop**: on `ZodError`, retry with the invalid JSON + error message as context
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## References
|
|
317
|
+
|
|
318
|
+
- [Full provider details](./references/provider-details.md) — per-vendor model IDs, limits, schema subsets, and docs
|
|
319
|
+
- [Anthropic Structured Outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)
|
|
320
|
+
- [OpenAI Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs/)
|
|
321
|
+
- [Gemini Structured Output](https://ai.google.dev/gemini-api/docs/structured-output)
|
|
322
|
+
- [Grok Structured Outputs](https://docs.x.ai/docs/guides/structured-outputs)
|
|
323
|
+
- [Zod 4 JSON Schema](https://zod.dev/json-schema)
|