From 0488e07062d4cd57bcffd173cdf7b3750c83cbcc Mon Sep 17 00:00:00 2001 From: rasmi Date: Tue, 12 May 2026 15:49:16 -0400 Subject: [PATCH] Specify optional type for fields allow to be unset. --- docs/assets/api/schemas.json | 364 +++++++++++------- scripts/deliberate_lab/types.py | 74 ++-- utils/src/experiment.validation.ts | 2 +- utils/src/participant.validation.ts | 6 +- utils/src/prompt.validation.ts | 6 +- utils/src/providers.validation.ts | 26 +- utils/src/shared.validation.ts | 14 +- utils/src/stages/chat_stage.validation.ts | 14 +- utils/src/stages/info_stage.validation.ts | 2 +- .../stages/private_chat_stage.validation.ts | 14 +- utils/src/stages/survey_stage.validation.ts | 17 +- utils/src/structured_output.validation.ts | 36 +- utils/src/variables.validation.ts | 4 +- 13 files changed, 342 insertions(+), 237 deletions(-) diff --git a/docs/assets/api/schemas.json b/docs/assets/api/schemas.json index 6141946e8..6f1f8f406 100644 --- a/docs/assets/api/schemas.json +++ b/docs/assets/api/schemas.json @@ -5,12 +5,7 @@ "CohortParticipantConfig": { "title": "CohortParticipantConfig", "type": "object", - "required": [ - "minParticipantsPerCohort", - "maxParticipantsPerCohort", - "includeAllParticipantsInCohortCount", - "botProtection" - ], + "required": ["includeAllParticipantsInCohortCount", "botProtection"], "properties": { "minParticipantsPerCohort": { "minimum": 0, @@ -65,13 +60,20 @@ "type": "string" }, "cohortValues": { - "type": "object", - "patternProperties": { - "^(.*)$": { - "type": "string" + "anyOf": [ + { + "type": "null" + }, + { + "type": "object", + "patternProperties": { + "^(.*)$": { + "type": "string" + } + }, + "title": "AnyOf" } - }, - "title": "CohortValues" + ] } } }, @@ -440,6 +442,36 @@ } } }, + "CohortDefinition": { + "title": "CohortDefinition", + "additionalProperties": false, + "type": "object", + "required": ["id", "alias", "name"], + "properties": { + "id": { + "minLength": 1, + "type": "string" + }, + "alias": { + "minLength": 1, + "type": "string" + }, + "name": { + "minLength": 1, + "type": "string" + }, + "description": { + "type": "string" + }, + "generatedCohortId": { + "type": "string" + }, + "maxParticipantsPerCohort": { + "minimum": 1, + "type": "integer" + } + } + }, "AssetAllocationStageConfig": { "title": "AssetAllocationStageConfig", "additionalProperties": false, @@ -659,8 +691,6 @@ "name", "descriptions", "progress", - "timeLimitInMinutes", - "timeMinimumInMinutes", "discussions" ], "properties": { @@ -1086,7 +1116,7 @@ } }, "youtubeVideoId": { - "type": "string" + "type": ["null", "string"] } } }, @@ -1299,15 +1329,7 @@ "title": "PrivateChatStageConfig", "additionalProperties": false, "type": "object", - "required": [ - "id", - "kind", - "name", - "descriptions", - "progress", - "timeLimitInMinutes", - "timeMinimumInMinutes" - ], + "required": ["id", "kind", "name", "descriptions", "progress"], "properties": { "id": { "minLength": 1, @@ -2199,7 +2221,7 @@ "title": "MultipleChoiceSurveyQuestion", "additionalProperties": false, "type": "object", - "required": ["id", "kind", "questionTitle", "options", "correctAnswerId"], + "required": ["id", "kind", "questionTitle", "options"], "properties": { "id": { "minLength": 1, @@ -2222,15 +2244,22 @@ "type": ["null", "string"] }, "displayType": { - "title": "MultipleChoiceDisplayType", "anyOf": [ { - "const": "radio", - "type": "string" + "type": "null" }, { - "const": "dropdown", - "type": "string" + "title": "MultipleChoiceDisplayType", + "anyOf": [ + { + "const": "radio", + "type": "string" + }, + { + "const": "dropdown", + "type": "string" + } + ] } ] }, @@ -2305,14 +2334,14 @@ "type": "string" }, "middleText": { - "type": "string" + "type": ["null", "string"] }, "useSlider": { - "type": "boolean" + "type": ["null", "boolean"] }, "stepSize": { "minimum": 1, - "type": "number" + "type": ["null", "number"] }, "condition": { "anyOf": [ @@ -2748,7 +2777,6 @@ "title": "ParticipantProfileBase", "additionalProperties": false, "type": "object", - "required": ["pronouns", "avatar", "name"], "properties": { "pronouns": { "type": ["null", "string"] @@ -2857,13 +2885,20 @@ "type": "string" }, "condition": { - "title": "Condition", "anyOf": [ { - "$ref": "#/$defs/ComparisonCondition" + "type": "null" }, { - "$ref": "#/$defs/ConditionGroup" + "title": "Condition", + "anyOf": [ + { + "$ref": "#/$defs/ComparisonCondition" + }, + { + "$ref": "#/$defs/ConditionGroup" + } + ] } ] } @@ -2880,13 +2915,20 @@ "type": "string" }, "condition": { - "title": "Condition", "anyOf": [ { - "$ref": "#/$defs/ComparisonCondition" + "type": "null" }, { - "$ref": "#/$defs/ConditionGroup" + "title": "Condition", + "anyOf": [ + { + "$ref": "#/$defs/ComparisonCondition" + }, + { + "$ref": "#/$defs/ConditionGroup" + } + ] } ] } @@ -2903,13 +2945,20 @@ "type": "string" }, "condition": { - "title": "Condition", "anyOf": [ { - "$ref": "#/$defs/ComparisonCondition" + "type": "null" }, { - "$ref": "#/$defs/ConditionGroup" + "title": "Condition", + "anyOf": [ + { + "$ref": "#/$defs/ComparisonCondition" + }, + { + "$ref": "#/$defs/ConditionGroup" + } + ] } ] } @@ -2952,13 +3001,20 @@ "type": "boolean" }, "condition": { - "title": "Condition", "anyOf": [ { - "$ref": "#/$defs/ComparisonCondition" + "type": "null" }, { - "$ref": "#/$defs/ConditionGroup" + "title": "Condition", + "anyOf": [ + { + "$ref": "#/$defs/ComparisonCondition" + }, + { + "$ref": "#/$defs/ConditionGroup" + } + ] } ] } @@ -3003,13 +3059,20 @@ "$ref": "#/$defs/ShuffleConfig" }, "condition": { - "title": "Condition", "anyOf": [ { - "$ref": "#/$defs/ComparisonCondition" + "type": "null" }, { - "$ref": "#/$defs/ConditionGroup" + "title": "Condition", + "anyOf": [ + { + "$ref": "#/$defs/ComparisonCondition" + }, + { + "$ref": "#/$defs/ConditionGroup" + } + ] } ] } @@ -3021,48 +3084,62 @@ "type": "object", "properties": { "maxTokens": { - "type": "integer" + "type": ["null", "integer"] }, "stopSequences": { - "type": "array", - "items": { - "type": "string" - } + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] }, "temperature": { - "type": "number" + "type": ["null", "number"] }, "topP": { - "type": "number" + "type": ["null", "number"] }, "frequencyPenalty": { - "type": "number" + "type": ["null", "number"] }, "presencePenalty": { - "type": "number" + "type": ["null", "number"] }, "reasoningLevel": { - "title": "ReasoningLevel", "anyOf": [ { - "const": "off", - "type": "string" - }, - { - "const": "minimal", - "type": "string" - }, - { - "const": "low", - "type": "string" - }, - { - "const": "medium", - "type": "string" + "type": "null" }, { - "const": "high", - "type": "string" + "title": "ReasoningLevel", + "anyOf": [ + { + "const": "off", + "type": "string" + }, + { + "const": "minimal", + "type": "string" + }, + { + "const": "low", + "type": "string" + }, + { + "const": "medium", + "type": "string" + }, + { + "const": "high", + "type": "string" + } + ] } ] }, @@ -3076,24 +3153,27 @@ "type": "boolean" }, "providerOptions": { - "$ref": "#/$defs/ProviderOptionsMap" + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/ProviderOptionsMap" + } + ] }, "customRequestBodyFields": { - "type": "array", - "items": { - "additionalProperties": false, - "type": "object", - "required": ["name", "value"], - "properties": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - } + "anyOf": [ + { + "type": "null" }, - "title": "CustomRequestBodyField" - } + { + "type": "array", + "items": { + "$ref": "#/$defs/CustomRequestBodyField" + } + } + ] } } }, @@ -3485,6 +3565,20 @@ } } }, + "CustomRequestBodyField": { + "title": "CustomRequestBodyField", + "additionalProperties": false, + "type": "object", + "required": ["name", "value"], + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "StructuredOutputConfig": { "title": "StructuredOutputConfig", "additionalProperties": false, @@ -3512,7 +3606,14 @@ ] }, "schema": { - "$ref": "#/$defs/StructuredOutputSchema" + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/StructuredOutputSchema" + } + ] }, "appendToPrompt": { "type": "boolean" @@ -3576,22 +3677,43 @@ ] }, "description": { - "type": "string" + "type": ["null", "string"] }, "properties": { - "type": "array", - "items": { - "$ref": "#/$defs/StructuredOutputSchemaProperty" - } + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/StructuredOutputSchemaProperty" + } + } + ] }, "arrayItems": { - "$ref": "#/$defs/StructuredOutputSchema" + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/StructuredOutputSchema" + } + ] }, "enumItems": { - "type": "array", - "items": { - "type": "string" - } + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] } } }, @@ -3677,7 +3799,14 @@ ] }, "schema": { - "$ref": "#/$defs/StructuredOutputSchema" + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/StructuredOutputSchema" + } + ] }, "appendToPrompt": { "type": "boolean" @@ -3701,10 +3830,8 @@ "additionalProperties": false, "type": "object", "required": [ - "wordsPerMinute", "minMessagesBeforeResponding", "canSelfTriggerCalls", - "maxResponses", "initialMessage" ], "properties": { @@ -4131,34 +4258,7 @@ "cohortDefinitions": { "type": "array", "items": { - "additionalProperties": false, - "type": "object", - "required": ["id", "alias", "name"], - "properties": { - "id": { - "minLength": 1, - "type": "string" - }, - "alias": { - "minLength": 1, - "type": "string" - }, - "name": { - "minLength": 1, - "type": "string" - }, - "description": { - "type": "string" - }, - "generatedCohortId": { - "type": "string" - }, - "maxParticipantsPerCohort": { - "minimum": 1, - "type": "integer" - } - }, - "title": "CohortDefinition" + "$ref": "#/$defs/CohortDefinition" } } }, diff --git a/scripts/deliberate_lab/types.py b/scripts/deliberate_lab/types.py index 6549f8eaa..4d9c8d763 100644 --- a/scripts/deliberate_lab/types.py +++ b/scripts/deliberate_lab/types.py @@ -51,19 +51,6 @@ class ProlificConfig(BaseModel): bootedRedirectCode: str -class CohortDefinition(BaseModel): - model_config = ConfigDict( - extra="forbid", - populate_by_name=True, - ) - id: Annotated[str, Field(min_length=1)] - alias: Annotated[str, Field(min_length=1)] - name: Annotated[str, Field(min_length=1)] - description: str | None = None - generatedCohortId: str | None = None - maxParticipantsPerCohort: Annotated[int | None, Field(ge=1)] = None - - class CohortParticipantConfig(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -146,6 +133,19 @@ class BalanceAcross(StrEnum): cohort = "cohort" +class CohortDefinition(BaseModel): + model_config = ConfigDict( + extra="forbid", + populate_by_name=True, + ) + id: Annotated[str, Field(min_length=1)] + alias: Annotated[str, Field(min_length=1)] + name: Annotated[str, Field(min_length=1)] + description: str | None = None + generatedCohortId: str | None = None + maxParticipantsPerCohort: Annotated[int | None, Field(ge=1)] = None + + class StageTextConfig(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -623,15 +623,6 @@ class ReasoningLevel(StrEnum): high = "high" -class CustomRequestBodyField(BaseModel): - model_config = ConfigDict( - extra="forbid", - populate_by_name=True, - ) - name: str - value: str - - class GoogleThinkingLevel(StrEnum): minimal = "minimal" low = "low" @@ -730,6 +721,15 @@ class OllamaProviderOptions(BaseModel): numPredict: int | None = None +class CustomRequestBodyField(BaseModel): + model_config = ConfigDict( + extra="forbid", + populate_by_name=True, + ) + name: str + value: str + + class StructuredOutputType(StrEnum): NONE = "NONE" JSON_FORMAT = "JSON_FORMAT" @@ -1014,9 +1014,7 @@ class ModelGenerationConfig(BaseModel): topP: float | None = None frequencyPenalty: float | None = None presencePenalty: float | None = None - reasoningLevel: Annotated[ReasoningLevel | None, Field(title="ReasoningLevel")] = ( - None - ) + reasoningLevel: ReasoningLevel | None = None reasoningBudget: int | None = None includeReasoning: bool | None = None disableSafetyFilters: bool | None = None @@ -1107,7 +1105,7 @@ class StaticVariableConfig(BaseModel): scope: Scope definition: VariableDefinition value: str - cohortValues: Annotated[dict[str, str] | None, Field(title="CohortValues")] = None + cohortValues: dict[str, str] | None = None class Object(BaseModel): @@ -1240,9 +1238,7 @@ class MultipleChoiceSurveyQuestion(BaseModel): questionTitle: str options: list[MultipleChoiceItem] correctAnswerId: str | None = None - displayType: Annotated[ - MultipleChoiceDisplayType | None, Field(title="MultipleChoiceDisplayType") - ] = None + displayType: MultipleChoiceDisplayType | None = None condition: ComparisonCondition | ConditionGroup | None = None @@ -1375,9 +1371,7 @@ class TextPromptItem(BaseModel): ) type: Literal["TEXT"] = "TEXT" text: str - condition: Annotated[ - ComparisonCondition | ConditionGroup | None, Field(title="Condition") - ] = None + condition: ComparisonCondition | ConditionGroup | None = None class ProfileInfoPromptItem(BaseModel): @@ -1386,9 +1380,7 @@ class ProfileInfoPromptItem(BaseModel): populate_by_name=True, ) type: Literal["PROFILE_INFO"] = "PROFILE_INFO" - condition: Annotated[ - ComparisonCondition | ConditionGroup | None, Field(title="Condition") - ] = None + condition: ComparisonCondition | ConditionGroup | None = None class ProfileContextPromptItem(BaseModel): @@ -1397,9 +1389,7 @@ class ProfileContextPromptItem(BaseModel): populate_by_name=True, ) type: Literal["PROFILE_CONTEXT"] = "PROFILE_CONTEXT" - condition: Annotated[ - ComparisonCondition | ConditionGroup | None, Field(title="Condition") - ] = None + condition: ComparisonCondition | ConditionGroup | None = None class StageContextPromptItem(BaseModel): @@ -1414,9 +1404,7 @@ class StageContextPromptItem(BaseModel): includeHelpText: bool includeStageDisplay: bool includeParticipantAnswers: bool - condition: Annotated[ - ComparisonCondition | ConditionGroup | None, Field(title="Condition") - ] = None + condition: ComparisonCondition | ConditionGroup | None = None class PromptItemGroup(BaseModel): @@ -1434,9 +1422,7 @@ class PromptItemGroup(BaseModel): | PromptItemGroup ] shuffleConfig: ShuffleConfig | None = None - condition: Annotated[ - ComparisonCondition | ConditionGroup | None, Field(title="Condition") - ] = None + condition: ComparisonCondition | ConditionGroup | None = None class StructuredOutputConfig(BaseModel): diff --git a/utils/src/experiment.validation.ts b/utils/src/experiment.validation.ts index 77d86c854..16abb222f 100644 --- a/utils/src/experiment.validation.ts +++ b/utils/src/experiment.validation.ts @@ -70,7 +70,7 @@ export const CohortDefinitionSchema = Type.Object( generatedCohortId: Type.Optional(Type.String()), maxParticipantsPerCohort: Type.Optional(Type.Integer({minimum: 1})), }, - strict, + {$id: 'CohortDefinition', ...strict}, ); export const ExperimentTemplateSchema = Type.Object( diff --git a/utils/src/participant.validation.ts b/utils/src/participant.validation.ts index a15c40c75..b8220355c 100644 --- a/utils/src/participant.validation.ts +++ b/utils/src/participant.validation.ts @@ -12,9 +12,9 @@ const strict = {additionalProperties: false} as const; /** ParticipantProfileBase input validation. */ export const ParticipantProfileBaseData = Type.Object( { - pronouns: Type.Union([Type.Null(), Type.String()]), - avatar: Type.Union([Type.Null(), Type.String()]), - name: Type.Union([Type.Null(), Type.String()]), + pronouns: Type.Optional(Type.Union([Type.Null(), Type.String()])), + avatar: Type.Optional(Type.Union([Type.Null(), Type.String()])), + name: Type.Optional(Type.Union([Type.Null(), Type.String()])), }, {$id: 'ParticipantProfileBase', ...strict}, ); diff --git a/utils/src/prompt.validation.ts b/utils/src/prompt.validation.ts index c52d7bd62..13239a26d 100644 --- a/utils/src/prompt.validation.ts +++ b/utils/src/prompt.validation.ts @@ -40,7 +40,7 @@ export const PromptItemTypeData = Type.Union( /** Base prompt item fields */ const BasePromptItemFields = { - condition: Type.Optional(ConditionSchema), + condition: Type.Optional(Type.Union([Type.Null(), ConditionSchema])), }; /** Text prompt item */ @@ -128,10 +128,10 @@ export const PromptItemData = Type.Union([ /** Agent chat settings - defined here to avoid circular imports with agent.validation.ts */ export const AgentChatSettingsData = Type.Object( { - wordsPerMinute: Type.Union([Type.Number(), Type.Null()]), + wordsPerMinute: Type.Optional(Type.Union([Type.Number(), Type.Null()])), minMessagesBeforeResponding: Type.Integer(), canSelfTriggerCalls: Type.Boolean(), - maxResponses: Type.Union([Type.Integer(), Type.Null()]), + maxResponses: Type.Optional(Type.Union([Type.Integer(), Type.Null()])), initialMessage: Type.String(), }, {$id: 'AgentChatSettings', ...strict}, diff --git a/utils/src/providers.validation.ts b/utils/src/providers.validation.ts index d7c7572dd..6a83860ee 100644 --- a/utils/src/providers.validation.ts +++ b/utils/src/providers.validation.ts @@ -182,29 +182,35 @@ export const CustomRequestBodyFieldData = Type.Object( name: Type.String(), value: Type.String(), }, - strict, + {$id: 'CustomRequestBodyField', ...strict}, ); /** Model generation config */ export const ModelGenerationConfigData = Type.Object( { // Universal settings - maxTokens: Type.Optional(Type.Integer()), - stopSequences: Type.Optional(Type.Array(Type.String())), - temperature: Type.Optional(Type.Number()), - topP: Type.Optional(Type.Number()), - frequencyPenalty: Type.Optional(Type.Number()), - presencePenalty: Type.Optional(Type.Number()), + maxTokens: Type.Optional(Type.Union([Type.Null(), Type.Integer()])), + stopSequences: Type.Optional( + Type.Union([Type.Null(), Type.Array(Type.String())]), + ), + temperature: Type.Optional(Type.Union([Type.Null(), Type.Number()])), + topP: Type.Optional(Type.Union([Type.Null(), Type.Number()])), + frequencyPenalty: Type.Optional(Type.Union([Type.Null(), Type.Number()])), + presencePenalty: Type.Optional(Type.Union([Type.Null(), Type.Number()])), // Reasoning settings - reasoningLevel: Type.Optional(ReasoningLevelData), + reasoningLevel: Type.Optional( + Type.Union([Type.Null(), ReasoningLevelData]), + ), reasoningBudget: Type.Optional(Type.Union([Type.Integer(), Type.Null()])), includeReasoning: Type.Optional(Type.Boolean()), disableSafetyFilters: Type.Optional(Type.Boolean()), // Provider-specific options - providerOptions: Type.Optional(ProviderOptionsMapData), + providerOptions: Type.Optional( + Type.Union([Type.Null(), ProviderOptionsMapData]), + ), // Legacy customRequestBodyFields: Type.Optional( - Type.Array(CustomRequestBodyFieldData), + Type.Union([Type.Null(), Type.Array(CustomRequestBodyFieldData)]), ), }, {$id: 'ModelGenerationConfig', ...strict}, diff --git a/utils/src/shared.validation.ts b/utils/src/shared.validation.ts index 3e57d00d6..0f241bb37 100644 --- a/utils/src/shared.validation.ts +++ b/utils/src/shared.validation.ts @@ -31,14 +31,12 @@ export const PermissionsConfigSchema = Type.Object({ /** CohortParticipantConfig input validation. */ export const CohortParticipantConfigSchema = Type.Object( { - minParticipantsPerCohort: Type.Union([ - Type.Null(), - Type.Integer({minimum: 0}), - ]), - maxParticipantsPerCohort: Type.Union([ - Type.Null(), - Type.Integer({minimum: 1}), - ]), + minParticipantsPerCohort: Type.Optional( + Type.Union([Type.Null(), Type.Integer({minimum: 0})]), + ), + maxParticipantsPerCohort: Type.Optional( + Type.Union([Type.Null(), Type.Integer({minimum: 1})]), + ), includeAllParticipantsInCohortCount: Type.Boolean(), botProtection: Type.Boolean(), }, diff --git a/utils/src/stages/chat_stage.validation.ts b/utils/src/stages/chat_stage.validation.ts index 79ff2ef30..7695055bf 100644 --- a/utils/src/stages/chat_stage.validation.ts +++ b/utils/src/stages/chat_stage.validation.ts @@ -62,14 +62,12 @@ export const ChatStageConfigData = Type.Composite( Type.Object( { kind: Type.Literal(StageKind.CHAT), - timeLimitInMinutes: Type.Union([ - Type.Integer({minimum: 1}), - Type.Null(), - ]), - timeMinimumInMinutes: Type.Union([ - Type.Integer({minimum: 1}), - Type.Null(), - ]), + timeLimitInMinutes: Type.Optional( + Type.Union([Type.Integer({minimum: 1}), Type.Null()]), + ), + timeMinimumInMinutes: Type.Optional( + Type.Union([Type.Integer({minimum: 1}), Type.Null()]), + ), discussions: Type.Array(ChatDiscussionData), }, strict, diff --git a/utils/src/stages/info_stage.validation.ts b/utils/src/stages/info_stage.validation.ts index 27b7b9c0d..f56cf4509 100644 --- a/utils/src/stages/info_stage.validation.ts +++ b/utils/src/stages/info_stage.validation.ts @@ -18,7 +18,7 @@ export const InfoStageConfigData = Type.Composite( kind: Type.Literal(StageKind.INFO), infoLines: Type.Array(Type.String()), // Optional YouTube video ID to display - youtubeVideoId: Type.Optional(Type.String()), + youtubeVideoId: Type.Optional(Type.Union([Type.Null(), Type.String()])), }, strict, ), diff --git a/utils/src/stages/private_chat_stage.validation.ts b/utils/src/stages/private_chat_stage.validation.ts index 1e6eb6709..2436dd684 100644 --- a/utils/src/stages/private_chat_stage.validation.ts +++ b/utils/src/stages/private_chat_stage.validation.ts @@ -19,14 +19,12 @@ export const PrivateChatStageConfigData = Type.Composite( kind: Type.Literal(StageKind.PRIVATE_CHAT), // If defined, ends chat after specified time limit // (starting from when the first message is sent) - timeLimitInMinutes: Type.Union([ - Type.Integer({minimum: 1}), - Type.Null(), - ]), - timeMinimumInMinutes: Type.Union([ - Type.Integer({minimum: 1}), - Type.Null(), - ]), + timeLimitInMinutes: Type.Optional( + Type.Union([Type.Integer({minimum: 1}), Type.Null()]), + ), + timeMinimumInMinutes: Type.Optional( + Type.Union([Type.Integer({minimum: 1}), Type.Null()]), + ), // If true, requires participant to go back and forth with mediator(s) // (rather than being able to send multiple messages at once) isTurnBasedChat: Type.Optional(Type.Boolean()), diff --git a/utils/src/stages/survey_stage.validation.ts b/utils/src/stages/survey_stage.validation.ts index 7c5f1f76c..0fc216901 100644 --- a/utils/src/stages/survey_stage.validation.ts +++ b/utils/src/stages/survey_stage.validation.ts @@ -53,9 +53,14 @@ export const MultipleChoiceSurveyQuestionData = Type.Object( kind: Type.Literal(SurveyQuestionKind.MULTIPLE_CHOICE), questionTitle: Type.String(), options: Type.Array(MultipleChoiceItemData), - correctAnswerId: Type.Union([Type.Null(), Type.String()]), + correctAnswerId: Type.Optional(Type.Union([Type.Null(), Type.String()])), displayType: Type.Optional( - Type.Enum(MultipleChoiceDisplayType, {$id: 'MultipleChoiceDisplayType'}), + Type.Union([ + Type.Null(), + Type.Enum(MultipleChoiceDisplayType, { + $id: 'MultipleChoiceDisplayType', + }), + ]), ), condition: Type.Optional(Type.Union([Type.Null(), ConditionSchema])), }, @@ -72,9 +77,11 @@ export const ScaleSurveyQuestionData = Type.Object( upperText: Type.String(), lowerValue: Type.Number(), lowerText: Type.String(), - middleText: Type.Optional(Type.String()), - useSlider: Type.Optional(Type.Boolean()), - stepSize: Type.Optional(Type.Number({minimum: 1})), + middleText: Type.Optional(Type.Union([Type.Null(), Type.String()])), + useSlider: Type.Optional(Type.Union([Type.Null(), Type.Boolean()])), + stepSize: Type.Optional( + Type.Union([Type.Null(), Type.Number({minimum: 1})]), + ), condition: Type.Optional(Type.Union([Type.Null(), ConditionSchema])), }, {$id: 'ScaleSurveyQuestion', ...strict}, diff --git a/utils/src/structured_output.validation.ts b/utils/src/structured_output.validation.ts index d24a71f5d..8d9d4dc76 100644 --- a/utils/src/structured_output.validation.ts +++ b/utils/src/structured_output.validation.ts @@ -51,20 +51,26 @@ export const StructuredOutputSchemaData = Type.Recursive( Type.Object( { type: StructuredOutputDataTypeData, - description: Type.Optional(Type.String()), + description: Type.Optional(Type.Union([Type.Null(), Type.String()])), properties: Type.Optional( - Type.Array( - Type.Object( - { - name: Type.String(), - schema: This, - }, - {$id: 'StructuredOutputSchemaProperty', ...strict}, + Type.Union([ + Type.Null(), + Type.Array( + Type.Object( + { + name: Type.String(), + schema: This, + }, + {$id: 'StructuredOutputSchemaProperty', ...strict}, + ), ), - ), + ]), + ), + + arrayItems: Type.Optional(Type.Union([Type.Null(), This])), + enumItems: Type.Optional( + Type.Union([Type.Null(), Type.Array(Type.String())]), ), - arrayItems: Type.Optional(This), - enumItems: Type.Optional(Type.Array(Type.String())), }, strict, ), @@ -79,7 +85,9 @@ export const StructuredOutputConfigData = Type.Object( { enabled: Type.Boolean(), type: StructuredOutputTypeData, - schema: Type.Optional(StructuredOutputSchemaData), + schema: Type.Optional( + Type.Union([Type.Null(), StructuredOutputSchemaData]), + ), appendToPrompt: Type.Boolean(), }, {$id: 'StructuredOutputConfig', ...strict}, @@ -99,7 +107,9 @@ export const ChatMediatorStructuredOutputConfigData = Type.Object( { enabled: Type.Boolean(), type: StructuredOutputTypeData, - schema: Type.Optional(StructuredOutputSchemaData), + schema: Type.Optional( + Type.Union([Type.Null(), StructuredOutputSchemaData]), + ), appendToPrompt: Type.Boolean(), shouldRespondField: Type.String(), messageField: Type.String(), diff --git a/utils/src/variables.validation.ts b/utils/src/variables.validation.ts index 14ead7d1e..eae992b17 100644 --- a/utils/src/variables.validation.ts +++ b/utils/src/variables.validation.ts @@ -97,7 +97,9 @@ export const StaticVariableConfigData = Type.Composite( default: VariableConfigType.STATIC, }), value: Type.String(), - cohortValues: Type.Optional(Type.Record(Type.String(), Type.String())), + cohortValues: Type.Optional( + Type.Union([Type.Null(), Type.Record(Type.String(), Type.String())]), + ), }, strict, ),