📝output-dev-types-file
- プラグイン
- outputai
- ソース
- GitHub で見る ↗
説明
`types.ts` ファイルを作成し、Output SDK ワークフロー用の Zod スキーマを定義します。 次のような場合に使用: 入力・出力スキーマの定義、型定義の作成、またはスキーマ関連エラーの修正が必要なとき。
原文を表示
Create types.ts files with Zod schemas for Output SDK workflows. Use when defining input/output schemas, creating type definitions, or fixing schema-related errors.
ユースケース
- ✓入力・出力スキーマを定義するとき
- ✓型定義を作成するとき
- ✓スキーマ関連エラーを修正するとき
本文(日本語訳)
Zodスキーマを使ったtypes.tsファイルの作成
概要
このスキルは、Output SDKワークフロー向けのtypes.tsファイルの作成方法を解説します。
これらのファイルには、入出力バリデーション用のZodスキーマと、それに対応するTypeScript型が含まれます。
次のような場合に使用
- 新しいワークフローの型定義を作成する
- ステップ用の新しいスキーマを追加する
- スキーマバリデーションエラーを修正する
- 既存の型定義をリファクタリングする
インポートに関する重要ルール
zは必ず@outputai/coreからインポートし、zodから直接インポートしてはいけません:
// 正しい
import { z } from '@outputai/core';
// 誤り — ランタイムエラーの原因になります
import { z } from 'zod';
関連スキル: インポートの問題をトラブルシューティングするにはoutput-error-zod-importを参照
基本構造
import { z } from '@outputai/core';
// 1. ワークフロー入力スキーマ
export const WorkflowInputSchema = z.object( {
// 入力フィールドを定義
} );
// 2. ワークフロー出力型
export type WorkflowInput = z.infer<typeof WorkflowInputSchema>;
export type WorkflowOutput = /* 出力型 */;
// 3. ステップスキーマ(各ステップ用)
export const StepNameInputSchema = z.object( {
// ステップの入力フィールド
} );
export const StepNameOutputSchema = z.object( {
// ステップの出力フィールド
} );
// 4. 型のエクスポート
export type StepNameInput = z.infer<typeof StepNameInputSchema>;
export type StepNameOutput = z.infer<typeof StepNameOutputSchema>;
重要: LLM出力向けスキーマの制約
Output.object()に渡されるスキーマは、ツール定義としてLLMプロバイダーに送信されます。
AnthropicはZodメソッドが生成するいくつかのJSON Schema制約を拒否します。
この点を誤ると、ランタイムエラーが発生します。
LLM出力スキーマで使用できないもの
- 数値:
z.number()に対する.min()、.max()はminimum/maximumを生成する — Anthropicに拒否されます。 - 配列:
z.array()に対する.min()、.max()、.length()はminItems/maxItemsを生成する — Anthropicがサポートするのは0または1のminItemsのみです。.length( 3 )や.min( 2 )のような値は拒否されます。
代わりに.describe()を使用する
.describe()はLLM出力の品質をガイドするための主要な手段です。
LLMプロバイダーはスキーマのフィールド名と説明を使って、各フィールドに何を入れるべきかを理解します。
意図が明確に伝わるよう、具体的でわかりやすい説明を記述してください。
重要: .describe()は、サポートされていない制約の代替となるだけでなく、プロンプトベースのフォーマット指示も置き換えます。
スキーマの内容をプロンプトにも記述しないでください — スキーマはプロバイダーに自動的に送信されるため、重複させるとパフォーマンスが低下し、内容のずれが生じるリスクがあります。
詳細はoutput-dev-prompt-fileを参照してください。
// LLM出力スキーマ(Output.object()経由でプロバイダーに送信)— .describe()のみ使用
const llmOutputSchema = z.object( {
score: z.number().describe( 'Quality score 0-100' ),
confidence: z.number().describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).describe( 'Exactly 3 predictions' )
} );
// ワークフロー/ステップのバリデーションスキーマ(ZodのみでLLMには送信しない)— .min()/.max()/.length() 使用可
const workflowOutputSchema = z.object( {
score: z.number().min( 0 ).max( 100 ).describe( 'Quality score 0-100' ),
confidence: z.number().min( 0 ).max( 1 ).describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).length( 3 ).describe( 'Exactly 3 predictions' )
} );
どちらを使うべきか
| コンテキスト | .min()/.max()/.length() |
.describe() |
|---|---|---|
Output.object()に渡すスキーマ |
不可(数値・配列) | 使用する |
ステップのinputSchema / outputSchema |
使用可 | 任意 |
ワークフローのinputSchema / outputSchema |
使用可 | 任意 |
evaluatorのoutputSchema |
使用可 | 任意 |
LLM向けスキーマはtypes.tsに定義する
Output.object()で使用するスキーマはすべてtypes.ts内で定義し、stepファンクション内でインポートして使用してください。
インラインで定義すると重複が生じ、上記の制約を守っているか確認するのが難しくなります。
よく使うスキーマパターン
基本型
import { z } from '@outputai/core';
// 文字列
const stringField = z.string();
const optionalString = z.string().optional();
const stringWithDefault = z.string().default( 'default value' );
const describedString = z.string().describe( 'フィールドの説明' );
// 数値
const numberField = z.number();
const integerField = z.number().int();
const rangedNumber = z.number().min( 1 ).max( 100 ); // ランタイムのみ — Output.object()スキーマには使用不可
// 真偽値
const booleanField = z.boolean();
const defaultBoolean = z.boolean().default( false );
// 列挙型
const enumField = z.enum( [ 'option1', 'option2', 'option3' ] );
const enumWithDefault = z.enum( [ 'small', 'medium', 'large' ] ).default( 'medium' );
複合型
import { z } from '@outputai/core';
// 配列
const stringArray = z.array( z.string() );
const objectArray = z.array( z.object( { id: z.string(), name: z.string() } ) );
// オブジェクト
const nestedObject = z.object( {
user: z.object( {
id: z.string(),
email: z.string().email()
} ),
settings: z.object( {
notifications: z.boolean()
} )
} );
// ユニオン型
const flexibleInput = z.union( [
z.string(),
z.array( z.string() )
] );
// レコード
const keyValueMap = z.record( z.string(), z.number() );
バリデーションパターン
import { z } from '@outputai/core';
// 文字列バリデーション
const emailField = z.string().email();
const urlField = z.string().url();
const uuidField = z.string().uuid();
const minLengthString = z.string().min( 1 );
const maxLengthString = z.string().max( 1000 );
// 数値バリデーション
const positiveNumber = z.number().positive();
const nonNegativeNumber = z.number().nonnegative();
const percentageNumber = z.number().min( 0 ).max( 100 );
// 配列バリデーション(ランタイムのみ — Output.object()スキーマには使用不可)
const nonEmptyArray = z.array( z.string() ).min( 1 );
const limitedArray = z.array( z.string() ).max( 10 );
const fixedLengthArray = z.array( z.string() ).length( 3 );
完全なサンプル
実際のワークフロー(image_infographic_nano)を元にした例:
import { z } from '@outputai/core';
// ============================================
// ワークフロースキーマ
// ============================================
export const WorkflowInputSchema = z.object( {
content: z.string().describe( 'Text content to generate image ideas from' ),
mode: z.enum( [ 'infographic' ] ).default( 'infographic' ).describe( 'Type of image to generate' ),
colorPalette: z.string().optional().describe( 'Color palette preference for the images' ),
artDirection: z.string().optional().describe( 'Art direction or style preference' ),
numberOfIdeas: z.number().min( 1 ).max( 10 ).default( 1 ).describe( 'Number of image concepts to generate' ),
referenceImageUrls: z.union( [
z.string(),
z.array( z.string() )
] ).optional().describe( 'Reference image URLs for style guidance (max 14)' ),
aspectRatio: z.enum( [ '1:1', '16:9', '9:16', '4:3', '3:4' ] ).default( '1:1' ).describe( 'Aspect ratio for generated images' ),
resolution: z.enum( [ '1K', '2K', '4K' ] ).default( '1K' ).describe( 'Resolution for generated images' ),
numberOfGenerations: z.number().min( 1 ).max( 10 ).default( 1 ).describe( 'Number of images to generate per concept' ),
storageNamespace: z.string().optional().describe( 'S3 folder path for storing images' )
} );
export type WorkflowInput = z.infer<typeof WorkflowInputSchema>;
export type WorkflowOutput = string[];
// ============================================
// ステップスキーマ
// ============================================
export const ValidateReferenceImagesInputSchema = z.object( {
referenceImageUrls: z.array( z.string() ).optional()
} );
export const GenerateImageIdeasInputSchema = z.object( {
content: z.string(),
numberOfIdeas: z.number(),
colorPalette: z.string().optional(),
artDirection: z.string().optional()
} );
export const GenerateImagesInputSchema = z.object( {
input: z.object( {
referenceImageUrls: z.union( [ z.string(), z.array( z.string() ) ] ).optional(),
aspectRatio: z.enum( [ '1:1', '16:9', '9:16', '4:3', '3:4' ] ),
resolution: z.enum( [ '1K', '2K', '4K' ] ),
numberOfGenerations: z.number(),
storageNamespace: z.string().optional()
} ),
prompt: z.string()
} );
// LLMレスポンスバリデーション用スキーマ
export const ImageIdeasSchema = z.object( {
ideas: z.array( z.string() ).describe( 'Array of detailed image prompts for Gemini' )
} );
// ============================================
// 型のエクスポート
// ============================================
export type ValidateReferenceImagesInput = z.infer<typeof ValidateReferenceImagesInputSchema>;
export type GenerateImageIdeasInput = z.infer<typeof GenerateImageIdeasInputSchema>;
export type GenerateImagesInput = z.infer<typeof GenerateImagesInputSchema>;
export type ImageIdeas = z.infer<typeof ImageIdeasSchema>;
ベストプラクティス
1. フィールドに説明的なdescriptionを付ける
// 良い例 — ドキュメントやエラーメッセージに役立つ
z.string().describe( 'User email address for notifications' )
// 避けるべき例 — エラー発生時にコンテキストがわからない
z.string()
2. 適切なデフォルト値を設定する
// 良い例 — オプションフィールドがなくてもワークフローが動作する
numberOfIdeas: z.number().min( 1 ).max( 10 ).default( 1 )
// 避けるべき例 — すべてのフィールドをユーザーに強制する
numberOfIdeas: z.number().min( 1 ).max( 10 )
3. ワークフロースキーマとステップスキーマを分離する
// ワークフロー入力スキーマ(ユーザーが提供するデータ)
export const WorkflowInputSchema = z.object( { ... } );
// ステップスキーマ(内部データの形状)
export const StepNameInputSchema = z.object( { ... } );
4. スキーマと型の両方をエクスポートする
// ランタイムバリデーション用にスキーマをエクスポート
export const UserSchema = z.object( { ... } );
// TypeScriptの型チェック用に型をエクスポート
export type User = z.infer<typeof UserSchema>;
確認チェックリスト
- [ ]
zが@outputai/coreからインポートされている - [ ]
WorkflowInputSchemaが定義・エクスポートされている - [ ]
WorkflowInput型がエクスポートされている - [ ]
WorkflowOutput型が定義されている - [ ] 各ステップに対応する入出力スキーマがある
- [ ] 重要なフィールドすべてに
.describe()が付いている - [ ] オプションフィールドに
.optional()または.default()が使われている - [ ] 数値フィールドに適切な制約が設定されている(ランタイムスキーマには
.min()/.max()、Output.object()スキーマには.describe()) - [ ] コードがスタイル規約に従っている(
output-dev-code-styleを参照)
関連スキル
output-dev-workflow-function— ワークフロー定義でスキ
原文(English)を表示
Creating types.ts Files with Zod Schemas
Overview
This skill documents how to create types.ts files for Output SDK workflows. These files contain Zod schemas for input/output validation and their corresponding TypeScript types.
When to Use This Skill
- Creating a new workflow's type definitions
- Adding new schemas for steps
- Fixing schema validation errors
- Refactoring existing type definitions
Critical Import Rule
ALWAYS import z from @outputai/core, NEVER from zod directly:
// CORRECT
import { z } from '@outputai/core';
// WRONG - will cause runtime errors
import { z } from 'zod';
Related Skill: output-error-zod-import for troubleshooting import issues
Basic Structure
import { z } from '@outputai/core';
// 1. Workflow Input Schema
export const WorkflowInputSchema = z.object( {
// Define input fields
} );
// 2. Workflow Output Type
export type WorkflowInput = z.infer<typeof WorkflowInputSchema>;
export type WorkflowOutput = /* output type */;
// 3. Step Schemas (for each step)
export const StepNameInputSchema = z.object( {
// Step input fields
} );
export const StepNameOutputSchema = z.object( {
// Step output fields
} );
// 4. Type Exports
export type StepNameInput = z.infer<typeof StepNameInputSchema>;
export type StepNameOutput = z.infer<typeof StepNameOutputSchema>;
CRITICAL: Schema Constraints for LLM Output
Schemas passed to Output.object() are sent to LLM providers as tool definitions. Anthropic rejects several JSON Schema constraints that Zod methods produce. Getting this wrong causes runtime errors.
What Is NOT Allowed in LLM Output Schemas
- Numbers:
.min(),.max()onz.number()produceminimum/maximum-- rejected by Anthropic. - Arrays:
.min(),.max(),.length()onz.array()produceminItems/maxItems-- Anthropic only supportsminItemsof0or1. Values like.length( 3 )or.min( 2 )will be rejected.
Use .describe() Instead
.describe() is the primary mechanism for guiding LLM output quality. LLM providers use field names and descriptions from the schema to understand what each field should contain. Write clear, specific descriptions that communicate your intent.
Important: .describe() replaces both unsupported constraints AND prompt-based format instructions. Do not also describe the schema in the prompt -- the schema is sent to the provider automatically, and duplicating it reduces performance and creates drift risk. See output-dev-prompt-file for details.
// LLM output schema (sent to provider via Output.object()) -- .describe() ONLY
const llmOutputSchema = z.object( {
score: z.number().describe( 'Quality score 0-100' ),
confidence: z.number().describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).describe( 'Exactly 3 predictions' )
} );
// Workflow/step validation schema (Zod-only, NOT sent to LLM) -- .min()/.max()/.length() OK
const workflowOutputSchema = z.object( {
score: z.number().min( 0 ).max( 100 ).describe( 'Quality score 0-100' ),
confidence: z.number().min( 0 ).max( 1 ).describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).length( 3 ).describe( 'Exactly 3 predictions' )
} );
When to Use Which
| Context | .min()/.max()/.length() |
.describe() |
|---|---|---|
Schema passed to Output.object() |
No (numbers or arrays) | Yes |
inputSchema / outputSchema on steps |
OK | Optional |
inputSchema / outputSchema on workflows |
OK | Optional |
outputSchema on evaluators |
OK | Optional |
LLM Schemas Must Live in types.ts
Define all schemas used in Output.object() in types.ts and import them in step functions. Never define them inline -- this causes duplication and makes it harder to verify they follow the constraints above.
Common Schema Patterns
Basic Types
import { z } from '@outputai/core';
// Strings
const stringField = z.string();
const optionalString = z.string().optional();
const stringWithDefault = z.string().default( 'default value' );
const describedString = z.string().describe( 'Field description' );
// Numbers
const numberField = z.number();
const integerField = z.number().int();
const rangedNumber = z.number().min( 1 ).max( 100 ); // runtime only — NOT safe for Output.object() schemas
// Booleans
const booleanField = z.boolean();
const defaultBoolean = z.boolean().default( false );
// Enums
const enumField = z.enum( [ 'option1', 'option2', 'option3' ] );
const enumWithDefault = z.enum( [ 'small', 'medium', 'large' ] ).default( 'medium' );
Complex Types
import { z } from '@outputai/core';
// Arrays
const stringArray = z.array( z.string() );
const objectArray = z.array( z.object( { id: z.string(), name: z.string() } ) );
// Objects
const nestedObject = z.object( {
user: z.object( {
id: z.string(),
email: z.string().email()
} ),
settings: z.object( {
notifications: z.boolean()
} )
} );
// Union Types
const flexibleInput = z.union( [
z.string(),
z.array( z.string() )
] );
// Records
const keyValueMap = z.record( z.string(), z.number() );
Validation Patterns
import { z } from '@outputai/core';
// String Validations
const emailField = z.string().email();
const urlField = z.string().url();
const uuidField = z.string().uuid();
const minLengthString = z.string().min( 1 );
const maxLengthString = z.string().max( 1000 );
// Number Validations
const positiveNumber = z.number().positive();
const nonNegativeNumber = z.number().nonnegative();
const percentageNumber = z.number().min( 0 ).max( 100 );
// Array Validations (runtime only — NOT safe for Output.object() schemas)
const nonEmptyArray = z.array( z.string() ).min( 1 );
const limitedArray = z.array( z.string() ).max( 10 );
const fixedLengthArray = z.array( z.string() ).length( 3 );
Complete Example
Based on a real workflow (image_infographic_nano):
import { z } from '@outputai/core';
// ============================================
// Workflow Schemas
// ============================================
export const WorkflowInputSchema = z.object( {
content: z.string().describe( 'Text content to generate image ideas from' ),
mode: z.enum( [ 'infographic' ] ).default( 'infographic' ).describe( 'Type of image to generate' ),
colorPalette: z.string().optional().describe( 'Color palette preference for the images' ),
artDirection: z.string().optional().describe( 'Art direction or style preference' ),
numberOfIdeas: z.number().min( 1 ).max( 10 ).default( 1 ).describe( 'Number of image concepts to generate' ),
referenceImageUrls: z.union( [
z.string(),
z.array( z.string() )
] ).optional().describe( 'Reference image URLs for style guidance (max 14)' ),
aspectRatio: z.enum( [ '1:1', '16:9', '9:16', '4:3', '3:4' ] ).default( '1:1' ).describe( 'Aspect ratio for generated images' ),
resolution: z.enum( [ '1K', '2K', '4K' ] ).default( '1K' ).describe( 'Resolution for generated images' ),
numberOfGenerations: z.number().min( 1 ).max( 10 ).default( 1 ).describe( 'Number of images to generate per concept' ),
storageNamespace: z.string().optional().describe( 'S3 folder path for storing images' )
} );
export type WorkflowInput = z.infer<typeof WorkflowInputSchema>;
export type WorkflowOutput = string[];
// ============================================
// Step Schemas
// ============================================
export const ValidateReferenceImagesInputSchema = z.object( {
referenceImageUrls: z.array( z.string() ).optional()
} );
export const GenerateImageIdeasInputSchema = z.object( {
content: z.string(),
numberOfIdeas: z.number(),
colorPalette: z.string().optional(),
artDirection: z.string().optional()
} );
export const GenerateImagesInputSchema = z.object( {
input: z.object( {
referenceImageUrls: z.union( [ z.string(), z.array( z.string() ) ] ).optional(),
aspectRatio: z.enum( [ '1:1', '16:9', '9:16', '4:3', '3:4' ] ),
resolution: z.enum( [ '1K', '2K', '4K' ] ),
numberOfGenerations: z.number(),
storageNamespace: z.string().optional()
} ),
prompt: z.string()
} );
// Schema for LLM response validation
export const ImageIdeasSchema = z.object( {
ideas: z.array( z.string() ).describe( 'Array of detailed image prompts for Gemini' )
} );
// ============================================
// Type Exports
// ============================================
export type ValidateReferenceImagesInput = z.infer<typeof ValidateReferenceImagesInputSchema>;
export type GenerateImageIdeasInput = z.infer<typeof GenerateImageIdeasInputSchema>;
export type GenerateImagesInput = z.infer<typeof GenerateImagesInputSchema>;
export type ImageIdeas = z.infer<typeof ImageIdeasSchema>;
Best Practices
1. Use Descriptive Field Descriptions
// Good - helps with documentation and error messages
z.string().describe( 'User email address for notifications' )
// Avoid - no context for errors
z.string()
2. Provide Sensible Defaults
// Good - workflow works without optional fields
numberOfIdeas: z.number().min( 1 ).max( 10 ).default( 1 )
// Avoid - forces users to provide every field
numberOfIdeas: z.number().min( 1 ).max( 10 )
3. Separate Workflow and Step Schemas
// Workflow input schema (what the user provides)
export const WorkflowInputSchema = z.object( { ... } );
// Step schemas (internal data shapes)
export const StepNameInputSchema = z.object( { ... } );
4. Export Both Schemas and Types
// Export schema for runtime validation
export const UserSchema = z.object( { ... } );
// Export type for TypeScript type checking
export type User = z.infer<typeof UserSchema>;
Verification Checklist
- [ ]
zis imported from@outputai/core - [ ] WorkflowInputSchema is defined and exported
- [ ] WorkflowInput type is exported
- [ ] WorkflowOutput type is defined
- [ ] Each step has corresponding input/output schemas
- [ ] All schemas have
.describe()for important fields - [ ] Optional fields use
.optional()or.default() - [ ] Numeric fields have appropriate constraints (
.min()/.max()for runtime schemas,.describe()forOutput.object()schemas) - [ ] Code follows style conventions (see output-dev-code-style)
Related Skills
output-dev-workflow-function- Using schemas in workflow definitionsoutput-dev-step-function- Using schemas in step definitionsoutput-dev-evaluator-function- Using schemas in evaluator definitionsoutput-dev-folder-structure- Where types.ts belongs in the projectoutput-error-zod-import- Troubleshooting schema import issuesoutput-dev-code-style- Code style conventions
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。