Files
dev/third_party/pi/packages/coding-agent/schemas/models.schema.json
alexion 6081e3e325 chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree.

git-subtree-dir: third_party/pi

git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
2026-10-15 17:58:48 -04:00

1158 lines
41 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://pi.dev/schemas/models.schema.json",
"$comment": "This file is generated from TypeScript source. Do not edit it manually; run npm run generate:schemas.",
"type": "object",
"required": [
"providers"
],
"properties": {
"$schema": {
"type": "string"
},
"providers": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"baseUrl": {
"type": "string",
"minLength": 1
},
"apiKey": {
"type": "string",
"minLength": 1
},
"api": {
"type": "string",
"minLength": 1
},
"oauth": {
"type": "string",
"const": "radius"
},
"headers": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "string"
}
}
},
"compat": {
"$ref": "#/$defs/ProviderCompat",
"description": "Provider and model compatibility overrides."
},
"authHeader": {
"type": "boolean"
},
"models": {
"type": "array",
"items": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"name": {
"type": "string",
"minLength": 1
},
"api": {
"type": "string",
"minLength": 1
},
"baseUrl": {
"type": "string",
"minLength": 1
},
"reasoning": {
"type": "boolean"
},
"thinkingLevelMap": {
"$ref": "#/$defs/ThinkingLevelMap"
},
"input": {
"type": "array",
"items": {
"enum": [
"text",
"image"
]
}
},
"inputLimits": {
"$ref": "#/$defs/ModelInputLimits"
},
"cost": {
"$ref": "#/$defs/ModelCost"
},
"promptCache": {
"$ref": "#/$defs/ModelPromptCache",
"description": "Best-effort prompt cache lifetime in seconds for each retention tier. A missing tier means the lifetime is unknown, so Pi does not warm it."
},
"contextWindow": {
"type": "number",
"exclusiveMinimum": 0
},
"maxTokens": {
"type": "number",
"exclusiveMinimum": 0
},
"samplingParams": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"samplingParamsByThinkingLevel": {
"type": "object",
"properties": {
"off": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"minimal": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"low": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"medium": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"high": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"xhigh": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"max": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
}
}
},
"headers": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "string"
}
}
},
"compat": {
"$ref": "#/$defs/ProviderCompat",
"description": "Provider and model compatibility overrides."
}
}
}
},
"modelOverrides": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"reasoning": {
"type": "boolean"
},
"thinkingLevelMap": {
"$ref": "#/$defs/ThinkingLevelMap"
},
"input": {
"type": "array",
"items": {
"enum": [
"text",
"image"
]
}
},
"inputLimits": {
"$ref": "#/$defs/ModelInputLimits"
},
"cost": {
"type": "object",
"properties": {
"input": {
"type": "number",
"description": "Input cost in USD per million tokens."
},
"output": {
"type": "number",
"description": "Output cost in USD per million tokens."
},
"cacheRead": {
"type": "number",
"description": "Cache-read cost in USD per million tokens."
},
"cacheWrite": {
"type": "number",
"description": "Cache-write cost in USD per million tokens."
},
"tiers": {
"type": "array",
"items": {
"type": "object",
"required": [
"inputTokensAbove",
"input",
"output",
"cacheRead",
"cacheWrite"
],
"properties": {
"inputTokensAbove": {
"type": "number",
"description": "Use this tier when total request input exceeds this token count."
},
"input": {
"type": "number",
"description": "Input cost in USD per million tokens."
},
"output": {
"type": "number",
"description": "Output cost in USD per million tokens."
},
"cacheRead": {
"type": "number",
"description": "Cache-read cost in USD per million tokens."
},
"cacheWrite": {
"type": "number",
"description": "Cache-write cost in USD per million tokens."
}
}
},
"description": "Request-wide pricing tiers. The highest matching input threshold applies to the full request."
}
}
},
"promptCache": {
"$ref": "#/$defs/ModelPromptCache",
"description": "Best-effort prompt cache lifetime in seconds for each retention tier. A missing tier means the lifetime is unknown, so Pi does not warm it."
},
"contextWindow": {
"type": "number",
"exclusiveMinimum": 0
},
"maxTokens": {
"type": "number",
"exclusiveMinimum": 0
},
"samplingParams": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"samplingParamsByThinkingLevel": {
"type": "object",
"properties": {
"off": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"minimal": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"low": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"medium": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"high": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"xhigh": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
},
"max": {
"type": "object",
"patternProperties": {
"^.*$": {}
}
}
}
},
"headers": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "string"
}
}
},
"compat": {
"$ref": "#/$defs/ProviderCompat",
"description": "Provider and model compatibility overrides."
}
}
}
}
}
}
}
}
}
},
"$defs": {
"ModelCost": {
"type": "object",
"required": [
"input",
"output",
"cacheRead",
"cacheWrite"
],
"properties": {
"input": {
"type": "number",
"description": "Input cost in USD per million tokens."
},
"output": {
"type": "number",
"description": "Output cost in USD per million tokens."
},
"cacheRead": {
"type": "number",
"description": "Cache-read cost in USD per million tokens."
},
"cacheWrite": {
"type": "number",
"description": "Cache-write cost in USD per million tokens."
},
"tiers": {
"type": "array",
"items": {
"type": "object",
"required": [
"inputTokensAbove",
"input",
"output",
"cacheRead",
"cacheWrite"
],
"properties": {
"inputTokensAbove": {
"type": "number",
"description": "Use this tier when total request input exceeds this token count."
},
"input": {
"type": "number",
"description": "Input cost in USD per million tokens."
},
"output": {
"type": "number",
"description": "Output cost in USD per million tokens."
},
"cacheRead": {
"type": "number",
"description": "Cache-read cost in USD per million tokens."
},
"cacheWrite": {
"type": "number",
"description": "Cache-write cost in USD per million tokens."
}
}
},
"description": "Request-wide pricing tiers. The highest matching input threshold applies to the full request."
}
}
},
"ModelInputLimits": {
"type": "object",
"properties": {
"maxRequestBytes": {
"type": "integer",
"minimum": 1,
"description": "Maximum serialized provider request size in bytes."
},
"images": {
"type": "object",
"properties": {
"resize": {
"type": "object",
"properties": {
"maxWidth": {
"type": "integer",
"minimum": 1
},
"maxHeight": {
"type": "integer",
"minimum": 1
},
"maxBytes": {
"type": "integer",
"minimum": 1,
"description": "Maximum base64-encoded payload size in bytes."
},
"jpegQuality": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
"description": "Cache-safe resize profile applied before a new image enters conversation history."
},
"maxPerMessage": {
"type": "integer",
"minimum": 1,
"description": "Maximum images accepted in one provider message."
},
"maxPerRequest": {
"type": "integer",
"minimum": 1,
"description": "Maximum images accepted across one provider request."
}
}
}
}
},
"ModelPromptCache": {
"type": "object",
"properties": {
"short": {
"type": "number",
"exclusiveMinimum": 0
},
"long": {
"type": "number",
"exclusiveMinimum": 0
}
}
},
"ProviderCompat": {
"type": "object",
"properties": {
"supportsStore": {
"type": "boolean",
"description": "Whether the provider supports the store field. Default: auto-detected from URL."
},
"supportsDeveloperRole": {
"type": "boolean",
"description": "Whether the provider supports the developer role instead of system. Defaults are API-specific."
},
"supportsReasoningEffort": {
"type": "boolean",
"description": "Whether the provider supports reasoning_effort. Default: auto-detected from URL."
},
"supportsUsageInStreaming": {
"type": "boolean",
"description": "Whether the provider supports stream_options.include_usage for token usage in streaming responses.",
"default": true
},
"supportsFinishReason": {
"type": "boolean",
"description": "Whether streamed responses include finish_reason. When false, pi infers stop or toolUse when the stream ends.",
"default": true
},
"maxTokensField": {
"anyOf": [
{
"type": "string",
"const": "max_completion_tokens"
},
{
"type": "string",
"const": "max_tokens"
}
],
"description": "Which field to use for max tokens. Default: auto-detected from URL."
},
"requiresToolResultName": {
"type": "boolean",
"description": "Whether tool results require the name field. Default: auto-detected from URL."
},
"requiresAssistantAfterToolResult": {
"type": "boolean",
"description": "Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL."
},
"requiresThinkingAsText": {
"type": "boolean",
"description": "Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL."
},
"requiresReasoningContentOnAssistantMessages": {
"type": "boolean",
"description": "Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL."
},
"thinkingFormat": {
"anyOf": [
{
"type": "string",
"const": "openai"
},
{
"type": "string",
"const": "openrouter"
},
{
"type": "string",
"const": "deepseek"
},
{
"type": "string",
"const": "together"
},
{
"type": "string",
"const": "baseten"
},
{
"type": "string",
"const": "zai"
},
{
"type": "string",
"const": "qwen"
},
{
"type": "string",
"const": "chat-template"
},
{
"type": "string",
"const": "qwen-chat-template"
},
{
"type": "string",
"const": "string-thinking"
},
{
"type": "string",
"const": "ant-ling"
}
],
"description": "Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. \"openai\" uses reasoning_effort, \"openrouter\" uses reasoning.effort, \"deepseek\" uses thinking.type plus reasoning_effort when supported, \"together\" uses reasoning.enabled plus reasoning_effort when supported, \"baseten\" uses configurable chat_template_args plus reasoning_effort when supported, \"zai\" uses thinking.type, \"qwen\" uses top-level enable_thinking, \"qwen-chat-template\" uses chat_template_kwargs.enable_thinking and preserve_thinking, \"chat-template\" uses configurable chat_template_kwargs, \"string-thinking\" uses top-level thinking, and \"ant-ling\" uses reasoning.effort only when the mapped effort is non-null."
},
"chatTemplateKwargs": {
"type": "object",
"patternProperties": {
"^.*$": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
},
{
"type": "object",
"required": [
"$var"
],
"properties": {
"$var": {
"anyOf": [
{
"type": "string",
"const": "thinking.enabled"
},
{
"type": "string",
"const": "thinking.effort"
},
{
"type": "string",
"const": "thinking.budget"
}
]
},
"omitWhenOff": {
"type": "boolean"
}
}
}
]
}
},
"description": "Kwargs sent as chat_template_kwargs when thinkingFormat is \"chat-template\". Use $var with \"thinking.enabled\", \"thinking.effort\", or \"thinking.budget\" for pi-controlled values."
},
"chatTemplateArgs": {
"type": "object",
"patternProperties": {
"^.*$": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
},
{
"type": "object",
"required": [
"$var"
],
"properties": {
"$var": {
"anyOf": [
{
"type": "string",
"const": "thinking.enabled"
},
{
"type": "string",
"const": "thinking.effort"
},
{
"type": "string",
"const": "thinking.budget"
}
]
},
"omitWhenOff": {
"type": "boolean"
}
}
}
]
}
},
"description": "Arguments sent as chat_template_args when thinkingFormat is \"baseten\". Use $var with \"thinking.enabled\", \"thinking.effort\", or \"thinking.budget\" for pi-controlled values."
},
"openRouterRouting": {
"type": "object",
"properties": {
"allow_fallbacks": {
"type": "boolean",
"description": "Whether to allow backup providers to serve requests.",
"default": true
},
"require_parameters": {
"type": "boolean",
"description": "Whether to filter providers to only those that support all parameters in the request.",
"default": false
},
"data_collection": {
"anyOf": [
{
"type": "string",
"const": "deny"
},
{
"type": "string",
"const": "allow"
}
],
"description": "Data collection setting. \"allow\": allow providers that may store or train on data. \"deny\": only use providers that do not collect user data.",
"default": "allow"
},
"zdr": {
"type": "boolean",
"description": "Whether to restrict routing to only ZDR (Zero Data Retention) endpoints."
},
"enforce_distillable_text": {
"type": "boolean",
"description": "Whether to restrict routing to only models that allow text distillation."
},
"order": {
"type": "array",
"items": {
"type": "string"
},
"description": "An ordered list of provider names or slugs to try in sequence, falling back to the next if unavailable."
},
"only": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of provider names or slugs to exclusively allow for this request."
},
"ignore": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of provider names or slugs to skip for this request."
},
"quantizations": {
"type": "array",
"items": {
"type": "string"
},
"description": "A list of quantization levels to filter providers by, for example [\"fp16\", \"bf16\", \"fp8\", \"fp6\", \"int8\", \"int4\", \"fp4\", \"fp32\"]."
},
"sort": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"by": {
"type": "string",
"description": "The sorting metric, such as \"price\", \"throughput\", or \"latency\"."
},
"partition": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Partitioning strategy: \"model\" or \"none\".",
"default": "model"
}
}
}
],
"description": "Sorting strategy. Can be a string such as \"price\", \"throughput\", or \"latency\", or an object."
},
"max_price": {
"type": "object",
"properties": {
"prompt": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
}
],
"description": "Price per million prompt tokens."
},
"completion": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
}
],
"description": "Price per million completion tokens."
},
"image": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
}
],
"description": "Price per image."
},
"audio": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
}
],
"description": "Price per audio unit."
},
"request": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
}
],
"description": "Price per request."
}
},
"description": "Maximum price per million tokens in USD."
},
"preferred_min_throughput": {
"anyOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"p50": {
"type": "number",
"description": "Minimum tokens per second at the 50th percentile."
},
"p75": {
"type": "number",
"description": "Minimum tokens per second at the 75th percentile."
},
"p90": {
"type": "number",
"description": "Minimum tokens per second at the 90th percentile."
},
"p99": {
"type": "number",
"description": "Minimum tokens per second at the 99th percentile."
}
}
}
],
"description": "Preferred minimum throughput in tokens per second. A number applies to p50."
},
"preferred_max_latency": {
"anyOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"p50": {
"type": "number",
"description": "Maximum latency in seconds at the 50th percentile."
},
"p75": {
"type": "number",
"description": "Maximum latency in seconds at the 75th percentile."
},
"p90": {
"type": "number",
"description": "Maximum latency in seconds at the 90th percentile."
},
"p99": {
"type": "number",
"description": "Maximum latency in seconds at the 99th percentile."
}
}
}
],
"description": "Preferred maximum latency in seconds. A number applies to p50."
}
},
"description": "OpenRouter provider routing preferences. Controls which upstream providers OpenRouter routes requests to. Sent as the provider field in the OpenRouter API request body. See https://openrouter.ai/docs/guides/routing/provider-selection."
},
"vercelGatewayRouting": {
"type": "object",
"properties": {
"only": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of provider slugs to exclusively use for this request, for example [\"bedrock\", \"anthropic\"]."
},
"order": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of provider slugs to try in order, for example [\"anthropic\", \"openai\"]."
}
},
"description": "Vercel AI Gateway routing preferences. Controls which upstream providers the gateway routes requests to. See https://vercel.com/docs/ai-gateway/models-and-providers/provider-options."
},
"zaiToolStream": {
"type": "boolean",
"description": "Whether z.ai supports top-level tool_stream for streaming tool call deltas.",
"default": false
},
"thinkingTokenBudgetField": {
"anyOf": [
{
"type": "string",
"const": "thinking_token_budget"
},
{
"type": "string",
"const": "thinking_budget"
},
{
"type": "string",
"const": "thinking_budget_tokens"
}
],
"description": "Top-level request field used to cap reasoning tokens from thinkingBudgets. Reasoning and the answer share max_tokens on these endpoints. \"thinking_token_budget\" is vLLM, \"thinking_budget\" is Qwen, DashScope, or SGLang, and \"thinking_budget_tokens\" is llama.cpp. Off by default and not set on the generated catalog."
},
"supportsThinkingTokenBudget": {
"type": "boolean",
"description": "Alias for thinkingTokenBudgetField: \"thinking_token_budget\" (vLLM). Prefer thinkingTokenBudgetField.",
"default": false
},
"supportsOpenAIGrammarTools": {
"type": "boolean",
"description": "Whether the provider supports OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools.",
"default": false
},
"supportsMidConvoSystemMessages": {
"type": "boolean",
"description": "Whether the exact model accepts system or developer messages after the conversation has started. When false, later system messages are folded into the leading system message.",
"default": false
},
"supportsMidConvoToolAdditions": {
"type": "boolean",
"description": "Whether system messages can introduce additional tools mid-conversation. Requires supportsMidConvoSystemMessages. The generated catalog enables this for capable models.",
"default": false
},
"supportsStrictMode": {
"type": "boolean",
"description": "Whether the provider supports strict tool schemas. Defaults are API-specific."
},
"cacheControlFormat": {
"type": "string",
"const": "anthropic",
"description": "Cache control convention for prompt caching. Anthropic applies cache_control markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content."
},
"sendSessionAffinityHeaders": {
"type": "boolean",
"description": "Whether to send session-affinity data from options.sessionId. Defaults are API-specific."
},
"sessionAffinityFormat": {
"anyOf": [
{
"type": "string",
"const": "openai"
},
{
"type": "string",
"const": "openai-nosession"
},
{
"type": "string",
"const": "openrouter"
}
],
"description": "Session-affinity header format. Defaults are API-specific or auto-detected."
},
"supportsLongCacheRetention": {
"type": "boolean",
"description": "Whether the provider supports long prompt cache retention. Defaults are API-specific or auto-detected."
},
"vllmPriority": {
"type": "number",
"description": "vLLM scheduler priority sent as the top-level priority request field. Lower values are handled earlier and the server default is 0. Only meaningful with --scheduling-policy priority. Off by default and not set on the generated catalog."
},
"supportsAdditionalTools": {
"type": "boolean",
"description": "Whether the model supports message-anchored additional_tools input items.",
"default": false
},
"supportsToolSearch": {
"type": "boolean",
"description": "Whether the model supports client-executed tool search for transcript-anchored additions.",
"default": false
},
"supportsExplicitPromptCacheMode": {
"type": "boolean",
"description": "Whether the model accepts prompt_cache_options. Older OpenAI models reject the parameter.",
"default": false
},
"supportsMidConvoEffort": {
"type": "boolean",
"description": "Whether thinking level changes are sent inside the conversation instead of changing the request's effort, so a change keeps the prompt cache. Used by the anthropic-messages and openai-responses APIs.",
"default": false
},
"supportsMaxOutputTokens": {
"type": "boolean",
"description": "Whether the provider accepts max_output_tokens. Some Codex-protocol gateways reject it.",
"default": true
},
"supportsEagerToolInputStreaming": {
"type": "boolean",
"description": "Whether the provider accepts per-tool eager_input_streaming. When false, the Anthropic provider omits tools[].eager_input_streaming and sends the legacy fine-grained-tool-streaming-2025-05-14 beta header for tool-enabled requests.",
"default": true
},
"supportsCacheControlOnTools": {
"type": "boolean",
"description": "Whether the provider supports Anthropic-style cache_control markers on tool definitions. When false, cache_control is omitted from tool parameters. Some Anthropic-compatible providers, such as Fireworks, do not support this field on tools and may reject or ignore it.",
"default": true
},
"supportsTemperature": {
"type": "boolean",
"description": "Whether the model accepts the Anthropic temperature request field. Claude Opus 4.7+ rejects non-default values.",
"default": true
},
"forceAdaptiveThinking": {
"type": "boolean",
"description": "Whether to force adaptive thinking (thinking.type: adaptive plus output_config.effort) regardless of model ID. Built-in models that require adaptive thinking set this in generated metadata. Custom Anthropic-compatible providers can set this to true for any model whose upstream requires the adaptive format. Set false to opt out on overridden built-in models.",
"default": false
},
"allowEmptySignature": {
"type": "boolean",
"description": "Whether to replay empty thinking signatures instead of converting thinking to text.",
"default": false
},
"supportsStrictTools": {
"type": "boolean",
"description": "Whether the provider supports Anthropic strict tool schemas. Generated Anthropic models enable it explicitly.",
"default": false
},
"supportsMidConvoToolChanges": {
"type": "boolean",
"description": "Whether the exact model accepts mid-conversation tool_addition and tool_removal blocks. Requires supportsMidConvoSystemMessages.",
"default": false
},
"allowedFallbackModels": {
"type": "array",
"items": {
"type": "object",
"required": [
"provider",
"model",
"cost"
],
"properties": {
"provider": {
"type": "string",
"minLength": 1
},
"model": {
"type": "string",
"minLength": 1
},
"cost": {
"$ref": "#/$defs/ModelCost"
}
},
"description": "An Anthropic server-side refusal fallback model with local pricing metadata."
},
"maxItems": 3,
"description": "Models Anthropic accepts for server-side refusal fallback, with local pricing metadata for returned fallback responses. When absent or empty, callers must omit fallbacks; Anthropic rejects the field for models with no permitted fallback targets."
}
},
"additionalProperties": true
},
"ThinkingLevelMap": {
"type": "object",
"properties": {
"off": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"minimal": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"low": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"medium": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"high": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"xhigh": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"max": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
}
}
}
}