{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "thinQit Dex request",
  "description": "The body of POST /v1/decide (DecideRequest in api/openapi.yaml): a state plus typed questions. Run it with the thinQit Dex extension or `dex decide --file`.",
  "markdownDescription": "The body of POST /v1/decide (DecideRequest in api/openapi.yaml): a state plus typed questions. Run it with the thinQit Dex extension or `dex decide --file`.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "state",
    "questions"
  ],
  "properties": {
    "model": {
      "$ref": "#/definitions/ModelName"
    },
    "state": {
      "$ref": "#/definitions/State"
    },
    "questions": {
      "type": "object",
      "description": "Question id to question. Ids are for your code only and never reach the model.",
      "markdownDescription": "Question id to question. Ids are for your code only and never reach the model.",
      "minProperties": 1,
      "maxProperties": 32,
      "propertyNames": {
        "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,63}$",
        "patternErrorMessage": "A question id starts with a letter and has at most 64 letters, digits, underscores or hyphens."
      },
      "additionalProperties": {
        "$ref": "#/definitions/Question"
      }
    },
    "fallback": {
      "type": "string",
      "enum": [
        "allow",
        "never"
      ],
      "default": "allow",
      "description": "`never` keeps the request on the GPU path even when the model is an alias. Exact versions never use the fallback. Send `never` for content moderation: the fallback's content filters block that content.",
      "markdownDescription": "`never` keeps the request on the GPU path even when the model is an alias. Exact versions never use the fallback. Send `never` for content moderation: the fallback's content filters block that content."
    },
    "$schema": {
      "type": "string",
      "description": "Editor hint only. The Dex CLI and the VS Code extension remove it before sending the request."
    }
  },
  "defaultSnippets": [
    {
      "label": "thinQit Dex request",
      "description": "A state and one question",
      "body": {
        "model": "dex-1",
        "state": "${1:The text to decide about}",
        "questions": {
          "${2:refund}": {
            "type": "check",
            "instructions": "${3:Does the customer ask for money back?}"
          }
        }
      }
    }
  ],
  "definitions": {
    "ModelName": {
      "type": "string",
      "description": "An alias such as `dex-1` or an exact version such as `dex-1.0.0`.",
      "markdownDescription": "An alias such as `dex-1` or an exact version such as `dex-1.0.0`.",
      "pattern": "^dex-[0-9]+(\\.[0-9]+\\.[0-9]+)?$",
      "default": "dex-1",
      "examples": [
        "dex-1",
        "dex-1.0.0"
      ]
    },
    "State": {
      "description": "The material the questions are about. A string, or JSON whose fields questions can point at with\n`{{path}}` references. A string of only whitespace, an empty object and an empty array are rejected (empty\nobjects and arrays inside the state are fine). At most 16,384 tokens after rendering.\n",
      "markdownDescription": "The material the questions are about. A string, or JSON whose fields questions can point at with\n`{{path}}` references. A string of only whitespace, an empty object and an empty array are rejected (empty\nobjects and arrays inside the state are fine). At most 16,384 tokens after rendering.\n",
      "oneOf": [
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 65536,
          "pattern": "\\S",
          "patternErrorMessage": "This text cannot be only whitespace."
        },
        {
          "type": "object",
          "minProperties": 1
        },
        {
          "type": "array",
          "minItems": 1
        }
      ]
    },
    "Question": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "enum": [
            "pick",
            "rate",
            "check"
          ],
          "description": "Question type: `pick` chooses one of labelled options, `rate` places the state on ordered levels, `check` answers yes or no.",
          "markdownDescription": "Question type: `pick` chooses one of labelled options, `rate` places the state on ordered levels, `check` answers yes or no."
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "type": {
                "const": "pick"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "$ref": "#/definitions/PickQuestion"
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "rate"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "$ref": "#/definitions/RateQuestion"
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "check"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "$ref": "#/definitions/CheckQuestion"
          }
        }
      ],
      "defaultSnippets": [
        {
          "label": "pick question",
          "description": "Choose one of labelled options",
          "body": {
            "type": "pick",
            "instructions": "${1:Which team should handle this?}",
            "options": {
              "${2:billing}": "${3:Payments and refunds}",
              "${4:technical}": null
            }
          }
        },
        {
          "label": "rate question",
          "description": "Place the state on ordered levels, lowest first",
          "body": {
            "type": "rate",
            "instructions": "${1:How urgent is this?}",
            "levels": [
              "${2:low}",
              "${3:normal}",
              "${4:high}"
            ]
          }
        },
        {
          "label": "check question",
          "description": "A yes/no question; the answer is the probability of yes",
          "body": {
            "type": "check",
            "instructions": "${1:Does the customer ask for money back?}"
          }
        }
      ]
    },
    "PickQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type",
        "instructions",
        "options"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "pick"
        },
        "instructions": {
          "$ref": "#/definitions/Instructions"
        },
        "criteria": {
          "$ref": "#/definitions/Criteria"
        },
        "options": {
          "type": "object",
          "description": "Label to description (or null). Key order is kept and shown to the model in that order. Labels have no\nleading or trailing whitespace and are unique after Unicode NFC normalisation and lower-casing (`Billing`\nand `billing` are the same label). A description of only whitespace is rejected.\n",
          "markdownDescription": "Label to description (or null). Key order is kept and shown to the model in that order. Labels have no\nleading or trailing whitespace and are unique after Unicode NFC normalisation and lower-casing (`Billing`\nand `billing` are the same label). A description of only whitespace is rejected.\n",
          "minProperties": 1,
          "maxProperties": 255,
          "propertyNames": {
            "minLength": 1,
            "maxLength": 100,
            "pattern": "^\\S(.*\\S)?$",
            "patternErrorMessage": "An option label cannot start or end with a space."
          },
          "additionalProperties": {
            "type": [
              "string",
              "null"
            ],
            "minLength": 1,
            "maxLength": 1000,
            "pattern": "\\S",
            "patternErrorMessage": "This text cannot be only whitespace."
          }
        },
        "min_confidence": {
          "$ref": "#/definitions/MinConfidence"
        }
      }
    },
    "RateQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type",
        "instructions",
        "levels"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "rate"
        },
        "instructions": {
          "$ref": "#/definitions/Instructions"
        },
        "criteria": {
          "$ref": "#/definitions/Criteria"
        },
        "levels": {
          "type": "array",
          "description": "Ordered from lowest (index 0) to highest. A level follows the label rule (no leading or trailing\nwhitespace), and levels are unique after Unicode NFC normalisation and lower-casing.\n",
          "markdownDescription": "Ordered from lowest (index 0) to highest. A level follows the label rule (no leading or trailing\nwhitespace), and levels are unique after Unicode NFC normalisation and lower-casing.\n",
          "minItems": 2,
          "maxItems": 10,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "pattern": "^\\S(.*\\S)?$",
            "patternErrorMessage": "A level cannot start or end with whitespace."
          }
        },
        "min_confidence": {
          "$ref": "#/definitions/MinConfidence"
        }
      }
    },
    "CheckQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type",
        "instructions"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "check"
        },
        "instructions": {
          "$ref": "#/definitions/Instructions"
        },
        "criteria": {
          "$ref": "#/definitions/Criteria"
        },
        "min_confidence": {
          "$ref": "#/definitions/MinConfidence"
        }
      }
    },
    "Instructions": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4000,
      "pattern": "\\S",
      "description": "What to decide; a string of only whitespace is rejected. May contain `{{path}}` references to state fields, such as `{{ticket.body}}`.",
      "markdownDescription": "What to decide; a string of only whitespace is rejected. May contain `{{path}}` references to state fields, such as `{{ticket.body}}`.",
      "patternErrorMessage": "This text cannot be only whitespace."
    },
    "Criteria": {
      "description": "Extra rules or definitions the model must apply. May contain `{{path}}` references. A string of only whitespace is rejected. `null` is the same as leaving the field out.",
      "markdownDescription": "Extra rules or definitions the model must apply. May contain `{{path}}` references. A string of only whitespace is rejected. `null` is the same as leaving the field out.",
      "oneOf": [
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 4000,
          "pattern": "\\S",
          "patternErrorMessage": "This text cannot be only whitespace."
        },
        {
          "type": "array",
          "minItems": 1,
          "maxItems": 20,
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "pattern": "\\S",
            "patternErrorMessage": "This text cannot be only whitespace."
          }
        },
        {
          "type": "null"
        }
      ]
    },
    "MinConfidence": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "When the answer's confidence is below this value, the answer carries `abstained` set to true.",
      "markdownDescription": "When the answer's confidence is below this value, the answer carries `abstained` set to true."
    }
  }
}
